Compare commits

..

2 Commits

Author SHA1 Message Date
rsync-bugs
594fe5e1cc preparing for release of 2.5.7 2003-12-04 04:27:22 +00:00
Martin Pool
9fb21d2882 Buffer management fix.
Prepare for 2.5.7 release.
2003-12-04 04:23:29 +00:00
80 changed files with 5101 additions and 6929 deletions

View File

@@ -1,6 +1,6 @@
ID
Makefile
autom4te*.cache
autom4te.cache
confdefs.h
config.cache
config.h
@@ -21,3 +21,4 @@ tls
trimslash
t_unsafe
wildtest
zlib/dummy

View File

@@ -48,6 +48,10 @@ completely implement the "New Sockets" API.
<http://www.ipv6.org/impl/mac.html> says that Apple do not support
IPv6 yet. If your build fails, try again with --disable-ipv6.
There is an unresolved problem with the OSX implimentation
of setgroups causing rsyncd to fail. The workaround is to
#undef HAVE_SETGROUPS in config.h
IBM AIX NOTES
-------------

View File

@@ -25,9 +25,9 @@ VERSION=@VERSION@
.SUFFIXES:
.SUFFIXES: .c .o
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h lib/pool_alloc.h
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
lib/permstring.o lib/pool_alloc.o @LIBOBJS@
lib/permstring.o @LIBOBJS@
ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \
zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
zlib/zutil.o zlib/adler32.o

229
NEWS
View File

@@ -1,190 +1,99 @@
NEWS for rsync 2.6.1 (26 Apr 2004)
Protocol: 28 (changed)
Changes since 2.6.0:
NEWS for rsync version 2.5.7:
SECURITY FIXES:
SECURITY:
- 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".
* Fix buffer handling bugs. (Andrew Tridgell, Martin Pool, Paul
Russell, Andrea Barisani)
NEWS for rsync version 2.5.6, aka the dwd-between-jobs release
Changes since version 2.5.5:
ENHANCEMENTS:
- Lower memory use, more optimal transfer of data over the socket,
and lower CPU usage (see the INTERNAL section for details).
* The --delete-after option now implies --delete. (Wayne Davison)
- The RSYNC_PROXY environment variable can now contain a
"USER:PASS@" prefix before the "HOST:PORT" information.
(Bardur Arantsson)
* The --suffix option can now be used with --backup-dir. (Michael
Zimmerman)
- 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.
* Combining "::" syntax with the -rsh/-e option now uses the
specified remote-shell as a transport to talk to a (newly-spawned)
server-daemon. This allows someone to use daemon features, such
as modules, over a secure protocol, such as ssh. (JD Paul)
- The configure script now accepts --with-rsyncd-conf=PATH to
override the default value of the /etc/rsyncd.conf file.
* The rsync:// syntax for daemon connections is now accepted in the
destination field.
- Added a couple extra diffs in the "patches" dir, removed the ones
that got applied, and rebuilt the rest.
* If the file name given to --include-from or --exclude-from is "-",
rsync will read from standard input. (J.W. Schultz)
- Documentation changes now attempt to describe some often mis-
understood features more clearly.
* New option --link-dest which is like --compare-dest except that
unchanged files are hard-linked in to the destination directory.
(J.W. Schultz)
* Don't report an error if an excluded file disappears during an
rsync run. (Eugene Chupriyanov and Bo Kersey)
* Added .svn to --cvs-exclude list to support subversion. (Jon
Middleton)
* Properly support IPv6 addresses in the rsyncd.conf "hosts allow"
and "hosts deny" fields. (Hideaki Yoshifuji)
* Changed exclude file handling to permit DOS or MAC style line
terminations. (J.W. Schultz)
* Ignore errors from chmod when -p/-a/--preserve-perms is not set.
(Dave Dykstra)
BUG FIXES:
* Fix "forward name lookup failed" errors on AIX 4.3.3. (John
L. Allen, Martin Pool)
- 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.
* Generate each file's rolling-checksum data as we send it, not
in a separate (memory-eating) pass before hand. This prevents
timeout errors on really large files. (Stefan Nehlsen)
- 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.
* Fix compilation on Tru64. (Albert Chin, Zoong Pham)
- 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.
* Better handling of some client-server errors. (Martin Pool)
- Fixed a byte-order problem in --batch-mode on big-endian machines.
(Jay Fenlason)
* Fixed a crash that would occur when sending a list of files that
contains a duplicate name (if it sorts to the end of the file
list) and using --delete. (Wayne Davison)
- Fixed configure bug when running "./configure --disable-ipv6".
* Fixed the file-name duplicate-removal code when dealing with multiple
dups in a row. (Wayne Davison)
- Fixed "make test" bug when build dir is not the source dir.
* Fixed a bug that caused rsync to lose the exit status of its child
processes and sometimes return an exit code of 0 instead of showing
an error. (David R. Staples, Dave Dykstra)
- 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.
* Fixed bug in --copy-unsafe-links that caused it to be completely
broken. (Dave Dykstra)
- 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).
* Prevent infinite recursion in cleanup code under certain circumstances.
(Sviatoslav Sviridov and Marc Espie)
- 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 a bug that prevented rsync from creating intervening directories
when --relative-paths/-R is set. (Craig Barratt)
- 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 compilation problem on Tru64 Unix (having to do with
sockaddr.sa_len and sockaddr.sin_len).
- 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.
* Prevent "Connection reset by peer" messages from Cygwin. (Randy O'Meara)
INTERNAL:
- Most of the I/O is now buffered, which results in a pretty large
speedup when running under MS Windows. (Craig Barratt)
* Many code cleanups and improved internal documentation. (Martin
Pool, Nelson Beebe)
- Optimizations to the name-handling/comparing code have made some
significant reductions in user-CPU time for large file sets.
* Portability fixes. (Dave Dykstra and Wayne Davison)
- Some cleanup of the variable types make the code more consistent.
* More test cases. (Martin Pool)
- Reduced memory requirements of hard link preservation.
(J.W. Schultz)
* Some test-case fixes. (Brian Poole, Wayne Davison)
- Implemented a new algorithm for hard-link handling that speeds up
the code significantly. (J.W. Schultz and Wayne Davison)
* Updated included popt to the latest vendor drop, version 1.6.4.
(Jos Backus)
- 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.)
* Updated config.guess and config.sub to latest versions; this
means rsync should build on more platforms. (Paul Green)

389
OLDNEWS
View File

@@ -1,252 +1,5 @@
NEWS for rsync 2.6.0 (1 Jan 2004)
Protocol: 27 (changed)
Changes since 2.5.7:
ENHANCEMENTS:
* "ssh" is now the default remote shell for rsync. If you want to
change this, configure like this: "./configure --with-rsh=rsh".
* Added --files-from, --no-relative, --no-implied-dirs, and --from0.
Note that --from0 affects the line-ending character for all the
files read by the --*-from options. (Wayne Davison)
* Length of csum2 is now per-file starting with protocol version
27. (J.W. Schultz)
* Per-file dynamic block size is now sqrt(file length). The
per-file checksum size is determined according to an algorithm
provided by Donovan Baarda which reduces the probability of rsync
algorithm corrupting data and falling back using the whole md4
checksums. (J.W. Schultz, Donovan Baarda)
* The --stats option no longer includes the (debug) malloc summary
unless the verbose option was specified at least twice.
* Added a new error/warning code for when files vanish from the
sending side. Made vanished source files not interfere with the
file-deletion pass when --delete-after was specified.
* Various trailing-info sections are now preceded by a newline.
BUG FIXES:
* Fixed several exclude/include matching bugs when using wild-cards.
This has a several user-visible effects, all of which make the
matching more consistent and intuitive. This should hopefully not
cause anyone problems since it makes the matching work more like
what people are expecting. (Wayne Davison)
- A pattern with a "**" no longer causes a "*" to match slashes.
For example, with "/*/foo/**", "foo" must be 2 levels deep.
[If your string has BOTH "*" and "**" wildcards, changing the
"*" wildcards to "**" will provide the old behavior in all
versions.]
- "**/foo" now matches at the base of the transfer (like /foo
does). [Use "/**/foo" to get the old behavior in all versions.]
- A non-anchored wildcard term floats to match beyond the base of
the transfer. E.g. "CVS/R*" matches at the end of the path,
just like the non-wildcard term "CVS/Root" does. [Use "/CVS/R*"
to get the old behavior in all versions.]
- Including a "**" in the match term causes it to be matched
against the entire path, not just the name portion, even if
there aren't any interior slashes in the term. E.g. "foo**bar"
would exclude "/path/foo-bar" (just like before) as well as
"/foo-path/baz-bar" (unlike before). [Use "foo*bar" to get the
old behavior in all versions.]
* The exclude list specified in the daemon's config file is now
properly applied to the pulled items no matter how deep the
user's file-args are in the source tree. (Wayne Davison)
* For protocol version >= 27, mdfour_tail() is called when the
block size (including checksum_seed) is a multiple of 64.
Previously it was not called, giving the wrong MD4 checksum.
(Craig Barratt)
* For protocol version >= 27, a 64 bit bit counter is used in
mdfour.c as required by the RFC. Previously only a 32 bit bit
counter was used, causing incorrect MD4 file checksums for
file sizes >= 512MB - 4. (Craig Barratt)
* Fixed a crash bug when interacting with older rsync versions and
multiple files of the same name are destined for the same dir.
(Wayne Davison)
* Keep tmp names from overflowing MAXPATHLEN.
* Make --link-dest honor the absence of -p, -o, and -g.
* Made rsync treat a trailing slash in the destination in a more
consistent manner.
* Fixed file I/O error detection. (John Van Essen)
* Fixed bogus "malformed address {hostname}" message in rsyncd log
when checking IP address against hostnames from "hosts allow"
and "hosts deny" parameters in config file.
* Print heap statistics when verbose >= 2 instead of when >= 1.
* Fixed a compression (-z) bug when syncing a mostly-matching file
that contains already-compressed data. (Yasuoka Masahiko and
Wayne Davison)
* Fixed a bug in the --backup code that could cause deleted files
to not get backed up.
* When the backup code makes new directories, create them with mode
0700 instead of 0755 (since the directory permissions in the
backup tree are not yet copied from the main tree).
* Call setgroups() in a more portable manner.
* Improved file-related error messages to better indicate exactly
what pathname failed. (Wayne Davison)
* Fixed some bugs in the handling of --delete and --exclude when
using the --relative (-R) option. (Wayne Davison)
* Fixed bug that prevented regular files from replacing
special files and caused a directory in --link-dest or
--compare-dest to block the creation of a file with the
same path. A directory still cannot be replaced by a
regular file unless --delete specified. (J.W. Schultz)
* Detect and report when open or opendir succeed but read and
readdir fail caused by network filesystem issues and truncated
files. (David Norwood, Michael Brown, J.W. Schultz)
* Added a fix that should give ssh time to restore the tty settings
if the user presses Ctrl-C at an ssh password prompt.
INTERNAL:
* Eliminated vestigial support for old versions that we stopped
supporting. (J.W. Schultz)
* Simplified some of the option-parsing code. (Wayne Davison)
* Some cleanup made to the exclude code, as well as some new
defines added to enhance readability. (Wayne Davison)
* Changed the protocol-version code so that it can interact at a
lower protocol level than the maximum supported by both sides.
Added an undocumented option, --protocol=N, to force the value
we advertise to the other side (primarily for testing purposes).
(Wayne Davison)
NEWS for rsync 2.5.7 (4 Dec 2003)
Protocol: 26 (unchanged)
Changes since 2.5.6:
SECURITY FIXES:
* Fix buffer handling bugs. (Andrew Tridgell, Martin Pool, Paul
Russell, Andrea Barisani)
NEWS for rsync 2.5.6, aka "the dwd-between-jobs release" (26 Jan 2003)
Protocol: 26 (unchanged)
Changes since 2.5.5:
ENHANCEMENTS:
* The --delete-after option now implies --delete. (Wayne Davison)
* The --suffix option can now be used with --backup-dir. (Michael
Zimmerman)
* Combining "::" syntax with the -rsh/-e option now uses the
specified remote-shell as a transport to talk to a (newly-spawned)
server-daemon. This allows someone to use daemon features, such
as modules, over a secure protocol, such as ssh. (JD Paul)
* The rsync:// syntax for daemon connections is now accepted in the
destination field.
* If the file name given to --include-from or --exclude-from is "-",
rsync will read from standard input. (J.W. Schultz)
* New option --link-dest which is like --compare-dest except that
unchanged files are hard-linked in to the destination directory.
(J.W. Schultz)
* Don't report an error if an excluded file disappears during an
rsync run. (Eugene Chupriyanov and Bo Kersey)
* Added .svn to --cvs-exclude list to support subversion. (Jon
Middleton)
* Properly support IPv6 addresses in the rsyncd.conf "hosts allow"
and "hosts deny" fields. (Hideaki Yoshifuji)
* Changed exclude file handling to permit DOS or MAC style line
terminations. (J.W. Schultz)
* Ignore errors from chmod when -p/-a/--preserve-perms is not set.
(Dave Dykstra)
BUG FIXES:
* Fix "forward name lookup failed" errors on AIX 4.3.3. (John
L. Allen, Martin Pool)
* Generate each file's rolling-checksum data as we send it, not
in a separate (memory-eating) pass before hand. This prevents
timeout errors on really large files. (Stefan Nehlsen)
* Fix compilation on Tru64. (Albert Chin, Zoong Pham)
* Better handling of some client-server errors. (Martin Pool)
* Fixed a crash that would occur when sending a list of files that
contains a duplicate name (if it sorts to the end of the file
list) and using --delete. (Wayne Davison)
* Fixed the file-name duplicate-removal code when dealing with multiple
dups in a row. (Wayne Davison)
* Fixed a bug that caused rsync to lose the exit status of its child
processes and sometimes return an exit code of 0 instead of showing
an error. (David R. Staples, Dave Dykstra)
* Fixed bug in --copy-unsafe-links that caused it to be completely
broken. (Dave Dykstra)
* Prevent infinite recursion in cleanup code under certain circumstances.
(Sviatoslav Sviridov and Marc Espie)
* Fixed a bug that prevented rsync from creating intervening directories
when --relative-paths/-R is set. (Craig Barratt)
* Prevent "Connection reset by peer" messages from Cygwin. (Randy O'Meara)
INTERNAL:
* Many code cleanups and improved internal documentation. (Martin
Pool, Nelson Beebe)
* Portability fixes. (Dave Dykstra and Wayne Davison)
* More test cases. (Martin Pool)
* Some test-case fixes. (Brian Poole, Wayne Davison)
* Updated included popt to the latest vendor drop, version 1.6.4.
(Jos Backus)
* Updated config.guess and config.sub to latest versions; this
means rsync should build on more platforms. (Paul Green)
NEWS for rsync 2.5.5, aka Snowy River (2 Apr 2002)
Protocol: 26 (unchanged)
Changes since 2.5.4:
rsync 2.5.5 "Snowy River" (2 April 2002)
protocol: 26 (unchanged)
ENHANCEMENTS:
@@ -285,15 +38,16 @@ Changes since 2.5.4:
* Improved network error handling. (Greg A. Woods)
NEWS for rsync 2.5.4, aka "Imitation lizard skin" (13 Mar 2002)
Protocol: 26 (unchanged)
Changes since 2.5.3:
rsync 2.5.4 (13 March 2002)
protocol: 26 (unchanged)
"Imitation lizard skin"
BUG FIXES:
* Additional fix for zlib double-free bug. (Martin Pool, Andrew
Tridgell) (CVE CAN-2002-0059)
ENHANCEMENTS:
* Merge in changes from zlib 1.1.3 to zlib 1.1.4. (Jos Backus)
@@ -303,9 +57,10 @@ Changes since 2.5.3:
* Additional test cases for --compress. (Martin Pool)
NEWS for rsync 2.5.3, aka "Happy 26" (11 Mar 2002)
Protocol: 26 (unchanged)
Changes since 2.5.2:
rsync 2.5.3 (11 March 2002)
protocol: 26 (unchanged)
"Happy 26"
SECURITY FIXES:
@@ -318,7 +73,7 @@ Changes since 2.5.2:
* Fix zlib double-free bug. (Owen Taylor, Mark J Cox) (CVE
CAN-2002-0059)
* Fixed problem that in many cases caused the error message
* Fixed problem that in many cases caused the error message
unexpected read size of 0 in map_ptr
and resulted in the wrong data being copied.
@@ -339,7 +94,7 @@ Changes since 2.5.2:
* Merge in changes from zlib 1.1.2 to zlib 1.1.3. (Note that
rsync still uses a custom version of zlib; you can not just link
against a system library. See zlib/README.rsync)
* Command to initiate connections is only shown with -vv, rather
than -v as in 2.5.2. Output from plain -v is more similar to
what was historically used so as not to break scripts that try
@@ -353,10 +108,8 @@ Changes since 2.5.2:
* If the daemon is unable to fork a child to accept a connection,
print an error message. (Colin Walters)
NEWS for rsync 2.5.2 (26 Jan 2002)
Protocol: 26 (changed)
Changes since 2.5.1:
rsync 2.5.2 (26 Jan 2002)
protocol: 26 (changed)
SECURITY FIXES:
@@ -383,7 +136,7 @@ Changes since 2.5.1:
connection.
* --statistics now shows memory heap usage on platforms that
support mallinfo().
support mallinfo().
* "The Ted T'so school of program optimization": make progress
visible and people will think it's faster. (With --progress,
@@ -392,17 +145,15 @@ Changes since 2.5.1:
* Improvements to batch mode support. This is still experimental
but testing would be welcome. (Jos Backus)
* New --ignore-existing option, patch previously distributed with
Vipul's Razor. (Debian #124286)
NEWS for rsync 2.5.1 (3 Jan 2002)
Protocol: 25 (unchanged)
Changes since 2.5.0:
BUG FIXES:
rsync 2.5.1 (2002-01-03)
protocol: 25 (unchanged)
BUG FIXES:
* Fix for segfault in --daemon mode configuration parser. (Paul
Mackerras)
@@ -424,19 +175,18 @@ Changes since 2.5.0:
ENHANCEMENTS:
* --progress and -P now show estimated data transfer rate (in a
multiple of bytes/s) and estimated time to completion. (Rik
Faith)
multiple of bytes/s) and estimated time to completion. (Rik
Faith)
* --no-detach option, required to run as a W32 service and also
useful when running on Unix under daemontools, AIX's SRC, or a
debugger. (Max Bowsher, Jos Backus)
useful when running on Unix under daemontools, AIX's SRC, or a
debugger. (Max Bowsher, Jos Backus)
* Clearer error messages for some conditions.
NEWS for rsync 2.5.0 (30 Nov 2001)
Protocol: 25 (changed)
Changes since 2.4.6:
rsync 2.5.0 (2001-11-30)
protocol: 25 (changed)
ANNOUNCEMENTS
@@ -498,7 +248,7 @@ Changes since 2.4.6:
* Attempt to fix error handling lockup bug.
* Give a non-0 exit code if *any* of the files we have been asked
to transfer fail to transfer.
to transfer fail to transfer
* For log messages containing ridiculously long strings that might
overflow a buffer rsync no longer aborts, but rather prints an
@@ -509,7 +259,7 @@ Changes since 2.4.6:
* Improved support for UNICOS (tested on Cray T3E and Cray SV1)
* autoconf2.52 (or later) is now required to rebuild the autoconf
scripts. It is not required to simply build rsync.
scripts. It is not required to simply build rsync.
* Platforms thought to work in this release:
@@ -552,46 +302,41 @@ Changes since 2.4.6:
build farm.
Partial Protocol History
RELEASE DATE VER. DATE OF COMMIT PROTOCOL
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
02 Apr 2002 2.5.5 26
13 Mar 2002 2.5.4 26
11 Mar 2002 2.5.3 26
26 Jan 2002 2.5.2 11 Jan 2002 26
03 Jan 2002 2.5.1 25
30 Nov 2001 2.5.0 23 Aug 2001 25
06 Sep 2000 2.4.6 24
19 Aug 2000 2.4.5 24
29 Jul 2000 2.4.4 24
09 Apr 2000 2.4.3 24
30 Mar 2000 2.4.2 24
30 Jan 2000 2.4.1 29 Jan 2000 24
29 Jan 2000 2.4.0 28 Jan 2000 23
25 Jan 2000 2.3.3 23 Jan 2000 22
08 Nov 1999 2.3.2 26 Jun 1999 21
06 Apr 1999 2.3.1 20
15 Mar 1999 2.3.0 15 Mar 1999 20
25 Nov 1998 2.2.1 19
03 Nov 1998 2.2.0 19
09 Sep 1998 2.1.1 19
20 Jul 1998 2.1.0 19
17 Jul 1998 2.0.19 19
18 Jun 1998 2.0.17 19
01 Jun 1998 2.0.16 19
27 May 1998 2.0.13 27 May 1998 19
26 May 1998 2.0.12 18
22 May 1998 2.0.11 18
18 May 1998 2.0.9 18 May 1998 18
17 May 1998 2.0.8 17
15 May 1998 2.0.1 17
14 May 1998 2.0.0 17
17 Apr 1998 1.7.4 17
13 Apr 1998 1.7.3 17
05 Apr 1998 1.7.2 17
26 Mar 1998 1.7.1 17
26 Mar 1998 1.7.0 26 Mar 1998 17 (MAX=30)
13 Jan 1998 1.6.9 13 Jan 1998 15 (MAX=20)
DATE RELEASE PROTOCOL
2003/01/26 20:11:16 release-2-5-6 26
2002/02/23 00:17:50 release-2-5-3 26
2002/01/25 23:00:21 release-2-5-2 26
2001/12/18 06:47:40 release-2-5-1 25
release-2-4-6 24
2000/08/16 08:34:18 release-2-4-5 24
2000/07/29 04:52:05 release-2-4-4 24
2000/03/30 14:15:00 release-2-4-2 24
2000/01/29 23:49:36 release-2-4-1 24
2000/01/29 02:56:37 release-2-4-0 23
release-2-3-3 21
1999/06/26 01:06:38 release-2-3-2 21
release-2-3-1 20
1999/03/15 21:17:59 release-2-3-0 20
1998/11/15 01:21:42 release-2-2-1 19
1998/11/03 07:08:28 release-2-2-0 19
1998/09/09 06:31:14 release-2-1-1 19
1998/07/17 14:43:05 release-2-0-19 19
1998/06/18 12:17:24 release-2-0-18 19
1998/06/18 09:51:56 release-2-0-17 19
1998/06/01 03:42:22 release-2-0-16 19
1998/05/27 13:47:34 release-2-0-13 19
1998/05/26 14:19:00 release-2-0-12 18
1998/05/21 05:55:33 release-2-0-11 18
1998/05/18 08:20:34 release-2-0-9 18
1998/05/17 05:56:33 release-2-0-8 17
1998/05/15 07:34:21 release-2-0-2 17
1998/05/13 15:44:11 release-2-0-0 17
1998/04/17 06:07:26 release-1-7-4 17
1998/04/05 06:43:55 release-1-7-2 17
1998/03/26 04:18:57 release-1-7-0 17 MAX=30
1998/01/13 15:57:32 release-1-6-9 15 MAX=20
1997/12/17 11:07:30 release-1-6-7 14
1997/12/15 18:36:21 release-1-6-4 14
* DATE OF COMMIT is the date the protocol change was committed to CVS.
* DATE OF COMMIT is the date the protocl change was committed
to cvs, not the release date.

1114
TODO
View File

File diff suppressed because it is too large Load Diff

11
acconfig.h Normal file
View File

@@ -0,0 +1,11 @@
#undef ino_t
#undef HAVE_CONNECT
#undef HAVE_SHORT_INO_T
#undef HAVE_GETOPT_LONG
#undef REPLACE_INET_NTOA
#undef REPLACE_INET_ATON
#undef HAVE_GETTIMEOFDAY_TZ
#undef ENABLE_IPV6
#undef HAVE_SOCKADDR_LEN
#undef HAVE_SOCKADDR_IN6_SCOPE_ID
#undef HAVE_SOCKETPAIR

View File

@@ -24,7 +24,7 @@
encode a buffer using base64 - simple and slow algorithm. null terminates
the result.
***************************************************************************/
void base64_encode(char *buf, int len, char *out)
static void base64_encode(char *buf, int len, char *out)
{
char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int bit_offset, byte_offset, idx, i;
@@ -33,7 +33,7 @@ void base64_encode(char *buf, int len, char *out)
memset(out, 0, bytes+1);
for (i = 0; i < bytes; i++) {
for (i=0;i<bytes;i++) {
byte_offset = (i*6)/8;
bit_offset = (i*6)%8;
if (bit_offset < 3) {
@@ -269,8 +269,7 @@ void auth_client(int fd, char *user, char *challenge)
char pass2[30];
extern char *password_file;
if (!user || !*user)
user = "nobody";
if (!user || !*user) return;
if (!(pass=getpassf(password_file)) && !(pass=getenv("RSYNC_PASSWORD"))) {
/* XXX: cyeoh says that getpass is deprecated, because

262
backup.c
View File

@@ -1,16 +1,16 @@
/*
/*
Copyright (C) Andrew Tridgell 1999
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.
@@ -23,8 +23,6 @@
extern int verbose;
extern int backup_suffix_len;
extern int backup_dir_len;
extern unsigned int backup_dir_remainder;
extern char backup_dir_buf[MAXPATHLEN];
extern char *backup_suffix;
extern char *backup_dir;
@@ -32,19 +30,17 @@ extern int am_root;
extern int preserve_devices;
extern int preserve_links;
extern int preserve_hard_links;
extern int orig_umask;
/* simple backup creates a backup with a suffix in the same directory */
static int make_simple_backup(char *fname)
{
char fnamebak[MAXPATHLEN];
if (stringjoin(fnamebak, sizeof fnamebak, fname, backup_suffix, NULL)
>= sizeof fnamebak) {
if (strlen(fname) + backup_suffix_len > MAXPATHLEN-1) {
rprintf(FERROR, "backup filename too long\n");
return 0;
}
snprintf(fnamebak, sizeof(fnamebak), "%s%s", fname, backup_suffix);
if (do_rename(fname, fnamebak) != 0) {
/* cygwin (at least version b19) reports EINVAL */
if (errno != ENOENT && errno != EINVAL) {
@@ -58,99 +54,151 @@ static int make_simple_backup(char *fname)
}
/* recursively make a directory path */
static int make_dir(char *name, int mask)
{
char newdir [MAXPATHLEN];
char *p, *d;
/* copy pathname over, look for last '/' */
for (p = d = newdir; *name; *d++ = *name++)
if (*name == '/')
p = d;
if (p == newdir)
return 0;
*p = 0;
/* make the new directory, if that fails then make its parent */
while (do_mkdir (newdir, mask) != 0)
if ((errno != ENOENT) || !make_dir (newdir, mask))
return 0;
return 1;
} /* make_dir */
/****************************************************************************
Create a directory given an absolute path, perms based upon another directory
path
****************************************************************************/
static int make_bak_dir(char *fullpath)
static int make_bak_dir(char *fname, char *bak_path)
{
STRUCT_STAT st;
char *rel = fullpath + backup_dir_len;
char *end = rel + strlen(rel);
char *p = end;
STRUCT_STAT *st2;
char fullpath[MAXPATHLEN];
extern int orig_umask;
char *p;
char *q;
while (strncmp(fullpath, "./", 2) == 0)
fullpath += 2;
while(strncmp(bak_path, "./", 2) == 0) bak_path += 2;
/* Try to find an existing dir, starting from the deepest dir. */
while (1) {
if (--p == fullpath) {
p += strlen(p);
goto failure;
}
if (*p == '/') {
*p = '\0';
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));
goto failure;
}
}
if(bak_path[strlen(bak_path)-1] != '/') {
snprintf(fullpath, sizeof(fullpath), "%s/", bak_path);
} else {
snprintf(fullpath, sizeof(fullpath), "%s", bak_path);
}
p = fullpath;
q = &fullpath[strlen(fullpath)]; /* End of bak_path string */
strcat(fullpath, fname);
/* Make all the dirs that we didn't find on the way here. */
while (1) {
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));
} else {
set_modtime(fullpath, st.st_mtime);
do_lchown(fullpath, st.st_uid, st.st_gid);
do_chmod(fullpath, st.st_mode);
/* Make the directories */
while ((p = strchr(p, '/'))) {
*p = 0;
if(do_lstat(fullpath, &st) != 0) {
do_mkdir(fullpath, 0777 & ~orig_umask);
if(p>q) {
if(do_lstat(q, &st) != 0) {
rprintf(FERROR, "make_bak_dir stat %s failed: %s\n",
full_fname(fullpath), strerror(errno));
} else {
st2 = &st;
set_modtime(fullpath, st2->st_mtime);
if(do_lchown(fullpath, st2->st_uid, st2->st_gid) != 0) {
rprintf(FERROR, "make_bak_dir chown %s failed: %s\n",
full_fname(fullpath), strerror(errno));
}
if(do_chmod(fullpath, st2->st_mode) != 0) {
rprintf(FERROR, "make_bak_dir failed to set permissions on %s: %s\n",
full_fname(fullpath), strerror(errno));
}
}
}
}
*p = '/';
p += strlen(p);
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));
goto failure;
}
p++;
}
return 0;
failure:
while (p != end) {
*p = '/';
p += strlen(p);
}
return -1;
}
/* robustly move a file, creating new directory structures if necessary */
static int robust_move(char *src, char *dst)
{
if (robust_rename(src, dst, 0755) < 0 && (errno != ENOENT
|| make_bak_dir(dst) < 0 || robust_rename(src, dst, 0755) < 0))
return -1;
return 0;
}
int keep_trying = 4;
int keep_path_extfs = 0;
int failed;
while (keep_trying) {
if (keep_path_extfs) {
failed = copy_file(src, dst, 0755);
if (!failed) {
do_unlink(src);
}
} else {
failed = robust_rename (src, dst);
}
if (failed) {
if (verbose > 2)
rprintf (FERROR, "robust_move failed: %s(%d)\n",
strerror (errno), errno);
switch (errno) {
/* external filesystem */
case EXDEV:
keep_path_extfs = 1;
keep_trying--;
break;
/* no directory to write to */
case ENOENT:
make_dir(dst, 0700);
keep_trying--;
break;
default:
keep_trying = 0;
} /* switch */
} else
keep_trying = 0;
} /* while */
return (!failed);
} /* robust_move */
/* If we have a --backup-dir, then we get here from make_backup().
* We will move the file to be deleted into a parallel directory tree. */
/* if we have a backup_dir, then we get here from make_backup().
We will move the file to be deleted into a parallel directory tree */
static int keep_backup(char *fname)
{
static int initialised;
char keep_name [MAXPATHLEN];
STRUCT_STAT st;
struct file_struct *file;
int kept = 0;
int ret_code;
if (!initialised) {
if (backup_dir_len && backup_dir[backup_dir_len - 1] == '/')
backup_dir[--backup_dir_len] = '\0';
if (verbose > 0)
rprintf (FINFO, "backup_dir is %s\n", backup_dir);
initialised = 1;
}
/* return if no file to keep */
#if SUPPORT_LINKS
if (do_lstat(fname, &st)) return 1;
if (do_lstat (fname, &st)) return 1;
#else
if (do_stat(fname, &st)) return 1;
if (do_stat (fname, &st)) return 1;
#endif
file = make_file(fname, NULL, NO_EXCLUDES);
@@ -159,24 +207,24 @@ static int keep_backup(char *fname)
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 (backup_dir_len+strlen(fname)+backup_suffix_len > MAXPATHLEN-1) {
rprintf (FERROR, "keep_backup filename too long\n");
return 0;
}
snprintf(keep_name, sizeof (keep_name), "%s/%s%s",
backup_dir, fname, backup_suffix);
#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) {
if(IS_DEVICE(file->mode)) {
if(am_root && preserve_devices) {
make_bak_dir(fname, backup_dir);
if(do_mknod(keep_name, file->mode, file->rdev) != 0) {
rprintf(FERROR, "mknod %s failed: %s\n",
full_fname(backup_dir_buf), strerror(errno));
} else if (verbose > 2) {
rprintf(FINFO,
"make_backup: DEVICE %s successful.\n",
fname);
full_fname(keep_name), strerror(errno));
} else if(verbose>2) {
rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname);
}
}
kept = 1;
@@ -184,13 +232,13 @@ static int keep_backup(char *fname)
}
#endif
if (!kept && S_ISDIR(file->mode)) {
if(!kept && S_ISDIR(file->mode)) {
/* make an empty directory */
make_bak_dir(backup_dir_buf);
do_mkdir(backup_dir_buf, file->mode);
make_bak_dir(fname, backup_dir);
do_mkdir(keep_name, file->mode);
ret_code = do_rmdir(fname);
if (verbose > 2) {
if(verbose>2) {
rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
full_fname(fname), ret_code);
}
@@ -198,50 +246,56 @@ static int keep_backup(char *fname)
}
#if SUPPORT_LINKS
if (!kept && preserve_links && S_ISLNK(file->mode)) {
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->link, keep_name)) {
if (verbose) {
rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
full_fname(backup_dir_buf), file->u.link);
full_fname(keep_name), file->link);
}
kept = 1;
}
make_bak_dir(backup_dir_buf);
if (do_symlink(file->u.link, backup_dir_buf) != 0) {
make_bak_dir(fname, backup_dir);
if(do_symlink(file->link, keep_name) != 0) {
rprintf(FERROR, "link %s -> %s : %s\n",
full_fname(backup_dir_buf), file->u.link, strerror(errno));
full_fname(keep_name), file->link, strerror(errno));
}
do_unlink(fname);
kept = 1;
}
#endif
if(!kept && preserve_hard_links && check_hard_link(file)) {
if(verbose > 1)
rprintf(FINFO, "%s is a hard link\n", f_name(file));
}
if (!kept && !S_ISREG(file->mode)) {
if(!kept && !S_ISREG(file->mode)) {
rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
fname);
fname);
}
/* move to keep tree if a file */
if (!kept) {
if (robust_move(fname, backup_dir_buf) != 0) {
if(!kept) {
if (!robust_move (fname, keep_name)) {
rprintf(FERROR, "keep_backup failed: %s -> \"%s\": %s\n",
full_fname(fname), backup_dir_buf, strerror(errno));
full_fname(fname), keep_name, strerror(errno));
}
}
set_perms(backup_dir_buf, file, NULL, 0);
free(file);
set_perms (keep_name, file, NULL, 0);
free_file (file);
free (file);
if (verbose > 1)
rprintf(FINFO, "keep_backup %s -> %s\n", fname, backup_dir_buf);
rprintf (FINFO, "keep_backup %s -> %s\n", fname, keep_name);
return 1;
}
} /* keep_backup */
/* main backup switch routine */
int make_backup(char *fname)
{
if (backup_dir)
return keep_backup(fname);
return make_simple_backup(fname);
return (keep_backup(fname));
else
return (make_simple_backup(fname));
}

530
batch.c
View File

@@ -1,5 +1,5 @@
/* -*- c-file-style: "linux" -*-
Weiss 1/1999
Batch utilities for rsync.
@@ -9,9 +9,6 @@
#include <time.h>
extern char *batch_prefix;
extern int csum_length;
extern int protocol_version;
extern struct stats stats;
struct file_list *batch_flist;
@@ -20,60 +17,122 @@ static char rsync_csums_file[] = ".rsync_csums";
static char rsync_delta_file[] = ".rsync_delta";
static char rsync_argvs_file[] = ".rsync_argvs";
static int f_csums = -1;
static int f_delta = -1;
static int fdb;
static int fdb_delta;
static int fdb_open;
static int fdb_close;
void write_batch_flist_info(int flist_count, struct file_struct **files)
void write_batch_flist_file(char *buff, int bytes_to_write)
{
char filename[MAXPATHLEN];
int i, f, save_pv;
int64 save_written;
stringjoin(filename, sizeof filename,
batch_prefix, rsync_flist_file, NULL);
if (fdb_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_flist_file, sizeof(filename));
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));
/*
* Open batch flist file for writing;
* create it if it doesn't exist
*/
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Write buffer to batch flist file */
if (write(fdb, buff, bytes_to_write) == -1) {
rprintf(FERROR, "Batch file %s write error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
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);
if (fdb_close) {
close(fdb);
}
send_file_entry(NULL, f, 0);
protocol_version = save_pv;
stats.total_written = save_written;
close(f);
}
void write_batch_flist_info(int flist_count, struct file_struct **fptr)
{
int i;
int bytes_to_write;
/* Write flist info to batch file */
bytes_to_write =
sizeof(unsigned) +
sizeof(time_t) +
sizeof(OFF_T) +
sizeof(mode_t) +
sizeof(INO64_T) +
sizeof(DEV64_T) +
sizeof(DEV64_T) +
sizeof(uid_t) +
sizeof(gid_t);
fdb_open = 1;
fdb_close = 0;
for (i = 0; i < flist_count; i++) {
write_batch_flist_file((char *) fptr[i], bytes_to_write);
write_char_bufs(fptr[i]->basename);
write_char_bufs(fptr[i]->dirname);
write_char_bufs(fptr[i]->basedir);
write_char_bufs(fptr[i]->link);
if (i == flist_count - 1) {
fdb_close = 1;
}
write_char_bufs(fptr[i]->sum);
}
}
void write_char_bufs(char *buf)
{
/* Write the size of the string which will follow */
char b[4];
SIVAL(b, 0, buf != NULL ? strlen(buf) : 0);
write_batch_flist_file(b, sizeof(int));
/* Write the string if there is one */
if (buf != NULL) {
write_batch_flist_file(buf, strlen(buf));
}
}
void write_batch_argvs_file(int argc, char *argv[])
{
int f;
int fdb;
int i;
char buff[256]; /* XXX */
char buff2[MAXPATHLEN + 6];
char filename[MAXPATHLEN];
stringjoin(filename, sizeof filename,
batch_prefix, rsync_argvs_file, NULL);
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_argvs_file, sizeof(filename));
f = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IEXEC);
if (f < 0) {
/*
* Open batch argvs file for writing;
* create it if it doesn't exist
*/
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE | S_IEXEC);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
buff[0] = '\0';
@@ -82,135 +141,281 @@ void write_batch_argvs_file(int argc, char *argv[])
for (i = 0; i < argc; ++i) {
if (i == argc - 2) /* Skip source directory on cmdline */
continue;
continue;
/*
* FIXME:
* I think directly manipulating argv[] is probably bogus
*/
if (!strncmp(argv[i], "--write-batch",
strlen("--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);
strlcat(buff, "--read-batch=", sizeof(buff));
strlcat(buff, batch_prefix, sizeof(buff));
} else
if (i == argc - 1) {
snprintf(buff2, sizeof buff2, "${1:-%s}", argv[i]);
strlcat(buff, buff2, sizeof buff);
snprintf(buff2, sizeof(buff2), "${1:-%s}", argv[i]);
strlcat(buff, buff2, sizeof(buff));
}
else {
strlcat(buff, argv[i], sizeof buff);
strlcat(buff, argv[i], sizeof(buff));
}
if (i < (argc - 1)) {
strlcat(buff, " ", sizeof buff);
strlcat(buff, " ", sizeof(buff));
}
}
strlcat(buff, "\n", sizeof buff);
if (!write(f, buff, strlen(buff))) {
strlcat(buff, "\n", sizeof(buff));
if (!write(fdb, buff, strlen(buff))) {
rprintf(FERROR, "Batch file %s write error: %s\n",
filename, strerror(errno));
close(f);
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
close(f);
close(fdb);
}
struct file_list *create_flist_from_batch(void)
{
char filename[MAXPATHLEN];
unsigned short flags;
int i, f, save_pv;
int64 save_read;
unsigned char flags;
stringjoin(filename, sizeof filename,
batch_prefix, rsync_flist_file, NULL);
fdb_open = 1;
fdb_close = 0;
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 = new(struct file_list);
if (!batch_flist) {
out_of_memory("create_flist_from_batch");
}
batch_flist->count = 0;
batch_flist->malloced = 1000;
batch_flist->files = new_array(struct file_struct *,
batch_flist->malloced);
if (!batch_flist->files) {
out_of_memory("create_flist_from_batch");
}
batch_flist = flist_new(WITH_HLINK, "create_flist_from_batch");
for (flags = read_batch_flags(); flags; flags = read_batch_flags()) {
save_read = stats.total_read;
save_pv = protocol_version;
protocol_version = read_int(f);
int i = batch_flist->count;
batch_flist->count = read_int(f);
flist_expand(batch_flist);
if (i >= batch_flist->malloced) {
if (batch_flist->malloced < 1000)
batch_flist->malloced += 1000;
else
batch_flist->malloced *= 2;
batch_flist->files
= realloc_array(batch_flist->files,
struct file_struct *,
batch_flist->malloced);
if (!batch_flist->files)
out_of_memory("create_flist_from_batch");
}
read_batch_flist_info(&batch_flist->files[i]);
batch_flist->files[i]->flags = flags;
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);
batch_flist->count++;
}
receive_file_entry(NULL, 0, NULL, 0); /* Signal that we're done. */
protocol_version = save_pv;
stats.total_read = save_read;
return batch_flist;
}
int read_batch_flist_file(char *buff, int len)
{
int bytes_read;
char filename[MAXPATHLEN];
if (fdb_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_flist_file, sizeof(filename));
/* Open batch flist file for reading */
fdb = do_open(filename, O_RDONLY, 0);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Read flist batch file */
switch (bytes_read = read(fdb, buff, len)) {
case -1:
rprintf(FERROR, "Batch file %s read error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
break;
case 0: /* EOF */
close(fdb);
}
return bytes_read;
}
unsigned char read_batch_flags(void)
{
int flags;
if (read_batch_flist_file((char *) &flags, 4)) {
return 1;
} else {
return 0;
}
}
void read_batch_flist_info(struct file_struct **fptr)
{
int int_str_len;
char char_str_len[4];
char buff[256];
struct file_struct *file;
file = new(struct file_struct);
if (!file)
out_of_memory("read_batch_flist_info");
memset((char *) file, 0, sizeof(*file));
*fptr = file;
/*
* Keep these in sync with bytes_to_write assignment
* in write_batch_flist_info()
*/
read_batch_flist_file((char *) &file->modtime, sizeof(time_t));
read_batch_flist_file((char *) &file->length, sizeof(OFF_T));
read_batch_flist_file((char *) &file->mode, sizeof(mode_t));
read_batch_flist_file((char *) &file->inode, sizeof(INO64_T));
read_batch_flist_file((char *) &file->dev, sizeof(DEV64_T));
read_batch_flist_file((char *) &file->rdev, sizeof(DEV64_T));
read_batch_flist_file((char *) &file->uid, sizeof(uid_t));
read_batch_flist_file((char *) &file->gid, sizeof(gid_t));
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file->basename = strdup(buff);
} else {
file->basename = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].dirname = strdup(buff);
} else {
file[0].dirname = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].basedir = strdup(buff);
} else {
file[0].basedir = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].link = strdup(buff);
} else {
file[0].link = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].sum = strdup(buff);
} else {
file[0].sum = NULL;
}
}
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);
static int fdb_open = 1;
char filename[MAXPATHLEN];
if (fdb_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_csums_file, sizeof(filename));
/*
* Open batch csums file for writing;
* create it if it doesn't exist
*/
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Write buffer to batch csums file */
if (write(fdb, buff, bytes_to_write) == -1) {
rprintf(FERROR, "Batch file %s write error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
}
void close_batch_csums_file(void)
{
close(f_csums);
f_csums = -1;
close(fdb);
}
/**
* Write csum info to batch file
* 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)
void write_batch_csum_info(int *flist_entry, int flist_count,
struct sum_struct *s)
{
size_t i;
int int_count;
char filename[MAXPATHLEN];
extern int csum_length;
if (f_csums < 0) {
stringjoin(filename, sizeof filename,
batch_prefix, rsync_csums_file, NULL);
fdb_open = 1;
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));
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].sum1, sizeof(uint32));
if ((*flist_entry == flist_count - 1)
&& (i == s->count - 1)) {
fdb_close = 1;
}
write_batch_csums_file(s->sums[i].sum2, csum_length);
}
}
@@ -218,13 +423,37 @@ void write_batch_csum_info(int *flist_entry, struct sum_struct *s)
int read_batch_csums_file(char *buff, int len)
{
static int fdb_open = 1;
int bytes_read;
char filename[MAXPATHLEN];
if ((bytes_read = read(f_csums, buff, len)) < 0) {
rprintf(FERROR, "Batch file read error: %s\n", strerror(errno));
close(f_csums);
if (fdb_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_csums_file, sizeof(filename));
/* Open batch flist file for reading */
fdb = do_open(filename, O_RDONLY, 0);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Read csums batch file */
bytes_read = read(fdb, buff, len);
if (bytes_read == -1) {
rprintf(FERROR, "Batch file %s read error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
return bytes_read;
}
@@ -236,97 +465,104 @@ void read_batch_csum_info(int flist_entry, struct sum_struct *s,
int file_chunk_ct;
uint32 file_sum1;
char file_sum2[SUM_LENGTH];
char filename[MAXPATHLEN];
extern int csum_length;
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));
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);
file_flist_entry, flist_entry);
close(fdb);
exit_cleanup(1);
} else {
read_batch_csums_file((char *) &file_chunk_ct, sizeof (int));
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));
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))
if ((s->sums[i].sum1 != file_sum1) ||
(memcmp(s->sums[i].sum2, file_sum2, csum_length)
!= 0)) {
*checksums_match = 0;
}
} /* end for */
}
}
void write_batch_delta_file(char *buff, int bytes_to_write)
{
static int fdb_delta_open = 1;
char filename[MAXPATHLEN];
if (f_delta < 0) {
stringjoin(filename, sizeof filename,
batch_prefix, rsync_delta_file, NULL);
if (fdb_delta_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_delta_file, sizeof(filename));
f_delta = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR);
if (f_delta < 0) {
/*
* Open batch delta file for writing;
* create it if it doesn't exist
*/
fdb_delta = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE);
if (fdb_delta == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
fdb_delta_open = 0;
}
if (write(f_delta, buff, bytes_to_write) < 0) {
/* Write buffer to batch delta file */
if (write(fdb_delta, buff, bytes_to_write) == -1) {
rprintf(FERROR, "Batch file %s write error: %s\n",
filename, strerror(errno));
close(f_delta);
filename, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
}
void close_batch_delta_file(void)
{
close(f_delta);
f_delta = -1;
close(fdb_delta);
}
int read_batch_delta_file(char *buff, int len)
{
static int fdb_delta_open = 1;
int bytes_read;
char filename[MAXPATHLEN];
if (f_delta < 0) {
stringjoin(filename, sizeof filename,
batch_prefix, rsync_delta_file, NULL);
if (fdb_delta_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_delta_file, sizeof(filename));
f_delta = do_open(filename, O_RDONLY, 0);
if (f_delta < 0) {
/* Open batch flist file for reading */
fdb_delta = do_open(filename, O_RDONLY, 0);
if (fdb_delta == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(f_delta);
filename, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
fdb_delta_open = 0;
}
bytes_read = read(f_delta, buff, len);
if (bytes_read < 0) {
/* Read delta batch file */
bytes_read = read(fdb_delta, buff, len);
if (bytes_read == -1) {
rprintf(FERROR, "Batch file %s read error: %s\n",
filename, strerror(errno));
close(f_delta);
filename, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}

View File

@@ -23,8 +23,8 @@ int csum_length=2; /* initial value */
#define CSUM_CHUNK 64
extern int checksum_seed;
extern int protocol_version;
int checksum_seed = 0;
extern int remote_version;
/*
a simple 32 bit checksum that can be upadted from either end
@@ -74,13 +74,7 @@ void get_checksum2(char *buf,int len,char *sum)
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
}
/*
* 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 || protocol_version >= 27) {
if (len - i > 0) {
mdfour_update(&m, (uchar *)(buf1+i), (len-i));
}
@@ -111,16 +105,8 @@ void file_checksum(char *fname,char *sum,OFF_T size)
mdfour_update(&m, (uchar *)tmpchunk, CSUM_CHUNK);
}
/*
* 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));
}
@@ -131,6 +117,16 @@ void file_checksum(char *fname,char *sum,OFF_T size)
}
void checksum_init(void)
{
if (remote_version >= 14)
csum_length = 2; /* adaptive */
else
csum_length = SUM_LENGTH;
}
static int sumresidue;
static char sumrbuf[CSUM_CHUNK];
static struct mdfour md;
@@ -184,7 +180,7 @@ void sum_update(char *p, int len)
void sum_end(char *sum)
{
if (sumresidue || protocol_version >= 27) {
if (sumresidue) {
mdfour_update(&md, (uchar *)sumrbuf, sumresidue);
}

View File

@@ -72,7 +72,7 @@ static char *cleanup_new_fname;
static struct file_struct *cleanup_file;
static int cleanup_fd1, cleanup_fd2;
static struct map_struct *cleanup_buf;
static pid_t cleanup_pid = 0;
static int cleanup_pid = 0;
extern int io_error;
pid_t cleanup_child_pid = -1;
@@ -118,24 +118,21 @@ void _exit_cleanup(int code, const char *file, int line)
if (cleanup_fd2 != -1) close(cleanup_fd2);
finish_transfer(cleanup_new_fname, fname, cleanup_file);
}
io_flush(FULL_FLUSH);
io_flush();
if (cleanup_fname)
do_unlink(cleanup_fname);
if (code) {
kill_all(SIGUSR1);
}
if (cleanup_pid && cleanup_pid == getpid()) {
if ((cleanup_pid != 0) && (cleanup_pid == (int) getpid())) {
char *pidf = lp_pid_file();
if (pidf && *pidf) {
unlink(lp_pid_file());
}
}
if (code == 0) {
if ((io_error & ~IOERR_VANISHED) || log_got_error)
code = RERR_PARTIAL;
else if (io_error)
code = RERR_VANISHED;
if (code == 0 && (io_error || log_got_error)) {
code = RERR_PARTIAL;
}
if (code) log_exit(code, file, line);
@@ -166,7 +163,7 @@ void cleanup_set(char *fnametmp, char *fname, struct file_struct *file,
cleanup_fd2 = fd2;
}
void cleanup_set_pid(pid_t pid)
void cleanup_set_pid(int pid)
{
cleanup_pid = pid;
}

View File

@@ -1,20 +1,20 @@
/* -*- c-file-style: "linux" -*-
rsync -- fast file replication program
Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
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 clientname.c
*
*
* Functions for looking up the remote name or addr of a socket.
*
* This file is now converted to use the new-style getaddrinfo()
@@ -39,7 +39,7 @@ extern int am_server;
/**
* Return the IP addr of the client as a string
* Return the IP addr of the client as a string
**/
char *client_addr(int fd)
{
@@ -50,18 +50,19 @@ char *client_addr(int fd)
static char addr_buf[100];
static int initialised;
if (initialised)
return addr_buf;
if (initialised) return addr_buf;
initialised = 1;
if (am_server) { /* daemon over --rsh mode */
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);
p = strchr(ssh_client, ' ');
if (p) {
len = MIN((unsigned int) (p - ssh_client),
sizeof(addr_buf) - 1);
strncpy(addr_buf, ssh_client, len);
*(addr_buf + len) = '\0';
}
@@ -100,54 +101,58 @@ char *client_name(int fd)
static char name_buf[100];
static char port_buf[100];
static int initialised;
struct sockaddr_storage ss;
struct sockaddr_storage ss, *ssp;
struct sockaddr_in sin;
#ifdef INET6
struct sockaddr_in6 sin6;
#endif
socklen_t ss_len;
if (initialised)
return name_buf;
if (initialised) return name_buf;
strcpy(name_buf, default_name);
initialised = 1;
memset(&ss, 0, sizeof ss);
if (am_server) {
/* daemon over --rsh mode */
if (am_server) { /* daemon over --rsh mode */
char *addr = client_addr(fd);
struct addrinfo hint, *answer;
int err;
memset(&hint, 0, sizeof hint);
hint.ai_flags = AI_NUMERICHOST;
hint.ai_socktype = SOCK_STREAM;
if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
rprintf(FERROR, RSYNC_NAME ": malformed address %s: %s\n",
addr, gai_strerror(err));
return name_buf;
}
switch (answer->ai_family) {
case AF_INET:
ss_len = sizeof (struct sockaddr_in);
memcpy(&ss, answer->ai_addr, ss_len);
break;
#ifdef INET6
case AF_INET6:
ss_len = sizeof (struct sockaddr_in6);
memcpy(&ss, answer->ai_addr, ss_len);
break;
#endif
int dots = 0;
char *p;
for (p = addr; *p && (dots <= 3); p++) {
if (*p == '.')
dots++;
}
freeaddrinfo(answer);
if (dots > 3) {
/* more than 4 parts to IP address, must be ipv6 */
ssp = (struct sockaddr_storage *) &sin6;
ss_len = sizeof sin6;
memset(ssp, 0, ss_len);
inet_pton(AF_INET6, addr, &sin6.sin6_addr);
sin6.sin6_family = AF_INET6;
} else
#endif
{
ssp = (struct sockaddr_storage *) &sin;
ss_len = sizeof sin;
memset(ssp, 0, ss_len);
inet_pton(AF_INET, addr, &sin.sin_addr);
sin.sin_family = AF_INET;
}
} else {
ss_len = sizeof ss;
ssp = &ss;
client_sockaddr(fd, &ss, &ss_len);
}
if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
if (!lookup_name(fd, ssp, ss_len, name_buf, sizeof name_buf,
port_buf, sizeof port_buf))
check_name(fd, &ss, name_buf);
check_name(fd, ssp, name_buf);
return name_buf;
}
@@ -164,7 +169,7 @@ void client_sockaddr(int fd,
struct sockaddr_storage *ss,
socklen_t *ss_len)
{
memset(ss, 0, sizeof *ss);
memset(ss, 0, sizeof(*ss));
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
/* FIXME: Can we really not continue? */
@@ -174,7 +179,7 @@ void client_sockaddr(int fd,
}
#ifdef INET6
if (get_sockaddr_family(ss) == AF_INET6 &&
if (get_sockaddr_family(ss) == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
/* OK, so ss is in the IPv6 family, but it is really
* an IPv4 address: something like
@@ -185,12 +190,12 @@ void client_sockaddr(int fd,
struct sockaddr_in6 sin6;
struct sockaddr_in *sin;
memcpy(&sin6, ss, sizeof sin6);
memcpy(&sin6, ss, sizeof(sin6));
sin = (struct sockaddr_in *)ss;
memset(sin, 0, sizeof *sin);
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
*ss_len = sizeof (struct sockaddr_in);
#if HAVE_SOCKADDR_IN_LEN
*ss_len = sizeof(struct sockaddr_in);
#ifdef HAVE_SOCKADDR_LEN
sin->sin_len = *ss_len;
#endif
sin->sin_port = sin6.sin6_port;
@@ -199,8 +204,8 @@ void client_sockaddr(int fd,
* (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
* to be present in the Linux headers. */
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
sizeof sin->sin_addr);
}
sizeof(sin->sin_addr));
}
#endif
}
@@ -216,7 +221,7 @@ int lookup_name(int fd, const struct sockaddr_storage *ss,
char *port_buf, size_t port_buf_len)
{
int name_err;
/* reverse lookup */
name_err = getnameinfo((struct sockaddr *) ss, ss_len,
name_buf, name_buf_len,
@@ -245,7 +250,7 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
{
int ss_family = get_sockaddr_family(ss);
const char fn[] = "compare_addrinfo_sockaddr";
if (ai->ai_family != ss_family) {
rprintf(FERROR,
"%s: response family %d != %d\n",
@@ -259,19 +264,18 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
sin1 = (const struct sockaddr_in *) ss;
sin2 = (const struct sockaddr_in *) ai->ai_addr;
return memcmp(&sin1->sin_addr, &sin2->sin_addr,
sizeof sin1->sin_addr);
}
#ifdef INET6
if (ss_family == AF_INET6) {
else if (ss_family == AF_INET6) {
const struct sockaddr_in6 *sin1, *sin2;
sin1 = (const struct sockaddr_in6 *) ss;
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
if (ai->ai_addrlen < sizeof(struct sockaddr_in6)) {
rprintf(FERROR,
"%s: too short sockaddr_in6; length=%d\n",
fn, ai->ai_addrlen);
@@ -289,9 +293,10 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
return 0;
}
#endif /* INET6 */
/* don't know */
return 1;
else {
/* don't know */
return 1;
}
}
@@ -313,7 +318,7 @@ int check_name(int fd,
int error;
int ss_family = get_sockaddr_family(ss);
memset(&hints, 0, sizeof hints);
memset(&hints, 0, sizeof(hints));
hints.ai_family = ss_family;
hints.ai_flags = AI_CANONNAME;
hints.ai_socktype = SOCK_STREAM;

View File

@@ -27,31 +27,17 @@
#include "rsync.h"
extern int am_sender;
extern int am_server;
extern int am_daemon;
extern int am_root;
extern int module_id;
extern int read_only;
extern int verbose;
extern int rsync_port;
extern int kludge_around_eof;
extern int daemon_over_rsh;
extern int list_only;
char *auth_user;
extern int sanitize_paths;
extern int filesfrom_fd;
extern int remote_protocol;
extern int protocol_version;
extern int io_timeout;
extern int orig_umask;
extern int no_detach;
extern int default_af_hint;
extern char *bind_address;
extern struct exclude_list_struct server_exclude_list;
extern struct exclude_struct **server_exclude_list;
extern char *exclude_path_prefix;
extern char *config_file;
char *auth_user;
/**
* Run a client connected to an rsyncd. The alternative to this
@@ -71,6 +57,8 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
{
int fd, ret;
char *p, *user=NULL;
extern char *bind_address;
extern int default_af_hint;
/* this is redundant with code in start_inband_exchange(), but
* this short-circuits a problem before we open a socket, and
@@ -87,10 +75,18 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
*p = 0;
}
if (verbose >= 2) {
/* FIXME: If we're going to use a socket program for
* testing, then this message is wrong. We need to
* say something like "(except really using %s)" */
rprintf(FINFO, "opening tcp connection to %s port %d\n",
host, rsync_port);
}
fd = open_socket_out_wrapped(host, rsync_port, bind_address,
default_af_hint);
if (fd == -1)
if (fd == -1) {
exit_cleanup(RERR_SOCKETIO);
}
ret = start_inband_exchange(user, path, fd, fd, argc);
@@ -104,6 +100,10 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
int sargc = 0;
char line[MAXPATHLEN];
char *p;
extern int kludge_around_eof;
extern int am_sender;
extern int daemon_over_rsh;
extern int list_only;
if (argc == 0 && !am_sender)
list_only = 1;
@@ -129,7 +129,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
sargs[sargc] = NULL;
io_printf(f_out, "@RSYNCD: %d\n", protocol_version);
io_printf(f_out, "@RSYNCD: %d\n", PROTOCOL_VERSION);
if (!read_line(f_in, line, sizeof(line)-1)) {
rprintf(FERROR, "rsync: did not see server greeting\n");
@@ -192,7 +192,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
io_printf(f_out, "\n");
if (protocol_version < 23) {
if (protocol_version == 22 || !am_sender)
if (protocol_version == 22 || (protocol_version > 17 && !am_sender))
io_start_multiplex_in(f_in);
}
@@ -217,6 +217,10 @@ static int rsync_module(int f_in, int f_out, int i)
int start_glob=0;
int ret;
char *request=NULL;
extern int am_sender;
extern int am_server;
extern int am_daemon;
extern int am_root;
if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
rprintf(FERROR,"rsync denied on module %s from %s (%s)\n",
@@ -258,7 +262,7 @@ static int rsync_module(int f_in, int f_out, int i)
module_id = i;
am_root = (MY_UID() == 0);
am_root = (getuid() == 0);
if (am_root) {
p = lp_uid(i);
@@ -294,19 +298,16 @@ static int rsync_module(int f_in, int f_out, int i)
exclude_path_prefix = "";
p = lp_include_from(i);
add_exclude_file(&server_exclude_list, p,
XFLG_FATAL_ERRORS | XFLG_DEF_INCLUDE);
add_exclude_file(&server_exclude_list, p, MISSING_FATAL, ADD_INCLUDE);
p = lp_include(i);
add_exclude(&server_exclude_list, p,
XFLG_WORD_SPLIT | XFLG_DEF_INCLUDE);
add_exclude_line(&server_exclude_list, p, ADD_INCLUDE);
p = lp_exclude_from(i);
add_exclude_file(&server_exclude_list, p,
XFLG_FATAL_ERRORS);
add_exclude_file(&server_exclude_list, p, MISSING_FATAL, ADD_EXCLUDE);
p = lp_exclude(i);
add_exclude(&server_exclude_list, p, XFLG_WORD_SPLIT);
add_exclude_line(&server_exclude_list, p, ADD_EXCLUDE);
exclude_path_prefix = NULL;
@@ -331,14 +332,14 @@ static int rsync_module(int f_in, int f_out, int i)
return -1;
}
if (!push_dir("/")) {
if (!push_dir("/", 0)) {
rsyserr(FERROR, 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))) {
if (!push_dir(lp_path(i), 0)) {
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
io_printf(f_out, "@ERROR: chdir failed\n");
return -1;
@@ -378,7 +379,7 @@ static int rsync_module(int f_in, int f_out, int i)
return -1;
}
am_root = (MY_UID() == 0);
am_root = (getuid() == 0);
}
io_printf(f_out, "@RSYNCD: OK\n");
@@ -418,6 +419,19 @@ static int rsync_module(int f_in, int f_out, int i)
}
}
if (sanitize_paths) {
/*
* Note that this is applied to all parameters, whether or not
* they are filenames, but no other legal parameters contain
* the forms that need to be sanitized so it doesn't hurt;
* it is not known at this point which parameters are files
* and which aren't.
*/
for (i = 1; i < argc; i++) {
sanitize_path(argv[i], NULL);
}
}
argp = argv;
ret = parse_arguments(&argc, (const char ***) &argp, 0);
@@ -439,12 +453,11 @@ static int rsync_module(int f_in, int f_out, int i)
#ifndef DEBUG
/* don't allow the logs to be flooded too fast */
if (verbose > lp_max_verbosity())
verbose = lp_max_verbosity();
if (verbose > 1) verbose = 1;
#endif
if (protocol_version < 23) {
if (protocol_version == 22 || am_sender)
if (protocol_version == 22 || (protocol_version > 17 && am_sender))
io_start_multiplex_out(f_out);
}
@@ -462,6 +475,7 @@ static int rsync_module(int f_in, int f_out, int i)
}
if (lp_timeout(i)) {
extern int io_timeout;
io_timeout = lp_timeout(i);
}
@@ -493,6 +507,8 @@ int start_daemon(int f_in, int f_out)
char line[200];
char *motd;
int i = -1;
extern char *config_file;
extern int am_server;
if (!lp_load(config_file, 0)) {
exit_cleanup(RERR_SYNTAX);
@@ -506,7 +522,7 @@ int start_daemon(int f_in, int f_out)
set_nonblocking(f_in);
}
io_printf(f_out, "@RSYNCD: %d\n", protocol_version);
io_printf(f_out, "@RSYNCD: %d\n", PROTOCOL_VERSION);
motd = lp_motd_file();
if (motd && *motd) {
@@ -563,7 +579,10 @@ int start_daemon(int f_in, int f_out)
int daemon_main(void)
{
extern char *config_file;
extern int orig_umask;
char *pid_file;
extern int no_detach;
if (is_a_socket(STDIN_FILENO)) {
int i;
@@ -597,7 +616,7 @@ int daemon_main(void)
if (((pid_file = lp_pid_file()) != NULL) && (*pid_file != '\0')) {
char pidbuf[16];
int fd;
pid_t pid = getpid();
int pid = (int) getpid();
cleanup_set_pid(pid);
if ((fd = do_open(lp_pid_file(), O_WRONLY|O_CREAT|O_TRUNC,
0666 & ~orig_umask)) == -1) {
@@ -605,7 +624,7 @@ int daemon_main(void)
rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
exit_cleanup(RERR_FILEIO);
}
snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
snprintf(pidbuf, sizeof(pidbuf), "%d\n", pid);
write(fd, pidbuf, strlen(pidbuf));
close(fd);
}

View File

@@ -38,6 +38,7 @@ extern int preserve_times;
extern int always_checksum;
extern int checksum_seed;
extern int protocol_version;
extern int verbose;
@@ -84,9 +85,11 @@ void setup_protocol(int f_out,int f_in)
}
if (am_server) {
if (!checksum_seed)
if (read_batch || write_batch)
checksum_seed = 32761;
else
checksum_seed = time(NULL);
write_int(f_out, checksum_seed);
write_int(f_out,checksum_seed);
} else {
checksum_seed = read_int(f_in);
}

133
config.guess vendored
View File

@@ -3,7 +3,7 @@
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
timestamp='2003-10-03'
timestamp='2003-01-10'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -106,7 +106,6 @@ trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
: ${TMPDIR=/tmp} ;
{ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
dummy=$tmp/dummy ;
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
@@ -236,56 +235,74 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:OpenBSD:*:*)
echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
*:MicroBSD:*:*)
echo ${UNAME_MACHINE}-unknown-microbsd${UNAME_RELEASE}
exit 0 ;;
alpha:OSF1:*:*)
if test $UNAME_RELEASE = "V4.0"; then
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
fi
# According to Compaq, /usr/sbin/psrinfo has been available on
# OSF/1 and Tru64 systems produced since 1995. I hope that
# covers most systems running today. This code pipes the CPU
# types through head -n 1, so we only detect the type of CPU 0.
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
UNAME_MACHINE="alpha" ;;
"EV4.5 (21064)")
UNAME_MACHINE="alpha" ;;
"LCA4 (21066/21068)")
UNAME_MACHINE="alpha" ;;
"EV5 (21164)")
UNAME_MACHINE="alphaev5" ;;
"EV5.6 (21164A)")
UNAME_MACHINE="alphaev56" ;;
"EV5.6 (21164PC)")
UNAME_MACHINE="alphapca56" ;;
"EV5.7 (21164PC)")
UNAME_MACHINE="alphapca57" ;;
"EV6 (21264)")
UNAME_MACHINE="alphaev6" ;;
"EV6.7 (21264A)")
UNAME_MACHINE="alphaev67" ;;
"EV6.8CB (21264C)")
UNAME_MACHINE="alphaev68" ;;
"EV6.8AL (21264B)")
UNAME_MACHINE="alphaev68" ;;
"EV6.8CX (21264D)")
UNAME_MACHINE="alphaev68" ;;
"EV6.9A (21264/EV69A)")
UNAME_MACHINE="alphaev69" ;;
"EV7 (21364)")
UNAME_MACHINE="alphaev7" ;;
"EV7.9 (21364A)")
UNAME_MACHINE="alphaev79" ;;
esac
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
eval $set_cc_for_build
cat <<EOF >$dummy.s
.data
\$Lformat:
.byte 37,100,45,37,120,10,0 # "%d-%x\n"
.text
.globl main
.align 4
.ent main
main:
.frame \$30,16,\$26,0
ldgp \$29,0(\$27)
.prologue 1
.long 0x47e03d80 # implver \$0
lda \$2,-1
.long 0x47e20c21 # amask \$2,\$1
lda \$16,\$Lformat
mov \$0,\$17
not \$1,\$18
jsr \$26,printf
ldgp \$29,0(\$26)
mov 0,\$16
jsr \$26,exit
.end main
EOF
$CC_FOR_BUILD -o $dummy $dummy.s 2>/dev/null
if test "$?" = 0 ; then
case `$dummy` in
0-0)
UNAME_MACHINE="alpha"
;;
1-0)
UNAME_MACHINE="alphaev5"
;;
1-1)
UNAME_MACHINE="alphaev56"
;;
1-101)
UNAME_MACHINE="alphapca56"
;;
2-303)
UNAME_MACHINE="alphaev6"
;;
2-307)
UNAME_MACHINE="alphaev67"
;;
2-1307)
UNAME_MACHINE="alphaev68"
;;
3-1307)
UNAME_MACHINE="alphaev7"
;;
esac
fi
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
exit 0 ;;
Alpha*:OpenVMS:*:*)
echo alpha-hp-vms
exit 0 ;;
Alpha\ *:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# Should we change UNAME_MACHINE based on the output of uname instead
@@ -324,9 +341,6 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
NILE*:*:*:dcosx)
echo pyramid-pyramid-svr4
exit 0 ;;
DRS?6000:unix:4.0:6*)
echo sparc-icl-nx6
exit 0 ;;
DRS?6000:UNIX_SV:4.2*:7*)
case `/usr/bin/uname -p` in
sparc) echo sparc-icl-nx7 && exit 0 ;;
@@ -734,7 +748,7 @@ EOF
echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit 0 ;;
*:UNICOS/mp:*:*)
echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit 0 ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
@@ -751,7 +765,7 @@ EOF
*:BSD/OS:*:*)
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit 0 ;;
*:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
*:FreeBSD:*:*)
# Determine whether the default compiler uses glibc.
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
@@ -763,10 +777,7 @@ EOF
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
# GNU/FreeBSD systems have a "k" prefix to indicate we are using
# FreeBSD's kernel, but not the complete OS.
case ${LIBC} in gnu) kernel_only='k' ;; esac
echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
exit 0 ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
@@ -777,8 +788,8 @@ EOF
i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32
exit 0 ;;
x86:Interix*:[34]*)
echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
x86:Interix*:3*)
echo i586-pc-interix3
exit 0 ;;
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks
@@ -807,9 +818,6 @@ EOF
arm*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit 0 ;;
cris:Linux:*:*)
echo cris-axis-linux-gnu
exit 0 ;;
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit 0 ;;
@@ -888,9 +896,6 @@ EOF
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux
exit 0 ;;
sh64*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit 0 ;;
sh*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit 0 ;;
@@ -948,9 +953,6 @@ EOF
LIBC=gnuaout
#endif
#endif
#ifdef __dietlibc__
LIBC=dietlibc
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
@@ -1052,7 +1054,7 @@ EOF
exit 0 ;;
M68*:*:R3V[567]*:*)
test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
@@ -1167,7 +1169,7 @@ EOF
*:QNX:*:4*)
echo i386-pc-qnx
exit 0 ;;
NSR-[DGKLNPTVWY]:NONSTOP_KERNEL:*:*)
NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
exit 0 ;;
*:NonStop-UX:*:*)
@@ -1208,9 +1210,6 @@ EOF
*:ITS:*:*)
echo pdp10-unknown-its
exit 0 ;;
SEI:*:*:SEIUX)
echo mips-sei-seiux${UNAME_RELEASE}
exit 0 ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2

72
config.sub vendored
View File

@@ -3,7 +3,7 @@
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
timestamp='2003-08-18'
timestamp='2003-01-22'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
@@ -118,7 +118,7 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-dietlibc | kfreebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
@@ -228,14 +228,13 @@ case $basic_machine in
| a29k \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
| c4x | clipper \
| clipper \
| d10v | d30v | dlx | dsp16xx \
| fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
| ip2k \
| m32r | m68000 | m68k | m88k | mcore \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
@@ -248,7 +247,6 @@ case $basic_machine in
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa64 | mipsisa64el \
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \
@@ -259,11 +257,11 @@ case $basic_machine in
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \
| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
| sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
| strongarm \
| tahoe | thumb | tic4x | tic80 | tron \
| tahoe | thumb | tic80 | tron \
| v850 | v850e \
| we32k \
| x86 | xscale | xstormy16 | xtensa \
@@ -298,7 +296,7 @@ case $basic_machine in
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* \
| bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* \
| clipper-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
@@ -306,7 +304,7 @@ case $basic_machine in
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
| ip2k-* \
| m32r-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | mcore-* \
@@ -321,7 +319,6 @@ case $basic_machine in
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa64-* | mipsisa64el-* \
| mipsisa64r2-* | mipsisa64r2el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipstx39-* | mipstx39el-* \
@@ -332,13 +329,11 @@ case $basic_machine in
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \
| romp-* | rs6000-* \
| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
| sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
| tahoe-* | thumb-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tron-* \
| tahoe-* | thumb-* | tic30-* | tic4x-* | tic54x-* | tic80-* | tron-* \
| v850-* | v850e-* | vax-* \
| we32k-* \
| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
@@ -376,9 +371,6 @@ case $basic_machine in
basic_machine=a29k-none
os=-bsd
;;
amd64)
basic_machine=x86_64-pc
;;
amdahl)
basic_machine=580-amdahl
os=-sysv
@@ -774,24 +766,18 @@ case $basic_machine in
pentiumpro | p6 | 6x86 | athlon | athlon_*)
basic_machine=i686-pc
;;
pentiumii | pentium2 | pentiumiii | pentium3)
pentiumii | pentium2)
basic_machine=i686-pc
;;
pentium4)
basic_machine=i786-pc
;;
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentiumpro-* | p6-* | 6x86-* | athlon-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
pentiumii-* | pentium2-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentium4-*)
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pn)
basic_machine=pn-gould
;;
@@ -850,10 +836,6 @@ case $basic_machine in
sb1el)
basic_machine=mipsisa64sb1el-unknown
;;
sei)
basic_machine=mips-sei
os=-seiux
;;
sequent)
basic_machine=i386-sequent
;;
@@ -861,9 +843,6 @@ case $basic_machine in
basic_machine=sh-hitachi
os=-hms
;;
sh64)
basic_machine=sh64-unknown
;;
sparclite-wrs | simso-wrs)
basic_machine=sparclite-wrs
os=-vxworks
@@ -938,18 +917,14 @@ case $basic_machine in
basic_machine=t90-cray
os=-unicos
;;
tic4x | c4x*)
basic_machine=tic4x-unknown
os=-coff
;;
tic54x | c54x*)
basic_machine=tic54x-unknown
os=-coff
;;
tic55x | c55x*)
basic_machine=tic55x-unknown
os=-coff
;;
tic6x | c6x*)
basic_machine=tic6x-unknown
os=-coff
;;
tx39)
basic_machine=mipstx39-unknown
;;
@@ -1052,7 +1027,7 @@ case $basic_machine in
we32k)
basic_machine=we32k-att
;;
sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele)
basic_machine=sh-unknown
;;
sh64)
@@ -1131,7 +1106,7 @@ case $os in
| -aos* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
@@ -1143,7 +1118,7 @@ case $os in
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
| -powermax* | -dnix* | -microbsd*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1167,9 +1142,6 @@ case $os in
-mac*)
os=`echo $os | sed -e 's|mac|macos|'`
;;
-linux-dietlibc)
os=-linux-dietlibc
;;
-linux*)
os=`echo $os | sed -e 's|linux|linux-gnu|'`
;;
@@ -1258,9 +1230,6 @@ case $os in
-aros*)
os=-aros
;;
-kaos*)
os=-kaos
;;
-none)
;;
*)
@@ -1292,9 +1261,6 @@ case $basic_machine in
arm*-semi)
os=-aout
;;
c4x-* | tic4x-*)
os=-coff
;;
# This must come before the *-dec entry.
pdp10-*)
os=-tops20

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.5.7
AC_SUBST(RSYNC_VERSION)
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
@@ -18,7 +18,6 @@ AC_CANONICAL_TARGET([])
dnl Checks for programs.
AC_PROG_CC
AC_PROG_CPP
AC_PROG_EGREP
AC_PROG_INSTALL
AC_PROG_CC_STDC
AC_SUBST(SHELL)
@@ -91,35 +90,14 @@ AC_ARG_WITH(included-popt,
[ --with-included-popt use bundled popt library, not from system])
AC_ARG_WITH(rsync-path,
[ --with-rsync-path=PATH set default --rsync-path to PATH (default: rsync)],
[ --with-rsync-path=PATH set default --rsync-path to PATH (default: \"rsync\")],
[ RSYNC_PATH="$with_rsync_path" ],
[ RSYNC_PATH="rsync" ])
AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [location of rsync on remote machine])
AC_ARG_WITH(rsyncd-conf,
AC_HELP_STRING([--with-rsyncd-conf=PATH], [set configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]),
[ if test ! -z "$with_rsyncd_conf" ; then
case $with_rsyncd_conf in
yes|no)
RSYNCD_SYSCONF="/etc/rsyncd.conf"
;;
/*)
RSYNCD_SYSCONF="$with_rsyncd_conf"
;;
*)
AC_MSG_ERROR(You must specify an absolute path to --with-rsyncd-conf=PATH)
;;
esac
else
RSYNCD_SYSCONF="/etc/rsyncd.conf"
fi ],
[ RSYNCD_SYSCONF="/etc/rsyncd.conf" ])
AC_DEFINE_UNQUOTED(RSYNCD_SYSCONF, "$RSYNCD_SYSCONF", [location of configuration file for rsync server])
AC_ARG_WITH(rsh,
AC_HELP_STRING([--with-rsh=CMD], [set remote shell command to CMD (default: ssh)]))
AC_HELP_STRING([--with-rsh=CMD], [set rsh command to CMD (default: \"remsh\" or \"rsh\")]))
AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0)
AC_DEFINE_UNQUOTED(HAVE_REMSH, $HAVE_REMSH, [remote shell is remsh not rsh])
@@ -127,8 +105,11 @@ AC_DEFINE_UNQUOTED(HAVE_REMSH, $HAVE_REMSH, [remote shell is remsh not rsh])
if test x"$with_rsh" != x
then
RSYNC_RSH="$with_rsh"
elif test x"$HAVE_REMSH" = x1
then
RSYNC_RSH="remsh"
else
RSYNC_RSH="ssh"
RSYNC_RSH="rsh"
fi
AC_DEFINE_UNQUOTED(RSYNC_RSH, "$RSYNC_RSH", [default -e command])
@@ -143,7 +124,7 @@ AC_TRY_RUN([
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
int main(void)
{
struct flock lock;
int status;
@@ -173,7 +154,7 @@ ipv6type=unknown
ipv6lib=none
ipv6trylibc=yes
AC_ARG_ENABLE(ipv6,
AC_ARG_ENABLE(ipv6,
AC_HELP_STRING([--disable-ipv6], [don't even try to use IPv6]))
if test "x$enable_ipv6" != xno
@@ -199,7 +180,7 @@ yes
#ifdef __KAME__
yes
#endif],
[ipv6type=$i;
[ipv6type=$i;
AC_DEFINE(INET6, 1, [true if you have IPv6])])
;;
linux-glibc)
@@ -269,7 +250,7 @@ fi
AC_MSG_CHECKING([whether to call shutdown on all sockets])
case $host_os in
*cygwin* ) AC_MSG_RESULT(yes)
AC_DEFINE(SHUTDOWN_ALL_SOCKETS, 1,
AC_DEFINE(SHUTDOWN_ALL_SOCKETS, 1,
[Define if sockets need to be shutdown])
;;
* ) AC_MSG_RESULT(no);;
@@ -279,12 +260,13 @@ AC_C_BIGENDIAN
AC_HEADER_DIRENT
AC_HEADER_TIME
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 \
netdb.h malloc.h float.h)
AC_HEADER_MAJOR
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h unistd.h utime.h grp.h)
AC_CHECK_HEADERS(compat.h sys/param.h ctype.h sys/wait.h sys/ioctl.h)
AC_CHECK_HEADERS(sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h sys/un.h)
AC_CHECK_HEADERS(glob.h mcheck.h sys/sysctl.h arpa/inet.h arpa/nameser.h)
AC_CHECK_HEADERS(netdb.h)
AC_CHECK_HEADERS(malloc.h)
AC_CHECK_HEADERS(float.h)
AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(long)
@@ -339,7 +321,7 @@ if test x"$ac_cv_func_connect" = x"no"; then
esac
dnl We can't just call AC_CHECK_FUNCS(connect) here, because the value
dnl has been cached.
if test x"$ac_cv_lib_socket_connect" = x"yes" ||
if test x"$ac_cv_lib_socket_connect" = x"yes" ||
test x"$ac_cv_lib_inet_connect" = x"yes"; then
# ac_cv_func_connect=yes
# don't! it would cause AC_CHECK_FUNC to succeed next time configure is run
@@ -351,8 +333,8 @@ AC_CHECK_LIB(resolv, inet_ntop)
dnl AC_MSG_NOTICE([Looking in libraries: $LIBS])
AC_CHECK_FUNCS(inet_ntop, , [AC_LIBOBJ(lib/inet_ntop)])
AC_CHECK_FUNCS(inet_pton, , [AC_LIBOBJ(lib/inet_pton)])
AC_CHECK_FUNCS(inet_ntop, , AC_LIBOBJ(lib/inet_ntop))
AC_CHECK_FUNCS(inet_pton, , AC_LIBOBJ(lib/inet_pton))
# Irix 6.5 has getaddrinfo but not the corresponding defines, so use
# builtin getaddrinfo if one of the defines don't exist
@@ -364,7 +346,7 @@ AC_CACHE_CHECK([whether defines needed by getaddrinfo exist],
#include <netdb.h>
#ifdef AI_PASSIVE
yes
#endif],
#endif],
rsync_cv_HAVE_GETADDR_DEFINES=yes,
rsync_cv_HAVE_GETADDR_DEFINES=no)])
if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes"; then
@@ -381,27 +363,19 @@ if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes"; then
[Define if you have the `getaddrinfo' function.])],
[AC_MSG_RESULT([no])
AC_LIBOBJ(lib/getaddrinfo)])])
AC_CHECK_FUNCS(getnameinfo, , [AC_LIBOBJ(lib/getnameinfo)])
AC_CHECK_FUNCS(getnameinfo, , AC_LIBOBJ(lib/getnameinfo))
else
AC_LIBOBJ(lib/getaddrinfo)
AC_LIBOBJ(lib/getnameinfo)
fi
AC_CHECK_MEMBER([struct sockaddr.sa_len],
[ AC_DEFINE(HAVE_SOCKADDR_LEN, 1, [Do we have sockaddr.sa_len?]) ],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
])
AC_CHECK_MEMBER([struct sockaddr_in.sin_len],
[ AC_DEFINE(HAVE_SOCKADDR_IN_LEN, 1, [Do we have sockaddr_in.sin_len?]) ],
AC_CHECK_MEMBER([struct sockaddr.sa_len],
[ AC_DEFINE(HAVE_SOCKADDR_LEN) ],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
])
AC_MSG_CHECKING(struct sockaddr_storage)
@@ -409,12 +383,12 @@ AC_TRY_COMPILE([#include <sys/types.h>
#include <sys/socket.h>],
[struct sockaddr_storage x;],
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1,
AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1,
[Define if you have strct sockaddr_storage.] ),
AC_MSG_RESULT(no))
AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id],
[ AC_DEFINE(HAVE_SOCKADDR_IN6_SCOPE_ID, 1, [Do we have sockaddr_in6.sin6_scope_id?]) ],
[ AC_DEFINE(HAVE_SOCKADDR_IN6_SCOPE_ID) ],
[],
[
#include <sys/types.h>
@@ -431,15 +405,15 @@ fi
dnl At the moment we don't test for a broken memcmp(), because all we
dnl need to do is test for equality, not comparison, and it seems that
dnl every platform has a memcmp that can do at least that.
dnl every platform has a memcmp that can do at least that.
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 \
memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk \
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid)
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo)
AC_CHECK_FUNCS(fchmod fstat strchr readlink link utime utimes strftime)
AC_CHECK_FUNCS(memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk)
AC_CHECK_FUNCS(strlcat strlcpy strtol mtrace mallinfo setgroups)
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
AC_TRY_RUN([
@@ -455,6 +429,15 @@ if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then
AC_DEFINE(HAVE_SOCKETPAIR, 1, [ ])
fi
AC_CACHE_CHECK([for working fnmatch],rsync_cv_HAVE_FNMATCH,[
AC_TRY_RUN([#include <fnmatch.h>
main() { exit((fnmatch("*.o", "x.o", FNM_PATHNAME) == 0 &&
fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME) != 0) ? 0: 1); }],
rsync_cv_HAVE_FNMATCH=yes,rsync_cv_HAVE_FNMATCH=no,rsync_cv_HAVE_FNMATCH=cross)])
if test x"$rsync_cv_HAVE_FNMATCH" = x"yes"; then
AC_DEFINE(HAVE_FNMATCH, 1, [ ])
fi
if test x"$with_included_popt" != x"yes"
then
AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
@@ -545,7 +528,7 @@ AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[
AC_TRY_RUN([
#include <sys/types.h>
#include <stdarg.h>
void foo(const char *format, ...) {
void foo(const char *format, ...) {
va_list ap;
int len;
char buf[5];
@@ -572,10 +555,10 @@ AC_TRY_RUN([#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
main() {
main() {
struct stat st;
char tpl[20]="/tmp/test.XXXXXX";
int fd = mkstemp(tpl);
char tpl[20]="/tmp/test.XXXXXX";
int fd = mkstemp(tpl);
if (fd == -1) exit(1);
unlink(tpl);
if (fstat(fd, &st) != 0) exit(1);
@@ -598,7 +581,7 @@ AC_TRY_RUN([
#include <arpa/inet.h>
main() { struct in_addr ip; ip.s_addr = 0x12345678;
if (strcmp(inet_ntoa(ip),"18.52.86.120") &&
strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(1); }
strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(1); }
exit(0);}],
rsync_cv_REPLACE_INET_NTOA=no,rsync_cv_REPLACE_INET_NTOA=yes,rsync_cv_REPLACE_INET_NTOA=cross)])
if test x"$rsync_cv_REPLACE_INET_NTOA" = x"yes"; then
@@ -612,7 +595,7 @@ AC_TRY_RUN([
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
main() { struct in_addr ip;
main() { struct in_addr ip;
if (inet_aton("example", &ip) == 0) exit(0); exit(1);}],
rsync_cv_REPLACE_INET_ATON=no,rsync_cv_REPLACE_INET_ATON=yes,rsync_cv_REPLACE_INET_ATON=cross)])
if test x"$rsync_cv_REPLACE_INET_ATON" = x"yes"; then
@@ -653,21 +636,6 @@ AC_SUBST(BUILD_POPT)
AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
AC_OUTPUT
if test x"$with_rsh" = x; then
if test x"$HAVE_REMSH" = x1; then
rmsh1='remsh:'
rmsh2='=remsh'
else
rmsh1='rsh: '
rmsh2='=rsh '
fi
AC_MSG_RESULT()
AC_MSG_RESULT([ **********************************************************************])
AC_MSG_RESULT([ * As of v2.6.0, the default remote shell is ssh instead of rsh!! *])
AC_MSG_RESULT([ * To use previous default of $rmsh1 ./configure --with-rsh$rmsh2 *])
AC_MSG_RESULT([ **********************************************************************])
fi
AC_MSG_RESULT()
AC_MSG_RESULT([ rsync ${RSYNC_VERSION} configuration successful])
AC_MSG_RESULT()

View File

@@ -26,7 +26,7 @@
#define RERR_SYNTAX 1 /* syntax or usage error */
#define RERR_PROTOCOL 2 /* protocol incompatibility */
#define RERR_FILESELECT 3 /* errors selecting input/output files, dirs */
#define RERR_UNSUPPORTED 4 /* requested action not supported */
#define RERR_UNSUPPORTED 4 /* requested action not supported */
#define RERR_STARTCLIENT 5 /* error starting client-server protocol */
#define RERR_SOCKETIO 10 /* error in socket IO */
@@ -39,7 +39,6 @@
#define RERR_WAITCHILD 21 /* some error returned by waitpid() */
#define RERR_MALLOC 22 /* error allocating core memory buffers */
#define RERR_PARTIAL 23 /* partial transfer */
#define RERR_VANISHED 24 /* file(s) vanished on sender side */
#define RERR_TIMEOUT 30 /* timeout in data send/receive */

586
exclude.c
View File

@@ -1,19 +1,19 @@
/* -*- c-file-style: "linux" -*-
*
*
* Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
* Copyright (C) 1996 by Paul Mackerras
* 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.
@@ -27,167 +27,96 @@
#include "rsync.h"
extern int verbose;
extern int eol_nulls;
extern int list_only;
extern int recurse;
extern int delete_mode;
extern char curr_dir[];
struct exclude_list_struct exclude_list = { 0, 0, "" };
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;
static struct exclude_struct **exclude_list;
/** 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)
static struct exclude_struct *make_exclude(const char *pattern, int include)
{
struct exclude_struct *ret;
const char *cp;
int ex_len;
ret = new(struct exclude_struct);
if (!ret)
out_of_memory("make_exclude");
if (!ret) out_of_memory("make_exclude");
memset(ret, 0, sizeof ret[0]);
ret->include = include;
memset(ret, 0, sizeof(*ret));
if (exclude_path_prefix)
ret->match_flags |= MATCHFLG_ABS_PATH;
if (exclude_path_prefix && *pattern == '/')
ex_len = strlen(exclude_path_prefix);
else
ex_len = 0;
ret->pattern = new_array(char, ex_len + pat_len + 1);
if (!ret->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);
pat_len += ex_len;
if (strpbrk(ret->pattern, "*[?")) {
ret->match_flags |= MATCHFLG_WILD;
if ((cp = strstr(ret->pattern, "**")) != NULL) {
ret->match_flags |= MATCHFLG_WILD2;
/* If the pattern starts with **, note that. */
if (cp == ret->pattern)
ret->match_flags |= MATCHFLG_WILD2_PREFIX;
}
if (strncmp(pattern,"- ",2) == 0) {
pattern += 2;
} else if (strncmp(pattern,"+ ",2) == 0) {
ret->include = 1;
pattern += 2;
} else {
ret->include = include;
}
if (pat_len > 1 && ret->pattern[pat_len-1] == '/') {
ret->pattern[pat_len-1] = 0;
ret->pattern = strdup(pattern);
if (!ret->pattern) out_of_memory("make_exclude");
if (strpbrk(pattern, "*[?")) {
ret->regular_exp = 1;
ret->fnmatch_flags = FNM_PATHNAME;
if (strstr(pattern, "**")) {
static int tested;
if (!tested) {
tested = 1;
if (fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME)==0) {
rprintf(FERROR,"WARNING: fnmatch FNM_PATHNAME is broken on your system\n");
}
}
ret->fnmatch_flags = 0;
}
}
if (strlen(pattern) > 1 && pattern[strlen(pattern)-1] == '/') {
ret->pattern[strlen(pattern)-1] = 0;
ret->directory = 1;
}
for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
ret->slash_cnt++;
if (!listp->tail)
listp->head = listp->tail = ret;
else {
listp->tail->next = ret;
listp->tail = ret;
if (!strchr(ret->pattern,'/')) {
ret->local = 1;
}
return ret;
}
static void free_exclude(struct exclude_struct *ex)
{
free(ex->pattern);
memset(ex,0,sizeof(*ex));
free(ex);
}
void free_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);
}
listp->head = listp->tail = NULL;
}
static int check_one_exclude(char *name, struct exclude_struct *ex,
int name_is_dir)
STRUCT_STAT *st)
{
char *p;
int match_start = 0;
int match_start=0;
char *pattern = ex->pattern;
/* 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. */
if (!ex->slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) {
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);
name = full_name;
}
if (ex->local && (p=strrchr(name,'/')))
name = p+1;
if (!name[0]) return 0;
if (ex->directory && !name_is_dir) return 0;
if (ex->directory && !S_ISDIR(st->st_mode)) return 0;
if (*pattern == '/') {
if (*pattern == '/' && *name != '/') {
match_start = 1;
pattern++;
if (*name == '/')
name++;
}
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)) {
int cnt = ex->slash_cnt + 1;
for (p = name + strlen(name) - 1; p >= name; p--) {
if (*p == '/' && !--cnt)
break;
}
name = p+1;
}
if (wildmatch(pattern, name))
if (ex->regular_exp) {
if (fnmatch(pattern, name, ex->fnmatch_flags) == 0) {
return 1;
if (ex->match_flags & MATCHFLG_WILD2_PREFIX) {
/* If the **-prefixed pattern has a '/' as the next
* character, then try to match the rest of the
* pattern at the root. */
if (pattern[2] == '/' && wildmatch(pattern+3, name))
return 1;
}
else if (!match_start && ex->match_flags & MATCHFLG_WILD2) {
/* A non-anchored match with an infix or trailing "**"
* (but not a prefixed "**") needs to try matching
* after every slash. */
while ((name = strchr(name, '/')) != NULL) {
name++;
if (wildmatch(pattern, name))
return 1;
}
}
} else if (match_start) {
if (strcmp(name,pattern) == 0)
return 1;
} else {
int l1 = strlen(name);
int l2 = strlen(pattern);
if (l2 <= l1 &&
if (l2 <= l1 &&
strcmp(name+(l1-l2),pattern) == 0 &&
(l1==l2 || name[l1-(l2+1)] == '/')) {
(l1==l2 || (!match_start && name[l1-(l2+1)] == '/'))) {
return 1;
}
}
@@ -198,249 +127,292 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
static void report_exclude_result(char const *name,
struct exclude_struct const *ent,
int name_is_dir, const char *type)
STRUCT_STAT const *st)
{
/* If a trailing slash is present to match only directories,
* then it is stripped out by make_exclude. So as a special
* case we add it back in here. */
if (verbose >= 2) {
rprintf(FINFO, "[%s] %scluding %s %s because of %spattern %s%s\n",
who_am_i(), ent->include ? "in" : "ex",
name_is_dir ? "directory" : "file", name, type,
ent->pattern, ent->directory ? "/" : "");
}
/* If a trailing slash is present to match only directories,
* then it is stripped out by make_exclude. So as a special
* case we add it back in here. */
if (verbose >= 2)
rprintf(FINFO, "%s %s %s because of pattern %s%s\n",
ent->include ? "including" : "excluding",
S_ISDIR(st->st_mode) ? "directory" : "file",
name, ent->pattern,
ent->directory ? "/" : "");
}
/*
* Return -1 if file "name" is defined to be excluded by the specified
* exclude list, 1 if it is included, and 0 if it was not matched.
* Return true if file NAME is defined to be excluded by either
* LOCAL_EXCLUDE_LIST or the globals EXCLUDE_LIST.
*/
int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir)
int check_exclude(char *name, struct exclude_struct **local_exclude_list,
STRUCT_STAT *st)
{
struct exclude_struct *ent;
int n;
struct exclude_struct *ent;
for (ent = listp->head; ent; ent = ent->next) {
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;
}
if (name && (name[0] == '.') && !name[1])
/* never exclude '.', even if somebody does --exclude '*' */
return 0;
if (exclude_list) {
for (n=0; exclude_list[n]; n++) {
ent = exclude_list[n];
if (check_one_exclude(name, ent, st)) {
report_exclude_result(name, ent, st);
return !ent->include;
}
}
}
if (local_exclude_list) {
for (n=0; local_exclude_list[n]; n++) {
ent = local_exclude_list[n];
if (check_one_exclude(name, ent, st)) {
report_exclude_result(name, ent, st);
return !ent->include;
}
}
}
return 0;
}
/* 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.
*/
static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr,
int xflags)
void add_exclude_list(const char *pattern, struct exclude_struct ***list, int include)
{
const unsigned char *s = (const unsigned char *)p;
int len;
int len=0;
if (list && *list)
for (; (*list)[len]; len++) ;
if (xflags & XFLG_WORD_SPLIT) {
/* Skip over any initial whitespace. */
while (isspace(*s))
s++;
/* Update for "!" check. */
p = (const char *)s;
}
/* Is this a '+' or '-' followed by a space (not whitespace)? */
if (!(xflags & XFLG_WORDS_ONLY)
&& (*s == '-' || *s == '+') && s[1] == ' ') {
*incl_ptr = *s == '+';
s += 2;
} else
*incl_ptr = xflags & XFLG_DEF_INCLUDE;
if (xflags & XFLG_WORD_SPLIT) {
const unsigned char *cp = s;
/* Token ends at whitespace or the end of the string. */
while (!isspace(*cp) && *cp != '\0')
cp++;
len = cp - s;
} else
len = strlen(s);
if (*p == '!' && len == 1 && !(xflags & XFLG_WORDS_ONLY))
*incl_ptr = -1;
*len_ptr = len;
return (const char *)s;
}
void add_exclude(struct exclude_list_struct *listp, const char *pattern,
int xflags)
{
int pat_len, incl;
const char *cp;
if (!pattern)
return;
cp = pattern;
pat_len = 0;
while (1) {
cp = get_exclude_tok(cp + pat_len, &pat_len, &incl, 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 (verbose > 2) {
rprintf(FINFO, "[%s] add_exclude(%.*s, %s%s)\n",
who_am_i(), pat_len, cp,
listp->debug_type,
incl ? "include" : "exclude");
}
if (strcmp(pattern,"!") == 0) {
if (verbose > 2)
rprintf(FINFO,"clearing exclude list\n");
while ((len)--) {
free_exclude((*list)[len]);
}
free((*list));
*list = NULL;
return;
}
*list = realloc_array(*list, struct exclude_struct *, len+2);
if (!*list || !((*list)[len] = make_exclude(pattern, include)))
out_of_memory("add_exclude");
if (verbose > 2) {
rprintf(FINFO,"add_exclude(%s,%s)\n",pattern,
include ? "include" : "exclude");
}
(*list)[len+1] = NULL;
}
void add_exclude_file(struct exclude_list_struct *listp, const char *fname,
int xflags)
void add_exclude(const char *pattern, int include)
{
FILE *fp;
add_exclude_list(pattern,&exclude_list, include);
}
struct exclude_struct **make_exclude_list(const char *fname,
struct exclude_struct **list1,
int fatal, int include)
{
struct exclude_struct **list=list1;
FILE *f;
char line[MAXPATHLEN];
char *eob = line + MAXPATHLEN - 1;
int word_split = xflags & XFLG_WORD_SPLIT;
if (!fname || !*fname)
return;
if (*fname != '-' || fname[1])
fp = fopen(fname, "rb");
else
fp = stdin;
if (!fp) {
if (xflags & XFLG_FATAL_ERRORS) {
if (strcmp(fname, "-")) {
f = fopen(fname,"r");
} else {
f = fdopen(0, "r");
}
if (!f) {
if (fatal) {
rsyserr(FERROR, errno,
"failed to open %s file %s",
xflags & XFLG_DEF_INCLUDE ? "include" : "exclude",
fname);
"failed to open %s file %s",
include ? "include" : "exclude",
fname);
exit_cleanup(RERR_FILEIO);
}
return;
return list;
}
while (1) {
char *s = line;
int ch;
while (1) {
if ((ch = getc(fp)) == EOF) {
if (ferror(fp) && errno == EINTR)
continue;
break;
}
if (word_split && isspace(ch))
break;
if (eol_nulls? !ch : (ch == '\n' || ch == '\r'))
break;
if (s < eob)
*s++ = ch;
while (fgets(line,MAXPATHLEN,f)) {
int l = strlen(line);
while (l && (line[l-1] == '\n' || line[l-1] == '\r')) l--;
line[l] = 0;
if (line[0] && (line[0] != ';') && (line[0] != '#')) {
/* Skip lines starting with semicolon or pound.
It probably wouldn't cause any harm to not skip
them but there's no need to save them. */
add_exclude_list(line,&list,include);
}
*s = '\0';
/* Skip an empty token and (when line parsing) comments. */
if (*line && (word_split || (*line != ';' && *line != '#')))
add_exclude(listp, line, xflags);
if (ch == EOF)
break;
}
fclose(fp);
fclose(f);
return list;
}
void add_exclude_file(const char *fname, int fatal, int include)
{
if (!fname || !*fname) return;
exclude_list = make_exclude_list(fname,exclude_list,fatal,include);
}
void send_exclude_list(int f)
{
struct exclude_struct *ent;
int i;
extern int remote_version;
extern int list_only, recurse;
/* This is a complete hack - blame Rusty.
*
* FIXME: This pattern shows up in the output of
* report_exclude_result(), which is not ideal. */
if (list_only && !recurse)
add_exclude(&exclude_list, "/*/*", 0);
for (ent = exclude_list.head; ent; ent = ent->next) {
unsigned int l;
char p[MAXPATHLEN+1];
l = strlcpy(p, ent->pattern, sizeof p);
if (l == 0 || l >= MAXPATHLEN)
continue;
if (ent->directory) {
p[l++] = '/';
p[l] = '\0';
}
if (ent->include) {
write_int(f, l + 2);
write_buf(f, "+ ", 2);
} else if ((*p == '-' || *p == '+') && p[1] == ' ') {
write_int(f, l + 2);
write_buf(f, "- ", 2);
} else
write_int(f, l);
write_buf(f, p, l);
if (list_only && !recurse) {
add_exclude("/*/*", 0);
}
write_int(f, 0);
if (!exclude_list) {
write_int(f,0);
return;
}
for (i=0;exclude_list[i];i++) {
int l;
char pattern[MAXPATHLEN];
strlcpy(pattern,exclude_list[i]->pattern,sizeof(pattern));
if (exclude_list[i]->directory) strlcat(pattern,"/", sizeof(pattern));
l = strlen(pattern);
if (l == 0) continue;
if (exclude_list[i]->include) {
if (remote_version < 19) {
rprintf(FERROR,"remote rsync does not support include syntax - aborting\n");
exit_cleanup(RERR_UNSUPPORTED);
}
write_int(f,l+2);
write_buf(f,"+ ",2);
} else {
write_int(f,l);
}
write_buf(f,pattern,l);
}
write_int(f,0);
}
void recv_exclude_list(int f)
{
char line[MAXPATHLEN+1]; /* Allows a trailing slash on a max-len dir */
char line[MAXPATHLEN];
unsigned int l;
while ((l = read_int(f)) != 0) {
if (l >= sizeof line)
overflow("recv_exclude_list");
read_sbuf(f, line, l);
add_exclude(&exclude_list, line, 0);
while ((l=read_int(f))) {
if (l >= MAXPATHLEN) overflow("recv_exclude_list");
read_sbuf(f,line,l);
add_exclude(line,0);
}
}
/* Get the next include/exclude arg from the string. It works in a similar way
** to strtok - initially an arg is sent over, from then on NULL. This
** routine takes into account any +/- in the strings and does not
** consider the space following it as a delimeter.
*/
char *get_exclude_tok(char *p)
{
static char *s;
static int more;
char *t;
if (p) {
s=p;
if (*p)
more=1;
}
if (!more)
return(NULL);
/* Skip over any initial spaces */
while (isspace(* (unsigned char *) s))
s++;
/* Are we at the end of the string? */
if (*s) {
/* remember the beginning of the token */
t=s;
/* Is this a '+' or '-' followed by a space (not whitespace)? */
if ((*s=='+' || *s=='-') && *(s+1)==' ')
s+=2;
/* Skip to the next space or the end of the string */
while (!isspace(* (unsigned char *) s) && *s != '\0')
s++;
} else {
t=NULL;
}
/* Have we reached the end of the string? */
if (*s)
*s++='\0';
else
more=0;
return(t);
}
void add_exclude_line(char *p)
{
char *tok;
if (!p || !*p) return;
p = strdup(p);
if (!p) out_of_memory("add_exclude_line");
for (tok=get_exclude_tok(p); tok; tok=get_exclude_tok(NULL))
add_exclude(tok, 0);
free(p);
}
void add_include_line(char *p)
{
char *tok;
if (!p || !*p) return;
p = strdup(p);
if (!p) out_of_memory("add_include_line");
for (tok=get_exclude_tok(p); tok; tok=get_exclude_tok(NULL))
add_exclude(tok, 1);
free(p);
}
static char *cvs_ignore_list[] = {
"RCS/", "SCCS/", "CVS/", ".svn/", "CVS.adm", "RCSLOG", "cvslog.*",
"tags", "TAGS", ".make.state", ".nse_depinfo",
"*~", "#*", ".#*", ", *", "*.old", "*.bak", "*.BAK", "*.orig",
"*.rej", ".del-*", "*.a", "*.o", "*.obj", "*.so", "*.Z", "*.elc", "*.ln",
"core", NULL};
static char default_cvsignore[] =
/* These default ignored items come from the CVS manual. */
"RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS"
" .make.state .nse_depinfo *~ #* .#* ,* _$* *$"
" *.old *.bak *.BAK *.orig *.rej .del-*"
" *.a *.olb *.o *.obj *.so *.exe"
" *.Z *.elc *.ln core"
/* The rest we added to suit ourself. */
" .svn/";
void add_cvs_excludes(void)
{
char fname[MAXPATHLEN];
char *p;
int i;
for (i=0; cvs_ignore_list[i]; i++)
add_exclude(cvs_ignore_list[i], 0);
add_exclude(&exclude_list, default_cvsignore,
XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
if ((p = getenv("HOME"))
&& pathjoin(fname, sizeof fname, p, ".cvsignore") < sizeof fname) {
add_exclude_file(&exclude_list, fname,
XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
snprintf(fname,sizeof(fname), "%s/.cvsignore",p);
add_exclude_file(fname,0,0);
}
add_exclude(&exclude_list, getenv("CVSIGNORE"),
XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
add_exclude_line(getenv("CVSIGNORE"));
}

View File

@@ -1,24 +1,24 @@
/*
/*
Copyright (C) Andrew Tridgell 1998
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.
*/
/*
File IO utilities used in rsync
File IO utilities used in rsync
*/
#include "rsync.h"
@@ -42,8 +42,8 @@ static int write_sparse(int f,char *buf,size_t len)
size_t l1=0, l2=0;
int ret;
for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
for (l1=0;l1<len && buf[l1]==0;l1++) ;
for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
last_byte = buf[len-1];
@@ -51,79 +51,37 @@ static int write_sparse(int f,char *buf,size_t len)
last_sparse=1;
if (l1 > 0) {
do_lseek(f,l1,SEEK_CUR);
do_lseek(f,l1,SEEK_CUR);
}
if (l1 == len)
if (l1 == len)
return len;
ret = write(f, buf + l1, len - (l1+l2));
if (ret == -1 || ret == 0)
return ret;
else if (ret != (int) (len - (l1+l2)))
else if (ret != (int) (len - (l1+l2)))
return (l1+ret);
if (l2 > 0)
do_lseek(f,l2,SEEK_CUR);
return len;
}
static char *wf_writeBuf;
static size_t wf_writeBufSize;
static size_t wf_writeBufCnt;
int flush_write_file(int f)
{
int ret = 0;
char *bp = wf_writeBuf;
while (wf_writeBufCnt > 0) {
if ((ret = write(f, bp, wf_writeBufCnt)) < 0) {
if (errno == EINTR)
continue;
return ret;
}
wf_writeBufCnt -= ret;
bp += ret;
}
return ret;
}
/*
* write_file does not allow incomplete writes. It loops internally
* until len bytes are written or errno is set.
*/
int write_file(int f,char *buf,size_t len)
{
int ret = 0;
while (len > 0) {
int r1;
if (sparse_files) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
r1 = write_sparse(f, buf, len1);
} else {
if (!wf_writeBuf) {
wf_writeBufSize = MAX_MAP_SIZE;
wf_writeBufCnt = 0;
wf_writeBuf = new_array(char, MAX_MAP_SIZE);
if (!wf_writeBuf)
out_of_memory("write_file");
}
r1 = MIN(len, wf_writeBufSize - wf_writeBufCnt);
if (r1) {
memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1);
wf_writeBufCnt += r1;
}
if (wf_writeBufCnt == wf_writeBufSize) {
if (flush_write_file(f) < 0)
return -1;
if (!r1 && len)
continue;
}
}
if (!sparse_files) {
return write(f,buf,len);
}
while (len>0) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
int r1 = write_sparse(f, buf, len1);
if (r1 <= 0) {
if (ret > 0) return ret;
return r1;
@@ -154,7 +112,6 @@ struct map_struct *map_file(int fd,OFF_T len)
map->p_offset = 0;
map->p_fd_offset = 0;
map->p_len = 0;
map->status = 0;
return map;
}
@@ -176,7 +133,7 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
}
/* in most cases the region will already be available */
if (offset >= map->p_offset &&
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
return (map->p + (offset - map->p_offset));
}
@@ -231,11 +188,7 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
}
if ((nread=read(map->fd,map->p + read_offset,read_size)) != read_size) {
if (nread < 0) {
nread = 0;
if (!map->status)
map->status = errno;
}
if (nread < 0) nread = 0;
/* the best we can do is zero the buffer - the file
has changed mid transfer! */
memset(map->p+read_offset+nread, 0, read_size - nread);
@@ -245,23 +198,18 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
map->p_offset = window_start;
map->p_len = window_size;
return map->p + (offset - map->p_offset);
return map->p + (offset - map->p_offset);
}
int unmap_file(struct map_struct *map)
void unmap_file(struct map_struct *map)
{
int ret;
if (map->p) {
free(map->p);
map->p = NULL;
}
ret = map->status;
memset(map, 0, sizeof(*map));
free(map);
return ret;
}

1524
flist.c
View File

File diff suppressed because it is too large Load Diff

View File

@@ -30,9 +30,6 @@ extern int preserve_links;
extern int am_root;
extern int preserve_devices;
extern int preserve_hard_links;
extern int preserve_perms;
extern int preserve_uid;
extern int preserve_gid;
extern int update_only;
extern int opt_ignore_existing;
extern int csum_length;
@@ -41,33 +38,31 @@ extern int size_only;
extern int io_timeout;
extern int protocol_version;
extern int always_checksum;
extern int modify_window;
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 only_existing;
extern int orig_umask;
extern int safe_symlinks;
/* choose whether to skip a particular file */
static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st)
static int skip_file(char *fname,
struct file_struct *file, STRUCT_STAT *st)
{
if (st->st_size != file->length) {
return 0;
}
if (link_dest) {
if (preserve_perms
&& (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS))
extern int preserve_perms;
extern int preserve_uid;
extern int preserve_gid;
if(preserve_perms
&& (st->st_mode & ~_S_IFMT) != (file->mode & ~_S_IFMT))
return 0;
if (am_root && preserve_uid && st->st_uid != file->uid)
if (preserve_uid && st->st_uid != file->uid)
return 0;
if (preserve_gid && file->gid != GID_NONE
&& st->st_gid != file->gid)
if (preserve_gid && st->st_gid != file->gid)
return 0;
}
@@ -79,14 +74,17 @@ static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st)
if (compare_dest != NULL) {
if (access(fname, 0) != 0) {
pathjoin(fnamecmpdest, sizeof fnamecmpdest,
compare_dest, fname);
snprintf(fnamecmpdest,MAXPATHLEN,"%s/%s",
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 (protocol_version < 21) {
return (memcmp(sum,file->sum,2) == 0);
} else {
return (memcmp(sum,file->sum,MD4_SUM_LENGTH) == 0);
}
}
if (size_only) {
@@ -102,13 +100,14 @@ static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st)
/*
* NULL sum_struct means we have no checksums
* NULL sum_struct means we have no checksums
*/
void write_sum_head(int f, struct sum_struct *sum)
{
static struct sum_struct null_sum;
if (sum == NULL)
if (sum == (struct sum_struct *)NULL)
sum = &null_sum;
write_int(f, sum->count);
@@ -136,11 +135,10 @@ void write_sum_head(int f, struct sum_struct *sum)
* This might be made one of several selectable heuristics.
*/
static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len)
static void sum_sizes_sqroot_baarda(struct sum_struct *sum, uint64 len)
{
extern unsigned int block_size;
unsigned int blength;
int s2length;
extern int block_size;
int blength, s2length, b;
uint32 c;
uint64 l;
@@ -169,7 +167,7 @@ static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len)
} else if (csum_length == SUM_LENGTH) {
s2length = SUM_LENGTH;
} else {
int b = BLOCKSUM_BIAS;
b = BLOCKSUM_BIAS;
l = len;
while (l >>= 1) {
b += 2;
@@ -194,9 +192,10 @@ static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len)
sum->remainder = (len % blength);
if (sum->count && verbose > 2) {
rprintf(FINFO, "count=%.0f rem=%u blength=%u s2length=%d flength=%.0f\n",
(double)sum->count, sum->remainder, sum->blength,
sum->s2length, (double)sum->flength);
rprintf(FINFO, "count=%ld rem=%ld blength=%ld s2length=%ld flength=%.0f\n",
(long) sum->count, (long) sum->remainder,
(long) sum->blength, (long) sum->s2length,
(double) sum->flength);
}
}
@@ -211,6 +210,10 @@ static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len)
* Whew. */
static BOOL disable_deltas_p(void)
{
extern int whole_file;
extern int local_server;
extern int write_batch;
if (whole_file > 0)
return True;
if (whole_file == 0 || write_batch)
@@ -224,18 +227,18 @@ static BOOL disable_deltas_p(void)
*
* 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(struct map_struct *buf, OFF_T len, int f_out)
{
size_t i;
struct sum_struct sum;
OFF_T offset = 0;
sum_sizes_sqroot(&sum, len);
sum_sizes_sqroot_baarda(&sum, len);
write_sum_head(f_out, &sum);
for (i = 0; i < sum.count; i++) {
unsigned int n1 = MIN(len, sum.blength);
int n1 = MIN(len, sum.blength);
char *map = map_ptr(buf, offset, n1);
uint32 sum1 = get_checksum1(map, n1);
char sum2[SUM_LENGTH];
@@ -244,9 +247,8 @@ static void generate_and_send_sums(struct map_struct *buf, size_t len, int f_out
if (verbose > 3) {
rprintf(FINFO,
"chunk[%.0f] offset=%.0f len=%u sum1=%08lx\n",
(double)i, (double)offset, n1,
(unsigned long)sum1);
"chunk[%ld] offset=%.0f len=%d sum1=%08lx\n",
(long)i,(double)offset,n1,(unsigned long)sum1);
}
write_int(f_out, sum1);
write_buf(f_out, sum2, sum.s2length);
@@ -265,17 +267,22 @@ static void generate_and_send_sums(struct map_struct *buf, size_t len, int f_out
* @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)
void recv_generator(char *fname, struct file_list *flist, int i, int f_out)
{
int fd;
STRUCT_STAT st;
struct map_struct *mapbuf;
struct map_struct *buf;
int statret;
struct file_struct *file = flist->files[i];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
extern char *compare_dest;
extern int list_only;
extern int preserve_perms;
extern int only_existing;
extern int orig_umask;
if (list_only)
return;
if (list_only) return;
if (verbose > 2)
rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
@@ -294,8 +301,7 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
/* 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 */
file->mode = (file->mode & ~CHMOD_BITS)
| (st.st_mode & CHMOD_BITS);
file->mode = (file->mode & _S_IFMT) | (st.st_mode & ~_S_IFMT);
}
if (S_ISDIR(file->mode)) {
@@ -334,11 +340,12 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
#if SUPPORT_LINKS
char lnk[MAXPATHLEN];
int l;
extern int safe_symlinks;
if (safe_symlinks && unsafe_symlink(file->u.link, fname)) {
if (safe_symlinks && unsafe_symlink(file->link, fname)) {
if (verbose) {
rprintf(FINFO, "ignoring unsafe symlink %s -> \"%s\"\n",
full_fname(fname), file->u.link);
full_fname(fname), file->link);
}
return;
}
@@ -349,7 +356,7 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
/* A link already pointing to the
* right place -- no further action
* required. */
if (strcmp(lnk,file->u.link) == 0) {
if (strcmp(lnk,file->link) == 0) {
set_perms(fname,file,&st,1);
return;
}
@@ -359,13 +366,13 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
* in place. */
delete_file(fname);
}
if (do_symlink(file->u.link,fname) != 0) {
if (do_symlink(file->link,fname) != 0) {
rprintf(FERROR, "symlink %s -> \"%s\" failed: %s\n",
full_fname(fname), file->u.link, strerror(errno));
full_fname(fname), file->link, strerror(errno));
} else {
set_perms(fname,file,NULL,0);
if (verbose) {
rprintf(FINFO,"%s -> %s\n", fname,file->u.link);
rprintf(FINFO,"%s -> %s\n", fname,file->link);
}
}
#endif
@@ -376,12 +383,12 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
if (am_root && preserve_devices && IS_DEVICE(file->mode)) {
if (statret != 0 ||
st.st_mode != file->mode ||
st.st_rdev != file->u.rdev) {
(DEV64_T)st.st_rdev != file->rdev) {
delete_file(fname);
if (verbose > 2)
rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
fname,(int)file->mode,(int)file->u.rdev);
if (do_mknod(fname,file->mode,file->u.rdev) != 0) {
fname,(int)file->mode,(int)file->rdev);
if (do_mknod(fname,file->mode,file->rdev) != 0) {
rprintf(FERROR, "mknod %s failed: %s\n",
full_fname(fname), strerror(errno));
} else {
@@ -396,8 +403,11 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
}
#endif
if (preserve_hard_links && hard_link_check(file, HL_CHECK_MASTER))
if (preserve_hard_links && check_hard_link(file)) {
if (verbose > 1)
rprintf(FINFO, "recv_generator: \"%s\" is a hard link\n",f_name(file));
return;
}
if (!S_ISREG(file->mode)) {
rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
@@ -406,10 +416,10 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
fnamecmp = fname;
if (statret == -1 && compare_dest != NULL) {
if ((statret == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
int saveerrno = errno;
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, compare_dest, fname);
snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",compare_dest,fname);
statret = link_stat(fnamecmpbuf,&st);
if (!S_ISREG(st.st_mode))
statret = -1;
@@ -418,11 +428,11 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
#if HAVE_LINK
else if (link_dest && !dry_run) {
if (do_link(fnamecmpbuf, fname) != 0) {
if (verbose > 0) {
if (verbose > 0)
rprintf(FINFO,"link %s => %s : %s\n",
fnamecmpbuf, fname,
fnamecmpbuf,
fname,
strerror(errno));
}
}
fnamecmp = fnamecmpbuf;
}
@@ -432,8 +442,6 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
}
if (statret == -1) {
if (preserve_hard_links && hard_link_check(file, HL_SKIP))
return;
if (errno == ENOENT) {
write_int(f_out,i);
if (!dry_run) write_sum_head(f_out, NULL);
@@ -451,8 +459,6 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
}
/* 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;
@@ -494,44 +500,40 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
rprintf(FERROR, "failed to open %s, continuing: %s\n",
full_fname(fnamecmp), strerror(errno));
/* pretend the file didn't exist */
if (preserve_hard_links && hard_link_check(file, HL_SKIP))
return;
write_int(f_out,i);
write_sum_head(f_out, NULL);
return;
}
if (st.st_size > 0)
mapbuf = map_file(fd,st.st_size);
else
mapbuf = NULL;
if (verbose > 3) {
rprintf(FINFO,"gen mapped %s of size %.0f\n", fnamecmp,
(double)st.st_size);
if (st.st_size > 0) {
buf = map_file(fd,st.st_size);
} else {
buf = NULL;
}
if (verbose > 3)
rprintf(FINFO,"gen mapped %s of size %.0f\n",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(buf, st.st_size, f_out);
close(fd);
if (mapbuf) unmap_file(mapbuf);
if (buf) unmap_file(buf);
}
void generate_files(int f, struct file_list *flist, char *local_name)
void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
{
int i;
int phase=0;
char fbuf[MAXPATHLEN];
if (verbose > 2) {
rprintf(FINFO, "generator starting pid=%ld count=%d\n",
(long)getpid(), flist->count);
}
if (verbose > 2)
rprintf(FINFO,"generator starting pid=%d count=%d\n",
(int)getpid(),flist->count);
if (verbose >= 2) {
rprintf(FINFO,
@@ -547,23 +549,21 @@ void generate_files(int f, struct file_list *flist, char *local_name)
for (i = 0; i < flist->count; i++) {
struct file_struct *file = flist->files[i];
struct file_struct copy;
mode_t saved_mode = file->mode;
if (!file->basename) continue;
if (!file->basename)
continue;
/* we need to ensure that any directories we create have writeable
permissions initially so that we can create the files within
them. This is then fixed after the files are transferred */
if (!am_root && S_ISDIR(file->mode) && !(file->mode & S_IWUSR)) {
copy = *file;
if (!am_root && S_ISDIR(file->mode)) {
file->mode |= S_IWUSR; /* user write */
/* XXX: Could this be causing a problem on SCO? Perhaps their
* handling of permissions is strange? */
copy.mode |= S_IWUSR; /* user write */
file = &copy;
}
recv_generator(local_name ? local_name : f_name_to(file, fbuf),
file, i, f);
recv_generator(local_name?local_name:f_name(file), flist,i,f);
file->mode = saved_mode;
}
phase++;
@@ -577,10 +577,9 @@ void generate_files(int f, struct file_list *flist, char *local_name)
/* files can cycle through the system more than once
* to catch initial checksum errors */
while ((i = get_redo_num()) != -1) {
for (i=read_int(f_recv); i != -1; i=read_int(f_recv)) {
struct file_struct *file = flist->files[i];
recv_generator(local_name ? local_name : f_name_to(file, fbuf),
file, i, f);
recv_generator(local_name?local_name:f_name(file), flist,i,f);
}
phase++;
@@ -588,19 +587,4 @@ void generate_files(int f, struct file_list *flist, char *local_name)
rprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
if (preserve_hard_links)
do_hard_links();
/* now we need to fix any directory permissions that were
* 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;
recv_generator(local_name ? local_name : f_name(file),
file, i, -1);
}
if (verbose > 2)
rprintf(FINFO,"generate_files finished\n");
}

View File

@@ -26,42 +26,24 @@
#include "rsync.h"
#ifndef NGROUPS
/* It ought to be defined, but just in case. */
# define NGROUPS 32
#endif
int
main(UNUSED(int argc), UNUSED(char *argv[]))
{
int n, i;
gid_t *list;
gid_t gid = MY_GID();
int gid_in_list = 0;
gid_t list[NGROUPS];
#ifdef HAVE_GETGROUPS
if ((n = getgroups(0, NULL)) < 0) {
if ((n = getgroups(NGROUPS, list)) == -1) {
perror("getgroups");
return 1;
}
#else
n = 0;
#endif
list = (gid_t*)malloc(sizeof (gid_t) * (n + 1));
if (!list) {
fprintf(stderr, "out of memory!\n");
exit(1);
}
#ifdef HAVE_GETGROUPS
if (n > 0)
n = getgroups(n, list);
#endif
for (i = 0; i < n; i++) {
printf("%lu ", (unsigned long)list[i]);
if (list[i] == gid)
gid_in_list = 1;
}
/* The default gid might not be in the list on some systems. */
if (!gid_in_list)
printf("%lu", (unsigned long)gid);
for (i = 0; i < n; i++)
printf("%u ", list[i]);
printf("\n");
return 0;

233
hlink.c
View File

@@ -1,18 +1,18 @@
/*
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
Copyright (C) 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,144 +22,138 @@
extern int dry_run;
extern int verbose;
extern int make_backups;
#if SUPPORT_HARD_LINKS
static int hlink_compare(struct file_struct **file1, struct file_struct **file2)
static int hlink_compare(struct file_struct *f1, struct file_struct *f2)
{
struct file_struct *f1 = *file1;
struct file_struct *f2 = *file2;
if (!S_ISREG(f1->mode) && !S_ISREG(f2->mode))
return 0;
if (!S_ISREG(f1->mode))
return -1;
if (!S_ISREG(f2->mode))
return 1;
if (f1->F_DEV != f2->F_DEV)
return (int) (f1->F_DEV > f2->F_DEV ? 1 : -1);
if (f1->dev != f2->dev)
return (int) (f1->dev > f2->dev ? 1 : -1);
if (f1->F_INODE != f2->F_INODE)
return (int) (f1->F_INODE > f2->F_INODE ? 1 : -1);
if (f1->inode != f2->inode)
return (int) (f1->inode > f2->inode ? 1 : -1);
return file_compare(file1, file2);
return file_compare(&f1, &f2);
}
static struct file_struct **hlink_list;
static struct file_struct *hlink_list;
static int hlink_count;
#define LINKED(p1,p2) ((p1)->F_DEV == (p2)->F_DEV \
&& (p1)->F_INODE == (p2)->F_INODE)
/* Analyze the data in the hlink_list[], remove items that aren't multiply
* linked, and replace the dev+inode data with the hlindex+next linked list. */
static void link_idev_data(struct file_list *flist)
{
struct file_struct *head;
int from, to, start;
alloc_pool_t hlink_pool;
alloc_pool_t idev_pool = flist->hlink_pool;
hlink_pool = pool_create(128 * 1024, sizeof (struct hlink),
out_of_memory, POOL_INTERN);
for (from = to = 0; from < hlink_count; from++) {
start = from;
head = hlink_list[start];
while (from < hlink_count-1
&& LINKED(hlink_list[from], hlink_list[from+1])) {
pool_free(idev_pool, 0, hlink_list[from]->link_u.idev);
hlink_list[from]->link_u.links = pool_talloc(hlink_pool,
struct hlink, 1, "hlink_list");
hlink_list[from]->F_HLINDEX = to;
hlink_list[from]->F_NEXT = hlink_list[from+1];
from++;
}
if (from > start) {
pool_free(idev_pool, 0, hlink_list[from]->link_u.idev);
hlink_list[from]->link_u.links = pool_talloc(hlink_pool,
struct hlink, 1, "hlink_list");
hlink_list[from]->F_HLINDEX = to;
hlink_list[from]->F_NEXT = head;
hlink_list[from]->flags |= FLAG_HLINK_EOL;
hlink_list[to++] = head;
} else {
pool_free(idev_pool, 0, head->link_u.idev);
head->link_u.idev = NULL;
}
}
if (!to) {
free(hlink_list);
hlink_list = NULL;
pool_destroy(hlink_pool);
hlink_pool = NULL;
} else {
hlink_count = to;
if (!(hlink_list = realloc_array(hlink_list,
struct file_struct *, hlink_count)))
out_of_memory("init_hard_links");
}
flist->hlink_pool = hlink_pool;
pool_destroy(idev_pool);
}
#endif
void init_hard_links(struct file_list *flist)
{
#if SUPPORT_HARD_LINKS
int i;
if (flist->count < 2)
return;
if (hlink_list)
free(hlink_list);
if (!(hlink_list = new_array(struct file_struct *, flist->count)))
if (!(hlink_list = new_array(struct file_struct, flist->count)))
out_of_memory("init_hard_links");
hlink_count = 0;
for (i = 0; i < flist->count; i++) {
if (flist->files[i]->link_u.idev)
hlink_list[hlink_count++] = flist->files[i];
}
for (i = 0; i < flist->count; i++)
memcpy(&hlink_list[i], flist->files[i],
sizeof(hlink_list[0]));
qsort(hlink_list, hlink_count,
sizeof hlink_list[0], (int (*)()) hlink_compare);
qsort(hlink_list, flist->count,
sizeof(hlink_list[0]), (int (*)()) hlink_compare);
if (!hlink_count) {
free(hlink_list);
hlink_list = NULL;
} else
link_idev_data(flist);
hlink_count = flist->count;
#endif
}
int hard_link_check(struct file_struct *file, int skip)
/* check if a file should be skipped because it is the same as an
earlier hard link */
int check_hard_link(struct file_struct *file)
{
if (!hlink_list || !file->link_u.links)
#if SUPPORT_HARD_LINKS
int low = 0, high = hlink_count - 1;
int ret = 0;
if (!hlink_list || !S_ISREG(file->mode))
return 0;
if (skip && !(file->flags & FLAG_HLINK_EOL))
hlink_list[file->F_HLINDEX] = file->F_NEXT;
if (hlink_list[file->F_HLINDEX] != file) {
if (verbose > 1) {
rprintf(FINFO, "\"%s\" is a hard link\n",
f_name(file));
while (low != high) {
int mid = (low + high) / 2;
ret = hlink_compare(&hlink_list[mid], file);
if (ret == 0) {
low = mid;
break;
}
if (ret > 0)
high = mid;
else
low = mid + 1;
}
/* XXX: To me this looks kind of dodgy -- why do we use [low]
* here and [low-1] below? -- mbp */
if (hlink_compare(&hlink_list[low], file) != 0)
return 0;
if (low > 0 &&
S_ISREG(hlink_list[low - 1].mode) &&
file->dev == hlink_list[low - 1].dev &&
file->inode == hlink_list[low - 1].inode) {
if (verbose >= 2) {
rprintf(FINFO, "check_hard_link: \"%s\" is a hard link to file %d, \"%s\"\n",
f_name(file), low-1, f_name(&hlink_list[low-1]));
}
return 1;
}
#endif
return 0;
}
#if SUPPORT_HARD_LINKS
static void hard_link_one(char *hlink1, char *hlink2)
static void hard_link_one(int i)
{
if (do_link(hlink1, hlink2)) {
if (verbose) {
rprintf(FINFO, "link %s => %s failed: %s\n",
hlink2, hlink1, strerror(errno));
STRUCT_STAT st1, st2;
if (link_stat(f_name(&hlink_list[i - 1]), &st1) != 0)
return;
if (link_stat(f_name(&hlink_list[i]), &st2) != 0) {
if (do_link
(f_name(&hlink_list[i - 1]),
f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
rprintf(FINFO, "link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i - 1]),
strerror(errno));
return;
}
} else {
if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino)
return;
if (robust_unlink(f_name(&hlink_list[i])) != 0 ||
do_link(f_name(&hlink_list[i - 1]),
f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
rprintf(FINFO, "link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i - 1]),
strerror(errno));
return;
}
}
else if (verbose)
rprintf(FINFO, "%s => %s\n", hlink2, hlink1);
if (verbose > 0)
rprintf(FINFO, "%s => %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i - 1]));
}
#endif
@@ -172,39 +166,18 @@ static void hard_link_one(char *hlink1, char *hlink2)
void do_hard_links(void)
{
#if SUPPORT_HARD_LINKS
struct file_struct *file, *first;
char hlink1[MAXPATHLEN];
char *hlink2;
STRUCT_STAT st1, st2;
int i;
if (!hlink_list)
return;
for (i = 0; i < hlink_count; i++) {
first = file = hlink_list[i];
if (link_stat(f_name_to(first, hlink1), &st1) != 0)
continue;
while ((file = file->F_NEXT) != first) {
hlink2 = f_name(file);
if (link_stat(hlink2, &st2) == 0) {
if (st2.st_dev == st1.st_dev
&& st2.st_ino == st1.st_ino)
continue;
if (make_backups) {
if (!make_backup(hlink2))
continue;
} else if (robust_unlink(hlink2)) {
if (verbose > 0) {
rprintf(FINFO,
"unlink %s failed: %s\n",
full_fname(hlink2),
strerror(errno));
}
continue;
}
}
hard_link_one(hlink1, hlink2);
for (i = 1; i < hlink_count; i++) {
if (S_ISREG(hlink_list[i].mode) &&
S_ISREG(hlink_list[i - 1].mode) &&
hlink_list[i].basename && hlink_list[i - 1].basename &&
hlink_list[i].dev == hlink_list[i - 1].dev &&
hlink_list[i].inode == hlink_list[i - 1].inode) {
hard_link_one(i);
}
}
#endif

611
io.c
View File

@@ -41,17 +41,14 @@
static int io_multiplexing_out;
static int io_multiplexing_in;
static int multiplex_in_fd = -1;
static int multiplex_out_fd = -1;
static int multiplex_in_fd;
static int multiplex_out_fd;
static time_t last_io;
static int no_flush;
extern int bwlimit;
extern int verbose;
extern int io_timeout;
extern int am_server;
extern int am_daemon;
extern int am_sender;
extern struct stats stats;
@@ -77,56 +74,19 @@ const char *io_read_phase = phase_unknown;
version is 24 or less. */
int kludge_around_eof = False;
int msg_fd_in = -1;
int msg_fd_out = -1;
static int io_filesfrom_f_in = -1;
static int io_filesfrom_f_out = -1;
static char io_filesfrom_buf[2048];
static char *io_filesfrom_bp;
static char io_filesfrom_lastchar;
static int io_filesfrom_buflen;
static int io_error_fd = -1;
static void read_loop(int fd, char *buf, size_t len);
struct redo_list {
struct redo_list *next;
int num;
};
static struct redo_list *redo_list_head;
static struct redo_list *redo_list_tail;
struct msg_list {
struct msg_list *next;
char *buf;
int len;
};
static struct msg_list *msg_list_head;
static struct msg_list *msg_list_tail;
static void redo_list_add(int num)
{
struct redo_list *rl;
if (!(rl = new(struct redo_list)))
exit_cleanup(RERR_MALLOC);
rl->next = NULL;
rl->num = num;
if (redo_list_tail)
redo_list_tail->next = rl;
else
redo_list_head = rl;
redo_list_tail = rl;
}
static void check_timeout(void)
{
extern int am_server, am_daemon;
time_t t;
if (!io_timeout)
return;
err_list_push();
if (!io_timeout) return;
if (!last_io) {
last_io = time(NULL);
@@ -144,180 +104,43 @@ static void check_timeout(void)
}
}
/** 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. */
void set_msg_fd_in(int fd)
/** Setup the fd used to propagate errors */
void io_set_error_fd(int fd)
{
msg_fd_in = fd;
io_error_fd = 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. */
void set_msg_fd_out(int fd)
{
msg_fd_out = fd;
set_nonblocking(msg_fd_out);
}
/* Add a message to the pending MSG_* list. */
static void msg_list_add(int code, char *buf, int len)
{
struct msg_list *ml;
if (!(ml = new(struct msg_list)))
exit_cleanup(RERR_MALLOC);
ml->next = NULL;
if (!(ml->buf = new_array(char, len+4)))
exit_cleanup(RERR_MALLOC);
SIVAL(ml->buf, 0, ((code+MPLEX_BASE)<<24) | len);
memcpy(ml->buf+4, buf, len);
ml->len = len+4;
if (msg_list_tail)
msg_list_tail->next = ml;
else
msg_list_head = ml;
msg_list_tail = ml;
}
void send_msg(enum msgcode code, char *buf, int len)
{
msg_list_add(code, buf, len);
msg_list_push(NORMAL_FLUSH);
}
/** Read a message from the MSG_* fd and dispatch it. This is only
* called by the generator. */
static void read_msg_fd(void)
/** Read some data from the error fd and write it to the write log code */
static void read_error_fd(void)
{
char buf[200];
size_t n;
int fd = msg_fd_in;
int fd = io_error_fd;
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. */
msg_fd_in = -1;
/* io_error_fd is temporarily disabled -- is this meant to
* prevent indefinite recursion? */
io_error_fd = -1;
read_loop(fd, buf, 4);
tag = IVAL(buf, 0);
len = tag & 0xFFFFFF;
tag = (tag >> 24) - MPLEX_BASE;
tag = tag >> 24;
tag -= MPLEX_BASE;
switch (tag) {
case MSG_DONE:
if (len != 0) {
rprintf(FERROR, "invalid message %d:%d\n", tag, len);
exit_cleanup(RERR_STREAMIO);
}
redo_list_add(-1);
break;
case MSG_REDO:
if (len != 4) {
rprintf(FERROR, "invalid message %d:%d\n", tag, len);
exit_cleanup(RERR_STREAMIO);
}
read_loop(fd, buf, 4);
redo_list_add(IVAL(buf,0));
break;
case MSG_INFO:
case MSG_ERROR:
case MSG_LOG:
while (len) {
n = len;
if (n >= sizeof buf)
n = sizeof buf - 1;
read_loop(fd, buf, n);
rwrite((enum logcode)tag, buf, n);
len -= n;
}
break;
default:
rprintf(FERROR, "unknown message %d:%d\n", tag, len);
exit_cleanup(RERR_STREAMIO);
while (len) {
n = len;
if (n > (sizeof(buf)-1))
n = sizeof(buf)-1;
read_loop(fd, buf, n);
rwrite((enum logcode)tag, buf, n);
len -= n;
}
msg_fd_in = fd;
io_error_fd = fd;
}
/* 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. */
int msg_list_push(int flush_it_all)
{
static int written = 0;
struct timeval tv;
fd_set fds;
if (msg_fd_out < 0)
return -1;
while (msg_list_head) {
struct msg_list *ml = msg_list_head;
int n = write(msg_fd_out, ml->buf + written, ml->len - written);
if (n < 0) {
if (errno == EINTR)
continue;
if (errno != EWOULDBLOCK && errno != EAGAIN)
return -1;
if (!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_usec = 0;
if (!select(msg_fd_out+1, NULL, &fds, NULL, &tv))
check_timeout();
} else if ((written += n) == ml->len) {
free(ml->buf);
msg_list_head = ml->next;
if (!msg_list_head)
msg_list_tail = NULL;
free(ml);
written = 0;
}
}
return 1;
}
int get_redo_num(void)
{
struct redo_list *next;
int num;
while (!redo_list_head)
read_msg_fd();
num = redo_list_head->num;
next = redo_list_head->next;
free(redo_list_head);
redo_list_head = next;
if (!next)
redo_list_tail = NULL;
return num;
}
/**
* When we're the receiver and we have a local --files-from list of names
* that needs to be sent over the socket to the sender, we have to do two
* things at the same time: send the sender a list of what files we're
* processing and read the incoming file+info list from the sender. We do
* this by augmenting the read_timeout() function to copy this data. It
* uses the io_filesfrom_buf to read a block of data from f_in (when it is
* ready, since it might be a pipe) and then blast it out f_out (when it
* is ready to receive more data).
*/
void io_set_filesfrom_fds(int f_in, int f_out)
{
io_filesfrom_f_in = f_in;
io_filesfrom_f_out = f_out;
io_filesfrom_bp = io_filesfrom_buf;
io_filesfrom_lastchar = '\0';
io_filesfrom_buflen = 0;
}
/**
* It's almost always an error to get an EOF when we're trying to read
@@ -329,28 +152,28 @@ 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 (void)
{
if (kludge_around_eof)
exit_cleanup(0);
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,
"%s: connection unexpectedly closed "
"(%.0f bytes read so far)\n",
RSYNC_NAME, (double)stats.total_read);
exit_cleanup (RERR_STREAMIO);
}
}
static void die_from_readerr(int err)
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));
RSYNC_NAME, strerror (err));
exit_cleanup(RERR_STREAMIO);
}
@@ -366,43 +189,24 @@ static void die_from_readerr(int err)
* give a better explanation. We can tell whether the connection has
* started by looking e.g. at whether the remote version is known yet.
*/
static int read_timeout(int fd, char *buf, size_t len)
static int read_timeout (int fd, char *buf, size_t len)
{
int n, ret=0;
io_flush(NORMAL_FLUSH);
io_flush();
while (ret == 0) {
/* until we manage to read *something* */
fd_set r_fds, w_fds;
fd_set fds;
struct timeval tv;
int fd_count = fd+1;
int count;
FD_ZERO(&r_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 (io_filesfrom_f_out >= 0) {
int new_fd;
if (io_filesfrom_buflen == 0) {
if (io_filesfrom_f_in >= 0) {
FD_SET(io_filesfrom_f_in, &r_fds);
new_fd = io_filesfrom_f_in;
} else {
io_filesfrom_f_out = -1;
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;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (io_error_fd != -1) {
FD_SET(io_error_fd, &fds);
if (io_error_fd > fd) fd_count = io_error_fd+1;
}
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
@@ -410,12 +214,9 @@ static int read_timeout(int fd, char *buf, size_t len)
errno = 0;
count = select(fd_count, &r_fds,
io_filesfrom_buflen? &w_fds : NULL,
NULL, &tv);
count = select(fd_count, &fds, NULL, NULL, &tv);
if (count == 0) {
msg_list_push(NORMAL_FLUSH);
check_timeout();
}
@@ -426,74 +227,11 @@ static int read_timeout(int fd, char *buf, size_t len)
continue;
}
if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds))
read_msg_fd();
if (io_filesfrom_f_out >= 0) {
if (io_filesfrom_buflen) {
if (FD_ISSET(io_filesfrom_f_out, &w_fds)) {
int l = write(io_filesfrom_f_out,
io_filesfrom_bp,
io_filesfrom_buflen);
if (l > 0) {
if (!(io_filesfrom_buflen -= l))
io_filesfrom_bp = io_filesfrom_buf;
else
io_filesfrom_bp += l;
} else {
/* XXX should we complain? */
io_filesfrom_f_out = -1;
}
}
} else if (io_filesfrom_f_in >= 0) {
if (FD_ISSET(io_filesfrom_f_in, &r_fds)) {
int l = read(io_filesfrom_f_in,
io_filesfrom_buf,
sizeof io_filesfrom_buf);
if (l <= 0) {
/* Send end-of-file marker */
io_filesfrom_buf[0] = '\0';
io_filesfrom_buf[1] = '\0';
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' */
while (s-- > io_filesfrom_buf) {
if (*s == '\n' || *s == '\r')
*s = '\0';
}
}
if (!io_filesfrom_lastchar) {
/* Last buf ended with a '\0', so don't
* let this buf start with one. */
while (l && !*io_filesfrom_bp)
io_filesfrom_bp++, l--;
}
if (!l)
io_filesfrom_bp = io_filesfrom_buf;
else {
char *f = io_filesfrom_bp;
char *t = f;
char *eob = f + l;
/* Eliminate any multi-'\0' runs. */
while (f != eob) {
if (!(*t++ = *f++)) {
while (f != eob && !*f)
f++, l--;
}
}
io_filesfrom_lastchar = f[-1];
}
io_filesfrom_buflen = l;
}
}
}
if (io_error_fd != -1 && FD_ISSET(io_error_fd, &fds)) {
read_error_fd();
}
if (!FD_ISSET(fd, &r_fds)) continue;
if (!FD_ISSET(fd, &fds)) continue;
n = read(fd, buf, len);
@@ -505,75 +243,28 @@ static int read_timeout(int fd, char *buf, size_t len)
last_io = time(NULL);
continue;
} else if (n == 0) {
whine_about_eof();
whine_about_eof ();
return -1; /* doesn't return */
} else if (n < 0) {
} else if (n == -1) {
if (errno == EINTR || errno == EWOULDBLOCK ||
errno == EAGAIN)
continue;
die_from_readerr(errno);
else
die_from_readerr (errno);
}
}
return ret;
}
/**
* Read a line into the "fname" buffer (which must be at least MAXPATHLEN
* characters long).
*/
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;
start:
s = fname;
while (1) {
cnt = read(fd, &ch, 1);
if (cnt < 0 && (errno == EWOULDBLOCK
|| errno == EINTR || errno == EAGAIN)) {
struct timeval tv;
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = io_timeout? io_timeout : SELECT_TIMEOUT;
tv.tv_usec = 0;
if (!select(fd+1, &fds, NULL, NULL, &tv))
check_timeout();
continue;
}
if (cnt != 1)
break;
if (nulls? !ch : (ch == '\r' || ch == '\n')) {
/* Skip empty lines if reading locally. */
if (!reading_remotely && s == fname)
continue;
break;
}
if (s < eob)
*s++ = ch;
}
*s = '\0';
/* Dump comments. */
if (*fname == '#' || *fname == ';')
goto start;
return s - fname;
}
/**
* Continue trying to read len bytes - don't return until len has been
* read.
**/
static void read_loop(int fd, char *buf, size_t len)
static void read_loop (int fd, char *buf, size_t len)
{
while (len) {
int n = read_timeout(fd, buf, len);
@@ -595,68 +286,47 @@ static int read_unbuffered(int fd, char *buf, size_t len)
static size_t remaining;
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 (!io_multiplexing_in || fd != multiplex_in_fd)
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;
}
while (ret == 0) {
if (remaining) {
len = MIN(len, remaining);
memcpy(buf, buffer + bufferIdx, len);
bufferIdx += len;
read_loop(fd, buf, len);
remaining -= len;
ret = len;
break;
continue;
}
read_loop(fd, line, 4);
tag = IVAL(line, 0);
remaining = tag & 0xFFFFFF;
tag = (tag >> 24) - MPLEX_BASE;
tag = tag >> 24;
switch (tag) {
case MSG_DATA:
if (!buffer || remaining > bufferSz) {
buffer = realloc_array(buffer, char, remaining);
if (!buffer) out_of_memory("read_unbuffered");
bufferSz = remaining;
}
read_loop(fd, buffer, remaining);
bufferIdx = 0;
break;
case MSG_INFO:
case MSG_ERROR:
if (remaining >= sizeof line) {
rprintf(FERROR, "multiplexing overflow %d:%ld\n\n",
tag, (long)remaining);
exit_cleanup(RERR_STREAMIO);
}
read_loop(fd, line, remaining);
rwrite((enum logcode)tag, line, remaining);
remaining = 0;
break;
default:
if (tag == MPLEX_BASE)
continue;
tag -= MPLEX_BASE;
if (tag != FERROR && tag != FINFO) {
rprintf(FERROR, "unexpected tag %d\n", tag);
exit_cleanup(RERR_STREAMIO);
}
}
if (remaining == 0)
io_flush(NORMAL_FLUSH);
if (remaining > sizeof(line) - 1) {
rprintf(FERROR, "multiplexing overflow %d\n\n",
remaining);
exit_cleanup(RERR_STREAMIO);
}
read_loop(fd, line, remaining);
line[remaining] = 0;
rprintf((enum logcode) tag, "%s", line);
remaining = 0;
}
return ret;
}
@@ -668,13 +338,15 @@ static int read_unbuffered(int fd, char *buf, size_t len)
* have been read. If all @p n can't be read then exit with an
* error.
**/
static void readfd(int fd, char *buffer, size_t N)
static void readfd (int fd, char *buffer, size_t N)
{
int ret;
size_t total=0;
while (total < N) {
ret = read_unbuffered(fd, buffer + total, N-total);
io_flush();
ret = read_unbuffered (fd, buffer + total, N-total);
total += ret;
}
@@ -695,6 +367,7 @@ int32 read_int(int f)
int64 read_longint(int f)
{
extern int remote_version;
int64 ret;
char b[8];
ret = read_int(f);
@@ -707,8 +380,10 @@ int64 read_longint(int f)
rprintf(FERROR,"Integer overflow - attempted 64 bit offset\n");
exit_cleanup(RERR_UNSUPPORTED);
#else
readfd(f,b,8);
ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
if (remote_version >= 16) {
readfd(f,b,8);
ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
}
#endif
return ret;
@@ -721,14 +396,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);
read_buf (f,buf,len);
buf[len] = 0;
}
unsigned char read_byte(int f)
{
unsigned char c;
read_buf(f, (char *)&c, 1);
read_buf (f, (char *)&c, 1);
return c;
}
@@ -751,7 +426,7 @@ static void sleep_for_bwlimit(int bytes_written)
assert(bytes_written > 0);
assert(bwlimit > 0);
tv.tv_usec = bytes_written * 1000 / bwlimit;
tv.tv_sec = tv.tv_usec / 1000000;
tv.tv_usec = tv.tv_usec % 1000000;
@@ -773,31 +448,33 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
int fd_count, count;
struct timeval tv;
msg_list_push(NORMAL_FLUSH);
err_list_push();
no_flush++;
while (total < len) {
FD_ZERO(&w_fds);
FD_ZERO(&r_fds);
FD_SET(fd,&w_fds);
fd_count = 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 (io_error_fd != -1) {
FD_SET(io_error_fd,&r_fds);
if (io_error_fd > fd_count)
fd_count = io_error_fd;
}
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
tv.tv_usec = 0;
errno = 0;
count = select(fd_count+1, msg_fd_in >= 0 ? &r_fds : NULL,
&w_fds, NULL, &tv);
count = select(fd_count+1,
io_error_fd != -1?&r_fds:NULL,
&w_fds,NULL,
&tv);
if (count == 0) {
msg_list_push(NORMAL_FLUSH);
check_timeout();
}
@@ -808,21 +485,23 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
continue;
}
if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds))
read_msg_fd();
if (io_error_fd != -1 && FD_ISSET(io_error_fd, &r_fds)) {
read_error_fd();
}
if (FD_ISSET(fd, &w_fds)) {
int ret;
size_t n = len-total;
ret = write(fd,buf+total,n);
if (ret < 0) {
if (errno == EINTR)
continue;
if (errno == EWOULDBLOCK || errno == EAGAIN) {
msleep(1);
continue;
}
if (ret == -1 && errno == EINTR) {
continue;
}
if (ret == -1 &&
(errno == EWOULDBLOCK || errno == EAGAIN)) {
msleep(1);
continue;
}
if (ret <= 0) {
@@ -852,7 +531,7 @@ 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)
void io_start_buffering(int fd)
{
if (io_buffer) return;
multiplex_out_fd = fd;
@@ -861,24 +540,19 @@ void io_start_buffering_out(int fd)
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(int fd, enum logcode 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)) {
n = sizeof buffer - 4;
if (n > (sizeof(buffer)-4)) {
n = sizeof(buffer)-4;
}
memcpy(&buffer[4], buf, n);
@@ -893,26 +567,26 @@ static void mplex_write(int fd, enum msgcode code, char *buf, size_t len)
}
void io_flush(int flush_it_all)
void io_flush(void)
{
int fd = multiplex_out_fd;
msg_list_push(flush_it_all);
if (!io_buffer_count || no_flush)
return;
err_list_push();
if (io_multiplexing_out)
mplex_write(fd, MSG_DATA, io_buffer, io_buffer_count);
else
if (!io_buffer_count || no_flush) return;
if (io_multiplexing_out) {
mplex_write(fd, FNONE, io_buffer, io_buffer_count);
} else {
writefd_unbuffered(fd, io_buffer, io_buffer_count);
}
io_buffer_count = 0;
}
void io_end_buffering(void)
{
io_flush(NORMAL_FLUSH);
io_flush();
if (!io_multiplexing_out) {
free(io_buffer);
io_buffer = NULL;
@@ -923,7 +597,7 @@ static void writefd(int fd,char *buf,size_t len)
{
stats.total_written += len;
msg_list_push(NORMAL_FLUSH);
err_list_push();
if (!io_buffer || fd != multiplex_out_fd) {
writefd_unbuffered(fd, buf, len);
@@ -938,9 +612,8 @@ static void writefd(int fd,char *buf,size_t len)
len -= n;
io_buffer_count += n;
}
if (io_buffer_count == IO_BUFFER_SIZE)
io_flush(NORMAL_FLUSH);
if (io_buffer_count == IO_BUFFER_SIZE) io_flush();
}
}
@@ -967,23 +640,19 @@ void write_int_named(int f, int32 x, const char *phase)
*/
void write_longint(int f, int64 x)
{
extern int remote_version;
char b[8];
if (x <= 0x7FFFFFFF) {
if (remote_version < 16 || x <= 0x7FFFFFFF) {
write_int(f, (int)x);
return;
}
#ifdef NO_INT64
rprintf(FERROR,"Integer overflow - attempted 64 bit offset\n");
exit_cleanup(RERR_UNSUPPORTED);
#else
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)
@@ -1041,9 +710,9 @@ void io_printf(int fd, const char *format, ...)
va_list ap;
char buf[1024];
int len;
va_start(ap, format);
len = vsnprintf(buf, sizeof buf, format, ap);
len = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (len < 0) exit_cleanup(RERR_STREAMIO);
@@ -1052,35 +721,35 @@ void io_printf(int fd, const char *format, ...)
}
/** Setup for multiplexing a MSG_* stream with the data stream. */
/** Setup for multiplexing an error stream with the data stream */
void io_start_multiplex_out(int fd)
{
multiplex_out_fd = fd;
io_flush(NORMAL_FLUSH);
io_start_buffering_out(fd);
io_flush();
io_start_buffering(fd);
io_multiplexing_out = 1;
}
/** Setup for multiplexing a MSG_* stream with the data stream. */
/** Setup for multiplexing an error stream with the data stream */
void io_start_multiplex_in(int fd)
{
multiplex_in_fd = fd;
io_flush(NORMAL_FLUSH);
io_flush();
io_multiplexing_in = 1;
}
/** Write an message to the multiplexed data stream. */
int io_multiplex_write(enum msgcode code, char *buf, size_t len)
/** Write an message to the multiplexed error stream */
int io_multiplex_write(enum logcode code, char *buf, size_t len)
{
if (!io_multiplexing_out) return 0;
io_flush(NORMAL_FLUSH);
io_flush();
stats.total_written += (len+4);
mplex_write(multiplex_out_fd, code, buf, len);
return 1;
}
/** Stop output multiplexing. */
/** Stop output multiplexing */
void io_multiplexing_close(void)
{
io_multiplexing_out = 0;

View File

@@ -1 +1,49 @@
.cvsignore
Makefile
a
b
config.cache
config.h
config.log
config.status
dist.tar.gz
dummy
rsync
rsync-0.1
rsync-0.1
rsync-0.1
rsync-0.1.tar.gz
rsync-0.2
rsync-0.2
rsync-0.2.tar.gz
rsync-0.3
rsync-0.3
rsync-0.3.tar.gz
rsync-0.4
rsync-0.4
rsync-0.4.tar.gz
rsync-0.5
rsync-0.5
rsync-0.5
rsync-0.5
rsync-0.5
rsync-0.5
rsync-0.5
rsync-0.5
rsync-0.5.tar.gz
rsync-0.6
rsync-0.7
rsync-0.7
rsync-0.8
rsync-0.8
rsync-0.8
rsync-0.8
rsync-ERSION
rsync.aux
rsync.dvi
rsync.log
tech_report.aux
tech_report.dvi
tech_report.log
tech_report.ps
test

View File

@@ -116,12 +116,10 @@
{
size_t len = strlen(s);
size_t ret = len;
if (bufsize > 0) {
if (len >= bufsize)
len = bufsize-1;
memcpy(d, s, len);
d[len] = 0;
}
if (bufsize <= 0) return 0;
if (len >= bufsize) len = bufsize-1;
memcpy(d, s, len);
d[len] = 0;
return ret;
}
#endif
@@ -140,9 +138,10 @@
size_t len2 = strlen(s);
size_t ret = len1 + len2;
if (len1 < bufsize - 1) {
if (len2 >= bufsize - len1)
len2 = bufsize - len1 - 1;
if (len1+len2 >= bufsize) {
len2 = bufsize - (len1+1);
}
if (len2 > 0) {
memcpy(d+len1, s, len2);
d[len1+len2] = 0;
}

View File

@@ -1,199 +0,0 @@
.ds d \-\^\-
.ds o \fR[\fP
.ds c \fR]\fP
.ds | \fR|\fP
.de D
\\.B \*d\\$1
..
.de DI
\\.BI \*d\\$1 \\$2
..
.de DR
\\.BR \*d\\$1 \\$2
..
.de Di
\\.BI \*d\\$1 " \\$2"
..
.de Db
\\.B \*d\\$1 " \\$2"
..
.de Df
\\.B \*d\*ono\*c\\$1
..
.de See
See \fB\\$1\fP for details.
..
.de SeeIn
See \fB\\$1\fP in \fB\\$2\fP for details.
..
.TH POOL_ALLOC 3
.SH NAME
pool_alloc, pool_free, pool_talloc, pool_tfree, pool_create, pool_destroy
\- Allocate and free memory in managed allocation pools.
.SH SYNOPSIS
.B #include "pool_alloc.h"
\fBstruct alloc_pool *pool_create(size_t \fIsize\fB, size_t \fIquantum\fB, void (*\fIbomb\fB)(char *), int \fIflags\fB);
\fBvoid pool_destroy(struct alloc_pool *\fIpool\fB);
\fBvoid *pool_alloc(struct alloc_pool *\fIpool\fB, size_t \fIsize\fB, char *\fImsg\fB);
\fBvoid pool_free(struct alloc_pool *\fIpool\fB, sise_t \fIsize\fB, void *\fIaddr\fB);
\fBvoid *pool_talloc(struct alloc_pool *\fIpool\fB, \fItype\fB), int \fIcount\fB, char *\fImsg\fB);
\fBvoid pool_tfree(struct alloc_pool *\fIpool\fB, \fItype\fB, int \fIcount\fB, void *\fIaddr\fB);
.SH DESCRIPTION
.P
The pool allocation routines use
.B malloc()
for underlying memory management.
What allocation pools do is cause
memory within a given pool to be in large contigious blocks
(called extents) that when freed will be reusable. Unlike
.B malloc()
the allocations are not managed individually.
Instead each extent tracks the total free memory within the
extent. Each extent can either be used to allocate memory
or to manage the freeing of memory within that extent.
When an extent has less free memory than a given
allocation request or when the first request to free
memory within that extent is received the extent ceases to
be used for allocation.
.P
This form of memory management is suited to large numbers of small
related allocations that are held for a while
and then freed as a group.
Because the
underlying allocations are done in large contigious extents
when an extent is freed it releases a large enough
contigious block of memory to be useful to subsequent
.B malloc()
and
.B pool_alloc()
calls even if allocations from other pools or from
.B malloc()
are made between allocations from a given pool.
.P
.B pool_create()
Creates an allocation pool for subsequent calls to the pool
allocation functions.
When an extent is created for allocations it will be
.I size
bytes.
Allocations from the pool have their sizes rounded up to a
multiple of
.I quantum
bytes in length.
Specifying
.B 0
for
.I quantum
Will produce a quantum that should meet maximal allignment
on most platforms.
If the
.B POOL_QALIGN
.I flag
is set allocations will be aligned to addresses that are a
multiple of
.IR quantum .
If the
.B POOL_CLEAR
.I flag
is set all allocations from the pool will be zero filled.
.P
.B pool_destroy()
destroys an allocation pool and frees all memory allocated
in that pool.
.P
.B pool_alloc()
allocates
.I size
bytes from the specified
.IR pool .
If
.I size
is
.B 0
.I quantum
bytes will be freed.
If the requested memory cannot be allocated
.B pool_alloc()
will call
.I bomb()
function, if defined, with
.I msg
as it's sole argument and
.B NULL
will be returned.
.P
.B pool_free()
frees
.I size
bytes pointed to by
.I addr
previously allocated in the specified
.IR pool .
The memory freed within an extent will not be reusable until
all of the memory in that extent has been freed but
depending on the order in which the
allocations are freed some extents may be released for reuse
while others are still in use.
If
.I size
is
.B 0
.I quantum
bytes will be freed.
If
.I addr
is
.B 0
no memory will be freed but subsequent allocations will come
from a new extent.
.P
.B pool_talloc()
is a macro that take a
.I type
and
.I count
instead of
.I size
and will cast the return value to the correct type.
.P
.B pool_tfree
is a macro to free memory previously allocated in the
specified
.IR pool .
.SH RETURN VALUE
.B pool_create()
returns a pointer to
.BR "struct alloc_pool" .
.P
.B pool_alloc()
and
.B pool_talloc()
return pointers to the allocated memory,
or NULL if the request fails.
For each extent so long as no allocations are smaller than varaible
allignment requirements this pointer will be suitably
alligned for any kind of variable.
The return type of
.B pool_alloc()
will normally require casting to the desired type but
.B pool_talloc()
will returns a pointer of the requested
.IR type .
.P
.BR pool_free() ,
.B pool_tfree()
and
.B pool_destroy()
return no value.
.SH SEE ALSO
.nf
malloc(3)
.SH AUTHOR
pool_alloc was created by J.W. Schultz of Pegasystems Technologies.
.SH BUGS AND ISSUES

View File

@@ -1,304 +0,0 @@
#include "rsync.h"
#define POOL_DEF_EXTENT (32 * 1024)
struct alloc_pool
{
size_t size; /* extent size */
size_t quantum; /* allocation quantum */
struct pool_extent *live; /* current extent for
* allocations */
struct pool_extent *free; /* unfreed extent list */
void (*bomb)();
/* function to call if
* malloc fails */
int flags;
/* statistical data */
unsigned long e_created; /* extents created */
unsigned long e_freed; /* extents detroyed */
uint64 n_allocated; /* calls to alloc */
uint64 n_freed; /* calls to free */
uint64 b_allocated; /* cum. bytes allocated */
uint64 b_freed; /* cum. bytes freed */
};
struct pool_extent
{
void *start; /* starting address */
size_t free; /* free bytecount */
size_t bound; /* bytes bound by padding,
* overhead and freed */
struct pool_extent *next;
};
struct align_test {
void *foo;
uint64 bar;
};
#define MINALIGN offsetof(struct align_test, bar)
/* Temporarily cast a void* var into a char* var when adding an offset (to
* keep some compilers from complaining about the pointer arithmetic). */
#define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) )
alloc_pool_t
pool_create(size_t size, size_t quantum,
void (*bomb)(char *), int flags)
{
struct alloc_pool *pool;
if (!(pool = (struct alloc_pool*) malloc(sizeof (struct alloc_pool))))
return pool;
memset(pool, 0, sizeof (struct alloc_pool));
pool->size = size /* round extent size to min alignment reqs */
? (size + MINALIGN - 1) & ~(MINALIGN - 1)
: POOL_DEF_EXTENT;
if (pool->flags & POOL_INTERN)
{
pool->size -= sizeof (struct pool_extent);
flags |= POOL_APPEND;
}
pool->quantum = quantum ? quantum : MINALIGN;
pool->bomb = bomb;
pool->flags = flags;
return pool;
}
void
pool_destroy(alloc_pool_t p)
{
struct alloc_pool *pool = (struct alloc_pool *) p;
struct pool_extent *cur, *next;
if (!pool)
return;
if (pool->live)
{
cur = pool->live;
free(cur->start);
if (!(pool->flags & POOL_APPEND))
free(cur);
}
for (cur = pool->free; cur; cur = next)
{
next = cur->next;
free(cur->start);
if (!(pool->flags & POOL_APPEND))
free(cur);
}
free(pool);
}
void *
pool_alloc(alloc_pool_t p, size_t len, char *bomb)
{
struct alloc_pool *pool = (struct alloc_pool *) p;
if (!pool)
return NULL;
if (!len)
len = pool->quantum;
else if (pool->quantum > 1 && len % pool->quantum)
len += pool->quantum - len % pool->quantum;
if (len > pool->size)
goto bomb;
if (!pool->live || len > pool->live->free)
{
void *start;
size_t free;
size_t bound;
size_t sqew;
size_t asize;
if (pool->live)
{
pool->live->next = pool->free;
pool->free = pool->live;
}
free = pool->size;
bound = 0;
asize = pool->size;
if (pool->flags & POOL_APPEND)
asize += sizeof (struct pool_extent);
if (!(start = (void *) malloc(asize)))
goto bomb;
if (pool->flags & POOL_CLEAR)
memset(start, 0, pool->size);
if (pool->flags & POOL_APPEND)
{
pool->live = PTR_ADD(start, free);
}
else if (!(pool->live = (struct pool_extent *) malloc(sizeof (struct pool_extent))))
{
goto bomb;
}
if (pool->flags & POOL_QALIGN && pool->quantum > 1
&& (sqew = (size_t)PTR_ADD(start, free) % pool->quantum))
{
bound += sqew;
free -= sqew;
}
pool->live->start = start;
pool->live->free = free;
pool->live->bound = bound;
pool->live->next = NULL;
pool->e_created++;
}
pool->n_allocated++;
pool->b_allocated += len;
pool->live->free -= len;
return PTR_ADD(pool->live->start, pool->live->free);
bomb:
if (pool->bomb)
(*pool->bomb)(bomb);
return NULL;
}
void
pool_free(alloc_pool_t p, size_t len, void *addr)
{
struct alloc_pool *pool = (struct alloc_pool *) p;
struct pool_extent *cur;
struct pool_extent *prev;
if (!pool)
return;
if (!len)
len = pool->quantum;
else if (pool->quantum > 1 && len % pool->quantum)
len += pool->quantum - len % pool->quantum;
if (!addr && pool->live)
{
pool->live->next = pool->free;
pool->free = pool->live;
pool->live = NULL;
return;
}
pool->n_freed++;
pool->b_freed += len;
cur = pool->live;
if (cur
&& addr >= cur->start
&& addr < PTR_ADD(cur->start, pool->size))
{
if (addr == PTR_ADD(cur->start, cur->free))
{
if (pool->flags & POOL_CLEAR)
memset(addr, 0, len);
pool->b_freed += len;
} else {
cur->bound += len;
}
if (cur->free + cur->bound >= pool->size)
{
size_t sqew;
cur->free = pool->size;
cur->bound = 0;
if (pool->flags & POOL_QALIGN && pool->quantum > 1
&& (sqew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum))
{
cur->bound += sqew;
cur->free -= sqew;
}
}
return;
}
for (prev = NULL, cur = pool->free; cur; prev = cur, cur = cur->next)
{
if (addr >= cur->start
&& addr < PTR_ADD(cur->start, pool->size))
break;
}
if (!cur)
return;
if (prev)
{
prev->next = cur->next;
cur->next = pool->free;
pool->free = cur;
}
cur->bound += len;
if (cur->free + cur->bound >= pool->size)
{
pool->free = cur->next;
free(cur->start);
if (!(pool->flags & POOL_APPEND))
free(cur);
pool->e_freed++;
}
return;
}
#define FDPRINT(label, value) \
snprintf(buf, BUFSIZ, label, value), \
write(fd, buf, strlen(buf));
#define FDEXTSTAT(ext) \
snprintf(buf, BUFSIZ, " %12ld %5ld\n", \
(long) ext->free, \
(long) ext->bound), \
write(fd, buf, strlen(buf))
void
pool_stats(alloc_pool_t p, int fd, int summarize)
{
struct alloc_pool *pool = (struct alloc_pool *) p;
struct pool_extent *cur;
char buf[BUFSIZ];
if (!pool)
return;
FDPRINT(" Extent size: %12ld\n", (long) pool->size);
FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum);
FDPRINT(" Extents created: %12ld\n", pool->e_created);
FDPRINT(" Extents freed: %12ld\n", pool->e_freed);
FDPRINT(" Alloc count: %12.0f\n", (double) pool->n_allocated);
FDPRINT(" Free Count: %12.0f\n", (double) pool->n_freed);
FDPRINT(" Alloc bytes: %12.0f\n", (double) pool->b_allocated);
FDPRINT(" Free bytes: %12.0f\n", (double) pool->b_freed);
if (summarize)
return;
if (!pool->live && !pool->free)
return;
write(fd, "\n", 1);
if (pool->live)
{
FDEXTSTAT(pool->live);
}
strcpy(buf, " FREE BOUND\n");
write(fd, buf, strlen(buf));
for (cur = pool->free; cur; cur = cur->next)
{
FDEXTSTAT(cur);
}
}

View File

@@ -1,20 +0,0 @@
#include <stddef.h>
#define POOL_CLEAR (1<<0) /* zero fill allocations */
#define POOL_QALIGN (1<<1) /* align data to quanta */
#define POOL_INTERN (1<<2) /* Allocate extent structures */
#define POOL_APPEND (1<<3) /* or appended to extent data */
typedef void *alloc_pool_t;
alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(char *), int flags);
void pool_destroy(alloc_pool_t pool);
void *pool_alloc(alloc_pool_t pool, size_t size, char *bomb);
void pool_free(alloc_pool_t pool, size_t size, void *addr);
#define pool_talloc(pool, type, count, bomb) \
((type *)pool_alloc(pool, sizeof(type) * count, bomb))
#define pool_tfree(pool, type, count, addr) \
(pool_free(pool, sizeof(type) * count, addr))

View File

@@ -6,17 +6,17 @@
* 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.
@@ -36,7 +36,7 @@
* 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
* 4) If it's a global then initialise it in init_globals. If a local
* (ie. service) parameter then initialise it in the sDefault structure
*
*
*
* Notes:
* The configuration file is processed sequentially for speed. It is NOT
@@ -61,7 +61,7 @@ typedef char pstring[1024];
typedef enum
{
P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
P_PATH,P_STRING,P_GSTRING,P_ENUM,P_SEP
P_STRING,P_GSTRING,P_ENUM,P_SEP
} parm_type;
typedef enum
@@ -93,7 +93,7 @@ struct parm_struct
#define iSERVICE(i) (*pSERVICE(i))
#define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
/*
/*
* This structure describes global (ie., server-wide) parameters.
*/
typedef struct
@@ -101,16 +101,16 @@ typedef struct
char *motd_file;
char *log_file;
char *pid_file;
char *socket_options;
int syslog_facility;
int max_verbosity;
char *socket_options;
} global;
static global Globals;
/*
* This structure describes a single service.
/*
* This structure describes a single service.
*/
typedef struct
{
@@ -144,7 +144,7 @@ typedef struct
/* This is a default service used to prime a services structure */
static service sDefault =
static service sDefault =
{
NULL, /* name */
NULL, /* path */
@@ -156,7 +156,7 @@ static service sDefault =
False, /* transfer logging */
False, /* ignore errors */
"nobody",/* uid */
/* TODO: This causes problems on Debian, where it is called
* "nogroup". Debian patch this in their version of the
* package, but it would be nice to be consistent. Possibly
@@ -165,7 +165,7 @@ static service sDefault =
* What is the best behaviour? Perhaps always using (gid_t)
* -2? */
"nobody",/* gid */
NULL, /* hosts allow */
NULL, /* hosts deny */
NULL, /* auth users */
@@ -222,7 +222,7 @@ static struct enum_list enum_facilities[] = {
{ LOG_NEWS, "news" },
#endif
#ifdef LOG_AUTH
{ LOG_AUTH, "security" },
{ LOG_AUTH, "security" },
#endif
#ifdef LOG_SYSLOG
{ LOG_SYSLOG, "syslog" },
@@ -268,14 +268,13 @@ static struct parm_struct parm_table[] =
{"socket options", P_STRING, P_GLOBAL, &Globals.socket_options,NULL, 0},
{"log file", P_STRING, P_GLOBAL, &Globals.log_file, NULL, 0},
{"pid file", P_STRING, P_GLOBAL, &Globals.pid_file, NULL, 0},
{"max verbosity", P_INTEGER, P_GLOBAL, &Globals.max_verbosity, NULL, 0},
{"timeout", P_INTEGER, P_LOCAL, &sDefault.timeout, NULL, 0},
{"max connections", P_INTEGER, P_LOCAL, &sDefault.max_connections,NULL, 0},
{"name", P_STRING, P_LOCAL, &sDefault.name, NULL, 0},
{"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, 0},
{"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL, 0},
{"path", P_PATH, P_LOCAL, &sDefault.path, NULL, 0},
{"path", P_STRING, P_LOCAL, &sDefault.path, NULL, 0},
{"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL, 0},
{"list", P_BOOL, P_LOCAL, &sDefault.list, NULL, 0},
{"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL, 0},
@@ -305,11 +304,10 @@ Initialise the global parameter structure.
***************************************************************************/
static void init_globals(void)
{
memset(&Globals, 0, sizeof Globals);
memset(&Globals, 0, sizeof(Globals));
#ifdef LOG_DAEMON
Globals.syslog_facility = LOG_DAEMON;
#endif
Globals.max_verbosity = 1;
}
/***************************************************************************
@@ -321,8 +319,8 @@ static void init_locals(void)
/*
In this section all the functions that are used to access the
parameters from the rest of the program are defined
In this section all the functions that are used to access the
parameters from the rest of the program are defined
*/
#define FN_GLOBAL_STRING(fn_name,ptr) \
@@ -349,7 +347,6 @@ FN_GLOBAL_STRING(lp_log_file, &Globals.log_file)
FN_GLOBAL_STRING(lp_pid_file, &Globals.pid_file)
FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
FN_GLOBAL_INTEGER(lp_max_verbosity, &Globals.max_verbosity)
FN_LOCAL_STRING(lp_name, name)
FN_LOCAL_STRING(lp_comment, comment)
@@ -379,11 +376,12 @@ FN_LOCAL_INTEGER(lp_timeout, timeout)
FN_LOCAL_INTEGER(lp_max_connections, max_connections)
/* local prototypes */
static int strwicmp(char *psz1, char *psz2);
static int map_parameter(char *parmname);
static BOOL set_boolean(BOOL *pb, char *parmvalue);
static int strwicmp( char *psz1, char *psz2 );
static int map_parameter( char *parmname);
static BOOL set_boolean( BOOL *pb, char *parmvalue );
static int getservicebyname(char *name, service *pserviceDest);
static void copy_service(service *pserviceDest, service *pserviceSource);
static void copy_service( service *pserviceDest,
service *pserviceSource);
static BOOL do_parameter(char *parmname, char *parmvalue);
static BOOL do_section(char *sectionname);
@@ -423,7 +421,7 @@ static void string_set(char **s, const char *v)
/***************************************************************************
add a new service to the services array initialising it with the given
add a new service to the services array initialising it with the given
service
***************************************************************************/
static int add_a_service(service *pservice, char *name)
@@ -435,7 +433,7 @@ static int add_a_service(service *pservice, char *name)
tservice = *pservice;
/* it might already exist */
if (name)
if (name)
{
i = getservicebyname(name,NULL);
if (i >= 0)
@@ -457,7 +455,7 @@ static int add_a_service(service *pservice, char *name)
init_service(pSERVICE(i));
copy_service(pSERVICE(i),&tservice);
if (name)
string_set(&iSERVICE(i).name,name);
string_set(&iSERVICE(i).name,name);
return(i);
}
@@ -495,7 +493,7 @@ static int strwicmp(char *psz1, char *psz2)
}
/***************************************************************************
Map a parameter's string representation to something we can use.
Map a parameter's string representation to something we can use.
Returns False if the parameter string is not recognised, else TRUE.
***************************************************************************/
static int map_parameter(char *parmname)
@@ -505,7 +503,7 @@ static int map_parameter(char *parmname)
if (*parmname == '-')
return(-1);
for (iIndex = 0; parm_table[iIndex].label; iIndex++)
for (iIndex = 0; parm_table[iIndex].label; iIndex++)
if (strwicmp(parm_table[iIndex].label, parmname) == 0)
return(iIndex);
@@ -516,7 +514,7 @@ static int map_parameter(char *parmname)
/***************************************************************************
Set a boolean variable from the text value stored in the passed string.
Returns True in success, False if the passed string does not correctly
Returns True in success, False if the passed string does not correctly
represent a boolean.
***************************************************************************/
static BOOL set_boolean(BOOL *pb, char *parmvalue)
@@ -550,7 +548,7 @@ static int getservicebyname(char *name, service *pserviceDest)
int iService;
for (iService = iNumServices - 1; iService >= 0; iService--)
if (strwicmp(iSERVICE(iService).name, name) == 0)
if (strwicmp(iSERVICE(iService).name, name) == 0)
{
if (pserviceDest != NULL)
copy_service(pserviceDest, pSERVICE(iService));
@@ -566,7 +564,7 @@ static int getservicebyname(char *name, service *pserviceDest)
Copy a service structure to another
***************************************************************************/
static void copy_service(service *pserviceDest,
static void copy_service(service *pserviceDest,
service *pserviceSource)
{
int i;
@@ -574,9 +572,9 @@ static void copy_service(service *pserviceDest,
for (i=0;parm_table[i].label;i++)
if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
void *def_ptr = parm_table[i].ptr;
void *src_ptr =
void *src_ptr =
((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
void *dest_ptr =
void *dest_ptr =
((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
switch (parm_table[i].type)
@@ -596,7 +594,6 @@ static void copy_service(service *pserviceDest,
*(char *)dest_ptr = *(char *)src_ptr;
break;
case P_PATH:
case P_STRING:
string_set(dest_ptr,*(char **)src_ptr);
break;
@@ -617,7 +614,6 @@ static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
int parmnum, i;
void *parm_ptr=NULL; /* where we are going to store the result */
void *def_ptr=NULL;
char *cp;
parmnum = map_parameter(parmname);
@@ -664,15 +660,6 @@ static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
sscanf(parmvalue,"%o",(int *)parm_ptr);
break;
case P_PATH:
string_set(parm_ptr,parmvalue);
if ((cp = *(char**)parm_ptr) != NULL) {
int len = strlen(cp);
while (len > 1 && cp[len-1] == '/') len--;
cp[len] = '\0';
}
break;
case P_STRING:
string_set(parm_ptr,parmvalue);
break;
@@ -724,7 +711,7 @@ static BOOL do_section(char *sectionname)
init_locals();
/* if we've just struck a global section, note the fact. */
bInGlobalSection = isglobal;
bInGlobalSection = isglobal;
/* check for multiple global sections */
if (bInGlobalSection)
@@ -756,7 +743,7 @@ static BOOL do_section(char *sectionname)
/***************************************************************************
Load the services array from the services file. Return True on success,
Load the services array from the services file. Return True on success,
False on failure.
***************************************************************************/
BOOL lp_load(char *pszFname, int globals_only)
@@ -766,11 +753,11 @@ BOOL lp_load(char *pszFname, int globals_only)
extern int am_root;
pstring n2;
BOOL bRetval;
bRetval = False;
bInGlobalSection = True;
init_globals();
if (pszFname)
@@ -783,7 +770,7 @@ BOOL lp_load(char *pszFname, int globals_only)
/* We get sections first, so have to start 'behind' to make up */
iServiceIndex = -1;
bRetval = pm_process(n2, globals_only?NULL:do_section, do_parameter);
return (bRetval);
}
@@ -807,7 +794,7 @@ int lp_number(char *name)
int iService;
for (iService = iNumServices - 1; iService >= 0; iService--)
if (strequal(lp_name(iService), name))
if (strequal(lp_name(iService), name))
break;
return (iService);

297
log.c
View File

@@ -1,18 +1,18 @@
/* -*- c-file-style: "linux"; -*-
Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 2000-2001 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.
@@ -27,18 +27,10 @@
*/
#include "rsync.h"
extern int am_daemon;
extern int am_server;
extern int am_sender;
extern int quiet;
extern int module_id;
extern int msg_fd_out;
extern char *auth_user;
extern char *log_format;
static int log_initialised;
static char *logfname;
static FILE *logfile;
static int log_error_fd = -1;
struct stats stats;
int log_got_error=0;
@@ -47,27 +39,26 @@ struct {
int code;
char const *name;
} const rerr_names[] = {
{ RERR_SYNTAX , "syntax or usage error" },
{ RERR_PROTOCOL , "protocol incompatibility" },
{ RERR_FILESELECT , "errors selecting input/output files, dirs" },
{ RERR_UNSUPPORTED, "requested action not supported" },
{ RERR_STARTCLIENT, "error starting client-server protocol" },
{ RERR_SOCKETIO , "error in socket IO" },
{ RERR_FILEIO , "error in file IO" },
{ RERR_STREAMIO , "error in rsync protocol data stream" },
{ RERR_MESSAGEIO , "errors with program diagnostics" },
{ RERR_IPC , "error in IPC code" },
{ RERR_SIGNAL , "received SIGUSR1 or SIGINT" },
{ 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_TIMEOUT , "timeout in data send/receive" },
{ RERR_SYNTAX , "syntax or usage error" },
{ RERR_PROTOCOL , "protocol incompatibility" },
{ RERR_FILESELECT , "errors selecting input/output files, dirs" },
{ RERR_UNSUPPORTED, "requested action not supported" },
{ RERR_STARTCLIENT, "error starting client-server protocol" },
{ RERR_SOCKETIO , "error in socket IO" },
{ RERR_FILEIO , "error in file IO" },
{ RERR_STREAMIO , "error in rsync protocol data stream" },
{ RERR_MESSAGEIO , "errors with program diagnostics" },
{ RERR_IPC , "error in IPC code" },
{ RERR_SIGNAL , "received SIGUSR1 or SIGINT" },
{ RERR_WAITCHILD , "some error returned by waitpid()" },
{ RERR_MALLOC , "error allocating core memory buffers" },
{ RERR_PARTIAL , "some files could not be transferred" },
{ RERR_TIMEOUT , "timeout in data send/receive" },
{ RERR_CMD_FAILED , "remote shell failed" },
{ RERR_CMD_KILLED , "remote shell killed" },
{ RERR_CMD_RUN, "remote command could not be run" },
{ RERR_CMD_NOTFOUND, "remote command not found" },
{ 0, NULL }
{ RERR_CMD_NOTFOUND, "remote command not found" },
{ 0, NULL }
};
@@ -77,12 +68,67 @@ struct {
*/
static char const *rerr_name(int code)
{
int i;
for (i = 0; rerr_names[i].name; i++) {
if (rerr_names[i].code == code)
return rerr_names[i].name;
int i;
for (i = 0; rerr_names[i].name; i++) {
if (rerr_names[i].code == code)
return rerr_names[i].name;
}
return NULL;
}
struct err_list {
struct err_list *next;
char *buf;
int len;
int written; /* how many bytes we have written so far */
};
static struct err_list *err_list_head;
static struct err_list *err_list_tail;
/* add an error message to the pending error list */
static void err_list_add(int code, char *buf, int len)
{
struct err_list *el;
el = new(struct err_list);
if (!el) exit_cleanup(RERR_MALLOC);
el->next = NULL;
el->buf = new_array(char, len+4);
if (!el->buf) exit_cleanup(RERR_MALLOC);
memcpy(el->buf+4, buf, len);
SIVAL(el->buf, 0, ((code+MPLEX_BASE)<<24) | len);
el->len = len+4;
el->written = 0;
if (err_list_tail) {
err_list_tail->next = el;
} else {
err_list_head = el;
}
err_list_tail = el;
}
/* try to push errors off the error list onto the wire */
void err_list_push(void)
{
if (log_error_fd == -1) return;
while (err_list_head) {
struct err_list *el = err_list_head;
int n = write(log_error_fd, el->buf+el->written, el->len - el->written);
/* don't check for an error if the best way of handling the error is
to ignore it */
if (n == -1) break;
if (n > 0) {
el->written += n;
}
if (el->written == el->len) {
free(el->buf);
err_list_head = el->next;
if (!err_list_head) err_list_tail = NULL;
free(el);
}
}
return NULL;
}
@@ -91,7 +137,7 @@ static void logit(int priority, char *buf)
if (logfname) {
if (!logfile)
log_open();
fprintf(logfile,"%s [%d] %s",
fprintf(logfile,"%s [%d] %s",
timestring(time(NULL)), (int)getpid(), buf);
fflush(logfile);
} else {
@@ -108,8 +154,8 @@ void log_init(void)
log_initialised = 1;
/* this looks pointless, but it is needed in order for the
* C library on some systems to fetch the timezone info
* before the chroot */
C library on some systems to fetch the timezone info
before the chroot */
t = time(NULL);
localtime(&t);
@@ -156,18 +202,27 @@ void log_close(void)
}
}
/* setup the error file descriptor - used when we are a server
that is receiving files */
void set_error_fd(int fd)
{
log_error_fd = fd;
set_nonblocking(log_error_fd);
}
/* this is the underlying (unformatted) rsync debugging function. Call
* it with FINFO, FERROR or FLOG */
it with FINFO, FERROR or FLOG */
void rwrite(enum logcode code, char *buf, int len)
{
FILE *f=NULL;
extern int am_daemon;
extern int am_server;
extern int quiet;
/* recursion can happen with certain fatal conditions */
if (quiet && code == FINFO)
return;
if (quiet && code == FINFO) return;
if (len < 0)
exit_cleanup(RERR_MESSAGEIO);
if (len < 0) exit_cleanup(RERR_MESSAGEIO);
buf[len] = 0;
@@ -176,14 +231,17 @@ void rwrite(enum logcode code, char *buf, int len)
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;
}
if (io_multiplex_write((enum msgcode)code, buf, len))
return;
/* first try to pass it off to our sibling */
if (am_server && log_error_fd != -1) {
err_list_add(code, buf, len);
err_list_push();
return;
}
/* next, if we are a server but not in daemon mode, and multiplexing
* is enabled, pass it to the other side. */
if (am_server && !am_daemon && io_multiplex_write(code, buf, len)) {
return;
}
/* otherwise, if in daemon mode and either we are not a server
@@ -192,9 +250,7 @@ void rwrite(enum logcode code, char *buf, int len)
* 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.
*/
* fall through to the next case. */
if (am_daemon && (!am_server || log_initialised)) {
static int depth;
int priority = LOG_INFO;
@@ -214,14 +270,14 @@ void rwrite(enum logcode code, char *buf, int len)
if (code == FERROR) {
log_got_error = 1;
f = stderr;
}
}
if (code == FINFO) {
if (am_server)
if (am_server)
f = stderr;
else
f = stdout;
}
}
if (!f) exit_cleanup(RERR_MESSAGEIO);
@@ -235,7 +291,7 @@ void rwrite(enum logcode code, char *buf, int len)
* FLOG. */
void rprintf(enum logcode code, const char *format, ...)
{
va_list ap;
va_list ap;
char buf[1024];
int len;
@@ -284,11 +340,11 @@ void rprintf(enum logcode code, const char *format, ...)
* message catalog we need to call it once before chroot-ing. */
void rsyserr(enum logcode code, int errcode, const char *format, ...)
{
va_list ap;
va_list ap;
char buf[1024];
int len;
size_t sys_len;
char *sysmsg;
char *sysmsg;
va_start(ap, format);
/* Note: might return <0 */
@@ -300,17 +356,17 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
if ((size_t) len > sizeof(buf)-1)
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);
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++;
strcpy(buf + len, ": ");
len += 2;
strcpy(buf + len, sysmsg);
len += sys_len;
strcpy(buf + len, "\n");
len++;
rwrite(code, buf, len);
}
@@ -320,6 +376,7 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
void rflush(enum logcode code)
{
FILE *f = NULL;
extern int am_daemon;
if (am_daemon) {
return;
@@ -327,18 +384,19 @@ void rflush(enum logcode code)
if (code == FLOG) {
return;
}
}
if (code == FERROR) {
f = stderr;
}
}
if (code == FINFO) {
if (am_server)
extern int am_server;
if (am_server)
f = stderr;
else
f = stdout;
}
}
if (!f) exit_cleanup(RERR_MESSAGEIO);
fflush(f);
@@ -347,15 +405,20 @@ void rflush(enum logcode code)
/* a generic logging routine for send/recv, with parameter
* substitiution */
substitiution */
static void log_formatted(enum logcode code,
char *format, char *op, struct file_struct *file,
struct stats *initial_stats)
{
extern int module_id;
extern char *auth_user;
char buf[1024];
char buf2[1024];
char *p, *s, *n;
size_t l;
extern struct stats stats;
extern int am_sender;
extern int am_daemon;
int64 b;
/* We expand % codes one by one in place in buf. We don't
@@ -366,56 +429,57 @@ static void log_formatted(enum logcode code,
memset(buf, 0, sizeof buf);
strlcpy(buf, format, sizeof(buf));
for (s = &buf[0]; s && (p = strchr(s,'%')); ) {
for (s=&buf[0];
s && (p=strchr(s,'%')); ) {
n = NULL;
s = p + 1;
switch (p[1]) {
case 'h': if (am_daemon) n = client_name(0); break;
case 'a': if (am_daemon) n = client_addr(0); break;
case 'l':
snprintf(buf2,sizeof(buf2),"%.0f",
(double)file->length);
case 'l':
snprintf(buf2,sizeof(buf2),"%.0f",
(double)file->length);
n = buf2;
break;
case 'p':
snprintf(buf2,sizeof(buf2),"%d",
(int)getpid());
case 'p':
snprintf(buf2,sizeof(buf2),"%d",
(int)getpid());
n = buf2;
break;
case 'o': n = op; break;
case 'f':
pathjoin(buf2, sizeof buf2,
file->basedir ? file->basedir : "",
case 'f':
snprintf(buf2, sizeof(buf2), "%s/%s",
file->basedir?file->basedir:"",
f_name(file));
clean_fname(buf2);
n = buf2;
n = buf2;
if (*n == '/') n++;
break;
case 'm': n = lp_name(module_id); break;
case 't': n = timestring(time(NULL)); break;
case 'P': n = lp_path(module_id); break;
case 'u': n = auth_user; break;
case 'b':
case 'b':
if (am_sender) {
b = stats.total_written -
b = stats.total_written -
initial_stats->total_written;
} else {
b = stats.total_read -
b = stats.total_read -
initial_stats->total_read;
}
snprintf(buf2,sizeof(buf2),"%.0f", (double)b);
snprintf(buf2,sizeof(buf2),"%.0f", (double)b);
n = buf2;
break;
case 'c':
case 'c':
if (!am_sender) {
b = stats.total_written -
b = stats.total_written -
initial_stats->total_written;
} else {
b = stats.total_read -
b = stats.total_read -
initial_stats->total_read;
}
snprintf(buf2,sizeof(buf2),"%.0f", (double)b);
snprintf(buf2,sizeof(buf2),"%.0f", (double)b);
n = buf2;
break;
}
@@ -453,6 +517,10 @@ static void log_formatted(enum logcode code,
/* log the outgoing transfer of a file */
void log_send(struct file_struct *file, struct stats *initial_stats)
{
extern int module_id;
extern int am_server;
extern char *log_format;
if (lp_transfer_logging(module_id)) {
log_formatted(FLOG, lp_log_format(module_id), "send", file, initial_stats);
} else if (log_format && !am_server) {
@@ -463,6 +531,10 @@ void log_send(struct file_struct *file, struct stats *initial_stats)
/* log the incoming transfer of a file */
void log_recv(struct file_struct *file, struct stats *initial_stats)
{
extern int module_id;
extern int am_server;
extern char *log_format;
if (lp_transfer_logging(module_id)) {
log_formatted(FLOG, lp_log_format(module_id), "recv", file, initial_stats);
} else if (log_format && !am_server) {
@@ -482,24 +554,33 @@ void log_recv(struct file_struct *file, struct stats *initial_stats)
void log_exit(int code, const char *file, int line)
{
if (code == 0) {
extern struct stats stats;
rprintf(FLOG,"wrote %.0f bytes read %.0f bytes total size %.0f\n",
(double)stats.total_written,
(double)stats.total_read,
(double)stats.total_size);
} else {
const char *name;
const char *name;
name = rerr_name(code);
if (!name)
name = "unexplained error";
/* VANISHED is not an error, only a warning */
if (code == RERR_VANISHED) {
rprintf(FINFO, "rsync warning: %s (code %d) at %s(%d)\n",
name, code, file, line);
} else {
rprintf(FERROR, "rsync error: %s (code %d) at %s(%d)\n",
name, code, file, line);
}
name = rerr_name(code);
if (!name)
name = "unexplained error";
rprintf(FERROR,"rsync error: %s (code %d) at %s(%d)\n",
name, code, file, line);
}
}
/*
* Log the incoming transfer of a file for interactive use,
* this will be called at the end where the client was run.
* Called when a file starts to be transferred.
*/
void log_transfer(struct file_struct *file, const char *fname)
{
extern int verbose;
if (!verbose) return;
rprintf(FINFO, "%s\n", fname);
}

261
main.c
View File

@@ -24,40 +24,14 @@
time_t starttime = 0;
extern struct stats stats;
extern int am_root;
extern char *files_from;
extern int filesfrom_fd;
extern char *remote_filesfrom_file;
extern int am_server;
extern int am_sender;
extern int am_generator;
extern int am_daemon;
extern int verbose;
extern int blocking_io;
extern int cvs_exclude;
extern int delete_mode;
extern int delete_excluded;
extern int delete_after;
extern int daemon_over_rsh;
extern int do_stats;
extern int dry_run;
extern int list_only;
extern int local_server;
extern int log_got_error;
extern int module_id;
extern int orig_umask;
extern int preserve_hard_links;
extern int protocol_version;
extern int recurse;
extern int relative_paths;
extern int rsync_port;
extern int read_batch;
extern int write_batch;
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;
/* there's probably never more than at most 2 outstanding child processes,
* but set it higher just in case.
@@ -81,7 +55,7 @@ void wait_process(pid_t pid, int *status)
while ((waited_pid = waitpid(pid, status, WNOHANG)) == 0) {
msleep(20);
io_flush(FULL_FLUSH);
io_flush();
}
if ((waited_pid == -1) && (errno == ECHILD)) {
@@ -108,6 +82,8 @@ void wait_process(pid_t pid, int *status)
static void report(int f)
{
time_t t = time(NULL);
extern int do_stats;
int send_stats;
if (do_stats && verbose > 1) {
/* These come out from every process */
@@ -115,16 +91,14 @@ static void report(int f)
show_flist_stats();
}
if (am_generator)
return;
if (am_daemon) {
log_exit(0, __FILE__, __LINE__);
if (f == -1 || !am_sender) return;
}
send_stats = verbose || protocol_version >= 20;
if (am_server) {
if (am_sender) {
if (am_sender && send_stats) {
int64 w;
/* store total_written in a temporary
* because write_longint changes it */
@@ -138,7 +112,7 @@ static void report(int f)
/* this is the client */
if (!am_sender) {
if (!am_sender && send_stats) {
int64 r;
stats.total_written = read_longint(f);
/* store total_read in a temporary, read_longint changes it */
@@ -148,6 +122,12 @@ static void report(int f)
}
if (do_stats) {
if (!am_sender && !send_stats) {
/* missing the bytes written by the generator */
rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
rprintf(FINFO, "Use --stats -v to show stats\n");
return;
}
rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
rprintf(FINFO,"Number of files transferred: %d\n",
stats.num_transferred_files);
@@ -191,18 +171,16 @@ static void show_malloc_stats(void)
mi = mallinfo();
rprintf(FINFO, "\n" RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
getpid(),
am_server ? "server " : "",
am_daemon ? "daemon " : "",
who_am_i());
am_sender ? "sender" : "receiver");
rprintf(FINFO, " arena: %10d (bytes from sbrk)\n", mi.arena);
rprintf(FINFO, " ordblks: %10d (chunks not in use)\n", mi.ordblks);
rprintf(FINFO, " smblks: %10d\n", mi.smblks);
rprintf(FINFO, " hblks: %10d (chunks from mmap)\n", mi.hblks);
rprintf(FINFO, " hblkhd: %10d (bytes from mmap)\n", mi.hblkhd);
rprintf(FINFO, " allmem: %10d (bytes from sbrk + mmap)\n",
mi.arena + mi.hblkhd);
rprintf(FINFO, " usmblks: %10d\n", mi.usmblks);
rprintf(FINFO, " fsmblks: %10d\n", mi.fsmblks);
rprintf(FINFO, " uordblks: %10d (bytes used)\n", mi.uordblks);
@@ -213,30 +191,34 @@ static void show_malloc_stats(void)
/* Start the remote shell. cmd may be NULL to use the default. */
static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
int *f_in, int *f_out)
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];
int i,argc=0;
pid_t ret;
char *tok, *dir = NULL;
char *tok,*dir=NULL;
int dash_l_set = 0;
extern int local_server;
extern char *rsync_path;
extern int blocking_io;
extern int daemon_over_rsh;
extern int read_batch;
if (!read_batch && !local_server) {
char *rsh_env = getenv(RSYNC_RSH_ENV);
if (!cmd)
cmd = rsh_env;
cmd = getenv(RSYNC_RSH_ENV);
if (!cmd)
cmd = RSYNC_RSH;
cmd = strdup(cmd);
if (!cmd)
goto oom;
for (tok = strtok(cmd, " "); tok; tok = strtok(NULL, " "))
for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
args[argc++] = tok;
}
/* check to see if we've already been given '-l user' in
* the remote-shell command */
the remote-shell command */
for (i = 0; i < argc-1; i++) {
if (!strcmp(args[i], "-l") && args[i+1][0] != '-')
dash_l_set = 1;
@@ -259,17 +241,11 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
args[argc++] = rsync_path;
if (blocking_io < 0) {
char *cp;
if ((cp = strrchr(cmd, '/')) != NULL)
cp++;
else
cp = cmd;
if (strcmp(cp, "rsh") == 0 || strcmp(cp, "remsh") == 0)
blocking_io = 1;
}
if ((blocking_io == -1) && (strcmp(cmd, RSYNC_RSH) == 0))
blocking_io = 1;
server_options(args,&argc);
}
args[argc++] = ".";
@@ -277,11 +253,6 @@ 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) {
@@ -309,10 +280,13 @@ oom:
}
static char *get_local_name(struct file_list *flist,char *name)
{
STRUCT_STAT st;
int e;
extern int orig_umask;
if (verbose > 2)
rprintf(FINFO,"get_local_name count=%d %s\n",
@@ -323,7 +297,7 @@ 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)) {
if (!push_dir(name, 0)) {
rprintf(FERROR, "push_dir %s failed: %s (1)\n",
full_fname(name), strerror(errno));
exit_cleanup(RERR_FILESELECT);
@@ -349,7 +323,7 @@ static char *get_local_name(struct file_list *flist,char *name)
rprintf(FINFO,"created directory %s\n",name);
}
if (!push_dir(name)) {
if (!push_dir(name, 0)) {
rprintf(FERROR, "push_dir %s failed: %s (2)\n",
full_fname(name), strerror(errno));
exit_cleanup(RERR_FILESELECT);
@@ -359,18 +333,20 @@ static char *get_local_name(struct file_list *flist,char *name)
}
static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
{
int i;
struct file_list *flist;
char *dir = argv[0];
extern int relative_paths;
extern int recurse;
if (verbose > 2) {
rprintf(FINFO, "server_sender starting pid=%ld\n",
(long)getpid());
}
if (verbose > 2)
rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
if (!relative_paths && !push_dir(dir)) {
if (!relative_paths && !push_dir(dir, 0)) {
rprintf(FERROR, "push_dir %s failed: %s (3)\n",
full_fname(dir), strerror(errno));
exit_cleanup(RERR_FILESELECT);
@@ -397,16 +373,14 @@ 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);
send_files(flist,f_out,f_in);
io_flush(FULL_FLUSH);
io_flush();
report(f_out);
if (protocol_version >= 24) {
/* final goodbye message */
read_int(f_in);
}
io_flush(FULL_FLUSH);
read_int(f_in);
}
io_flush();
exit_cleanup(0);
}
@@ -415,7 +389,12 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
{
int pid;
int status=0;
int recv_pipe[2];
int error_pipe[2];
extern int preserve_hard_links;
extern int delete_after;
extern int recurse;
extern int delete_mode;
if (preserve_hard_links)
init_hard_links(flist);
@@ -427,14 +406,20 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
}
}
if (fd_pair(recv_pipe) < 0) {
rprintf(FERROR,"pipe failed in do_recv\n");
exit_cleanup(RERR_SOCKETIO);
}
if (fd_pair(error_pipe) < 0) {
rprintf(FERROR,"error pipe failed in do_recv\n");
exit_cleanup(RERR_SOCKETIO);
}
io_flush(NORMAL_FLUSH);
io_flush();
if ((pid=do_fork()) == 0) {
close(recv_pipe[0]);
close(error_pipe[0]);
if (f_in != f_out) close(f_out);
@@ -442,42 +427,41 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
io_multiplexing_close();
/* set place to send errors */
set_msg_fd_out(error_pipe[1]);
set_error_fd(error_pipe[1]);
recv_files(f_in,flist,local_name);
io_flush(FULL_FLUSH);
recv_files(f_in,flist,local_name,recv_pipe[1]);
io_flush();
report(f_in);
send_msg(MSG_DONE, "", 0);
io_flush(FULL_FLUSH);
write_int(recv_pipe[1],1);
close(recv_pipe[1]);
io_flush();
/* finally we go to sleep until our parent kills us
* with a USR2 signal. We sleep for a short time as on
* some OSes a signal won't interrupt a sleep! */
while (1)
msleep(20);
with a USR2 signal. We sleep for a short time as on
some OSes a signal won't interrupt a sleep! */
while (msleep(20))
;
}
am_generator = 1;
close(recv_pipe[1]);
close(error_pipe[1]);
if (f_in != f_out) close(f_in);
io_start_buffering_out(f_out);
io_start_buffering(f_out);
set_msg_fd_in(error_pipe[0]);
io_set_error_fd(error_pipe[0]);
generate_files(f_out, flist, local_name);
generate_files(f_out,flist,local_name,recv_pipe[0]);
get_redo_num(); /* Read final MSG_DONE and any prior messages. */
report(-1);
io_flush(FULL_FLUSH);
read_int(recv_pipe[0]);
close(recv_pipe[0]);
if (protocol_version >= 24) {
/* send a final goodbye message */
write_int(f_out, -1);
}
io_flush(FULL_FLUSH);
io_flush();
set_msg_fd_in(-1);
io_set_error_fd(-1);
kill(pid, SIGUSR2);
wait_process(pid, &status);
return status;
@@ -488,13 +472,16 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
{
int status;
struct file_list *flist;
char *local_name = NULL;
char *local_name=NULL;
char *dir = NULL;
extern int delete_mode;
extern int delete_excluded;
extern int module_id;
extern int read_batch;
extern struct file_list *batch_flist;
if (verbose > 2) {
rprintf(FINFO, "server_recv(%d) starting pid=%ld\n",
argc, (long)getpid());
}
if (verbose > 2)
rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
if (am_daemon && lp_read_only(module_id) && !am_sender) {
rprintf(FERROR,"ERROR: module is read only\n");
@@ -507,14 +494,13 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
dir = argv[0];
argc--;
argv++;
if (!am_daemon && !push_dir(dir)) {
if (!am_daemon && !push_dir(dir, 0)) {
rprintf(FERROR, "push_dir %s failed: %s (4)\n",
full_fname(dir), strerror(errno));
exit_cleanup(RERR_FILESELECT);
}
}
io_start_buffering_in(f_in);
if (delete_mode && !delete_excluded)
recv_exclude_list(f_in);
@@ -558,6 +544,9 @@ int child_main(int argc, char *argv[])
void start_server(int f_in, int f_out, int argc, char *argv[])
{
extern int cvs_exclude;
extern int read_batch;
setup_protocol(f_out, f_in);
set_nonblocking(f_in);
@@ -589,6 +578,10 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
struct file_list *flist = NULL;
int status = 0, status2 = 0;
char *local_name = NULL;
extern pid_t cleanup_child_pid;
extern int write_batch;
extern int read_batch;
extern struct file_list *batch_flist;
cleanup_child_pid = pid;
if (read_batch)
@@ -603,21 +596,21 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
io_start_multiplex_in(f_in);
if (am_sender) {
io_start_buffering_out(f_out);
extern int cvs_exclude;
extern int delete_mode;
extern int delete_excluded;
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 (!read_batch) /* don't write to pipe */
if (!read_batch) /* dw -- don't write to pipe */
flist = send_file_list(f_out,argc,argv);
if (verbose > 3)
rprintf(FINFO,"file list sent\n");
io_flush(NORMAL_FLUSH);
send_files(flist,f_out,f_in);
io_flush(FULL_FLUSH);
if (protocol_version >= 24) {
/* final goodbye message */
read_int(f_in);
@@ -625,15 +618,15 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
if (pid != -1) {
if (verbose > 3)
rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
io_flush(FULL_FLUSH);
io_flush();
wait_process(pid, &status);
}
report(-1);
io_flush(FULL_FLUSH);
exit_cleanup(status);
}
if (argc == 0) {
extern int list_only;
list_only = 1;
}
@@ -660,7 +653,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
if (pid != -1) {
if (verbose > 3)
rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
io_flush(FULL_FLUSH);
io_flush();
wait_process(pid, &status);
}
@@ -700,6 +693,11 @@ static int start_client(int argc, char *argv[])
int ret;
pid_t pid;
int f_in,f_out;
extern int local_server;
extern char *shell_cmd;
extern int rsync_port;
extern int daemon_over_rsh;
extern int read_batch;
int rc;
/* Don't clobber argv[] so that ps(1) can still show the right
@@ -828,7 +826,7 @@ static int start_client(int argc, char *argv[])
}
if (shell_machine) {
p = strrchr(shell_machine,'@');
p = strchr(shell_machine,'@');
if (p) {
*p = 0;
shell_user = shell_machine;
@@ -850,6 +848,7 @@ static int start_client(int argc, char *argv[])
}
if (argc == 0 && !am_sender) {
extern int list_only;
list_only = 1;
}
@@ -857,7 +856,7 @@ static int start_client(int argc, char *argv[])
&f_in,&f_out);
/* if we're running an rsync server on the remote host over a
* remote shell command, we need to do the RSYNCD protocol first */
remote shell command, we need to do the RSYNCD protocol first */
if (daemon_over_rsh) {
int tmpret;
tmpret = start_inband_exchange(shell_user, shell_path,
@@ -882,6 +881,7 @@ static RETSIGTYPE sigusr1_handler(UNUSED(int val))
static RETSIGTYPE sigusr2_handler(UNUSED(int val))
{
extern int log_got_error;
if (log_got_error) _exit(RERR_PARTIAL);
_exit(0);
}
@@ -898,14 +898,14 @@ static RETSIGTYPE sigchld_handler(UNUSED(int val))
* zombie children, maybe that's why he did it.
*/
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
/* save the child's exit status */
for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
if (pid_stat_table[cnt].pid == 0) {
pid_stat_table[cnt].pid = pid;
pid_stat_table[cnt].status = status;
break;
}
}
/* save the child's exit status */
for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
if (pid_stat_table[cnt].pid == 0) {
pid_stat_table[cnt].pid = pid;
pid_stat_table[cnt].status = status;
break;
}
}
}
#endif
}
@@ -964,7 +964,11 @@ static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
int main(int argc,char *argv[])
{
extern int am_root;
extern int orig_umask;
extern int dry_run;
int ret;
extern int write_batch;
int orig_argc;
char **orig_argv;
@@ -982,7 +986,7 @@ int main(int argc,char *argv[])
#endif /* def MAINTAINER_MODE */
starttime = time(NULL);
am_root = (MY_UID() == 0);
am_root = (getuid() == 0);
memset(&stats, 0, sizeof(stats));
@@ -992,7 +996,7 @@ int main(int argc,char *argv[])
}
/* we set a 0 umask so that correct file permissions can be
* carried across */
carried across */
orig_umask = (int)umask(0);
if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
@@ -1011,12 +1015,10 @@ int main(int argc,char *argv[])
signal(SIGPIPE, SIG_IGN);
/* Initialize push_dir here because on some old systems getcwd
* (implemented by forking "pwd" and reading its output) doesn't
* work when there are other child processes. Also, on all systems
* that implement getcwd that way "pwd" can't be found after chroot. */
push_dir(NULL);
init_flist();
(implemented by forking "pwd" and reading its output) doesn't
work when there are other child processes. Also, on all systems
that implement getcwd that way "pwd" can't be found after chroot. */
push_dir(NULL,0);
if (write_batch && !am_server) {
write_batch_argvs_file(orig_argc, orig_argv);
@@ -1033,6 +1035,13 @@ int main(int argc,char *argv[])
if (dry_run)
verbose = MAX(verbose,1);
#ifndef SUPPORT_LINKS
if (!am_server && preserve_links) {
rprintf(FERROR,"ERROR: symbolic links not supported\n");
exit_cleanup(RERR_UNSUPPORTED);
}
#endif
if (am_server) {
set_nonblocking(STDIN_FILENO);
set_nonblocking(STDOUT_FILENO);

219
match.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.
@@ -19,14 +19,17 @@
#include "rsync.h"
extern int csum_length;
extern int verbose;
extern int am_server;
extern int do_progress;
extern int remote_version;
typedef unsigned short tag;
#define TABLESIZE (1<<16)
#define NULL_TAG ((size_t)-1)
#define NULL_TAG (-1)
static int false_alarms;
static int tag_hits;
@@ -40,46 +43,47 @@ static int total_matches;
extern struct stats stats;
struct target {
tag t;
size_t i;
tag t;
int i;
};
static struct target *targets;
static size_t *tag_table;
static int *tag_table;
#define gettag2(s1,s2) (((s1) + (s2)) & 0xFFFF)
#define gettag(sum) gettag2((sum)&0xFFFF,(sum)>>16)
static int compare_targets(struct target *t1,struct target *t2)
{
return (int)t1->t - (int)t2->t;
return((int)t1->t - (int)t2->t);
}
static void build_hash_table(struct sum_struct *s)
{
size_t i;
int i;
if (!tag_table)
tag_table = new_array(size_t, TABLESIZE);
if (!tag_table)
tag_table = new_array(int, TABLESIZE);
targets = new_array(struct target, s->count);
if (!tag_table || !targets)
out_of_memory("build_hash_table");
targets = new_array(struct target, s->count);
if (!tag_table || !targets)
out_of_memory("build_hash_table");
for (i = 0; i < s->count; i++) {
targets[i].i = i;
targets[i].t = gettag(s->sums[i].sum1);
}
for (i=0;i<(int) s->count;i++) {
targets[i].i = i;
targets[i].t = gettag(s->sums[i].sum1);
}
qsort(targets,s->count,sizeof(targets[0]),(int (*)())compare_targets);
qsort(targets,s->count,sizeof(targets[0]),(int (*)())compare_targets);
for (i = 0; i < TABLESIZE; i++)
tag_table[i] = NULL_TAG;
for (i=0;i<TABLESIZE;i++)
tag_table[i] = NULL_TAG;
for (i = s->count; i-- > 0; )
tag_table[targets[i].t] = i;
for (i=s->count-1;i>=0;i--) {
tag_table[targets[i].t] = i;
}
}
@@ -105,7 +109,7 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
OFF_T j;
if (verbose > 2 && i >= 0)
rprintf(FINFO,"match at %.0f last_match=%.0f j=%d len=%u n=%.0f\n",
rprintf(FINFO,"match at %.0f last_match=%.0f j=%d len=%d n=%.0f\n",
(double)offset,(double)last_match,i,s->sums[i].len,(double)n);
send_token(f,i,buf,last_match,n,i<0?0:s->sums[i].len);
@@ -115,8 +119,8 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
stats.matched_data += s->sums[i].len;
n += s->sums[i].len;
}
for (j = 0; j < n; j += CHUNK_SIZE) {
for (j=0;j<n;j+=CHUNK_SIZE) {
int n1 = MIN(CHUNK_SIZE,n-j);
sum_update(map_ptr(buf,last_match+j,n1),n1);
}
@@ -127,134 +131,129 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
else
last_match = offset;
if (buf && do_progress) {
if (buf) {
show_progress(last_match, buf->file_size);
if (i == -1)
end_progress(buf->file_size);
if (i == -1) end_progress(buf->file_size);
}
}
static void hash_search(int f,struct sum_struct *s,
struct map_struct *buf, OFF_T len)
struct map_struct *buf,OFF_T len)
{
OFF_T offset, end;
unsigned int k;
size_t last_i;
int j,k, last_i;
char sum2[SUM_LENGTH];
uint32 s1, s2, sum;
uint32 s1, s2, sum;
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;
last_i = -1;
if (verbose > 2) {
rprintf(FINFO,"hash search b=%u len=%.0f\n",
s->blength, (double)len);
}
k = MIN(len, s->blength);
map = (schar *)map_ptr(buf, 0, k);
if (verbose > 2)
rprintf(FINFO,"hash search b=%ld len=%.0f\n",
(long) s->n, (double)len);
/* cast is to make s->n signed; it should always be reasonably
* small */
k = MIN(len, (OFF_T) s->n);
map = (schar *)map_ptr(buf,0,k);
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
if (verbose > 3)
rprintf(FINFO, "sum=%.8x k=%u\n", sum, k);
rprintf(FINFO, "sum=%.8x k=%d\n", sum, k);
offset = 0;
end = len + 1 - s->sums[s->count-1].len;
if (verbose > 3) {
rprintf(FINFO, "hash search s->blength=%u len=%.0f count=%.0f\n",
s->blength, (double)len, (double)s->count);
}
if (verbose > 3)
rprintf(FINFO, "hash search s->n=%ld len=%.0f count=%ld\n",
(long) s->n, (double) len, (long) s->count);
do {
tag t = gettag2(s1,s2);
int done_csum2 = 0;
size_t j = tag_table[t];
j = tag_table[t];
if (verbose > 4)
rprintf(FINFO,"offset=%.0f sum=%08x\n",(double)offset,sum);
if (j == NULL_TAG)
if (j == NULL_TAG) {
goto null_tag;
}
sum = (s1 & 0xffff) | (s2 << 16);
tag_hits++;
for (; j < s->count && targets[j].t == t; j++) {
unsigned int l;
size_t i = targets[j].i;
if (sum != s->sums[i].sum1)
continue;
for (; j < (int) s->count && targets[j].t == t; j++) {
int l, i = targets[j].i;
if (sum != s->sums[i].sum1) continue;
/* also make sure the two blocks are the same length */
l = MIN((OFF_T)s->blength, len-offset);
if (l != s->sums[i].len)
continue;
l = MIN(s->n,len-offset);
if (l != s->sums[i].len) continue;
if (verbose > 3)
rprintf(FINFO,"potential match at %.0f target=%.0f %.0f sum=%08x\n",
(double)offset,(double)j,(double)i,sum);
rprintf(FINFO,"potential match at %.0f target=%d %d sum=%08x\n",
(double)offset,j,i,sum);
if (!done_csum2) {
map = (schar *)map_ptr(buf,offset,l);
get_checksum2((char *)map,l,sum2);
done_csum2 = 1;
}
if (memcmp(sum2,s->sums[i].sum2,s->s2length) != 0) {
if (memcmp(sum2,s->sums[i].sum2,csum_length) != 0) {
false_alarms++;
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 last_i can hint at a better match */
for (j++; j < (int) s->count && targets[j].t == t; j++) {
int 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 */
if (sum != s->sums[i2].sum1) break;
if (memcmp(sum2,s->sums[i2].sum2,csum_length) != 0) break;
/* we've found an adjacent match - the RLL coder
will be happy */
i = i2;
break;
}
}
last_i = i;
matched(f,s,buf,offset,i);
offset += s->sums[i].len - 1;
k = MIN(s->blength, len-offset);
map = (schar *)map_ptr(buf, offset, k);
k = MIN((len-offset), s->n);
map = (schar *)map_ptr(buf,offset,k);
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
matches++;
break;
}
null_tag:
/* Trim off the first byte from the checksum */
map = (schar *)map_ptr(buf, offset, k+1);
map = (schar *)map_ptr(buf,offset,k+1);
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);
s2 += s1;
} else
} else {
--k;
}
/* By matching early we avoid re-reading the
data 3 times in the case where a token
@@ -262,13 +261,13 @@ 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) {
matched(f,s,buf,offset - s->blength, -2);
if (offset > last_match &&
offset-last_match >= CHUNK_SIZE+s->n &&
(end-offset > CHUNK_SIZE)) {
matched(f,s,buf,offset - s->n, -2);
}
} while (++offset < end);
matched(f,s,buf,len,-1);
map_ptr(buf,len-1,1);
}
@@ -291,30 +290,30 @@ 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;
extern int write_batch; /* dw */
last_match = 0;
false_alarms = 0;
tag_hits = 0;
matches = 0;
data_transfer = 0;
matches=0;
data_transfer=0;
sum_init();
if (len > 0 && s->count>0) {
build_hash_table(s);
if (verbose > 2)
if (verbose > 2)
rprintf(FINFO,"built hash table\n");
hash_search(f,s,buf,len);
if (verbose > 2)
if (verbose > 2)
rprintf(FINFO,"done hash search\n");
} else {
OFF_T j;
/* by doing this in pieces we avoid too many seeks */
for (j = 0; j < len-CHUNK_SIZE; j += CHUNK_SIZE) {
for (j=0;j<(len-CHUNK_SIZE);j+=CHUNK_SIZE) {
int n1 = MIN(CHUNK_SIZE,(len-CHUNK_SIZE)-j);
matched(f,s,buf,j+n1,-2);
}
@@ -323,21 +322,23 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
sum_end(file_sum);
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 (remote_version >= 14) {
if (verbose > 2)
rprintf(FINFO,"sending file_sum\n");
write_buf(f,file_sum,MD4_SUM_LENGTH);
if (write_batch) /* dw */
write_batch_delta_file(file_sum, MD4_SUM_LENGTH);
}
if (targets) {
free(targets);
targets=NULL;
}
if (verbose > 2)
rprintf(FINFO, "false_alarms=%d tag_hits=%d matches=%d\n",
false_alarms, tag_hits, matches);
total_tag_hits += tag_hits;
total_false_alarms += false_alarms;
total_matches += matches;

View File

@@ -58,7 +58,7 @@ BEGIN {
next;
}
!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time|^const/ {
!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time/ {
next;
}

402
options.c
View File

@@ -21,9 +21,7 @@
#include "rsync.h"
#include "popt.h"
extern int sanitize_paths;
extern char curr_dir[MAXPATHLEN];
extern struct exclude_list_struct exclude_list;
extern struct exclude_struct **exclude_list;
int make_backups = 0;
@@ -48,27 +46,27 @@ int preserve_gid = 0;
int preserve_times = 0;
int update_only = 0;
int cvs_exclude = 0;
int dry_run = 0;
int local_server = 0;
int ignore_times = 0;
int delete_mode = 0;
int delete_excluded = 0;
int one_file_system = 0;
int dry_run=0;
int local_server=0;
int ignore_times=0;
int delete_mode=0;
int delete_excluded=0;
int one_file_system=0;
int protocol_version = PROTOCOL_VERSION;
int sparse_files = 0;
int do_compression = 0;
int am_root = 0;
int orig_umask = 0;
int sparse_files=0;
int do_compression=0;
int am_root=0;
int orig_umask=0;
int relative_paths = -1;
int implied_dirs = 1;
int numeric_ids = 0;
int force_delete = 0;
int io_timeout = 0;
int io_error = 0;
int read_only = 0;
int module_id = -1;
int am_server = 0;
int am_sender = 0;
int am_generator = 0;
char *files_from = NULL;
int filesfrom_fd = -1;
char *remote_filesfrom_file = NULL;
@@ -76,22 +74,21 @@ int eol_nulls = 0;
int recurse = 0;
int am_daemon = 0;
int daemon_over_rsh = 0;
int do_stats = 0;
int do_progress = 0;
int keep_partial = 0;
int safe_symlinks = 0;
int copy_unsafe_links = 0;
int size_only = 0;
int bwlimit = 0;
int delete_after = 0;
int only_existing = 0;
int opt_ignore_existing = 0;
int max_delete = 0;
int ignore_errors = 0;
int modify_window = 0;
int blocking_io = -1;
int checksum_seed = 0;
unsigned int block_size = 0;
int do_stats=0;
int do_progress=0;
int keep_partial=0;
int safe_symlinks=0;
int copy_unsafe_links=0;
int block_size=0;
int size_only=0;
int bwlimit=0;
int delete_after=0;
int only_existing=0;
int opt_ignore_existing=0;
int max_delete=0;
int ignore_errors=0;
int modify_window=0;
int blocking_io=-1;
/** Network address family. **/
@@ -110,7 +107,6 @@ int write_batch = 0;
int read_batch = 0;
int backup_dir_len = 0;
int backup_suffix_len;
unsigned int backup_dir_remainder;
char *backup_suffix = NULL;
char *tmpdir = NULL;
@@ -121,7 +117,6 @@ char *log_format = NULL;
char *password_file = NULL;
char *rsync_path = RSYNC_PATH;
char *backup_dir = NULL;
char backup_dir_buf[MAXPATHLEN];
int rsync_port = RSYNC_PORT;
int link_dest = 0;
@@ -130,11 +125,8 @@ 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;
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
@@ -170,11 +162,11 @@ static void print_rsync_version(enum logcode f)
rprintf(f, "%s version %s protocol version %d\n",
RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
rprintf(f,
"Copyright (C) 1996-2004 by Andrew Tridgell and others\n");
"Copyright (C) 1996-2002 by Andrew Tridgell and others\n");
rprintf(f, "<http://rsync.samba.org/>\n");
rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
"%shard links, %ssymlinks, batchfiles, \n",
(int) (sizeof (OFF_T) * 8),
(int) (sizeof(OFF_T) * 8),
got_socketpair, hardlinks, links);
/* Note that this field may not have type ino_t. It depends
@@ -182,8 +174,8 @@ static void print_rsync_version(enum logcode f)
* macros. */
rprintf(f, " %sIPv6, %d-bit system inums, %d-bit internal inums\n",
ipv6,
(int) (sizeof dumstat->st_ino * 8),
(int) (sizeof (uint64) * 8));
(int) (sizeof(dumstat->st_ino) * 8),
(int) (sizeof(INO64_T) * 8));
#ifdef MAINTAINER_MODE
rprintf(f, " panic action: \"%s\"\n",
get_panic_action());
@@ -227,14 +219,14 @@ void usage(enum logcode F)
rprintf(F," -R, --relative use relative path names\n");
rprintf(F," --no-relative turn off --relative\n");
rprintf(F," --no-implied-dirs don't send implied dirs with -R\n");
rprintf(F," -b, --backup make backups (see --suffix & --backup-dir)\n");
rprintf(F," -b, --backup make backups (default %s suffix)\n",BACKUP_SUFFIX);
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," --suffix=SUFFIX override backup suffix\n");
rprintf(F," -u, --update update only (don't overwrite newer files)\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");
rprintf(F," --safe-links ignore \"unsafe\" symlinks\n");
rprintf(F," -L, --copy-links copy the referent of symlinks\n");
rprintf(F," --copy-unsafe-links copy links outside the source tree\n");
rprintf(F," --safe-links ignore links outside the destination tree\n");
rprintf(F," -H, --hard-links preserve hard links\n");
rprintf(F," -p, --perms preserve permissions\n");
rprintf(F," -o, --owner preserve owner (root only)\n");
@@ -250,19 +242,19 @@ void usage(enum logcode F)
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");
rprintf(F," --ignore-existing ignore files that already exist on receiving side\n");
rprintf(F," --ignore-existing ignore files that already exist on the receiving side\n");
rprintf(F," --delete delete files that don't exist on the sending side\n");
rprintf(F," --delete-excluded also delete excluded files on the receiving side\n");
rprintf(F," --delete-after receiver deletes after transferring, not before\n");
rprintf(F," --ignore-errors delete even if there are I/O errors\n");
rprintf(F," --delete-after delete after transferring, not before\n");
rprintf(F," --ignore-errors delete even if there are IO 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," --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," --timeout=TIME set IO timeout in seconds\n");
rprintf(F," -I, --ignore-times don't exclude files that match length and time\n");
rprintf(F," --size-only only use file size when determining if a file should be transferred\n");
rprintf(F," --modify-window=NUM Timestamp window (seconds) for file match (default=%d)\n",modify_window);
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");
@@ -274,14 +266,14 @@ 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 file names we read are separated by nulls, not newlines\n");
rprintf(F," --version print version number\n");
rprintf(F," --daemon run as an rsync daemon\n");
rprintf(F," --daemon run as a rsync daemon\n");
rprintf(F," --no-detach do not detach from the parent\n");
rprintf(F," --address=ADDRESS bind to the specified address\n");
rprintf(F," --config=FILE specify alternate rsyncd.conf file\n");
rprintf(F," --port=PORT specify alternate rsyncd port number\n");
rprintf(F," --blocking-io use blocking I/O for the remote shell\n");
rprintf(F," --blocking-io use blocking IO for the remote shell\n");
rprintf(F," --no-blocking-io turn off --blocking-io\n");
rprintf(F," --stats give some file transfer stats\n");
rprintf(F," --progress show progress during transfer\n");
@@ -305,8 +297,7 @@ 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_REFUSED_BASE = 9000};
OPT_READ_BATCH, OPT_WRITE_BATCH};
static struct poptOption long_options[] = {
/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
@@ -361,10 +352,10 @@ static struct poptOption long_options[] = {
{"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 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 },
{"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
/* TODO: Should this take an optional int giving the compression level? */
{"compress", 'z', POPT_ARG_NONE, &do_compression, 0, 0, 0 },
{"daemon", 0, POPT_ARG_NONE, &daemon_opt, 0, 0, 0 },
{"daemon", 0, POPT_ARG_NONE, &am_daemon, 0, 0, 0 },
{"no-detach", 0, POPT_ARG_NONE, &no_detach, 0, 0, 0 },
{"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 },
{"progress", 0, POPT_ARG_NONE, &do_progress, 0, 0, 0 },
@@ -417,34 +408,33 @@ void option_error(void)
/**
* Tweak the option table to disable all options that the rsyncd.conf
* file has told us to refuse.
* Check to see if we should refuse this option
**/
static void set_refuse_options(char *bp)
static int check_refuse_options(char *ref, int opt)
{
struct poptOption *op;
char *cp;
int i, len;
char *p;
const char *name;
while (1) {
if ((cp = strchr(bp, ' ')) != NULL)
*cp= '\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;
break;
}
}
if (!cp)
break;
*cp = ' ';
bp = cp + 1;
for (i=0; long_options[i].longName; i++) {
if (long_options[i].val == opt) break;
}
if (!long_options[i].longName) return 0;
name = long_options[i].longName;
len = strlen(name);
while ((p = strstr(ref,name))) {
if ((p==ref || p[-1]==' ') &&
(p[len] == ' ' || p[len] == 0)) {
snprintf(err_buf,sizeof(err_buf),
"The '%s' option is not supported by this server\n", name);
return 1;
}
ref += len;
}
return 0;
}
@@ -471,12 +461,8 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
{
int opt;
char *ref = lp_refuse_options(module_id);
const char *arg;
poptContext pc;
if (ref && *ref)
set_refuse_options(ref);
/* TODO: Call poptReadDefaultConfig; handle errors. */
/* The context leaks in case of an error, but if there's a
@@ -484,6 +470,10 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0);
while ((opt = poptGetNextOpt(pc)) != -1) {
if (ref) {
if (check_refuse_options(ref, opt)) return 0;
}
/* most options are handled automatically by popt;
* only special cases are returned and listed here. */
@@ -510,41 +500,53 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
break;
case OPT_EXCLUDE:
add_exclude(&exclude_list, poptGetOptArg(pc), 0);
add_exclude(&exclude_list, poptGetOptArg(pc),
ADD_EXCLUDE);
break;
case OPT_INCLUDE:
add_exclude(&exclude_list, poptGetOptArg(pc),
XFLG_DEF_INCLUDE);
ADD_INCLUDE);
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);
add_exclude_file(&exclude_list, poptGetOptArg(pc),
MISSING_FATAL, ADD_EXCLUDE);
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);
add_exclude_file(&exclude_list, poptGetOptArg(pc),
MISSING_FATAL, ADD_INCLUDE);
break;
case 'h':
usage(FINFO);
exit_cleanup(0);
case 'H':
#if SUPPORT_HARD_LINKS
preserve_hard_links=1;
#else
/* FIXME: Don't say "server" if this is
* happening on the client. */
/* FIXME: Why do we have the duplicated
* rprintf? Everybody who gets this message
* ought to send it to the client and also to
* the logs. */
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 /* SUPPORT_HARD_LINKS */
break;
case 'v':
verbose++;
break;
case 'q':
if (frommain)
quiet++;
if (frommain) quiet++;
break;
case OPT_SENDER:
@@ -563,17 +565,16 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
case OPT_WRITE_BATCH:
/* popt stores the filename in batch_prefix for us */
write_batch = 1;
checksum_seed = FIXED_CHECKSUM_SEED;
break;
case OPT_READ_BATCH:
/* popt stores the filename in batch_prefix for us */
read_batch = 1;
checksum_seed = FIXED_CHECKSUM_SEED;
break;
case OPT_LINK_DEST:
#if HAVE_LINK
compare_dest = (char *)poptGetOptArg(pc);
link_dest = 1;
break;
#else
@@ -584,66 +585,24 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
return 0;
#endif
default:
/* A large opt value means that set_refuse_options()
* turned this option off (opt-BASE is its index). */
if (opt >= OPT_REFUSED_BASE) {
struct poptOption *op =
&long_options[opt-OPT_REFUSED_BASE];
int n = snprintf(err_buf, sizeof err_buf,
"This server does not support --%s\n",
op->longName) - 1;
if (op->shortName) {
snprintf(err_buf+n, sizeof err_buf-n,
" (-%c)\n", op->shortName);
}
} else {
snprintf(err_buf, sizeof err_buf,
"%s%s: %s\n",
am_server ? "on remote machine: " : "",
poptBadOption(pc, POPT_BADOPTION_NOALIAS),
poptStrerror(opt));
}
/* FIXME: If --daemon is specified, then errors for later
* parameters seem to disappear. */
snprintf(err_buf, sizeof(err_buf),
"%s%s: %s\n",
am_server ? "on remote machine: " : "",
poptBadOption(pc, POPT_BADOPTION_NOALIAS),
poptStrerror(opt));
return 0;
}
}
#if !SUPPORT_LINKS
if (preserve_links && !am_sender) {
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
#if !SUPPORT_HARD_LINKS
if (preserve_hard_links) {
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);
}
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 (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,
@@ -667,54 +626,17 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
if (relative_paths < 0)
relative_paths = files_from? 1 : 0;
*argv = poptGetArgs(pc);
if (*argv)
*argc = count_args(*argv);
else
*argc = 0;
if (sanitize_paths) {
int i;
for (i = *argc; i-- > 0; )
(*argv)[i] = alloc_sanitize_path((*argv)[i], NULL);
if (tmpdir)
tmpdir = alloc_sanitize_path(tmpdir, curr_dir);
if (compare_dest)
compare_dest = alloc_sanitize_path(compare_dest, curr_dir);
if (backup_dir)
backup_dir = alloc_sanitize_path(backup_dir, curr_dir);
if (files_from)
files_from = alloc_sanitize_path(files_from, curr_dir);
}
if (daemon_opt) {
daemon_opt = 0;
am_daemon = 1;
return 1;
}
if (!backup_suffix)
backup_suffix = backup_dir ? "" : BACKUP_SUFFIX;
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",
backup_suffix);
exit_cleanup(RERR_SYNTAX);
}
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);
}
if (backup_dir_buf[backup_dir_len - 1] != '/') {
backup_dir_buf[backup_dir_len++] = '/';
backup_dir_buf[backup_dir_len] = '\0';
}
if (verbose > 1 && !am_sender)
rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf);
} else if (!backup_suffix_len && (!am_server || !am_sender)) {
if (backup_dir)
backup_dir_len = strlen(backup_dir);
else if (!backup_suffix_len) {
rprintf(FERROR,
"--suffix cannot be a null string without --backup-dir\n");
exit_cleanup(RERR_SYNTAX);
@@ -723,17 +645,20 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
if (do_progress && !verbose)
verbose = 1;
*argv = poptGetArgs(pc);
if (*argv)
*argc = count_args(*argv);
else
*argc = 0;
if (files_from) {
char *colon;
if (*argc != 2 && !(am_server && am_sender && *argc == 1)) {
if (*argc != 2) {
usage(FERROR);
exit_cleanup(RERR_SYNTAX);
}
if (strcmp(files_from, "-") == 0) {
if (strcmp(files_from, "-") == 0)
filesfrom_fd = 0;
if (am_server)
remote_filesfrom_file = "-";
}
else if ((colon = find_colon(files_from)) != 0) {
if (am_server) {
usage(FERROR);
@@ -745,6 +670,9 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
exit_cleanup(RERR_SYNTAX);
}
} else {
extern int sanitize_paths;
if (sanitize_paths)
sanitize_path(strdup(files_from), NULL);
filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
if (filesfrom_fd < 0) {
rsyserr(FERROR, errno,
@@ -771,7 +699,13 @@ void server_options(char **args,int *argc)
{
int ac = *argc;
static char argstr[50];
char *arg;
static char bsize[30];
static char iotime[30];
static char mdelete[30];
static char mwindow[30];
static char bw[50];
/* Leave room for ``--(write|read)-batch='' */
static char fext[MAXPATHLEN + 15];
int i, x;
@@ -792,7 +726,7 @@ void server_options(char **args,int *argc)
x = 1;
argstr[0] = '-';
for (i = 0; i < verbose; i++)
for (i=0;i<verbose;i++)
argstr[x++] = 'v';
/* the -q option is intentionally left out */
@@ -851,38 +785,37 @@ void server_options(char **args,int *argc)
argstr[x] = 0;
if (x != 1)
args[ac++] = argstr;
if (x != 1) args[ac++] = argstr;
if (block_size) {
if (asprintf(&arg, "-B%u", block_size) < 0)
goto oom;
args[ac++] = arg;
snprintf(bsize,sizeof(bsize),"-B%d",block_size);
args[ac++] = bsize;
}
if (max_delete && am_sender) {
if (asprintf(&arg, "--max-delete=%d", max_delete) < 0)
goto oom;
args[ac++] = arg;
snprintf(mdelete,sizeof(mdelete),"--max-delete=%d",max_delete);
args[ac++] = mdelete;
}
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 (batch_prefix != NULL) {
char *fmt = "";
if (write_batch)
fmt = "--write-batch=%s";
else
if (read_batch)
fmt = "--read-batch=%s";
snprintf(fext,sizeof(fext),fmt,batch_prefix);
args[ac++] = fext;
}
if (io_timeout) {
if (asprintf(&arg, "--timeout=%d", io_timeout) < 0)
goto oom;
args[ac++] = arg;
snprintf(iotime,sizeof(iotime),"--timeout=%d",io_timeout);
args[ac++] = iotime;
}
if (bwlimit) {
if (asprintf(&arg, "--bwlimit=%d", bwlimit) < 0)
goto oom;
args[ac++] = arg;
snprintf(bw,sizeof(bw),"--bwlimit=%d",bwlimit);
args[ac++] = bw;
}
if (backup_dir) {
@@ -891,25 +824,28 @@ void server_options(char **args,int *argc)
}
/* Only send --suffix if it specifies a non-default value. */
if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
if (strcmp(backup_suffix, backup_dir? "" : BACKUP_SUFFIX) != 0) {
char *s = malloc(9+backup_suffix_len+1);
if (!s)
out_of_memory("server_options");
/* We use the following syntax to avoid weirdness with '~'. */
if (asprintf(&arg, "--suffix=%s", backup_suffix) < 0)
goto oom;
args[ac++] = arg;
sprintf(s, "--suffix=%s", backup_suffix);
args[ac++] = s;
}
if (delete_mode && !delete_excluded)
args[ac++] = "--delete";
if (delete_excluded)
args[ac++] = "--delete-excluded";
else if (delete_mode)
args[ac++] = "--delete";
if (size_only)
args[ac++] = "--size-only";
if (modify_window_set) {
if (asprintf(&arg, "--modify-window=%d", modify_window) < 0)
goto oom;
args[ac++] = arg;
snprintf(mwindow,sizeof(mwindow),"--modify-window=%d",
modify_window);
args[ac++] = mwindow;
}
if (keep_partial)
@@ -966,10 +902,6 @@ void server_options(char **args,int *argc)
}
*argc = ac;
return;
oom:
out_of_memory("server_options");
}
/**
@@ -981,14 +913,12 @@ char *find_colon(char *s)
char *p, *p2;
p = strchr(s,':');
if (!p)
return NULL;
if (!p) return NULL;
/* now check to see if there is a / in the string before the : - if there is then
discard the colon on the assumption that the : is part of a filename */
p2 = strchr(s,'/');
if (p2 && p2 < p)
return NULL;
if (p2 && p2 < p) return NULL;
return p;
}

View File

@@ -1,10 +1,10 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: 2.6.1
Version: 2.5.7
Release: 1
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-%{version}.tar.gz
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.5.7.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
@@ -21,18 +21,11 @@ A technical report describing the rsync algorithm is included with
this package.
%changelog
* Thu Jan 30 2003 Horst von Brand <vonbrand@inf.utfsm.cl>
Fixed "Sept" date in %changelog here
Use %{_mandir} to point to manpages
Support for compressed manpages (* at end catches them in %files)
Add doc/README-SGML and doc/rsync.sgml to %doc
* Mon Sep 11 2000 John H Terpstra <jht@turbolinux.com>
* Mon Sept 11 2000 John H Terpstra <jht@turbolinux.com>
Changed target paths to be Linux Standards Base compliant
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
@@ -69,25 +62,23 @@ previous package(s).)
%setup
%build
./configure --prefix=/usr --mandir=%{_mandir}
./configure --prefix=/usr --mandir=/usr/share/man
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/bin
mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man{1,5}
mkdir -p $RPM_BUILD_ROOT/usr/{bin,share/man/{man1,man5}}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1 $RPM_BUILD_ROOT/%{_mandir}/man1
install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/%{_mandir}/man5
install -m644 rsync.1 $RPM_BUILD_ROOT/usr/share/man/man1
install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/usr/share/man/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) %{_mandir}/man1/rsync.1*
%attr(-,root,root) %{_mandir}/man5/rsyncd.conf.5*
%attr(-,root,root) /usr/share/man/man1/rsync.1
%attr(-,root,root) /usr/share/man/man5/rsyncd.conf.5
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING
%attr(-,root,root) %doc doc/README-SGML doc/rsync.sgml

View File

@@ -0,0 +1,93 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: PVERSION
Release: PRELEASE
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-PVERSION.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
%description
rsync is a replacement for rcp that has many more features.
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
differences in the files across the link, without requiring that both
sets of files are present at one of the ends of the link beforehand.
A technical report describing the rsync algorithm is included with
this package.
%changelog
* Thu Jan 30 2003 Horst von Brand <vonbrand@inf.utfsm.cl>
Fixed "Sept" date in %changelog here
Use %{_mandir} to point to manpages
Support for compressed manpages (* at end catches them in %files)
Add doc/README-SGML and doc/rsync.sgml to %doc
* Mon Sep 11 2000 John H Terpstra <jht@turbolinux.com>
Changed target paths to be Linux Standards Base compliant
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
* Sat May 16 1998 John H Terpstra <jht@aquasoft.com.au>
Upgraded to Rsync 2.0.6
-new feature anonymous rsync
* Mon Apr 6 1998 Douglas N. Arnold <dna@math.psu.edu>
Upgrade to rsync version 1.7.2.
* Sun Mar 1 1998 Douglas N. Arnold <dna@math.psu.edu>
Built 1.6.9-1 based on the 1.6.3-2 spec file of John A. Martin.
Changes from 1.6.3-2 packaging: added latex and dvips commands
to create tech_report.ps.
* Mon Aug 25 1997 John A. Martin <jam@jamux.com>
Built 1.6.3-2 after finding no rsync-1.6.3-1.src.rpm although there
was an ftp://ftp.redhat.com/pub/contrib/alpha/rsync-1.6.3-1.alpha.rpm
showing no packager nor signature but giving
"Source RPM: rsync-1.6.3-1.src.rpm".
Changes from 1.6.2-1 packaging: added '$RPM_OPT_FLAGS' to make, strip
to '%build', removed '%prefix'.
* Thu Apr 10 1997 Michael De La Rue <miked@ed.ac.uk>
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
previous package(s).)
%prep
%setup
%build
./configure --prefix=/usr --mandir=%{_mandir}
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/bin
mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man{1,5}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1 $RPM_BUILD_ROOT/%{_mandir}/man1
install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/%{_mandir}/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) %{_mandir}/man1/rsync.1*
%attr(-,root,root) %{_mandir}/man5/rsyncd.conf.5*
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING
%attr(-,root,root) %doc doc/README-SGML doc/rsync.sgml

View File

@@ -0,0 +1,81 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: 2.5.7
Release: 1
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.5.7.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
%description
rsync is a replacement for rcp that has many more features.
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
differences in the files across the link, without requiring that both
sets of files are present at one of the ends of the link beforehand.
A technical report describing the rsync algorithm is included with
this package.
%changelog
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
* Sat May 16 1998 John H Terpstra <jht@aquasoft.com.au>
Upgraded to Rsync 2.0.6
-new feature anonymous rsync
* Mon Apr 6 1998 Douglas N. Arnold <dna@math.psu.edu>
Upgrade to rsync version 1.7.2.
* Sun Mar 1 1998 Douglas N. Arnold <dna@math.psu.edu>
Built 1.6.9-1 based on the 1.6.3-2 spec file of John A. Martin.
Changes from 1.6.3-2 packaging: added latex and dvips commands
to create tech_report.ps.
* Mon Aug 25 1997 John A. Martin <jam@jamux.com>
Built 1.6.3-2 after finding no rsync-1.6.3-1.src.rpm although there
was an ftp://ftp.redhat.com/pub/contrib/alpha/rsync-1.6.3-1.alpha.rpm
showing no packager nor signature but giving
"Source RPM: rsync-1.6.3-1.src.rpm".
Changes from 1.6.2-1 packaging: added '$RPM_OPT_FLAGS' to make, strip
to '%build', removed '%prefix'.
* Thu Apr 10 1997 Michael De La Rue <miked@ed.ac.uk>
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
previous package(s).)
%prep
%setup
%build
./configure --prefix=/usr
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/{bin,man/{man1,man5}}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1 $RPM_BUILD_ROOT/usr/man/man1
install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/usr/man/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) /usr/man/man1/rsync.1
%attr(-,root,root) /usr/man/man5/rsyncd.conf.5
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING

View File

@@ -0,0 +1,81 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: 2.5.7
Release: 1
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.5.7.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
%description
rsync is a replacement for rcp that has many more features.
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
differences in the files across the link, without requiring that both
sets of files are present at one of the ends of the link beforehand.
A technical report describing the rsync algorithm is included with
this package.
%changelog
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
* Sat May 16 1998 John H Terpstra <jht@aquasoft.com.au>
Upgraded to Rsync 2.0.6
-new feature anonymous rsync
* Mon Apr 6 1998 Douglas N. Arnold <dna@math.psu.edu>
Upgrade to rsync version 1.7.2.
* Sun Mar 1 1998 Douglas N. Arnold <dna@math.psu.edu>
Built 1.6.9-1 based on the 1.6.3-2 spec file of John A. Martin.
Changes from 1.6.3-2 packaging: added latex and dvips commands
to create tech_report.ps.
* Mon Aug 25 1997 John A. Martin <jam@jamux.com>
Built 1.6.3-2 after finding no rsync-1.6.3-1.src.rpm although there
was an ftp://ftp.redhat.com/pub/contrib/alpha/rsync-1.6.3-1.alpha.rpm
showing no packager nor signature but giving
"Source RPM: rsync-1.6.3-1.src.rpm".
Changes from 1.6.2-1 packaging: added '$RPM_OPT_FLAGS' to make, strip
to '%build', removed '%prefix'.
* Thu Apr 10 1997 Michael De La Rue <miked@ed.ac.uk>
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
previous package(s).)
%prep
%setup
%build
./configure --prefix=/usr
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/{bin,man/{man1,man5}}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1* $RPM_BUILD_ROOT/usr/man/man1
install -m644 rsyncd.conf.5* $RPM_BUILD_ROOT/usr/man/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) /usr/man/man1/rsync.1*
%attr(-,root,root) /usr/man/man5/rsyncd.conf.5*
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING

16
pipe.c
View File

@@ -21,13 +21,6 @@
#include "rsync.h"
extern int am_sender;
extern int am_server;
extern int blocking_io;
extern int orig_umask;
extern int read_batch;
extern int filesfrom_fd;
/**
* Create a child connected to use on stdin/stdout.
*
@@ -46,6 +39,7 @@ 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];
extern int blocking_io;
if (verbose >= 2) {
print_child_argv(command);
@@ -64,6 +58,7 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
}
if (pid == 0) {
extern int orig_umask;
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
close(to_child_pipe[1]) < 0 ||
close(from_child_pipe[0]) < 0 ||
@@ -78,8 +73,9 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
close(from_child_pipe[1]);
umask(orig_umask);
set_blocking(STDIN_FILENO);
if (blocking_io > 0)
if (blocking_io) {
set_blocking(STDOUT_FILENO);
}
execvp(command[0], command);
rprintf(FERROR, "Failed to exec %s : %s\n",
command[0], strerror(errno));
@@ -103,6 +99,10 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
pid_t pid;
int to_child_pipe[2];
int from_child_pipe[2];
extern int read_batch;
extern int am_sender;
extern int am_server;
extern int filesfrom_fd;
if (fd_pair(to_child_pipe) < 0 ||
fd_pair(from_child_pipe) < 0) {

View File

@@ -5,3 +5,5 @@ config.h
config.log
config.status
dummy
rsync
zlib/dummy

View File

@@ -907,10 +907,10 @@ int poptGetNextOpt(poptContext con)
#ifndef DBL_EPSILON
#define DBL_EPSILON 2.2204460492503131e-16
#endif
#define MY_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
if ((MY_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
#define _ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
if ((_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
return POPT_ERROR_OVERFLOW;
if ((FLT_MIN - MY_ABS(aDouble)) > DBL_EPSILON)
if ((FLT_MIN - _ABS(aDouble)) > DBL_EPSILON)
return POPT_ERROR_OVERFLOW;
*((float *) opt->arg) = aDouble;
}
@@ -1055,7 +1055,7 @@ poptContext poptFreeContext(poptContext con)
}
int poptAddAlias(poptContext con, struct poptAlias alias,
/*@unused@*/ UNUSED(int flags))
/*@unused@*/ int flags)
{
poptItem item = (poptItem) alloca(sizeof(*item));
memset(item, 0, sizeof(*item));

View File

@@ -363,7 +363,7 @@ int poptDupArgv(int argc, /*@null@*/ const char **argv,
* @retval argcPtr address of returned no. of arguments
* @retval argvPtr address of returned argument array
*/
int poptParseArgvString(const unsigned char * s,
int poptParseArgvString(const char * s,
/*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr)
/*@modifies *argcPtr, *argvPtr @*/;

View File

@@ -10,7 +10,7 @@
#include "poptint.h"
/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */
static void configLine(poptContext con, unsigned char * line)
static void configLine(poptContext con, char * line)
/*@modifies con @*/
{
/*@-type@*/
@@ -92,9 +92,9 @@ static void configLine(poptContext con, unsigned char * line)
int poptReadConfigFile(poptContext con, const char * fn)
{
const unsigned char * file, * chptr, * end;
unsigned char * buf;
/*@dependent@*/ unsigned char * dst;
const char * file, * chptr, * end;
char * buf;
/*@dependent@*/ char * dst;
int fd, rc;
off_t fileLength;
@@ -159,8 +159,7 @@ int poptReadConfigFile(poptContext con, const char * fn)
return 0;
}
int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv))
{
int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) {
char * fn, * home;
int rc;

View File

@@ -17,9 +17,9 @@
* @param key option(s)
*/
static void displayArgs(poptContext con,
/*@unused@*/ UNUSED(enum poptCallbackReason foo),
/*@unused@*/ enum poptCallbackReason foo,
struct poptOption * key,
/*@unused@*/ UNUSED(const char * arg), /*@unused@*/ UNUSED(void * data))
/*@unused@*/ const char * arg, /*@unused@*/ void * data)
/*@globals fileSystem@*/
/*@modifies fileSystem@*/
{
@@ -84,7 +84,7 @@ getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
/*@observer@*/ /*@null@*/ static const char *const
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@*/
/*@*/
{
@@ -191,11 +191,11 @@ static void singleOptionHelp(FILE * fp, int maxLeftCol,
{
int indentLength = maxLeftCol + 5;
int lineLength = 79 - indentLength;
const unsigned char * help = D_(translation_domain, opt->descrip);
const char * help = D_(translation_domain, opt->descrip);
const char * argDescrip = getArgDescrip(opt, translation_domain);
int helpLength;
unsigned char * defs = NULL;
unsigned char * left;
char * defs = NULL;
char * left;
int nb = maxLeftCol + 1;
/* Make sure there's more than enough room in target buffer. */
@@ -314,7 +314,7 @@ static void singleOptionHelp(FILE * fp, int maxLeftCol,
helpLength = strlen(help);
while (helpLength > lineLength) {
const unsigned char * ch;
const char * ch;
char format[10];
ch = help + lineLength - 1;
@@ -475,7 +475,7 @@ static int showHelpIntro(poptContext con, FILE * fp)
return len;
}
void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
{
int leftColWidth;
@@ -634,7 +634,7 @@ static int showShortOptions(const struct poptOption * opt, FILE * fp,
return strlen(s) + 4;
}
void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
{
int cursor;

View File

@@ -51,10 +51,10 @@ int poptDupArgv(int argc, const char **argv,
return 0;
}
int poptParseArgvString(const unsigned char * s, int * argcPtr, const char *** argvPtr)
int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
{
const unsigned char * src;
unsigned char quote = '\0';
const char * src;
char quote = '\0';
int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
const char ** argv = malloc(sizeof(*argv) * argvAlloced);
int argc = 0;

View File

@@ -69,6 +69,5 @@ char *alloca ();
#define xstrdup(_str) strdup(_str)
#endif /* HAVE_MCHECK_H && defined(__GNUC__) */
#define UNUSED(x) x __attribute__((__unused__))
#include "popt.h"

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.
@@ -21,24 +21,15 @@
#include "rsync.h"
extern struct stats stats;
extern int am_server;
#define PROGRESS_HISTORY_SECS 5
struct progress_history {
struct timeval time;
OFF_T ofs;
};
static struct progress_history ph_start;
static struct progress_history ph_list[PROGRESS_HISTORY_SECS];
static int newest_hpos, oldest_hpos;
static OFF_T last_ofs;
static struct timeval print_time;
static struct timeval start_time;
static OFF_T start_ofs;
static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
{
return (t2->tv_sec - t1->tv_sec) * 1000L
+ (t2->tv_usec - t1->tv_usec) / 1000;
return (t2->tv_sec - t1->tv_sec) * 1000
+ (t2->tv_usec - t1->tv_usec) / 1000;
}
@@ -52,103 +43,79 @@ static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
int is_last)
{
char eol[256];
const char *units;
int pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
unsigned long diff;
double rate, remain;
int remain_h, remain_m, remain_s;
int pct = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
unsigned long diff = msdiff(&start_time, now);
double rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
const char *units;
/* If we've finished transferring this file, show the time taken;
* otherwise show expected time to complete. That's kind of
* inconsistent, but people can probably cope. Hopefully we'll
* get more consistent and complete progress reporting soon. --
* mbp */
double remain = is_last
? (double) diff / 1000.0
: rate ? (double) (size-ofs) / rate / 1000.0 : 0.0;
int remain_h, remain_m, remain_s;
if (is_last) {
/* Compute stats based on the starting info. */
diff = msdiff(&ph_start.time, now);
if (!diff)
diff = 1;
rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0;
/* Switch to total time taken for our last update. */
remain = (double) diff / 1000.0;
} else {
/* Compute stats based on recent progress. */
diff = msdiff(&ph_list[oldest_hpos].time, now);
rate = diff ? (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0
/ diff / 1024.0 : 0;
remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
}
if (rate > 1024*1024) {
rate /= 1024.0 * 1024.0;
units = "GB/s";
} else if (rate > 1024) {
rate /= 1024.0;
units = "MB/s";
} else {
units = "kB/s";
}
if (rate > 1024*1024) {
rate /= 1024.0 * 1024.0;
units = "GB/s";
} else if (rate > 1024) {
rate /= 1024.0;
units = "MB/s";
} else {
units = "kB/s";
}
remain_s = (int) remain % 60;
remain_m = (int) (remain / 60.0) % 60;
remain_h = (int) (remain / 3600.0);
if (is_last) {
snprintf(eol, sizeof eol, " (%d, %.1f%% of %d)\n",
stats.num_transferred_files,
(float)((stats.current_file_index+1) * 100)
/ stats.num_files,
stats.num_files);
} else
strcpy(eol, "\r");
rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
(double) ofs, pct, rate, units,
remain_h, remain_m, remain_s, eol);
remain_s = (int) remain % 60;
remain_m = (int) (remain / 60.0) % 60;
remain_h = (int) (remain / 3600.0);
rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
(double) ofs, pct, rate, units,
remain_h, remain_m, remain_s,
is_last ? "\n" : "\r");
}
void end_progress(OFF_T size)
{
extern int am_server;
if (!am_server) {
struct timeval now;
gettimeofday(&now, NULL);
rprint_progress(size, size, &now, True);
}
memset(&ph_start, 0, sizeof ph_start);
last_ofs = 0;
start_ofs = 0;
print_time.tv_sec = print_time.tv_usec = 0;
start_time.tv_sec = start_time.tv_usec = 0;
}
void show_progress(OFF_T ofs, OFF_T size)
{
extern int am_server;
struct timeval now;
if (am_server)
return;
gettimeofday(&now, NULL);
if (!ph_start.time.tv_sec) {
int i;
/* Try to guess the real starting time when the sender started
* to send us data by using the time we last received some data
* in the last file (if it was recent enough). */
if (msdiff(&ph_list[newest_hpos].time, &now) <= 1500) {
ph_start.time = ph_list[newest_hpos].time;
ph_start.ofs = 0;
} else {
ph_start.time.tv_sec = now.tv_sec;
ph_start.time.tv_usec = now.tv_usec;
ph_start.ofs = ofs;
}
for (i = 0; i < PROGRESS_HISTORY_SECS; i++)
ph_list[i] = ph_start;
if (!start_time.tv_sec) {
gettimeofday(&now, NULL);
start_time.tv_sec = now.tv_sec;
start_time.tv_usec = now.tv_usec;
start_ofs = ofs;
if (am_server)
return;
}
else {
if (msdiff(&ph_list[newest_hpos].time, &now) < 1000)
if (am_server)
return;
newest_hpos = oldest_hpos;
oldest_hpos = (oldest_hpos + 1) % PROGRESS_HISTORY_SECS;
ph_list[newest_hpos].time.tv_sec = now.tv_sec;
ph_list[newest_hpos].time.tv_usec = now.tv_usec;
ph_list[newest_hpos].ofs = ofs;
gettimeofday(&now, NULL);
}
rprint_progress(ofs, size, &now, False);
if (ofs > last_ofs + 1000
&& msdiff(&print_time, &now) > 250) {
rprint_progress(ofs, size, &now, False);
last_ofs = ofs;
print_time.tv_sec = now.tv_sec;
print_time.tv_usec = now.tv_usec;
}
}

View File

@@ -1,18 +1,18 @@
/* -*- c-file-style: "linux" -*-
Copyright (C) 1996-2000 by Andrew Tridgell
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.
@@ -23,65 +23,96 @@
extern int verbose;
extern int recurse;
extern int delete_mode;
extern int delete_after;
extern int max_delete;
extern int remote_version;
extern int csum_length;
extern struct stats stats;
extern int dry_run;
extern int am_server;
extern int relative_paths;
extern int preserve_hard_links;
extern int preserve_perms;
extern int cvs_exclude;
extern int io_error;
extern char *tmpdir;
extern char *compare_dest;
extern int make_backups;
extern int do_progress;
extern char *backup_dir;
extern char *backup_suffix;
extern int backup_suffix_len;
extern int cleanup_got_literal;
extern int module_id;
extern int ignore_errors;
extern int orig_umask;
static void delete_one(char *fn, int is_dir)
static struct delete_list {
DEV64_T dev;
INO64_T inode;
} *delete_list;
static int dlist_len, dlist_alloc_len;
/* yuck! This function wouldn't have been necessary if I had the sorting
algorithm right. Unfortunately fixing the sorting algorithm would introduce
a backward incompatibility as file list indexes are sent over the link.
*/
static int delete_already_done(struct file_list *flist,int j)
{
if (!is_dir) {
if (robust_unlink(fn) != 0) {
rprintf(FERROR, "delete_one: unlink %s failed: %s\n",
full_fname(fn), strerror(errno));
int i;
STRUCT_STAT st;
if (link_stat(f_name(flist->files[j]), &st)) return 1;
for (i=0;i<dlist_len;i++) {
if (st.st_ino == delete_list[i].inode &&
st.st_dev == delete_list[i].dev)
return 1;
}
return 0;
}
static void add_delete_entry(struct file_struct *file)
{
if (dlist_len == dlist_alloc_len) {
dlist_alloc_len += 1024;
delete_list = realloc_array(delete_list, struct delete_list,
dlist_alloc_len);
if (!delete_list) out_of_memory("add_delete_entry");
}
delete_list[dlist_len].dev = file->dev;
delete_list[dlist_len].inode = file->inode;
dlist_len++;
if (verbose > 3)
rprintf(FINFO,"added %s to delete list\n", f_name(file));
}
static void delete_one(struct file_struct *f)
{
if (!S_ISDIR(f->mode)) {
if (robust_unlink(f_name(f)) != 0) {
rprintf(FERROR,"delete_one: unlink %s: %s\n",f_name(f),strerror(errno));
} else if (verbose) {
rprintf(FINFO, "deleting %s\n", fn);
rprintf(FINFO,"deleting %s\n",f_name(f));
}
} 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));
}
} else {
if (do_rmdir(f_name(f)) != 0) {
if (errno != ENOTEMPTY && errno != EEXIST)
rprintf(FERROR,"delete_one: rmdir %s: %s\n",
f_name(f), strerror(errno));
} else if (verbose) {
rprintf(FINFO, "deleting directory %s\n", fn);
rprintf(FINFO,"deleting directory %s\n",f_name(f));
}
}
}
static int is_backup_file(char *fn)
{
int k = strlen(fn) - backup_suffix_len;
return k > 0 && strcmp(fn+k, backup_suffix) == 0;
}
/* This deletes any files on the receiving side that are not present
* on the sending side. */
/* this deletes any files on the receiving side that are not present
on the sending side. For version 1.6.4 I have changed the behaviour
to match more closely what most people seem to expect of this option */
void delete_files(struct file_list *flist)
{
struct file_list *local_file_list;
int i, j;
char *argv[1], fbuf[MAXPATHLEN];
char *name;
extern int module_id;
extern int ignore_errors;
extern int max_delete;
static int deletion_count;
if (cvs_exclude)
@@ -92,125 +123,112 @@ void delete_files(struct file_list *flist)
return;
}
for (j = 0; j < flist->count; j++) {
if (!(flist->files[j]->flags & FLAG_TOP_DIR)
|| !S_ISDIR(flist->files[j]->mode))
continue;
for (j=0;j<flist->count;j++) {
if (!S_ISDIR(flist->files[j]->mode) ||
!(flist->files[j]->flags & FLAG_DELETE)) continue;
argv[0] = f_name_to(flist->files[j], fbuf);
if (remote_version < 19 &&
delete_already_done(flist, j)) continue;
if (!(local_file_list = send_file_list(-1, 1, argv)))
name = strdup(f_name(flist->files[j]));
if (!(local_file_list = send_file_list(-1,1,&name))) {
free(name);
continue;
}
if (verbose > 1)
rprintf(FINFO, "deleting in %s\n", fbuf);
rprintf(FINFO,"deleting in %s\n", name);
for (i = local_file_list->count-1; i >= 0; i--) {
if (max_delete && deletion_count > max_delete)
break;
if (!local_file_list->files[i]->basename)
continue;
if (flist_find(flist,local_file_list->files[i]) < 0) {
for (i=local_file_list->count-1;i>=0;i--) {
if (max_delete && deletion_count > max_delete) break;
if (!local_file_list->files[i]->basename) continue;
if (remote_version < 19 &&
S_ISDIR(local_file_list->files[i]->mode))
add_delete_entry(local_file_list->files[i]);
if (-1 == flist_find(flist,local_file_list->files[i])) {
char *f = f_name(local_file_list->files[i]);
if (make_backups && (backup_dir || !is_backup_file(f))) {
int k = strlen(f) - strlen(backup_suffix);
/* Hi Andrew, do we really need to play with backup_suffix here? */
if (make_backups && ((k <= 0) ||
(strcmp(f+k,backup_suffix) != 0))) {
(void) make_backup(f);
if (verbose)
rprintf(FINFO, "deleting %s\n", f);
} else {
int mode = local_file_list->files[i]->mode;
delete_one(f, S_ISDIR(mode) != 0);
deletion_count++;
delete_one(local_file_list->files[i]);
}
deletion_count++;
}
}
flist_free(local_file_list);
free(name);
}
}
/*
* get_tmpname() - create a tmp filename for a given filename
*
* If a tmpdir is defined, use that as the directory to
* put it in. Otherwise, the tmp filename is in the same
* directory as the given name. Note that there may be no
* directory at all in the given name!
*
* The tmp filename is basically the given filename with a
* dot prepended, and .XXXXXX appended (for mkstemp() to
* put its unique gunk in). Take care to not exceed
* either the MAXPATHLEN or NAME_MAX, esp. the last, as
* the basename basically becomes 8 chars longer. In that
* case, the original name is shortened sufficiently to
* make it all fit.
*
* Of course, there's no real reason for the tmp name to
* look like the original, except to satisfy us humans.
* As long as it's unique, rsync will work.
*/
static int get_tmpname(char *fnametmp, char *fname)
{
char *f;
int length = 0;
int maxname;
/* open tmp file */
if (tmpdir) {
/* Note: this can't overflow, so the return value is safe */
length = strlcpy(fnametmp, tmpdir, MAXPATHLEN - 2);
fnametmp[length++] = '/';
fnametmp[length] = '\0'; /* always NULL terminated */
}
if ((f = strrchr(fname, '/')) != NULL) {
++f;
if (!tmpdir) {
length = f - fname;
/* copy up to and including the slash */
strlcpy(fnametmp, fname, length + 1);
f = strrchr(fname,'/');
if (f == NULL)
f = fname;
else
f++;
if (strlen(tmpdir)+strlen(f)+10 > MAXPATHLEN) {
rprintf(FERROR,"filename too long\n");
return 0;
}
} else
f = fname;
fnametmp[length++] = '.';
fnametmp[length] = '\0'; /* always NULL terminated */
snprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f);
return 1;
}
maxname = MIN(MAXPATHLEN - 7 - length, NAME_MAX - 8);
f = strrchr(fname,'/');
if (maxname < 1) {
rprintf(FERROR, "temporary filename too long: %s\n", fname);
fnametmp[0] = '\0';
if (strlen(fname)+9 > MAXPATHLEN) {
rprintf(FERROR,"filename too long\n");
return 0;
}
strlcpy(fnametmp + length, f, maxname);
strcat(fnametmp + length, ".XXXXXX");
if (f) {
*f = 0;
snprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX",
fname,f+1);
*f = '/';
} else {
snprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname);
}
return 1;
}
static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
OFF_T total_size)
{
int i;
struct sum_struct sum;
unsigned int len;
unsigned int n,remainder,len,count;
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;
read_sum_head(f_in, &sum);
count = read_int(f_in);
n = read_int(f_in);
remainder = read_int(f_in);
sum_init();
for (i=recv_token(f_in,&data); i != 0; i=recv_token(f_in,&data)) {
while ((i = recv_token(f_in, &data)) != 0) {
if (do_progress)
show_progress(offset, total_size);
show_progress(offset, total_size);
if (i > 0) {
extern int cleanup_got_literal;
if (verbose > 3) {
rprintf(FINFO,"data recv %d at %.0f\n",
i,(double)offset);
@@ -218,64 +236,63 @@ static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
stats.literal_data += i;
cleanup_got_literal = 1;
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));
rprintf(FERROR,"write failed on %s : %s\n",fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
offset += i;
continue;
}
}
i = -(i+1);
offset2 = i*(OFF_T)sum.blength;
len = sum.blength;
if (i == (int) sum.count-1 && sum.remainder != 0)
len = sum.remainder;
offset2 = i*(OFF_T)n;
len = n;
if (i == (int) count-1 && remainder != 0)
len = remainder;
stats.matched_data += len;
if (verbose > 3)
rprintf(FINFO,"chunk[%d] of size %d at %.0f offset=%.0f\n",
i,len,(double)offset2,(double)offset);
if (mapbuf) {
map = map_ptr(mapbuf,offset2,len);
if (buf) {
map = map_ptr(buf,offset2,len);
see_token(map, len);
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));
rprintf(FERROR,"write failed on %s : %s\n",
fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
offset += len;
}
flush_write_file(fd);
if (do_progress)
end_progress(total_size);
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));
rprintf(FERROR,"write failed on %s : %s\n",
fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
sum_end(file_sum1);
read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
if (verbose > 2) {
rprintf(FINFO,"got file_sum\n");
}
if (fd != -1 && memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0) {
return 0;
if (remote_version >= 14) {
read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
if (verbose > 2) {
rprintf(FINFO,"got file_sum\n");
}
if (fd != -1 &&
memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0) {
return 0;
}
}
return 1;
}
@@ -285,68 +302,64 @@ static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
* 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 f_gen)
{
int fd1,fd2;
STRUCT_STAT st;
char *fname, fbuf[MAXPATHLEN];
char *fname;
char template[MAXPATHLEN];
char fnametmp[MAXPATHLEN];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
struct map_struct *mapbuf;
struct map_struct *buf;
int i;
struct file_struct *file;
int phase=0;
int recv_ok;
extern struct stats stats;
extern int preserve_perms;
extern int delete_after;
extern int orig_umask;
struct stats initial_stats;
if (verbose > 2) {
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
if (flist->hlink_pool) {
pool_destroy(flist->hlink_pool);
flist->hlink_pool = NULL;
}
while (1) {
while (1) {
cleanup_disable();
i = read_int(f_in);
if (i == -1) {
if (phase == 0) {
if (phase==0 && remote_version >= 13) {
phase++;
csum_length = SUM_LENGTH;
if (verbose > 2)
rprintf(FINFO,"recv_files phase=%d\n",phase);
send_msg(MSG_DONE, "", 0);
write_int(f_gen,-1);
continue;
}
break;
}
if (i < 0 || i >= flist->count) {
rprintf(FERROR,"Invalid file index %d in recv_files (count=%d)\n",
rprintf(FERROR,"Invalid file index %d in recv_files (count=%d)\n",
i, flist->count);
exit_cleanup(RERR_PROTOCOL);
}
file = flist->files[i];
fname = f_name(file);
stats.current_file_index = i;
stats.num_transferred_files++;
stats.total_transferred_size += file->length;
cleanup_got_literal = 0;
if (local_name)
fname = local_name;
else
fname = f_name_to(file, fbuf);
if (dry_run) {
if (!am_server && verbose) { /* log transfer */
rprintf(FINFO, "%s\n", fname);
if (!am_server) {
log_transfer(file, fname);
}
continue;
}
@@ -358,108 +371,95 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
fnamecmp = fname;
/* open the file */
/* open the file */
fd1 = do_open(fnamecmp, O_RDONLY, 0);
if (fd1 == -1 && compare_dest != NULL) {
if ((fd1 == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
compare_dest, fname);
snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
compare_dest,fname);
fnamecmp = fnamecmpbuf;
fd1 = do_open(fnamecmp, O_RDONLY, 0);
}
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
rprintf(FERROR, "fstat %s failed: %s\n",
full_fname(fnamecmp), strerror(errno));
rprintf(FERROR,"fstat %s : %s\n",fnamecmp,strerror(errno));
receive_data(f_in,NULL,-1,NULL,file->length);
close(fd1);
continue;
}
if (fd1 != -1 && S_ISDIR(st.st_mode) && fnamecmp == fname) {
/* this special handling for directories
* wouldn't be necessary if robust_rename()
* and the underlying robust_unlink could cope
* with directories
*/
rprintf(FERROR,"recv_files: %s is a directory\n",
full_fname(fnamecmp));
receive_data(f_in, NULL, -1, NULL, file->length);
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
rprintf(FERROR,"%s : not a regular file (recv_files)\n",fnamecmp);
receive_data(f_in,NULL,-1,NULL,file->length);
close(fd1);
continue;
}
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
close(fd1);
fd1 = -1;
mapbuf = NULL;
}
if (fd1 != -1 && !preserve_perms) {
/* if the file exists already and we aren't preserving
* permissions then act as though the remote end sent
* us the file permissions we already have */
/* if the file exists already and we aren't perserving
presmissions then act as though the remote end sent
us the file permissions we already have */
file->mode = st.st_mode;
}
if (fd1 != -1 && st.st_size > 0) {
mapbuf = map_file(fd1,st.st_size);
buf = 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;
} else {
buf = NULL;
}
if (!get_tmpname(fnametmp,fname)) {
if (mapbuf) unmap_file(mapbuf);
if (buf) unmap_file(buf);
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. */
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 &&
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);
strlcpy(fnametmp, template, sizeof(fnametmp));
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);
rprintf(FERROR,"mkstemp %s failed: %s\n",fnametmp,strerror(errno));
receive_data(f_in,buf,-1,NULL,file->length);
if (buf) unmap_file(buf);
if (fd1 != -1) close(fd1);
continue;
}
cleanup_set(fnametmp, fname, file, buf, fd1, fd2);
cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2);
if (!am_server && verbose) { /* log transfer */
rprintf(FINFO, "%s\n", fname);
if (!am_server) {
log_transfer(file, fname);
}
/* recv file data */
recv_ok = receive_data(f_in,mapbuf,fd2,fname,file->length);
recv_ok = receive_data(f_in,buf,fd2,fname,file->length);
log_recv(file, &initial_stats);
if (mapbuf) unmap_file(mapbuf);
if (buf) unmap_file(buf);
if (fd1 != -1) {
close(fd1);
}
close(fd2);
if (verbose > 2)
rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
@@ -470,23 +470,35 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
if (!recv_ok) {
if (csum_length == SUM_LENGTH) {
rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
full_fname(fname));
fname);
} else {
char buf[4];
if (verbose > 1)
rprintf(FINFO,"redoing %s(%d)\n",fname,i);
SIVAL(buf, 0, i);
send_msg(MSG_REDO, buf, 4);
write_int(f_gen,i);
}
}
}
if (delete_after && recurse && delete_mode && !local_name
&& flist->count > 0)
delete_files(flist);
if (delete_after) {
if (recurse && delete_mode && !local_name && flist->count>0) {
delete_files(flist);
}
}
if (preserve_hard_links)
do_hard_links();
/* now we need to fix any directory permissions that were
modified during the transfer */
for (i = 0; i < flist->count; i++) {
file = flist->files[i];
if (!file->basename || !S_ISDIR(file->mode)) continue;
recv_generator(local_name?local_name:f_name(file),flist,i,-1);
}
if (verbose > 2)
rprintf(FINFO,"recv_files finished\n");
return 0;
}

198
rsync.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.
@@ -26,9 +26,6 @@ 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;
@@ -46,8 +43,8 @@ void free_sums(struct sum_struct *s)
/*
* delete a file or directory. If force_delete is set then delete
* recursively
* delete a file or directory. If force_delete is set then delete
* recursively
*/
int delete_file(char *fname)
{
@@ -64,66 +61,91 @@ int delete_file(char *fname)
#else
ret = do_stat(fname, &st);
#endif
if (ret)
return -1;
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));
if (ret) {
return -1;
}
if (do_rmdir(fname) == 0 || errno == ENOENT)
return 0;
if (!force_delete || !recurse
|| (errno != ENOTEMPTY && errno != EEXIST)) {
rprintf(FERROR, "delete_file: rmdir %s failed: %s\n",
full_fname(fname), strerror(errno));
if (!S_ISDIR(st.st_mode)) {
if (robust_unlink(fname) == 0 || errno == ENOENT) return 0;
rprintf(FERROR,"delete_file: unlink(%s) : %s\n", fname, strerror(errno));
return -1;
}
if (do_rmdir(fname) == 0 || errno == ENOENT) return 0;
if (!force_delete || !recurse ||
(errno != ENOTEMPTY && errno != EEXIST)) {
rprintf(FERROR,"delete_file: rmdir(%s) : %s\n", fname, strerror(errno));
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));
d = opendir(fname);
if (!d) {
rprintf(FERROR,"delete_file: opendir(%s): %s\n",
fname,strerror(errno));
return -1;
}
for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) {
for (di=readdir(d); di; di=readdir(d)) {
char *dname = d_name(di);
if (dname[0] == '.' && (dname[1] == '\0'
|| (dname[1] == '.' && dname[2] == '\0')))
if (strcmp(dname,".")==0 ||
strcmp(dname,"..")==0)
continue;
pathjoin(buf, sizeof buf, fname, dname);
snprintf(buf, sizeof(buf), "%s/%s", fname, dname);
if (verbose > 0)
rprintf(FINFO, "deleting %s\n", buf);
rprintf(FINFO,"deleting %s\n", 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));
closedir(d);
return -1;
}
}
closedir(d);
if (do_rmdir(fname) != 0) {
rprintf(FERROR, "delete_file: rmdir %s failed: %s\n",
full_fname(fname), strerror(errno));
rprintf(FERROR,"delete_file: rmdir(%s) : %s\n", fname, strerror(errno));
return -1;
}
return 0;
}
static int is_in_group(gid_t gid)
{
#ifdef GETGROUPS_T
static gid_t last_in = (gid_t) -2, last_out;
static int ngroups = -2;
static GETGROUPS_T *gidset;
int n;
if (gid == last_in)
return last_out;
if (ngroups < -1) {
/* treat failure (-1) as if not member of any group */
ngroups = getgroups(0, 0);
if (ngroups > 0) {
gidset = new_array(GETGROUPS_T, ngroups);
ngroups = getgroups(ngroups, gidset);
}
}
last_in = gid;
last_out = 0;
for (n = 0; n < ngroups; n++) {
if (gidset[n] == gid) {
last_out = 1;
break;
}
}
return last_out;
#else
return 0;
#endif
}
int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
int report)
int report)
{
int updated = 0;
STRUCT_STAT st2;
@@ -133,8 +155,7 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
if (!st) {
if (link_stat(fname,&st2) != 0) {
rprintf(FERROR, "stat %s failed: %s\n",
full_fname(fname), strerror(errno));
rprintf(FERROR,"stat %s : %s\n",fname,strerror(errno));
return 0;
}
st = &st2;
@@ -143,45 +164,37 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
if (preserve_times && !S_ISLNK(st->st_mode) &&
cmp_modtime(st->st_mtime, file->modtime) != 0) {
/* don't complain about not setting times on directories
* because some filesystems can't do it */
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));
rprintf(FERROR,"failed to set times on %s : %s\n",
fname,strerror(errno));
return 0;
} else {
updated = 1;
}
updated = 1;
}
change_uid = am_root && preserve_uid && st->st_uid != file->uid;
change_gid = preserve_gid && file->gid != GID_NONE
&& st->st_gid != file->gid;
change_gid = preserve_gid && file->gid != (gid_t) -1 && \
st->st_gid != file->gid;
if (change_gid && !am_root) {
/* enforce bsd-style group semantics: non-root can only
change to groups that the user is a member of */
change_gid = is_in_group(file->gid);
}
if (change_uid || change_gid) {
if (verbose > 2) {
if (change_uid) {
rprintf(FINFO,
"set uid of %s from %ld to %ld\n",
fname, (long)st->st_uid, (long)file->uid);
}
if (change_gid) {
rprintf(FINFO,
"set gid of %s from %ld to %ld\n",
fname, (long)st->st_gid, (long)file->gid);
}
}
if (do_lchown(fname,
change_uid ? file->uid : st->st_uid,
change_gid ? file->gid : st->st_gid) != 0) {
change_uid?file->uid:st->st_uid,
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",
change_uid ? "chown" : "chgrp",
full_fname(fname), strerror(errno));
unless have the privilege */
rprintf(FERROR,"chown %s : %s\n", fname,strerror(errno));
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 */
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);
}
@@ -190,17 +203,17 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
#ifdef HAVE_CHMOD
if (!S_ISLNK(st->st_mode)) {
if ((st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) {
if (st->st_mode != file->mode) {
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));
if (do_chmod(fname,file->mode) != 0) {
rprintf(FERROR,"failed to set permissions on %s : %s\n",
fname,strerror(errno));
return 0;
}
}
}
#endif
if (verbose > 1 && report) {
if (updated)
rprintf(FINFO,"%s\n",fname);
@@ -213,15 +226,6 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
void sig_int(void)
{
/* KLUGE: if the user hits Ctrl-C while ssh is prompting
* for a password, then our cleanup's sending of a SIGUSR1
* signal to all our children may kill ssh before it has a
* chance to restore the tty settings (i.e. turn echo back
* on). By sleeping for a short time, ssh gets a bigger
* chance to do the right thing. If child processes are
* not ssh waiting for a password, then this tiny delay
* shouldn't hurt anything. */
msleep(400);
exit_cleanup(RERR_SIGNAL);
}
@@ -230,24 +234,26 @@ void sig_int(void)
and ownership */
void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
{
int ret;
if (make_backups && !make_backup(fname))
return;
/* move tmp file over real file */
ret = robust_rename(fnametmp, fname, file->mode & INITACCESSPERMS);
if (ret < 0) {
rprintf(FERROR, "%s %s -> \"%s\": %s\n",
ret == -2 ? "copy" : "rename",
full_fname(fnametmp), fname, strerror(errno));
if (robust_rename(fnametmp,fname) != 0) {
if (errno == EXDEV) {
/* rename failed on cross-filesystem link.
Copy the file instead. */
if (copy_file(fnametmp,fname, file->mode & INITACCESSPERMS)) {
rprintf(FERROR,"copy %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
} else {
set_perms(fname,file,NULL,0);
}
} else {
rprintf(FERROR,"rename %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
}
do_unlink(fnametmp);
} else {
set_perms(fname,file,NULL,0);
}
}
const char *who_am_i(void)
{
return am_sender ? "sender" : am_generator ? "generator" : "receiver";
}

303
rsync.h
View File

@@ -24,10 +24,9 @@
#define BLOCK_SIZE 700
#define RSYNC_RSH_ENV "RSYNC_RSH"
#define RSYNC_RSH_IO_ENV "RSYNC_RSH_IO"
#define RSYNC_NAME "rsync"
/* RSYNCD_SYSCONF is now set in config.h */
#define RSYNCD_SYSCONF "/etc/rsyncd.conf"
#define RSYNCD_USERCONF "rsyncd.conf"
#define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock"
@@ -39,51 +38,32 @@
incompatible with older versions :-( */
#define CHAR_OFFSET 0
/* These flags are only used during the flist transfer. */
#define XMIT_TOP_DIR (1<<0)
#define XMIT_SAME_MODE (1<<1)
#define XMIT_EXTENDED_FLAGS (1<<2)
#define XMIT_SAME_RDEV_pre28 XMIT_EXTENDED_FLAGS /* Only in protocols < 28 */
#define XMIT_SAME_UID (1<<3)
#define XMIT_SAME_GID (1<<4)
#define XMIT_SAME_NAME (1<<5)
#define XMIT_LONG_NAME (1<<6)
#define XMIT_SAME_TIME (1<<7)
#define XMIT_SAME_RDEV_MAJOR (1<<8)
#define XMIT_HAS_IDEV_DATA (1<<9)
#define XMIT_SAME_DEV (1<<10)
#define XMIT_RDEV_MINOR_IS_SMALL (1<<11)
/* These flags are used in the live flist data. */
#define FLAG_TOP_DIR (1<<0)
#define FLAG_HLINK_EOL (1<<1) /* generator only */
#define FLAG_MOUNT_POINT (1<<2) /* sender only */
#define FLAG_DELETE (1<<0)
#define SAME_MODE (1<<1)
#define SAME_RDEV (1<<2)
#define SAME_UID (1<<3)
#define SAME_GID (1<<4)
#define SAME_DIR (1<<5)
#define SAME_NAME SAME_DIR
#define LONG_NAME (1<<6)
#define SAME_TIME (1<<7)
/* update this if you make incompatible changes */
#define PROTOCOL_VERSION 28
#define PROTOCOL_VERSION 26
/* We refuse to interoperate with versions that are not in this range.
* Note that we assume we'll work with later versions: the onus is on
* people writing them to make sure that they don't send us anything
* we won't understand.
*
* Interoperation with old but supported protocol versions
* should cause a warning to be printed. At a future date
* the old protocol will become the minimum and
* compatibility code removed.
*
* There are two possible explanations for the limit at
* MAX_PROTOCOL_VERSION: either to allow new major-rev versions that
* do not interoperate with us, and (more likely) so that we can
* detect an attempt to connect rsync to a non-rsync server, which is
* unlikely to begin by sending a byte between MIN_PROTOCL_VERSION and
* MAX_PROTOCOL_VERSION. */
#define MIN_PROTOCOL_VERSION 20
#define OLD_PROTOCOL_VERSION 25
#define MAX_PROTOCOL_VERSION 40
* There are two possible explanations for the limit at thirty: either
* to allow new major-rev versions that do not interoperate with us,
* and (more likely) so that we can detect an attempt to connect rsync
* to a non-rsync server, which is unlikely to begin by sending a byte
* between 15 and 30. */
#define MIN_PROTOCOL_VERSION 15
#define MAX_PROTOCOL_VERSION 30
#define RSYNC_PORT 873
@@ -93,44 +73,22 @@
#define MAX_MAP_SIZE (256*1024)
#define IO_BUFFER_SIZE (4092)
#define IOERR_GENERAL (1<<0) /* For backward compatibility, this must == 1 */
#define IOERR_VANISHED (1<<1)
#define MAX_ARGS 1000
#define MPLEX_BASE 7
#define NO_EXCLUDES 0
#define SERVER_EXCLUDES 1
#define ALL_EXCLUDES 2
#define XFLG_FATAL_ERRORS (1<<0)
#define XFLG_DEF_INCLUDE (1<<1)
#define XFLG_WORDS_ONLY (1<<2)
#define XFLG_WORD_SPLIT (1<<3)
#define FULL_FLUSH 1
#define NORMAL_FLUSH 0
/* Log-message categories. FLOG is only used on the daemon side to
* output messages to the log file. */
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 */
};
/* Log values. I *think* what these mean is: FLOG goes to the server
* logfile; FERROR and FINFO try to end up on the client, with
* different levels of filtering. */
enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
#include "errcode.h"
#include "config.h"
/* The default RSYNC_RSH is always set in config.h. */
/* The default RSYNC_RSH is always set in config.h, either to "remsh",
* "rsh", or otherwise something specified by the user. HAVE_REMSH
* controls parameter munging for HP/UX, etc. */
#include <sys/types.h>
@@ -148,10 +106,6 @@ enum msgcode {
#include <stdlib.h>
#endif
#if defined(HAVE_MALLOC_H) && (defined(HAVE_MALLINFO) || !defined(HAVE_STDLIB_H))
#include <malloc.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
@@ -160,6 +114,10 @@ enum msgcode {
#include <string.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#ifdef TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
@@ -216,10 +174,20 @@ enum msgcode {
#endif
#endif
#ifdef HAVE_FNMATCH
#include <fnmatch.h>
#else
#include "lib/fnmatch.h"
#endif
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
/* these are needed for the uid/gid mapping code */
#include <pwd.h>
#include <grp.h>
@@ -246,19 +214,12 @@ enum msgcode {
# endif
#endif
#if MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#elif MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#endif
#ifdef HAVE_COMPAT_H
#include <compat.h>
#endif
#include <assert.h>
#include "lib/pool_alloc.h"
#define BOOL int
@@ -312,17 +273,6 @@ enum msgcode {
#define NO_INT64
#endif
#if (SIZEOF_LONG == 8)
#define uint64 unsigned long
#elif (SIZEOF_INT == 8)
#define uint64 unsigned int
#elif HAVE_LONGLONG
#define uint64 unsigned long long
#else
/* As long as it gets... */
#define uint64 unsigned off_t
#endif
/* Starting from protocol version 26, we always use 64-bit
* ino_t and dev_t internally, even if this platform does not
* allow files to have 64-bit inums. That's because the
@@ -345,14 +295,17 @@ enum msgcode {
* device numbers will be truncated. But it's a kind of silly thing
* to do anyhow.
*
* FIXME: I don't think the code in flist.c has ever worked on a system
* where dev_t is a struct.
* FIXME: In future, we should probable split the device number into
* major/minor, and transfer the two parts as 32-bit ints. That gives
* you somewhat more of a chance that they'll come from a big machine
* to a little one in a useful way.
*
* FIXME: Really we need an unsigned type, and we perhaps ought to
* cope with platforms on which this is an unsigned int or even a
* struct. Later.
*/
struct idev {
uint64 inode;
uint64 dev;
};
#define INO64_T int64
#define DEV64_T int64
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
@@ -369,17 +322,11 @@ struct idev {
/* the length of the md4 checksum */
#define MD4_SUM_LENGTH 16
#define SUM_LENGTH 16
#define SHORT_SUM_LENGTH 2
#define BLOCKSUM_BIAS 10
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
#ifndef NAME_MAX
#define NAME_MAX 255
#endif
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
@@ -388,76 +335,47 @@ struct idev {
#define IN_LOOPBACKNET 127
#endif
#define GID_NONE (gid_t) -1
#define HL_CHECK_MASTER 0
#define HL_SKIP 1
struct hlink {
int hlindex;
struct file_struct *next;
};
#define F_DEV link_u.idev->dev
#define F_INODE link_u.idev->inode
#define F_HLINDEX link_u.links->hlindex
#define F_NEXT link_u.links->next
struct file_struct {
union {
dev_t rdev; /* The device number, if this is a device */
char *sum; /* Only a normal file can have a checksum */
char *link; /* Points to symlink string, if a symlink */
} u;
unsigned flags;
time_t modtime;
OFF_T length;
mode_t mode;
INO64_T inode;
/** Device this file lives upon */
DEV64_T dev;
/** If this is a device node, the device number. */
DEV64_T rdev;
uid_t uid;
gid_t gid;
char *basename;
char *dirname;
char *basedir;
union {
struct idev *idev;
struct hlink *links;
} link_u;
time_t modtime;
uid_t uid;
gid_t gid;
mode_t mode;
uchar flags; /* this item MUST remain last */
char *link;
char *sum;
};
/*
* Start the flist array at FLIST_START entries and grow it
* by doubling until FLIST_LINEAR then grow by FLIST_LINEAR
*/
#define FLIST_START (32 * 1024)
#define FLIST_LINEAR (FLIST_START * 512)
/*
* Extent size for allocation pools A minimum size of 128KB
* is needed to mmap them so that freeing will release the
* space to the OS.
*
* Larger sizes reduce leftover fragments and speed free calls
* (when they happen) Smaller sizes increase the chance of
* freed allocations freeing whole extents.
*/
#define FILE_EXTENT (256 * 1024)
#define HLINK_EXTENT (128 * 1024)
#define ARENA_SIZE (32 * 1024)
#define WITH_HLINK 1
#define WITHOUT_HLINK 0
struct string_area {
char *base;
char *end;
char *current;
struct string_area *next;
};
struct file_list {
int count;
int malloced;
alloc_pool_t file_pool;
alloc_pool_t hlink_pool;
struct file_struct **files;
struct string_area *string_area;
};
struct sum_buf {
OFF_T offset; /**< offset in file of this chunk */
unsigned int len; /**< length of chunk of file */
int len; /**< length of chunk of file */
int i; /**< index of this chunk */
uint32 sum1; /**< simple checksum */
char sum2[SUM_LENGTH]; /**< checksum */
@@ -466,43 +384,24 @@ struct sum_buf {
struct sum_struct {
OFF_T flength; /**< total file length */
size_t count; /**< how many chunks */
unsigned int blength; /**< block_length */
unsigned int remainder; /**< flength % block_length */
int s2length; /**< sum2_length */
size_t remainder; /**< flength % block_length */
size_t n; /**< block_length */
struct sum_buf *sums; /**< points to info for each chunk */
};
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 status; /* first errno from read errors */
OFF_T file_size; /* File size (from stat) */
OFF_T p_offset; /* Window start */
OFF_T p_fd_offset; /* offset of cursor in fd ala lseek */
char *p;
int fd,p_size,p_len;
OFF_T file_size, p_offset, p_fd_offset;
};
#define MATCHFLG_WILD (1<<0) /* pattern has '*', '[', and/or '?' */
#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 */
struct exclude_struct {
struct exclude_struct *next;
char *pattern;
int match_flags;
int regular_exp;
int fnmatch_flags;
int include;
int directory;
int slash_cnt;
};
struct exclude_list_struct {
struct exclude_struct *head;
struct exclude_struct *tail;
char *debug_type;
int local;
};
struct stats {
@@ -515,7 +414,6 @@ struct stats {
int flist_size;
int num_files;
int num_transferred_files;
int current_file_index;
};
@@ -530,7 +428,6 @@ static inline int flist_up(struct file_list *flist, int i)
#include "byteorder.h"
#include "lib/mdfour.h"
#include "lib/wildmatch.h"
#include "lib/permstring.h"
#include "lib/addrinfo.h"
@@ -545,13 +442,11 @@ int asprintf(char **ptr, const char *format, ...);
int vasprintf(char **ptr, const char *format, va_list ap);
#endif
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
#define vsnprintf rsync_vsnprintf
int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
#if !defined(HAVE_VSNPRINTF) && !defined(HAVE_C99_VSNPRINTF)
int vsnprintf (char *str, size_t count, const char *fmt, va_list args);
#endif
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
#define snprintf rsync_snprintf
#if !defined(HAVE_SNPRINTF) && !defined(HAVE_C99_VSNPRINTF)
int snprintf(char *str,size_t count,const char *fmt,...);
#endif
@@ -598,24 +493,10 @@ extern int errno;
#define STDERR_FILENO 2
#endif
#ifndef S_IRUSR
#define S_IRUSR 0400
#endif
#ifndef S_IWUSR
#define S_IWUSR 0200
#endif
#ifndef ACCESSPERMS
#define ACCESSPERMS 0777
#endif
#ifndef S_ISVTX
#define S_ISVTX 0
#endif
#define CHMOD_BITS (S_ISUID | S_ISGID | S_ISVTX | ACCESSPERMS)
#ifndef _S_IFMT
#define _S_IFMT 0170000
#endif
@@ -679,6 +560,9 @@ extern int errno;
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) || S_ISFIFO(mode))
#ifndef ACCESSPERMS
#define ACCESSPERMS 0777
#endif
/* Initial mask on permissions given to temporary files. Mask off setuid
bits and group access because of potential race-condition security
holes, and mask other access because mode 707 is bizarre */
@@ -715,10 +599,6 @@ void rsyserr(enum logcode, int, const char *, ...)
#define inet_ntoa rep_inet_ntoa
#endif
/* Make sure that the O_BINARY flag is defined. */
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifndef HAVE_STRLCPY
size_t strlcpy(char *d, const char *s, size_t bufsize);
@@ -734,17 +614,6 @@ size_t strlcat(char *d, const char *s, size_t bufsize);
#define exit_cleanup(code) _exit_cleanup(code, __FILE__, __LINE__)
#ifdef HAVE_GETEUID
#define MY_UID() geteuid()
#else
#define MY_UID() getuid()
#endif
#ifdef HAVE_GETEGID
#define MY_GID() getegid()
#else
#define MY_GID() getgid()
#endif
extern int verbose;

393
rsync.yo
View File

@@ -1,5 +1,5 @@
mailto(rsync-bugs@samba.org)
manpage(rsync)(1)(26 Apr 2004)()()
manpage(rsync)(1)(26 Jan 2003)()()
manpagename(rsync)(faster, flexible replacement for rcp)
manpagesynopsis()
@@ -35,7 +35,7 @@ itemize(
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
it() can use any transparent remote shell, including rsh or ssh
it() does not require root privileges
it() pipelining of file transfers to minimize latency costs
it() support for anonymous or authenticated rsync servers (ideal for
@@ -51,8 +51,8 @@ itemize(
source nor destination path contains a : separator
it() for copying from the local machine to a remote machine using
a remote shell program as the transport (such as ssh or
rsh). This is invoked when the destination path contains a
a remote shell program as the transport (such as rsh or
ssh). This is invoked when the destination path contains a
single : separator.
it() for copying from a remote machine to the local machine
@@ -61,11 +61,11 @@ itemize(
it() for copying from a remote rsync server to the local
machine. This is invoked when the source path contains a ::
separator or an rsync:// URL.
separator or a rsync:// URL.
it() for copying from the local machine to a remote rsync
server. This is invoked when the destination path contains a ::
separator or an rsync:// URL.
separator or a rsync:// URL.
it() for copying from a remote machine using a remote shell
program as the transport, using rsync server on the remote
@@ -77,7 +77,7 @@ itemize(
using a remote shell program as the transport, using rsync
server on the remote machine. This is invoked when the
destination path contains a :: separator and the
--rsh=COMMAND option is also provided.
--rsh=COMMMAND option is also provided.
it() for listing files on a remote machine. This is done the
same way as rsync transfers except that you leave off the
@@ -93,9 +93,9 @@ See the file README for installation instructions.
Once installed, you can use rsync to any machine that you can access via
a remote shell (as well as some that you can access using the rsync
daemon-mode protocol). For remote transfers, a modern rsync uses ssh
daemon-mode protocol). For remote transfers, rsync typically uses rsh
for its communications, but it may have been configured to use a
different remote shell by default, such as rsh or remsh.
different remote shell by default, such as ssh.
You can also specify any remote shell you like, either by using the -e
command line option, or by setting the RSYNC_RSH environment variable.
@@ -111,7 +111,7 @@ manpagesection(USAGE)
You use rsync in the same way you use rcp. You must specify a source
and a destination, one of which may be remote.
Perhaps the best way to explain the syntax is with some examples:
Perhaps the best way to explain the syntax is some examples:
quote(rsync *.c foo:src/)
@@ -126,7 +126,7 @@ quote(rsync -avz foo:src/bar /data/tmp)
This would recursively transfer all files from the directory src/bar on the
machine foo into the /data/tmp/bar directory on the local machine. The
files are transferred in "archive" mode, which ensures that symbolic
links, devices, attributes, permissions, ownerships, etc. are preserved
links, devices, attributes, permissions, ownerships etc are preserved
in the transfer. Additionally, compression will be used to reduce the
size of data portions of the transfer.
@@ -162,15 +162,15 @@ running on TCP port 873.
You may establish the connection via a web proxy by setting the
environment variable RSYNC_PROXY to a hostname:port pair pointing to
your web proxy. Note that your web proxy's configuration must support
proxy connections to port 873.
your web proxy. Note that your web proxy's configuration must allow
proxying to port 873.
Using rsync in this way is the same as using it with a remote shell except
that:
itemize(
it() you use a double colon :: instead of a single colon to
separate the hostname from the path or an rsync:// URL.
separate the hostname from the path or a rsync:// URL.
it() the remote server may print a message of the day when you
connect.
@@ -194,8 +194,8 @@ users. On those systems using --password-file is recommended.
manpagesection(CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM)
It is sometimes useful to be able to set up file transfers using rsync
server capabilities on the remote machine, while still using ssh or
rsh for transport. This is especially useful when you want to connect
server capabilities on the remote machine, while still using rsh or
ssh for transport. This is especially useful when you want to connect
to a remote machine via ssh (for encryption or to get through a
firewall), but you still want to have access to the rsync server
features (see RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM,
@@ -217,7 +217,7 @@ used to check against the rsyncd.conf on the remote host.
manpagesection(RUNNING AN RSYNC SERVER)
An rsync server is configured using a configuration file. Please see the
An rsync server is configured using a config file. Please see the
rsyncd.conf(5) man page for more information. By default the configuration
file is called /etc/rsyncd.conf, unless rsync is running over a remote
shell program and is not running as root; in that case, the default name
@@ -234,8 +234,18 @@ user is root (e.g. chroot, setuid/setgid, etc.). There is no need to
configure inetd or the services map to include the rsync server port
if you run an rsync server only via a remote shell program.
To run an rsync server out of a single-use ssh key, see this section
in the rsyncd.conf(5) man page.
To run an rsync server out of a single-use ssh key, use the
"command=em(COMMAND)" syntax in the remote user's
authorized_keys entry, where command would be
quote(rsync --server --daemon .)
NOTE: rsync's argument parsing expects the trailing ".", so make sure
that it's there. If you want to use a rsyncd.conf(5)-style
configuration file other than the default, you can added a
--config option to the em(command):
quote(rsync --server --daemon --config=em(file) .)
manpagesection(EXAMPLES)
@@ -285,14 +295,14 @@ verb(
-R, --relative use relative path names
--no-relative turn off --relative
--no-implied-dirs don't send implied dirs with -R
-b, --backup make backups (see --suffix & --backup-dir)
-b, --backup make backups (see --suffix)
--backup-dir make backups into this directory
--suffix=SUFFIX backup suffix (default ~ w/o --backup-dir)
--suffix=SUFFIX define backup suffix (default ~ w/o --backup-dir)
-u, --update update only (don't overwrite newer files)
-l, --links copy symlinks as symlinks
-L, --copy-links copy the referent of all symlinks
--copy-unsafe-links copy the referent of "unsafe" symlinks
--safe-links ignore "unsafe" symlinks
-L, --copy-links copy the referent of symlinks
--copy-unsafe-links copy links outside the source tree
--safe-links ignore links outside the destination tree
-H, --hard-links preserve hard links
-p, --perms preserve permissions
-o, --owner preserve owner (root only)
@@ -305,24 +315,24 @@ verb(
--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)
-e, --rsh=COMMAND specify the remote shell
-e, --rsh=COMMAND specify the remote shell to use
--rsync-path=PATH specify path to rsync on the remote machine
--existing only update files that already exist
--ignore-existing ignore files that already exist on receiver
--delete delete files that don't exist on sender
--delete-excluded also delete excluded files on receiver
--delete-after receiver deletes after transfer, not before
--ignore-errors delete even if there are I/O errors
--ignore-existing ignore files that already exist on the receiving side
--delete delete files that don't exist on the sending side
--delete-excluded also delete excluded files on the receiving side
--delete-after delete after transferring, not before
--ignore-errors delete even if there are IO errors
--max-delete=NUM don't delete more than NUM files
--partial keep partially transferred files
--force force deletion of dirs even if not empty
--force force deletion of directories even if not empty
--numeric-ids don't map uid/gid values by user/group name
--timeout=TIME set I/O timeout in seconds
-I, --ignore-times turn off mod time & file size quick check
--size-only ignore mod time for quick check (use size)
--modify-window=NUM compare mod times with reduced accuracy
--timeout=TIME set IO timeout in seconds
-I, --ignore-times don't exclude files that match length and time
--size-only only use file size when determining if a file should be transferred
--modify-window=NUM Timestamp window (seconds) for file match (default=0)
-T --temp-dir=DIR create temporary files in directory DIR
--compare-dest=DIR also compare received files relative to DIR
--compare-dest=DIR also compare destination files relative to DIR
--link-dest=DIR create hardlinks to DIR for unchanged files
-P equivalent to --partial --progress
-z, --compress compress file data
@@ -332,22 +342,22 @@ verb(
--include=PATTERN don't exclude files matching PATTERN
--include-from=FILE don't exclude patterns listed in FILE
--files-from=FILE read FILE for list of source-file names
-0 --from0 all file lists are delimited by nulls
-0 --from0 file names we read are separated by nulls, not newlines
--version print version number
--daemon run as an rsync daemon
--daemon run as a rsync daemon
--no-detach do not detach from the parent
--address=ADDRESS bind to the specified address
--config=FILE specify alternate rsyncd.conf file
--port=PORT specify alternate rsyncd port number
--blocking-io use blocking I/O for the remote shell
--blocking-io use blocking IO for the remote shell
--no-blocking-io turn off --blocking-io
--stats give some file transfer stats
--progress show progress during transfer
--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=PREFIX write batch fileset starting with PREFIX
-h, --help show this help screen
@@ -381,12 +391,12 @@ from the remote server. This flag is useful when invoking rsync from
cron.
dit(bf(-I, --ignore-times)) Normally rsync will skip any files that are
already the same size and have the same modification time-stamp.
This option turns off this "quick check" behavior.
already the same length and have the same time-stamp. This option turns
off this behavior.
dit(bf(--size-only)) Normally rsync will not transfer any files that are
already the same size and have the same modification time-stamp. With the
--size-only option, files will not be transferred if they have the same size,
dit(bf(--size-only)) Normally rsync will skip any files that are
already the same length and have the same time-stamp. With the
--size-only option files will be skipped if they have the same size,
regardless of timestamp. This is useful when starting to use rsync
after using another mirroring system which may not preserve timestamps
exactly.
@@ -402,7 +412,7 @@ dit(bf(-c, --checksum)) This forces the sender to checksum all files using
a 128-bit MD4 checksum before transfer. The checksum is then
explicitly checked on the receiver and any files of the same name
which already exist and have the same checksum and size on the
receiver are not transferred. This option can be quite slow.
receiver are skipped. This option can be quite slow.
dit(bf(-a, --archive)) This is equivalent to -rlptgoD. It is a quick
way of saying you want recursion and want to preserve almost
@@ -458,8 +468,6 @@ very useful for incremental backups. You can additionally
specify a backup suffix using the --suffix option
(otherwise the files backed up in the specified directory
will keep their original filenames).
If DIR is a relative path, it is relative to the destination directory
(which changes in a recursive transfer).
dit(bf(--suffix=SUFFIX)) This option allows you to override the default
backup suffix used with the --backup (-b) option. The default suffix is a ~
@@ -469,26 +477,19 @@ dit(bf(-u, --update)) This forces rsync to skip any files for which the
destination file already exists and has a date later than the source
file.
In the currently implementation, a difference of file format is always
considered to be important enough for an update, no matter what date
is on the objects. In other words, if the source has a directory or a
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(-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 is copied, rather than the symlink.
dit(bf(--copy-unsafe-links)) This tells rsync to copy the referent of
symbolic links that point outside the copied tree. Absolute symlinks
symbolic links that point outside the source tree. Absolute symlinks
are also treated like ordinary files, and so are any symlinks in the
source path itself when --relative is used.
dit(bf(--safe-links)) This tells rsync to ignore any symbolic links
which point outside the copied tree. All absolute symlinks are
which point outside the destination tree. All absolute symlinks are
also ignored. Using this option in conjunction with --relative may
give unexpected results.
@@ -505,7 +506,7 @@ 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
"disk" is actually a networked filesystem). This is the default when both
"disk" is actually a networked file system). This is the default when both
the source and target are on the local machine.
dit(bf(--no-whole-file)) Turn off --whole-file, for use when it is the
@@ -521,16 +522,15 @@ other files (including updated files) retain their existing permissions
dit(bf(-o, --owner)) This option causes rsync to set the owner of the
destination file to be the same as the source file. On most systems,
only the super-user can set file ownership. By default, the preservation
is done by name, but may fall back to using the ID number in some
circumstances. See the --numeric-ids option for a full discussion.
only the super-user can set file ownership. Note that if the remote system
is a daemon using chroot, the --numeric-ids option is implied because the
remote system cannot get access to the usernames from /etc/passwd.
dit(bf(-g, --group)) This option causes rsync to set the group of the
destination file to be the same as the source file. If the receiving
program is not running as the super-user, only groups that the
receiver is a member of will be preserved. By default, the preservation
is done by name, but may fall back to using the ID number in some
circumstances. See the --numeric-ids option for a full discussion.
receiver is a member of will be preserved (by group name, not group id
number).
dit(bf(-D, --devices)) This option causes rsync to transfer character and
block device information to the remote system to recreate these
@@ -579,7 +579,7 @@ This option can be dangerous if used incorrectly! It is a very good idea
to run first using the dry run option (-n) to see what files would be
deleted to make sure important files aren't listed.
If the sending side detects any I/O errors then the deletion of any
If the sending side detects any IO errors then the deletion of any
files at the destination will be automatically disabled. This is to
prevent temporary filesystem failures (such as NFS errors) on the
sending side causing a massive deletion of files on the
@@ -590,13 +590,13 @@ receiving side that are not on the sending side, this tells rsync to also
delete any files on the receiving side that are excluded (see --exclude).
Implies --delete.
dit(bf(--delete-after)) By default rsync does file deletions on the
receiving side before transferring files to try to ensure that there is
sufficient space on the receiving filesystem. If you want to delete
after transferring, use the --delete-after switch. Implies --delete.
dit(bf(--delete-after)) By default rsync does file deletions before
transferring files to try to ensure that there is sufficient space on
the receiving filesystem. If you want to delete after transferring
then use the --delete-after switch. Implies --delete.
dit(bf(--ignore-errors)) Tells --delete to go ahead and delete files
even when there are I/O errors.
even when there are IO errors.
dit(bf(--force)) This options tells rsync to delete directories even if
they are not empty when they are to be replaced by non-directories. This
@@ -608,11 +608,11 @@ the rsync algorithm. 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
remote copies of rsync. Typically, rsync is configured to use ssh by
default, but you may prefer to use rsh on a local network.
remote copies of rsync. Typically, rsync is configured to use rsh by
default, but you may prefer to use ssh because of its high security.
If this option is used with bf([user@]host::module/path), then the
remote shell em(COMMAND) will be used to run an rsync server on the
remote shell em(COMMMAND) will be used to run an rsync server on the
remote host, and all data will be transmitted through that remote
shell connection, rather than through a direct socket connection to a
running rsync server on the remote host. See the section "CONNECTING
@@ -643,17 +643,16 @@ a file should be ignored.
The exclude list is initialized to:
quote(RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS .make.state
.nse_depinfo *~ #* .#* ,* _$* *$ *.old *.bak *.BAK *.orig *.rej
.del-* *.a *.olb *.o *.obj *.so *.exe *.Z *.elc *.ln core .svn/)
quote(RCS/ SCCS/ CVS/ .svn/ CVS.adm RCSLOG cvslog.* tags TAGS .make.state
.nse_depinfo *~ #* .#* ,* *.old *.bak *.BAK *.orig *.rej .del-*
*.a *.o *.obj *.so *.Z *.elc *.ln core)
then files listed in a $HOME/.cvsignore are added to the list and any
files listed in the CVSIGNORE environment variable (all cvsignore names
are delimited by whitespace).
files listed in the CVSIGNORE environment variable (space delimited).
Finally, any file is ignored if it is in the same directory as a
.cvsignore file and matches one of the patterns listed therein.
See the bf(cvs(1)) manual for more information.
.cvsignore file and matches one of the patterns listed therein. See
the bf(cvs(1)) manual for more information.
dit(bf(--exclude=PATTERN)) This option allows you to selectively exclude
certain files from the list of files to be transferred. This is most
@@ -662,7 +661,8 @@ useful in combination with a recursive transfer.
You may use as many --exclude options on the command line as you like
to build up the list of files to exclude.
See the EXCLUDE PATTERNS section for detailed information on this option.
See the EXCLUDE PATTERNS section for information on the syntax of
this option.
dit(bf(--exclude-from=FILE)) This option is similar to the --exclude
option, but instead it adds all exclude patterns listed in the file
@@ -674,7 +674,8 @@ dit(bf(--include=PATTERN)) This option tells rsync to not exclude the
specified pattern of filenames. This is useful as it allows you to
build up quite complex exclude/include rules.
See the EXCLUDE PATTERNS section for detailed information on this option.
See the EXCLUDE PATTERNS section for information on the syntax of
this option.
dit(bf(--include-from=FILE)) This specifies a list of include patterns
from a file.
@@ -720,8 +721,6 @@ was located on the remote "src" host.
dit(bf(-0, --from0)) This tells rsync that the filenames it reads from a
file are terminated by a null ('\0') character, not a NL, CR, or CR+LF.
This affects --exclude-from, --include-from, and --files-from.
It does not affect --cvs-exclude (since all names read from a .cvsignore
file are split on whitespace).
dit(bf(-T, --temp-dir=DIR)) This option instructs rsync to use DIR as a
scratch directory when creating temporary copies of the files
@@ -739,19 +738,14 @@ 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/
)
to the destination directory.
dit(bf(-z, --compress)) With this option, rsync compresses any data from
the files that it sends to the destination machine. This
@@ -764,22 +758,19 @@ compressing transport, as it takes advantage of the implicit
information sent for matching data blocks.
dit(bf(--numeric-ids)) With this option rsync will transfer numeric group
and user IDs rather than using user and group names and mapping them
and user ids rather than using user and group names and mapping them
at both ends.
By default rsync will use the username and groupname to determine
By default rsync will use the user name and group name to determine
what ownership to give files. The special uid 0 and the special group
0 are never mapped via user/group names even if the --numeric-ids
option is not specified.
If a user or group has no name on the source system or it has no match
on the destination system, then the numeric ID
from the source system is used instead. See also the comments on the
"use chroot" setting in the rsyncd.conf manpage for information on how
the chroot setting affects rsync's ability to look up the names of the
users and groups and what you can do about it.
If the source system is a daemon using chroot, or if a user or group
name does not exist on the destination system, then the numeric id
from the source system is used instead.
dit(bf(--timeout=TIMEOUT)) This option allows you to set a maximum I/O
dit(bf(--timeout=TIMEOUT)) This option allows you to set a maximum IO
timeout in seconds. If no data is transferred for the specified time
then rsync will exit. The default is 0, which means no timeout.
@@ -818,11 +809,12 @@ the default is rsyncd.conf in the current directory (typically $HOME).
dit(bf(--port=PORT)) This specifies an alternate TCP port number to use
rather than the default port 873.
dit(bf(--blocking-io)) This tells rsync to use blocking I/O when launching
a remote shell transport. If the remote shell is either rsh or remsh,
rsync defaults to using
blocking I/O, otherwise it defaults to using non-blocking I/O. (Note that
ssh prefers non-blocking I/O.)
dit(bf(--blocking-io)) This tells rsync to use blocking IO when launching
a remote shell transport. If -e or --rsh are not specified or are set to
the default "rsh", this defaults to blocking IO, otherwise it defaults to
non-blocking IO. You may find the --blocking-io option is needed for some
remote shells that can't handle non-blocking IO. (Note that ssh prefers
non-blocking IO.)
dit(bf(--no-blocking-io)) Turn off --blocking-io, for use when it is the
default.
@@ -847,36 +839,13 @@ showing the progress of the transfer. This gives a bored user
something to watch.
Implies --verbose without incrementing verbosity.
When the file is transferring, the data looks like this:
verb(
782448 63% 110.64kB/s 0:00:04
)
This tells you the current file size, the percentage of the transfer that
is complete, the current calculated file-completion rate (including both
data over the wire and data being matched locally), and the estimated time
remaining in this transfer.
After the a file is complete, it the data looks like this:
verb(
1238099 100% 146.38kB/s 0:00:08 (5, 57.1% of 396)
)
This tells you the final file size, that it's 100% complete, the final
transfer rate for the file, the amount of elapsed time it took to transfer
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(--password-file)) This option allows you to provide a password
in a file for accessing a remote rsync server. Note that this option
is only useful when accessing an rsync server using the built in
is only useful when accessing a rsync server using the built in
transport, not when using a remote shell as the transport. The file
must not be world readable. It should contain just the password as a
single line.
@@ -886,7 +855,7 @@ transfer rate in kilobytes per second. This option is most effective when
using rsync with large files (several megabytes and up). Due to the nature
of rsync transfers, blocks of data are sent, then if rsync determines the
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
result is an average transfer rate equalling the specified limit. A value
of zero specifies no limit.
dit(bf(--write-batch=PREFIX)) Generate a set of files that can be
@@ -904,7 +873,7 @@ manpagesection(EXCLUDE PATTERNS)
The exclude and include patterns specified to rsync allow for flexible
selection of which files to transfer and which files to skip.
Rsync builds an ordered list of include/exclude options as specified on
rsync builds an ordered list of include/exclude options as specified on
the command line. Rsync checks each file and directory
name against each exclude/include pattern in turn. The first matching
pattern is acted on. If it is an exclude pattern, then that file is
@@ -912,61 +881,16 @@ skipped. If it is an include pattern then that filename is not
skipped. If no matching include/exclude pattern is found then the
filename is not skipped.
The filenames matched against the exclude/include patterns are relative
to the "root of the transfer". If you think of the transfer as a
subtree of names that are being sent from sender to receiver, the root
is where the tree starts to be duplicated in the destination directory.
This root governs where patterns that start with a / match (see below).
The filenames matched against the exclude/include patterns
are relative to the destination directory, or "top
directory", so patterns should not include the path elements
of the source or destination directories. The only way in
which a pattern will match the absolute path of a file or
directory is if the source path is the root directory.
Because the matching is relative to the transfer-root, changing the
trailing slash on a source path or changing your use of the --relative
option affects the path you need to use in your matching (in addition to
changing how much of the file tree is duplicated on the destination
system). The following examples demonstrate this.
Let's say that we want to match two source files, one with an absolute
path of "/home/me/foo/bar", and one with a path of "/home/you/bar/baz".
Here is how the various command choices differ for a 2-source transfer:
verb(
Example cmd: rsync -a /home/me /home/you /dest
+/- pattern: /me/foo/bar
+/- pattern: /you/bar/baz
Target file: /dest/me/foo/bar
Target file: /dest/you/bar/baz
Example cmd: rsync -a /home/me/ /home/you/ /dest
+/- pattern: /foo/bar (note missing "me")
+/- pattern: /bar/baz (note missing "you")
Target file: /dest/foo/bar
Target file: /dest/bar/baz
Example cmd: rsync -a --relative /home/me/ /home/you /dest
+/- pattern: /home/me/foo/bar (note full path)
+/- pattern: /home/you/bar/baz (ditto)
Target file: /dest/home/me/foo/bar
Target file: /dest/home/you/bar/baz
Example cmd: cd /home; rsync -a --relative me/foo you/ /dest
+/- pattern: /me/foo/bar (starts at specified path)
+/- pattern: /you/bar/baz (ditto)
Target file: /dest/me/foo/bar
Target file: /dest/you/bar/baz
)
The easiest way to see what name you should include/exclude is to just
look at the output when using --verbose and put a / in front of the name
(use the --dry-run option if you're not yet ready to copy any files).
Note that, when using the --recursive (-r) option (which is implied by -a),
every subcomponent of
every path is visited from the top down, so include/exclude patterns get
Note that when used with -r (which is implied by -a), every subcomponent of
every path is visited from top down, so include/exclude patterns get
applied recursively to each subcomponent.
The exclude patterns actually short-circuit the directory traversal stage
when rsync finds the files to send. If a pattern excludes a particular
parent directory, it can render a deeper include pattern ineffectual
because rsync did not descend through that excluded section of the
hierarchy.
Note also that the --include and --exclude options take one pattern
each. To add multiple patterns use the --include-from and
@@ -980,15 +904,16 @@ itemize(
start of the filename, otherwise it is matched against the end of
the filename.
This is the equivalent of a leading ^ in regular expressions.
Thus "/foo" would match a file called "foo" at the transfer-root
(see above for how this is different from the filesystem-root).
Thus "/foo" would match a file called "foo" at the top of the
transferred tree.
On the other hand, "foo" would match any file called "foo"
anywhere in the tree because the algorithm is applied recursively from
top down; it behaves as if each path component gets a turn at being the
end of the file name.
The leading / does not make the pattern an absolute pathname.
it() if the pattern ends with a / then it will only match a
directory, not a file, link, or device.
directory, not a file, link or device.
it() if the pattern contains a wildcard character from the set
*?[ then expression matching is applied using the shell filename
@@ -1006,11 +931,11 @@ itemize(
it() if the pattern starts with "+ " (a plus followed by a space)
then it is always considered an include pattern, even if specified as
part of an exclude option. The prefix is discarded before matching.
part of an exclude option. The "+ " part is discarded before matching.
it() if the pattern starts with "- " (a minus followed by a space)
then it is always considered an exclude pattern, even if specified as
part of an include option. The prefix is discarded before matching.
part of an include option. The "- " part is discarded before matching.
it() if the pattern is a single exclamation mark ! then the current
include/exclude list is reset, removing all previously defined patterns.
@@ -1018,45 +943,25 @@ itemize(
The +/- rules are most useful in a list that was read from a file, allowing
you to have a single exclude list that contains both include and exclude
options in the proper order.
options.
Remember that the matching occurs at every step in the traversal of the
directory hierarchy, so you must be sure that all the parent directories of
the files you want to include are not excluded. This is particularly
important when using a trailing '*' rule. For instance, this won't work:
If you end an exclude list with --exclude '*', note that since the
algorithm is applied recursively that unless you explicitly include
parent directories of files you want to include then the algorithm
will stop at the parent directories and never see the files below
them. To include all directories, use --include '*/' before the
--exclude '*'.
verb(
+ /some/path/this-file-will-not-be-found
+ /file-is-included
- *
)
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
include rules for all the parent dirs that need to be visited. For
instance, this set of rules works fine:
verb(
+ /some/
+ /some/path/
+ /some/path/this-file-is-found
+ /file-also-included
- *
)
Here are some examples of exclude/include matching:
Here are some exclude/include examples:
itemize(
it() --exclude "*.o" would exclude all filenames matching *.o
it() --exclude "/foo" would exclude a file called foo in the transfer-root directory
it() --exclude "/foo" would exclude a file called foo in the top directory
it() --exclude "foo/" would exclude any directory called foo
it() --exclude "/foo/*/bar" would exclude any file called bar two
levels below a directory called foo in the transfer-root directory
levels below a directory called foo in the top directory
it() --exclude "/foo/**/bar" would exclude any file called bar two
or more levels below a directory called foo in the transfer-root directory
or more levels below a directory called foo in the top directory
it() --include "*/" --include "*.c" --exclude "*" would include all
directories and C source files
it() --include "foo/" --include "foo/bar.c" --exclude "*" would include
@@ -1110,11 +1015,11 @@ once, instead of sending the same data to every host individually.
Example:
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=pfx -a /source/dir/ /adest/dir/
$ rcp pfx.rsync_* remote:
$ rsh remote rsync --read-batch=pfx -a /bdest/dir/
# or alternatively
$ rsh remote ./pfx.rsync_argvs /bdest/dir/
)
In this example, rsync is used to update /adest/dir/ with /source/dir/
@@ -1168,7 +1073,7 @@ ensure the rsync module they copy does not include symbolic links to
bf(/etc/passwd) in the public section of the site. Using
bf(--copy-unsafe-links) will cause any links to be copied as the file
they point to on the destination. Using bf(--safe-links) will cause
unsafe links to be omitted altogether.
unsafe links to be ommitted altogether.
Symbolic links are considered unsafe if they are absolute symlinks
(start with bf(/)), empty, or if they contain enough bf("..")
@@ -1186,7 +1091,7 @@ for its transport. The way to diagnose this problem is to run your
remote shell like this:
verb(
ssh remotehost /bin/true > out.dat
rsh remotehost /bin/true > out.dat
)
then look at out.dat. If everything is working correctly then out.dat
@@ -1210,19 +1115,18 @@ 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 speciifed 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
dit(bf(11)) Error in file I/O
dit(bf(10)) Error in socket IO
dit(bf(11)) Error in file IO
dit(bf(12)) Error in rsync protocol data stream
dit(bf(13)) Errors with program diagnostics
dit(bf(14)) Error in IPC code
dit(bf(20)) Received SIGUSR1 or SIGINT
dit(bf(21)) Some error returned by waitpid()
dit(bf(22)) Error allocating core memory buffers
dit(bf(23)) Partial transfer due to error
dit(bf(24)) Partial transfer due to vanished source files
dit(bf(23)) Partial transfer
dit(bf(30)) Timeout in data send/receive
enddit()
@@ -1243,13 +1147,12 @@ redirect your rsync client to use a web proxy when connecting to a
rsync daemon. You should set RSYNC_PROXY to a hostname:port pair.
dit(bf(RSYNC_PASSWORD)) Setting RSYNC_PASSWORD to the required
password allows you to run authenticated rsync connections to an rsync
password allows you to run authenticated rsync connections to a rsync
daemon without user intervention. Note that this does not supply a
password to a shell transport such as ssh.
dit(bf(USER) or bf(LOGNAME)) The USER or LOGNAME environment variables
are used to determine the default username sent to an rsync server.
If neither is set, the username defaults to "nobody".
are used to determine the default username sent to a rsync server.
dit(bf(HOME)) The HOME environment variable is used to find the user's
default .cvsignore file.
@@ -1270,11 +1173,11 @@ manpagebugs()
times are transferred as unix time_t values
When transferring to FAT filesystems rsync may resync
When transferring to FAT filesystmes rsync may resync
unmodified files.
See the comments on the --modify-window option.
file permissions, devices, etc. are transferred as native numerical
file permissions, devices etc are transferred as native numerical
values
see also the comments on the --delete option
@@ -1306,13 +1209,19 @@ Thanks to Richard Brent, Brendan Mackay, Bill Waite, Stephen Rothwell
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.
Especial thanks also to: David Dykstra, Jos Backus, Sebastian Krahmer.
manpageauthor()
rsync was originally written by Andrew Tridgell and Paul Mackerras.
Many people have later contributed to it.
rsync was written by Andrew Tridgell <tridge@samba.org> and Paul
Mackerras.
rsync is now maintained by Martin Pool <mbp@samba.org>.
Mailing lists for support and development are available at
url(http://lists.samba.org)(lists.samba.org)
If you suspect you have found a security vulnerability in rsync,
please send it directly to Martin Pool and Andrew Tridgell. For other
enquiries, please use the mailing list.

View File

@@ -1,5 +1,5 @@
mailto(rsync-bugs@samba.org)
manpage(rsyncd.conf)(5)(26 Apr 2004)()()
manpage(rsyncd.conf)(5)(26 Jan 2003)()()
manpagename(rsyncd.conf)(configuration file for rsync server)
manpagesynopsis()
@@ -93,7 +93,7 @@ useful on systems (such as AIX) where syslog() doesn't work for
chrooted programs.
dit(bf(pid file)) The "pid file" option tells the rsync daemon to write
its process ID to that file.
its process id to that file.
dit(bf(syslog facility)) The "syslog facility" option allows you to
specify the syslog facility name to use when logging messages from the
@@ -135,31 +135,11 @@ 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
(see below). When "use chroot" is false, for security reasons,
when reading, and of implying the --numeric-ids option because /etc/passwd
becomes inaccessible. 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
such as --backup-dir, --compare-dest, etc. interpret an absolute path as
rooted in the module's "path" dir, just as if chroot was specified).
The default for "use chroot" is true.
In order to preserve usernames and groupnames, rsync needs to be able to
use the standard library functions for looking up names and IDs (i.e.
getpwuid(), getgrgid(), getpwname(), and getgrnam()). This means a
process in the chroot namespace will need to have access to the resources
used by these library functions (traditionally /etc/passwd and
/etc/group). If these resources are not available, rsync will only be
able to copy the IDs, just as if the --numeric-ids option had been
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.
path, and leading slashes are removed from absolute paths. The default for
"use chroot" is true.
dit(bf(max connections)) The "max connections" option allows you to
specify the maximum number of simultaneous connections you will allow.
@@ -184,13 +164,13 @@ listed when the client asks for a listing of available modules. By
setting this to false you can create hidden modules. The default is
for modules to be listable.
dit(bf(uid)) The "uid" option specifies the user name or user ID that
dit(bf(uid)) The "uid" option specifies the user name or user id that
file transfers to and from that module should take place as when the daemon
was run as root. In combination with the "gid" option this determines what
file permissions are available. The default is uid -2, which is normally
the user "nobody".
dit(bf(gid)) The "gid" option specifies the group name or group ID that
dit(bf(gid)) The "gid" option specifies the group name or group id that
file transfers to and from that module should take place as when the daemon
was run as root. This complements the "uid" option. The default is gid -2,
which is normally the group "nobody".
@@ -249,7 +229,7 @@ connect without a password (this is called "anonymous rsync").
See also the bf(CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL
PROGRAM) section in rsync(1) for information on how handle an
rsyncd.conf-level username that differs from the remote-shell-level
username when using a remote shell to connect to an rsync server.
username when using a remote shell to connect to a rsync server.
dit(bf(secrets file)) The "secrets file" option specifies the name of
a file that contains the username:password pairs used for
@@ -267,7 +247,7 @@ by "other"; see "strict modes".
dit(bf(strict modes)) The "strict modes" option determines whether or not
the permissions on the secrets file will be checked. If "strict modes" is
true, then the secrets file must not be readable by any user ID other
true, then the secrets file must not be readable by any user id other
than the one that the rsync daemon is running under. If "strict modes" is
false, the check is not performed. The default is true. This option
was added to accommodate rsync running on the Windows operating system.
@@ -326,10 +306,10 @@ rejected. See the "hosts allow" option for more information.
The default is no "hosts deny" option, which means all hosts can connect.
dit(bf(ignore errors)) The "ignore errors" option tells rsyncd to
ignore I/O errors on the server when deciding whether to run the delete
ignore IO errors on the server when deciding whether to run the delete
phase of the transfer. Normally rsync skips the --delete step if any
I/O errors have occurred in order to prevent disasterous deletion due
to a temporary resource shortage or other I/O error. In some cases this
IO errors have occurred in order to prevent disasterous deletion due
to a temporary resource shortage or other IO error. In some cases this
test is counter productive so you can use this option to turn off this
behaviour.
@@ -354,7 +334,7 @@ itemize(
it() %h for the remote host name
it() %a for the remote IP address
it() %l for the length of the file in bytes
it() %p for the process ID of this rsync session
it() %p for the process id of this rsync session
it() %o for the operation, which is either "send" or "recv"
it() %f for the filename
it() %P for the module path
@@ -373,7 +353,7 @@ A perl script called rsyncstats to summarize this format is included
in the rsync source code distribution.
dit(bf(timeout)) The "timeout" option allows you to override the
clients choice for I/O timeout for this module. Using this option you
clients choice for IO timeout for this module. Using this option you
can ensure that rsync won't wait on a dead client forever. The timeout
is specified in seconds. A value of zero means no timeout and is the
default. A good choice for anonymous rsync servers may be 600 (giving
@@ -419,32 +399,6 @@ encryption.
Future versions of rsync may support SSL for better authentication and
encryption, but that is still being investigated.
manpagesection(RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM)
If rsync is run with both the --daemon and --rsh (-e) options, it will
spawn an rsync daemon using a remote shell connection. Several
configuration options will not be available unless the remote user is
root (e.g. chroot, setuid/setgid, etc.). There is no need to configure
inetd or the services map to include the rsync server port if you run an
rsync server only via a remote shell program.
ADVANCED: To run an rsync server out of a single-use ssh key, use the
"command=em(COMMAND)" syntax in the remote user's authorized_keys entry,
where command would be
quote(rsync --server --daemon .)
NOTE: rsync's argument parsing expects the trailing ".", so make sure
that it's there. If you want to use an rsyncd.conf(5)-style
configuration file other than the default, you can added a
--config option to the em(command):
quote(rsync --server --daemon --config=em(file) .)
Note that the "--server" here is the internal option that rsync uses to
run the remote version of rsync that it communicates with, and thus you
should not be using the --server option under normal circumstances.
manpagesection(EXAMPLES)
A simple rsyncd.conf file that allow anonymous rsync to a ftp area at
@@ -514,7 +468,7 @@ Please report bugs! The rsync bug tracking system is online at
url(http://rsync.samba.org/)(http://rsync.samba.org/)
manpagesection(VERSION)
This man page is current for version 2.x of rsync.
This man page is current for version 2.0 of rsync
manpagesection(CREDITS)

View File

@@ -142,7 +142,7 @@ echo "$0 running in `pwd`"
echo " rsync_bin=$rsync_bin"
echo " srcdir=$srcdir"
testuser=`id -un || whoami || echo UNKNOWN`
testuser=`whoami || echo UNKNOWN`
echo " testuser=$testuser"
echo " os=`uname -a`"
@@ -220,11 +220,6 @@ do
echo "----- $testbase log follows"
cat "$scratchdir/test.log"
echo "----- $testbase log ends"
if [ -f "$scratchdir/rsyncd.log" ]; then
echo "----- $testbase rsyncd.log follows"
cat "$scratchdir/rsyncd.log"
echo "----- $testbase rsyncd.log ends"
fi
fi
case $result in

301
sender.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.
@@ -20,13 +20,12 @@
#include "rsync.h"
extern int verbose;
extern int remote_version;
extern int csum_length;
extern struct stats stats;
extern int io_error;
extern int dry_run;
extern int am_server;
extern int am_daemon;
extern int protocol_version;
/**
@@ -36,22 +35,7 @@ extern int protocol_version;
* and transmits them to the receiver. The sender process runs on the
* machine holding the source files.
**/
void read_sum_head(int f, struct sum_struct *sum)
{
sum->count = read_int(f);
sum->blength = read_int(f);
if (protocol_version < 27) {
sum->s2length = csum_length;
} else {
sum->s2length = read_int(f);
if (sum->s2length > MD4_SUM_LENGTH) {
rprintf(FERROR, "Invalid checksum length %ld\n",
(long)sum->s2length);
exit_cleanup(RERR_PROTOCOL);
}
}
sum->remainder = read_int(f);
}
/**
* Receive the checksums for a buffer
@@ -65,24 +49,24 @@ static struct sum_struct *receive_sums(int f)
s = new(struct sum_struct);
if (!s) out_of_memory("receive_sums");
read_sum_head(f, s);
s->count = read_int(f);
s->n = read_int(f);
s->remainder = read_int(f);
s->sums = NULL;
if (verbose > 3) {
rprintf(FINFO, "count=%ld n=%u rem=%u\n",
(long)s->count, s->blength, s->remainder);
}
if (verbose > 3)
rprintf(FINFO,"count=%ld n=%ld rem=%ld\n",
(long) s->count, (long) s->n, (long) s->remainder);
if (s->count == 0)
if (s->count == 0)
return(s);
s->sums = new_array(struct sum_buf, s->count);
if (!s->sums) 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);
read_buf(f,s->sums[i].sum2,csum_length);
s->sums[i].offset = offset;
s->sums[i].i = i;
@@ -90,13 +74,13 @@ static struct sum_struct *receive_sums(int f)
if (i == (int) s->count-1 && s->remainder != 0) {
s->sums[i].len = s->remainder;
} else {
s->sums[i].len = s->blength;
s->sums[i].len = s->n;
}
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);
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;
@@ -106,74 +90,78 @@ static struct sum_struct *receive_sums(int f)
void send_files(struct file_list *flist, int f_out, int f_in)
{
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_STAT st;
char fname[MAXPATHLEN];
char fname[MAXPATHLEN];
int i;
struct file_struct *file;
int phase = 0;
extern struct stats stats;
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 j;
int done;
extern int write_batch; /* dw */
extern int read_batch; /* dw */
int checksums_match; /* dw */
int buff_len; /* dw */
char buff[CHUNK_SIZE]; /* dw */
int j; /* dw */
int done; /* dw */
if (verbose > 2)
rprintf(FINFO, "send_files starting\n");
rprintf(FINFO,"send_files starting\n");
while (1) {
unsigned int offset;
int offset=0;
i = read_int(f_in);
if (i == -1) {
if (phase == 0) {
if (phase==0 && remote_version >= 13) {
phase++;
csum_length = SUM_LENGTH;
write_int(f_out, -1);
write_int(f_out,-1);
if (verbose > 2)
rprintf(FINFO, "send_files phase=%d\n", phase);
rprintf(FINFO,"send_files phase=%d\n",phase);
continue;
}
break;
}
if (i < 0 || i >= flist->count) {
rprintf(FERROR, "Invalid file index %d (count=%d)\n",
rprintf(FERROR,"Invalid file index %d (count=%d)\n",
i, flist->count);
exit_cleanup(RERR_PROTOCOL);
}
file = flist->files[i];
stats.current_file_index = i;
stats.num_transferred_files++;
stats.total_transferred_size += file->length;
fname[0] = 0;
if (file->basedir) {
/* N.B. We're sure that this fits, so offset is OK. */
offset = strlcpy(fname, file->basedir, sizeof fname);
if (!offset || fname[offset-1] != '/')
fname[offset++] = '/';
} else
offset = 0;
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);
strlcpy(fname,file->basedir,MAXPATHLEN);
if (strlen(fname) == MAXPATHLEN-1) {
io_error = 1;
rprintf(FERROR, "send_files failed on long-named directory %s\n",
fname);
return;
}
write_int(f_out, i);
strlcat(fname,"/",MAXPATHLEN);
offset = strlen(file->basedir)+1;
}
strlcat(fname,f_name(file),MAXPATHLEN);
if (verbose > 2)
rprintf(FINFO,"send_files(%d,%s)\n",i,fname);
if (dry_run) {
if (!am_server) {
log_transfer(file, fname+offset);
}
write_int(f_out,i);
continue;
}
@@ -181,138 +169,129 @@ void send_files(struct file_list *flist, int f_out, int f_in)
s = receive_sums(f_in);
if (!s) {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "receive_sums failed\n");
io_error = 1;
rprintf(FERROR,"receive_sums failed\n");
return;
}
if (write_batch)
write_batch_csum_info(&i, s);
write_batch_csum_info(&i,flist->count,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));
}
io_error = 1;
rprintf(FERROR,"send_files failed to open %s: %s\n",
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));
if (do_fstat(fd,&st) != 0) {
io_error = 1;
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);
buf = map_file(fd,st.st_size);
} else {
buf = NULL;
}
if (verbose > 2)
rprintf(FINFO, "send_files mapped %s of size %.0f\n",
fname, (double)st.st_size);
write_int(f_out, i);
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_batch_delta_file((char *)&i,sizeof(i));
write_sum_head(f_out, s);
write_int(f_out,s->count);
write_int(f_out,s->n);
write_int(f_out,s->remainder);
}
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);
if (verbose > 2)
if (!read_batch)
rprintf(FINFO,"calling match_sums %s\n",fname);
if (!am_server) {
log_transfer(file, fname+offset);
}
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);
if (read_batch) { /* dw */
/* 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_int(f_out,s->count);
write_int(f_out,s->n);
write_int(f_out,s->remainder);
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);
} /* j=i */
} else { /* not checksum match */
rprintf (FINFO, "readbatch & checksums don't match\n");
rprintf (FINFO, "filename=%s is being skipped\n", fname);
continue;
}
} else {
match_sums(f_out, s, buf, 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;
}
} else {
match_sums(f_out,s,buf,st.st_size);
log_send(file, &initial_stats);
}
if (!read_batch) { /* dw */
if (buf) unmap_file(buf);
close(fd);
}
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);
}
free_sums(s);
if (verbose > 2)
rprintf(FINFO, "sender finished %s\n", fname);
rprintf(FINFO,"sender finished %s\n",fname);
}
if (verbose > 2)
rprintf(FINFO, "send files finished\n");
rprintf(FINFO,"send files finished\n");
match_report();
write_int(f_out, -1);
if (write_batch || read_batch) {
close_batch_csums_file();
close_batch_delta_file();
write_int(f_out,-1);
if (write_batch || read_batch) { /* dw */
close_batch_csums_file();
close_batch_delta_file();
}
}

434
socket.c
View File

@@ -1,20 +1,20 @@
/* -*- c-file-style: "linux" -*-
rsync -- fast file replication program
Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
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 socket.c
*
*
* Socket functions used in rsync.
*
* This file is now converted to use the new-style getaddrinfo()
@@ -36,45 +36,21 @@
/**
* Establish a proxy connection on an open socket to a web proxy by
* using the CONNECT method. If proxy_user and proxy_pass are not NULL,
* they are used to authenticate to the proxy using the "Basic"
* proxy-authorization protocol
* using the HTTP CONNECT method.
**/
static int establish_proxy_connection(int fd, char *host, int port,
char *proxy_user, char *proxy_pass)
static int establish_proxy_connection(int fd, char *host, int port)
{
char *cp, buffer[1024];
char *authhdr, authbuf[1024];
int len;
char buffer[1024];
char *cp;
if (proxy_user && proxy_pass) {
stringjoin(buffer, sizeof buffer,
proxy_user, ":", proxy_pass, NULL);
len = strlen(buffer);
if ((len*8 + 5) / 6 >= (int)sizeof authbuf) {
rprintf(FERROR,
"authentication information is too long\n");
return -1;
}
base64_encode(buffer, len, authbuf);
authhdr = "\r\nProxy-Authorization: Basic ";
} else {
*authbuf = '\0';
authhdr = "";
}
snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n",
host, port, authhdr, authbuf);
len = strlen(buffer);
if (write(fd, buffer, len) != len) {
snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
if (write(fd, buffer, strlen(buffer)) != (int) strlen(buffer)) {
rprintf(FERROR, "failed to write to proxy: %s\n",
strerror(errno));
return -1;
}
for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
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));
@@ -94,7 +70,8 @@ static int establish_proxy_connection(int fd, char *host, int port,
buffer);
return -1;
}
for (cp = &buffer[5]; isdigit(*(uchar*)cp) || *cp == '.'; cp++) {}
for (cp = &buffer[5]; isdigit(* (unsigned char *) cp) || (*cp == '.'); cp++)
;
while (*cp == ' ')
cp++;
if (*cp != '2') {
@@ -104,7 +81,8 @@ static int establish_proxy_connection(int fd, char *host, int port,
}
/* throw away the rest of the HTTP header */
while (1) {
for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
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));
@@ -113,9 +91,9 @@ static int establish_proxy_connection(int fd, char *host, int port,
if (*cp == '\n')
break;
}
if (cp > buffer && *cp == '\n')
if ((cp > buffer) && (*cp == '\n'))
cp--;
if (cp == buffer && (*cp == '\n' || *cp == '\r'))
if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r')))
break;
}
return 0;
@@ -126,13 +104,14 @@ static int establish_proxy_connection(int fd, char *host, int port,
* Try to set the local address for a newly-created socket. Return -1
* if this fails.
**/
int try_bind_local(int s, int ai_family, int ai_socktype,
int try_bind_local(int s,
int ai_family, int ai_socktype,
const char *bind_address)
{
int error;
struct addrinfo bhints, *bres_all, *r;
memset(&bhints, 0, sizeof bhints);
memset(&bhints, 0, sizeof(bhints));
bhints.ai_family = ai_family;
bhints.ai_socktype = ai_socktype;
bhints.ai_flags = AI_PASSIVE;
@@ -181,59 +160,42 @@ int open_socket_out(char *host, int port, const char *bind_address,
int af_hint)
{
int type = SOCK_STREAM;
int error, s;
int error;
int s;
struct addrinfo hints, *res0, *res;
char portbuf[10];
char *h, *cp;
char *h;
int proxied = 0;
char buffer[1024];
char *proxy_user = NULL, *proxy_pass = NULL;
char *cp;
/* if we have a RSYNC_PROXY env variable then redirect our
* connetcion via a web proxy at the given address. */
* connetcion via a web proxy at the given address. The format
* is hostname:port */
h = getenv("RSYNC_PROXY");
proxied = h != NULL && *h != '\0';
proxied = (h != NULL) && (*h != '\0');
if (proxied) {
strlcpy(buffer, h, sizeof buffer);
/* Is the USER:PASS@ prefix present? */
if ((cp = strchr(buffer, '@')) != NULL) {
*cp++ = '\0';
/* The remainder is the HOST:PORT part. */
h = cp;
if ((cp = strchr(buffer, ':')) == NULL) {
rprintf(FERROR,
"invalid proxy specification: should be USER:PASS@HOST:PORT\n");
return -1;
}
*cp++ = '\0';
proxy_user = buffer;
proxy_pass = cp;
} else {
/* The whole buffer is the HOST:PORT part. */
h = buffer;
}
if ((cp = strchr(h, ':')) == NULL) {
strlcpy(buffer, h, sizeof(buffer));
cp = strchr(buffer, ':');
if (cp == NULL) {
rprintf(FERROR,
"invalid proxy specification: should be HOST:PORT\n");
return -1;
}
*cp++ = '\0';
strlcpy(portbuf, cp, sizeof portbuf);
strcpy(portbuf, cp);
h = buffer;
if (verbose >= 2) {
rprintf(FINFO, "connection via http proxy %s port %s\n",
h, portbuf);
}
} else {
snprintf(portbuf, sizeof portbuf, "%d", port);
snprintf(portbuf, sizeof(portbuf), "%d", port);
h = host;
}
memset(&hints, 0, sizeof hints);
memset(&hints, 0, sizeof(hints));
hints.ai_family = af_hint;
hints.ai_socktype = type;
error = getaddrinfo(h, portbuf, &hints, &res0);
@@ -253,26 +215,26 @@ int open_socket_out(char *host, int port, const char *bind_address,
if (s < 0)
continue;
if (bind_address
&& try_bind_local(s, res->ai_family, type,
bind_address) == -1) {
close(s);
s = -1;
continue;
}
if (bind_address)
if (try_bind_local(s, res->ai_family, type,
bind_address) == -1) {
close(s);
s = -1;
continue;
}
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
close(s);
s = -1;
continue;
}
if (proxied
&& establish_proxy_connection(s, host, port,
proxy_user, proxy_pass) != 0) {
if (proxied &&
establish_proxy_connection(s, host, port) != 0) {
close(s);
s = -1;
continue;
}
break;
} else
break;
}
freeaddrinfo(res0);
if (s < 0) {
@@ -296,19 +258,18 @@ int open_socket_out(char *host, int port, const char *bind_address,
*
* @param bind_address Local address to use. Normally NULL to get the stack default.
**/
int open_socket_out_wrapped(char *host, int port, const char *bind_address,
int af_hint)
int open_socket_out_wrapped (char *host,
int port,
const char *bind_address,
int af_hint)
{
char *prog = getenv("RSYNC_CONNECT_PROG");
char *prog;
if (verbose >= 2) {
rprintf(FINFO, "%sopening tcp connection to %s port %d\n",
prog ? "Using RSYNC_CONNECT_PROG instead of " : "",
host, port);
}
if (prog)
return sock_exec(prog);
return open_socket_out(host, port, bind_address, af_hint);
if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
return sock_exec (prog);
else
return open_socket_out (host, port, bind_address,
af_hint);
}
@@ -318,94 +279,72 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_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.
*
* 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.
*
* 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.
*
*
* @param bind_address Local address to bind, or NULL to allow it to
* default.
**/
static int *open_socket_in(int type, int port, const char *bind_address,
int af_hint)
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 s;
struct addrinfo hints, *all_ai, *resp;
char portbuf[10];
int error;
memset(&hints, 0, sizeof hints);
memset(&hints, 0, sizeof(hints));
hints.ai_family = af_hint;
hints.ai_socktype = type;
hints.ai_flags = AI_PASSIVE;
snprintf(portbuf, sizeof portbuf, "%d", port);
snprintf(portbuf, sizeof(portbuf), "%d", port);
error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
if (error) {
rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
bind_address, gai_strerror(error));
return NULL;
}
/* 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;
return -1;
}
/* 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) {
s = socket(resp->ai_family, resp->ai_socktype,
resp->ai_protocol);
if (s == -1) {
if (s == -1)
/* See if there's another address that will work... */
continue;
}
setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof one);
#ifdef IPV6_V6ONLY
if (resp->ai_family == AF_INET6) {
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&one, sizeof one);
}
#endif
/* Now we've got a socket - we need to bind it. */
if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) {
/* now we've got a socket - we need to bind it */
if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) {
/* Nope, try another */
close(s);
continue;
}
*sp++ = s;
}
*socks = sp - socks - 1; /* Save count. */
if (all_ai)
freeaddrinfo(all_ai);
if (*socks == 0) {
rprintf(FERROR,
RSYNC_NAME ": open inbound socket on port %d failed: "
"%s\n", port, strerror(errno));
free(socks);
return NULL;
return s;
}
return socks;
rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
"%s\n",
port,
strerror(errno));
freeaddrinfo(all_ai);
return -1;
}
@@ -415,64 +354,55 @@ static int *open_socket_in(int type, int port, const char *bind_address,
int is_a_socket(int fd)
{
int v;
socklen_t l = sizeof (int);
socklen_t l;
l = sizeof(int);
/* Parameters to getsockopt, setsockopt etc are very
* unstandardized across platforms, so don't be surprised if
* there are compiler warnings on e.g. SCO OpenSwerver or AIX.
* It seems they all eventually get the right idea.
*
* Debian says: ``The fifth argument of getsockopt and
* setsockopt is in reality an int [*] (and this is what BSD
* 4.* and libc4 and libc5 have). Some POSIX confusion
* resulted in the present socklen_t. The draft standard has
* not been adopted yet, but glibc2 already follows it and
* also has socklen_t [*]. See also accept(2).''
*
* We now return to your regularly scheduled programming. */
return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0;
/* Parameters to getsockopt, setsockopt etc are very
* unstandardized across platforms, so don't be surprised if
* there are compiler warnings on e.g. SCO OpenSwerver or AIX.
* It seems they all eventually get the right idea.
*
* Debian says: ``The fifth argument of getsockopt and
* setsockopt is in reality an int [*] (and this is what BSD
* 4.* and libc4 and libc5 have). Some POSIX confusion
* resulted in the present socklen_t. The draft standard has
* not been adopted yet, but glibc2 already follows it and
* also has socklen_t [*]. See also accept(2).''
*
* We now return to your regularly scheduled programming. */
return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
}
static RETSIGTYPE sigchld_handler(UNUSED(int val))
{
signal(SIGCHLD, sigchld_handler);
#ifdef WNOHANG
while (waitpid(-1, NULL, WNOHANG) > 0) {}
#endif
signal(SIGCHLD, sigchld_handler);
}
void start_accept_loop(int port, int (*fn)(int, int))
{
fd_set deffds;
int *sp, maxfd, i, j;
int s;
extern char *bind_address;
extern int default_af_hint;
/* open an incoming socket */
sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
if (sp == NULL)
s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
if (s == -1)
exit_cleanup(RERR_SOCKETIO);
/* 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);
exit_cleanup(RERR_SOCKETIO);
}
FD_SET(sp[i], &deffds);
if (maxfd < sp[i])
maxfd = sp[i];
if (listen(s, 5) == -1) {
close(s);
exit_cleanup(RERR_SOCKETIO);
}
/* now accept incoming connections - forking a new process
* for each incoming connection */
for each incoming connection */
while (1) {
fd_set fds;
pid_t pid;
@@ -481,38 +411,30 @@ void start_accept_loop(int port, int (*fn)(int, int))
socklen_t addrlen = sizeof addr;
/* close log file before the potentially very long select so
* file can be trimmed by another process instead of growing
* forever */
file can be trimmed by another process instead of growing
forever */
log_close();
#ifdef FD_COPY
FD_COPY(&deffds, &fds);
#else
fds = deffds;
#endif
FD_ZERO(&fds);
FD_SET(s, &fds);
if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
continue;
fd = -1;
for (i = 1; i <= *sp; i++) {
if (FD_ISSET(sp[i], &fds)) {
fd = accept(sp[i], (struct sockaddr *)&addr,
&addrlen);
break;
}
}
if (fd < 0)
continue;
if(!FD_ISSET(s, &fds)) continue;
fd = accept(s,(struct sockaddr *)&addr,&addrlen);
if (fd == -1) continue;
signal(SIGCHLD, sigchld_handler);
if ((pid = fork()) == 0) {
int ret;
close(sp[i]);
close(s);
/* open log file in child before possibly giving
* up privileges */
up privileges */
log_open();
ret = fn(fd, fd);
close_all();
@@ -532,7 +454,6 @@ void start_accept_loop(int port, int (*fn)(int, int))
close(fd);
}
}
free(sp);
}
@@ -578,7 +499,7 @@ struct
#endif
{NULL,0,0,0,0}};
/**
* Set user socket options
@@ -586,16 +507,13 @@ struct
void set_socket_options(int fd, char *options)
{
char *tok;
if (!options || !*options)
return;
if (!options || !*options) return;
options = strdup(options);
if (!options) out_of_memory("set_socket_options");
if (!options)
out_of_memory("set_socket_options");
for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) {
for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
int ret=0,i;
int value = 1;
char *p;
@@ -607,10 +525,9 @@ void set_socket_options(int fd, char *options)
got_value = 1;
}
for (i = 0; socket_options[i].name; i++) {
for (i=0;socket_options[i].name;i++)
if (strcmp(socket_options[i].name,tok)==0)
break;
}
if (!socket_options[i].name) {
rprintf(FERROR,"Unknown socket option %s\n",tok);
@@ -621,10 +538,9 @@ void set_socket_options(int fd, char *options)
case OPT_BOOL:
case OPT_INT:
ret = setsockopt(fd,socket_options[i].level,
socket_options[i].option,
(char *)&value, sizeof (int));
socket_options[i].option,(char *)&value,sizeof(int));
break;
case OPT_ON:
if (got_value)
rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
@@ -632,12 +548,11 @@ void set_socket_options(int fd, char *options)
{
int on = socket_options[i].value;
ret = setsockopt(fd,socket_options[i].level,
socket_options[i].option,
(char *)&on, sizeof (int));
socket_options[i].option,(char *)&on,sizeof(int));
}
break;
break;
}
if (ret != 0)
rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
strerror(errno));
@@ -664,15 +579,15 @@ void become_daemon(void)
#ifdef TIOCNOTTY
i = open("/dev/tty", O_RDWR);
if (i >= 0) {
ioctl(i, (int)TIOCNOTTY, (char *)0);
ioctl(i, (int) TIOCNOTTY, (char *)0);
close(i);
}
#endif /* TIOCNOTTY */
#endif
/* make sure that stdin, stdout an stderr don't stuff things
* up (library functions, for example) */
for (i = 0; i < 3; i++) {
close(i);
up (library functions, for example) */
for (i=0;i<3;i++) {
close(i);
open("/dev/null", O_RDWR);
}
}
@@ -681,7 +596,7 @@ void become_daemon(void)
/**
* This is like socketpair but uses tcp. It is used by the Samba
* regression test code.
*
*
* The function guarantees that nobody else can attach to the socket,
* or if they do that this function fails and the socket gets closed
* returns 0 on success, -1 on failure the resulting file descriptors
@@ -692,65 +607,56 @@ static int socketpair_tcp(int fd[2])
int listener;
struct sockaddr_in sock;
struct sockaddr_in sock2;
socklen_t socklen = sizeof sock;
socklen_t socklen = sizeof(sock);
int connect_done = 0;
fd[0] = fd[1] = listener = -1;
memset(&sock, 0, sizeof sock);
memset(&sock, 0, sizeof(sock));
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1)
goto failed;
memset(&sock2, 0, sizeof sock2);
#if HAVE_SOCKADDR_IN_LEN
sock2.sin_len = sizeof sock2;
memset(&sock2, 0, sizeof(sock2));
#ifdef HAVE_SOCKADDR_LEN
sock2.sin_len = sizeof(sock2);
#endif
sock2.sin_family = PF_INET;
sock2.sin_family = PF_INET;
bind(listener, (struct sockaddr *)&sock2, sizeof sock2);
bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
if (listen(listener, 1) != 0)
goto failed;
if (listen(listener, 1) != 0) goto failed;
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0)
goto failed;
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1)
goto failed;
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
set_nonblocking(fd[1]);
sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) == -1) {
if (errno != EINPROGRESS)
goto failed;
} else
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
if (errno != EINPROGRESS) goto failed;
} else {
connect_done = 1;
}
if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1)
goto failed;
if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
close(listener);
if (connect_done == 0) {
if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0
&& errno != EISCONN)
goto failed;
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
&& errno != EISCONN) goto failed;
}
set_blocking(fd[1]);
set_blocking (fd[1]);
/* all OK! */
return 0;
failed:
if (fd[0] != -1)
close(fd[0]);
if (fd[1] != -1)
close(fd[1]);
if (listener != -1)
close(listener);
if (fd[0] != -1) close(fd[0]);
if (fd[1] != -1) close(fd[1]);
if (listener != -1) close(listener);
return -1;
}
@@ -768,22 +674,30 @@ static int socketpair_tcp(int fd[2])
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));
rprintf (FERROR, RSYNC_NAME
": socketpair_tcp failed (%s)\n",
strerror(errno));
return -1;
}
if (verbose >= 2)
rprintf(FINFO, "Running socket program: \"%s\"\n", prog);
if (fork() == 0) {
close(fd[0]);
close(0);
close(1);
dup(fd[1]);
dup(fd[1]);
exit(system(prog));
if (verbose > 3) {
/* Can't use rprintf because we've forked. */
fprintf (stderr,
RSYNC_NAME ": execute socket program \"%s\"\n",
prog);
}
exit (system (prog));
}
close(fd[1]);
close (fd[1]);
return fd[0];
}

View File

@@ -31,27 +31,19 @@ extern int read_only;
extern int list_only;
extern int preserve_perms;
#define RETURN_ERROR_IF(x,e) \
do { \
if (x) { \
errno = (e); \
return -1; \
} \
} while (0)
#define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS)
#define CHECK_RO if (read_only || list_only) {errno = EROFS; return -1;}
int do_unlink(char *fname)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return unlink(fname);
}
int do_symlink(char *fname1, char *fname2)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return symlink(fname1, fname2);
}
@@ -59,7 +51,7 @@ int do_symlink(char *fname1, char *fname2)
int do_link(char *fname1, char *fname2)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return link(fname1, fname2);
}
#endif
@@ -67,7 +59,7 @@ int do_link(char *fname1, char *fname2)
int do_lchown(const char *path, uid_t owner, gid_t group)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return lchown(path, owner, group);
}
@@ -75,7 +67,7 @@ int do_lchown(const char *path, uid_t owner, gid_t group)
int do_mknod(char *pathname, mode_t mode, dev_t dev)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return mknod(pathname, mode, dev);
}
#endif
@@ -83,16 +75,18 @@ int do_mknod(char *pathname, mode_t mode, dev_t dev)
int do_rmdir(char *pathname)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return rmdir(pathname);
}
int do_open(char *pathname, int flags, mode_t mode)
{
if (flags != O_RDONLY) {
RETURN_ERROR_IF(dry_run, 0);
RETURN_ERROR_IF_RO_OR_LO;
if (dry_run) return -1;
CHECK_RO
}
/* some systems can't handle a double / */
if (pathname[0] == '/' && pathname[1] == '/') pathname++;
return open(pathname, flags | O_BINARY, mode);
}
@@ -102,9 +96,9 @@ int do_chmod(const char *path, mode_t mode)
{
int code;
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
code = chmod(path, mode);
if (code != 0 && preserve_perms)
if ((code != 0) && preserve_perms)
return code;
return 0;
}
@@ -113,7 +107,7 @@ int do_chmod(const char *path, mode_t mode)
int do_rename(char *fname1, char *fname2)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return rename(fname1, fname2);
}
@@ -139,8 +133,9 @@ void trim_trailing_slashes(char *name)
int do_mkdir(char *fname, mode_t mode)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
if (dry_run)
return 0;
CHECK_RO;
trim_trailing_slashes(fname);
return mkdir(fname, mode);
}
@@ -149,26 +144,22 @@ int do_mkdir(char *fname, mode_t mode)
/* like mkstemp but forces permissions */
int do_mkstemp(char *template, mode_t perms)
{
RETURN_ERROR_IF(dry_run, 0);
RETURN_ERROR_IF(read_only, EROFS);
if (dry_run) return -1;
if (read_only) {errno = EROFS; return -1;}
#if defined(HAVE_SECURE_MKSTEMP) && defined(HAVE_FCHMOD)
{
int fd = mkstemp(template);
if (fd == -1)
return -1;
if (fchmod(fd, perms) != 0 && preserve_perms) {
int errno_save = errno;
if (fd == -1) return -1;
if ((fchmod(fd, perms) != 0) && preserve_perms) {
close(fd);
unlink(template);
errno = errno_save;
return -1;
}
return fd;
}
#else
if (!mktemp(template))
return -1;
if (!mktemp(template)) return -1;
return do_open(template, O_RDWR|O_EXCL|O_CREAT, perms);
#endif
}

View File

@@ -28,7 +28,7 @@
int modify_window = 0;
int module_id = -1;
struct exclude_list_struct server_exclude_list;
struct exclude_struct **server_exclude_list;
void rprintf(UNUSED(enum logcode code), const char *format, ...)
{
@@ -45,7 +45,7 @@ struct exclude_list_struct server_exclude_list;
exit(code);
}
int check_exclude(UNUSED(struct exclude_list_struct *listp), UNUSED(char *name),
int check_exclude(UNUSED(struct exclude_struct **list), UNUSED(char *name),
UNUSED(int name_is_dir))
{
/* This function doesn't really get called in this test context, so

View File

@@ -18,6 +18,8 @@ set -x
fromdir="$scratchdir/from"
todir="$scratchdir/to"
# TODO: I guess some systems will not have 'id', and therefore we have
# to ship or emulate it.
mygrps="`rsync_getgroups`" || fail "Can't get groups"
mkdir "$fromdir"
@@ -31,5 +33,6 @@ sleep 2
checkit "$RSYNC -rtgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0
# last [] may have failed but if we get here then we've won

View File

@@ -33,5 +33,6 @@ chgrp 5003 "$name2" || test_skipped "Can't chgrp (probably need root)"
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0
# last [] may have failed but if we get here then we've won

View File

@@ -27,7 +27,5 @@ RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
export RSYNC_CONNECT_PROG
hands_setup
checkit "$RSYNC -avvvvz localhost::test-from/ \"$TO/\"" "$FROM" "$TO"
checkit "$RSYNC -avvz localhost::test-from/ \"$TO/\"" "$FROM" "$TO"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -21,7 +21,5 @@ RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
export RSYNC_CONNECT_PROG
hands_setup
checkit "$RSYNC -avvvvz \"$FROM/\" localhost::test-to/" "$FROM" "$TO"
checkit "$RSYNC -avvz \"$FROM/\" localhost::test-to/" "$FROM" "$TO"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -16,23 +16,14 @@ set -x
fromdir="$scratchdir/from"
todir="$scratchdir/to"
case `id -u` in
'') ;; # If "id" failed, try to continue...
0) ;;
*) test_skipped "Rsync won't copy devices unless we're root" ;;
esac
# TODO: Need to test whether hardlinks are possible on this OS/filesystem
mkdir "$fromdir"
mknod "$fromdir/char" c 41 67 || test_skipped "Can't create char device node unless root"
mknod "$fromdir/char2" c 42 68 || test_skipped "Can't create char device node unless root"
mknod "$fromdir/char3" c 42 69 || test_skipped "Can't create char device node unless root"
mknod "$fromdir/char" c 42 69 || test_skipped "Can't create char device node unless root"
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"
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0
# last [] may have failed but if we get here then we've won

View File

@@ -49,5 +49,5 @@ then
test_fail "name2 was not copied exactly once"
fi
# The script would have aborted on error, so getting here means we've won.
exit 0
# last [] may have failed but if we get here then we've won

View File

@@ -14,36 +14,23 @@
set -x
HOME="$scratchdir"
CVSIGNORE='*.junk'
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 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 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.
@@ -85,21 +72,4 @@ $RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
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.
rm "$chkdir"/foo/*.old
rm "$chkdir"/bar/down/to/foo/*.bak
rm "$chkdir"/bar/down/to/foo/*.junk
rm "$chkdir"/bar/down/to/home-cvs-exclude
rm "$chkdir"/mid/one-in-one-out
$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"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -25,5 +25,4 @@ runtest "extra data" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
cp ${FROM}/text ${TO}/ThisShouldGo
runtest " --delete" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -33,5 +33,6 @@ cp "$name2" "$name4" || fail "Can't copy file"
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0
# last [] may have failed but if we get here then we've won

View File

@@ -19,6 +19,3 @@ 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}
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -1,51 +0,0 @@
#! /bin/sh
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
# This program is distributable under the terms of the GNU GPL (see
# COPYING).
# Make sure we can merge files from multiple directories into one.
. $srcdir/testsuite/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
mkdir "$from3dir"/sub2
mkdir "$chkdir" "$chkdir"/sub1 "$chkdir"/sub2
echo "one" >"$from1dir"/one
cp -p "$from1dir"/one "$from2dir"/one
cp -p "$from1dir"/one "$from3dir"/one
echo "two" >"$from1dir"/two
echo "three" >"$from2dir"/three
echo "four" >"$from3dir"/four
echo "five" >"$from1dir"/five
echo "six" >"$from3dir"/six
echo "sub1" >"$from2dir"/sub1/uno
cp -p "$from2dir"/sub1/uno "$from3dir"/sub1/uno
echo "sub2" >"$from3dir"/sub1/dos
echo "sub3" >"$from2dir"/sub1/tres
echo "subby" >"$from3dir"/sub2/subby
cp -p "$from1dir"/one "$from1dir"/two "$from2dir"/three "$from3dir"/four "$from1dir"/five "$from3dir"/six "$chkdir"
cp -p "$from2dir"/sub1/uno "$from3dir"/sub1/dos "$from2dir"/sub1/tres "$chkdir"/sub1
cp -p "$from3dir"/sub2/subby "$chkdir"/sub2
# Get rid of any directory-time differences
touch "$fromdir"? "$chkdir" "$fromdir"?/sub? "$chkdir"/sub?
checkit "$RSYNC -aHvv \"$fromdir\"?/ \"$todir/\"" "$chkdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -196,7 +196,6 @@ pid file = $pidfile
use chroot = no
hosts allow = localhost, 127.0.0.1
log file = $logfile
max verbosity = 9
uid = 0
gid = 0

View File

@@ -35,5 +35,6 @@ then
test_fail "absolute symlink was copied"
fi
# The script would have aborted on error, so getting here means we've won.
exit 0
# last [] may have failed but if we get here then we've one

View File

@@ -24,5 +24,4 @@ diff $diffopt "$scratchdir/slash.out" - <<EOF
/Users/Wierd Macintosh Name/// Ooh, translucent plastic
EOF
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -11,10 +11,9 @@
set -x
"$TOOLDIR/wildtest" "$srcdir/wildtest.txt" >"$scratchdir/wild.out"
"$TOOLDIR/wildtest" >"$scratchdir/wild.out"
diff $diffopt "$scratchdir/wild.out" - <<EOF
No wildmatch errors found.
EOF
# The script would have aborted on error, so getting here means we've won.
exit 0

30
tls.c
View File

@@ -1,16 +1,16 @@
/* -*- c-file-style: "linux" -*-
*
* 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 version
* 2 as published by the Free Software Foundation.
*
*
* 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.
@@ -86,7 +86,7 @@ static void list_file (const char *fname)
strcpy(linkbuf, " -> ");
/* const-cast required for silly UNICOS headers */
len = readlink((char *) fname, linkbuf+4, sizeof(linkbuf) - 4);
if (len == -1)
if (len == -1)
failed("readlink", fname);
else
/* it's not nul-terminated */
@@ -99,7 +99,7 @@ static void list_file (const char *fname)
if (buf.st_mtime) {
mt = gmtime(&buf.st_mtime);
sprintf(datebuf, "%04d-%02d-%02d %02d:%02d:%02d",
mt->tm_year + 1900,
mt->tm_mon + 1,
@@ -110,18 +110,16 @@ static void list_file (const char *fname)
} else {
strcpy(datebuf, " ");
}
/* TODO: Perhaps escape special characters in fname? */
printf("%s ", permbuf);
if (IS_DEVICE(buf.st_mode)) {
printf("%5ld,%6ld",
(long)major(buf.st_rdev),
(long)minor(buf.st_rdev));
} else /* NB: use double for size since it might not fit in a long. */
printf("%12.0f", (double)buf.st_size);
printf(" %6ld.%-6ld %6ld %s %s%s\n",
(long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
/* NB: need to pass size as a double because it might be be
* too large for a long. */
printf("%s %12.0f %6ld.%-6ld %6d %s %s%s\n",
permbuf, (double) buf.st_size,
(long) buf.st_uid, (long) buf.st_gid,
buf.st_nlink,
datebuf, fname, linkbuf);
}

81
token.c
View File

@@ -51,7 +51,7 @@ void set_compression(char *fname)
strlower(fname);
for (tok=strtok(dont," ");tok;tok=strtok(NULL," ")) {
if (wildmatch(tok, fname)) {
if (fnmatch(tok, fname, 0) == 0) {
compression_level = 0;
break;
}
@@ -90,8 +90,8 @@ 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;
extern int write_batch; /* dw */
int hold_int; /* dw */
if (n > 0) {
int l = 0;
@@ -100,8 +100,8 @@ static void simple_send_token(int f,int token,
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);
write_batch_delta_file( (char *) &n1, sizeof(int) );
write_batch_delta_file(map_ptr(buf,offset+l,n1),n1);
}
l += n1;
}
@@ -110,8 +110,8 @@ static void simple_send_token(int f,int 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) );
hold_int = -(token+1);
write_batch_delta_file( (char *) &hold_int, sizeof(int) );
}
}
}
@@ -127,12 +127,6 @@ static void simple_send_token(int f,int token,
#define MAX_DATA_COUNT 16383 /* fit 14 bit count into 2 bytes with flags */
/* zlib.h says that if we want to be able to compress something in a single
* call, avail_out must be at least 0.1% larger than avail_in plus 12 bytes.
* We'll add in 0.1%+16, just to be safe (and we'll avoid floating point,
* to ensure that this is a compile-time value). */
#define AVAIL_OUT_SIZE(avail_in_size) ((avail_in_size)*1001/1000+16)
/* For coding runs of tokens */
static int last_token = -1;
static int run_start;
@@ -144,14 +138,6 @@ static z_stream tx_strm;
/* Output buffer */
static char *obuf;
/* We want obuf to be able to hold both MAX_DATA_COUNT+2 bytes as well as
* AVAIL_OUT_SIZE(CHUNK_SIZE) bytes, so make sure that it's large enough. */
#if MAX_DATA_COUNT+2 > AVAIL_OUT_SIZE(CHUNK_SIZE)
#define OBUF_SIZE (MAX_DATA_COUNT+2)
#else
#define OBUF_SIZE AVAIL_OUT_SIZE(CHUNK_SIZE)
#endif
/* Send a deflated token */
static void
send_deflated_token(int f, int token,
@@ -159,8 +145,8 @@ send_deflated_token(int f, int token,
{
int n, r;
static int init_done, flush_pending;
extern int write_batch;
char temp_byte;
extern int write_batch; /* dw */
char temp_byte; /* dw */
if (last_token == -1) {
/* initialization */
@@ -174,7 +160,7 @@ send_deflated_token(int f, int token,
rprintf(FERROR, "compression init failed\n");
exit_cleanup(RERR_STREAMIO);
}
if ((obuf = new_array(char, OBUF_SIZE)) == NULL)
if ((obuf = new_array(char, MAX_DATA_COUNT+2)) == NULL)
out_of_memory("send_deflated_token");
init_done = 1;
} else
@@ -193,27 +179,26 @@ 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));
if (write_batch) { /* dw */
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 (write_batch) { /* dw */
temp_byte = (char)(n==0? TOKEN_LONG: TOKENRUN_LONG);
write_batch_delta_file(&temp_byte,sizeof(temp_byte));
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));
if (write_batch) { /* dw */
write_batch_delta_file((char *)&n,sizeof(char));
temp_byte = (char) n >> 8;
write_batch_delta_file(&temp_byte,sizeof(temp_byte));
}
}
last_run_end = last_token;
@@ -273,8 +258,8 @@ 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);
if (write_batch) /* dw */
write_batch_delta_file(obuf,n+2);
}
}
} while (nb != 0 || tx_strm.avail_out == 0);
@@ -284,9 +269,9 @@ 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));
if (write_batch) { /* dw */
temp_byte = END_FLAG;
write_batch_delta_file((char *)&temp_byte,sizeof(temp_byte));
}
} else if (token != -2) {
@@ -295,7 +280,7 @@ send_deflated_token(int f, int token,
tx_strm.next_in = (Bytef *) map_ptr(buf, offset, toklen);
tx_strm.avail_in = toklen;
tx_strm.next_out = (Bytef *) obuf;
tx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE);
tx_strm.avail_out = MAX_DATA_COUNT;
r = deflate(&tx_strm, Z_INSERT_ONLY);
if (r != Z_OK || tx_strm.avail_in != 0) {
rprintf(FERROR, "deflate on token returned %d (%d bytes left)\n",
@@ -338,7 +323,7 @@ recv_deflated_token(int f, char **data)
exit_cleanup(RERR_STREAMIO);
}
if (!(cbuf = new_array(char, MAX_DATA_COUNT))
|| !(dbuf = new_array(char, AVAIL_OUT_SIZE(CHUNK_SIZE))))
|| !(dbuf = new_array(char, CHUNK_SIZE)))
out_of_memory("recv_deflated_token");
init_done = 1;
} else {
@@ -367,9 +352,9 @@ recv_deflated_token(int f, char **data)
/* check previous inflated stuff ended correctly */
rx_strm.avail_in = 0;
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE);
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_SYNC_FLUSH);
n = AVAIL_OUT_SIZE(CHUNK_SIZE) - rx_strm.avail_out;
n = CHUNK_SIZE - rx_strm.avail_out;
/*
* Z_BUF_ERROR just means no progress was
* made, i.e. the decompressor didn't have
@@ -423,9 +408,9 @@ recv_deflated_token(int f, char **data)
case r_inflating:
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE);
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_NO_FLUSH);
n = AVAIL_OUT_SIZE(CHUNK_SIZE) - rx_strm.avail_out;
n = CHUNK_SIZE - rx_strm.avail_out;
if (r != Z_OK) {
rprintf(FERROR, "inflate returned %d (%d bytes)\n", r, n);
exit_cleanup(RERR_STREAMIO);
@@ -480,7 +465,7 @@ static void see_deflate_token(char *buf, int len)
}
}
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE);
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_SYNC_FLUSH);
if (r != Z_OK) {
rprintf(FERROR, "inflate (token) returned %d\n", r);

335
uidlist.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.
@@ -19,19 +19,12 @@
/* handle the mapping of uid/gid and user/group names between systems.
If the source username/group does not exist on the target then use
the numeric IDs. Never do any mapping for uid=0 or gid=0 as these
the numeric ids. Never do any mapping for uid=0 or gid=0 as these
are special.
*/
#include "rsync.h"
#ifdef HAVE_GETGROUPS
# if !defined(GETGROUPS_T)
# define GETGROUPS_T gid_t
# endif
#endif
extern int verbose;
extern int preserve_uid;
extern int preserve_gid;
extern int numeric_ids;
@@ -46,26 +39,24 @@ struct idlist {
static struct idlist *uidlist;
static struct idlist *gidlist;
static struct idlist *add_to_list(struct idlist **root, int id, char *name,
int id2)
static struct idlist *add_list(int id, char *name)
{
struct idlist *node = new(struct idlist);
if (!node)
out_of_memory("add_to_list");
node->next = *root;
node->name = name;
node->id = id;
node->id2 = id2;
*root = node;
return node;
struct idlist *list = new(struct idlist);
if (!list) out_of_memory("add_list");
list->next = NULL;
list->name = strdup(name);
if (!list->name) out_of_memory("add_list");
list->id = (int)id;
return list;
}
/* turn a uid into a user name */
static char *uid_to_name(uid_t uid)
{
struct passwd *pass = getpwuid(uid);
if (pass)
return strdup(pass->pw_name);
if (pass) return(pass->pw_name);
return NULL;
}
@@ -73,15 +64,14 @@ static char *uid_to_name(uid_t uid)
static char *gid_to_name(gid_t gid)
{
struct group *grp = getgrgid(gid);
if (grp)
return strdup(grp->gr_name);
if (grp) return(grp->gr_name);
return NULL;
}
static int map_uid(int id, char *name)
{
uid_t uid;
if (uid != 0 && name_to_uid(name, &uid))
if (name_to_uid(name, &uid) && uid != 0)
return uid;
return id;
}
@@ -89,180 +79,113 @@ 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 (name_to_gid(name, &gid) && gid != 0)
return gid;
return id;
}
static int is_in_group(gid_t gid)
{
#ifdef HAVE_GETGROUPS
static gid_t last_in = GID_NONE, last_out;
static int ngroups = -2;
static GETGROUPS_T *gidset;
int n;
if (gid == last_in)
return last_out;
if (ngroups < -1) {
gid_t mygid = MY_GID();
if ((ngroups = getgroups(0, NULL)) < 0)
ngroups = 0;
gidset = new_array(GETGROUPS_T, ngroups+1);
if (!gidset)
out_of_memory("is_in_group");
if (ngroups > 0)
ngroups = getgroups(ngroups, gidset);
/* The default gid might not be in the list on some systems. */
for (n = 0; n < ngroups; n++) {
if (gidset[n] == mygid)
break;
}
if (n == ngroups)
gidset[ngroups++] = mygid;
if (verbose > 3) {
int pos;
char *gidbuf = new_array(char, ngroups*21+32);
if (!gidbuf)
out_of_memory("is_in_group");
sprintf(gidbuf, "process has %d gid%s: ",
ngroups, ngroups == 1? "" : "s");
pos = strlen(gidbuf);
for (n = 0; n < ngroups; n++) {
sprintf(gidbuf+pos, " %d", (int)gidset[n]);
pos += strlen(gidbuf+pos);
}
rprintf(FINFO, "%s\n", gidbuf);
free(gidbuf);
}
}
last_in = gid;
for (n = 0; n < ngroups; n++) {
if (gidset[n] == gid)
return last_out = 1;
}
return last_out = 0;
#else
static gid_t mygid = GID_NONE;
if (mygid == GID_NONE) {
mygid = MY_GID();
if (verbose > 3)
rprintf(FINFO, "process has gid %d\n", (int)mygid);
}
return gid == mygid;
#endif
}
/* Add a uid to the list of uids. Only called on receiving side. */
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));
if (verbose > 3) {
rprintf(FINFO, "uid %d(%s) maps to %d\n",
id, name ? name : "", id2);
}
return node;
}
/* Add a gid to the list of gids. Only called on receiving side. */
static struct idlist *recv_add_gid(int id, char *name)
{
int id2 = name ? map_gid(id, name) : id;
struct idlist *node;
if (!am_root && !is_in_group(id2))
id2 = GID_NONE;
node = add_to_list(&gidlist, id, name, id2);
if (verbose > 3) {
rprintf(FINFO, "gid %d(%s) maps to %d\n",
id, name ? name : "", id2);
}
return node;
}
/* this function is a definate candidate for a faster algorithm */
static uid_t match_uid(uid_t uid)
{
static uid_t last_in, last_out;
struct idlist *list;
struct idlist *list = uidlist;
if (uid == 0)
return 0;
if (uid == last_in)
return last_out;
if (uid == last_in) return last_out;
last_in = uid;
for (list = uidlist; list; list = list->next) {
if (list->id == (int)uid)
return last_out = (uid_t)list->id2;
while (list) {
if (list->id == (int)uid) {
last_out = (uid_t)list->id2;
return last_out;
}
list = list->next;
}
return last_out = uid;
last_out = uid;
return last_out;
}
static gid_t match_gid(gid_t gid)
{
static gid_t last_in = GID_NONE, last_out = GID_NONE;
struct idlist *list;
static gid_t last_in, last_out;
struct idlist *list = gidlist;
if (gid == GID_NONE)
return GID_NONE;
if (gid == last_in)
return last_out;
if (gid == last_in) return last_out;
last_in = gid;
for (list = gidlist; list; list = list->next) {
if (list->id == (int)gid)
return last_out = (gid_t)list->id2;
while (list) {
if (list->id == (int)gid) {
last_out = (gid_t)list->id2;
return last_out;
}
list = list->next;
}
list = recv_add_gid(gid, NULL);
return last_out = list->id2;
if (am_root)
last_out = gid;
else
last_out = (gid_t) -1;
return last_out;
}
/* Add a uid to the list of uids. Only called on sending side. */
/* add a uid to the list of uids */
void add_uid(uid_t uid)
{
struct idlist *list;
struct idlist *list = uidlist;
char *name;
if (uid == 0) /* don't map root */
if (numeric_ids) return;
/* don't map root */
if (uid==0) return;
if (!list) {
if (!(name = uid_to_name(uid))) return;
uidlist = add_list((int)uid, name);
return;
for (list = uidlist; list; list = list->next) {
if (list->id == (int)uid)
return;
}
add_to_list(&uidlist, (int)uid, uid_to_name(uid), 0);
while (list->next) {
if (list->id == (int)uid) return;
list = list->next;
}
if (list->id == (int)uid) return;
if (!(name = uid_to_name(uid))) return;
list->next = add_list((int)uid, name);
}
/* Add a gid to the list of gids. Only called on sending side. */
/* add a gid to the list of gids */
void add_gid(gid_t gid)
{
struct idlist *list;
struct idlist *list = gidlist;
char *name;
if (gid == 0) /* don't map root */
if (numeric_ids) return;
/* don't map root */
if (gid==0) return;
if (!list) {
if (!(name = gid_to_name(gid))) return;
gidlist = add_list((int)gid, name);
return;
for (list = gidlist; list; list = list->next) {
if (list->id == (int)gid)
return;
}
add_to_list(&gidlist, (int)gid, gid_to_name(gid), 0);
while (list->next) {
if (list->id == (int)gid) return;
list = list->next;
}
if (list->id == (int)gid) return;
if (!(name = gid_to_name(gid))) return;
list->next = add_list((int)gid, name);
}
@@ -271,80 +194,102 @@ void send_uid_list(int f)
{
struct idlist *list;
if (numeric_ids)
return;
if (numeric_ids) return;
if (preserve_uid) {
int len;
/* we send sequences of uid/byte-length/name */
for (list = uidlist; list; list = list->next) {
if (!list->name)
continue;
len = strlen(list->name);
list = uidlist;
while (list) {
int len = strlen(list->name);
write_int(f, list->id);
write_byte(f, len);
write_buf(f, list->name, len);
list = list->next;
}
/* terminate the uid list with a 0 uid. We explicitly exclude
* 0 from the list */
0 from the list */
write_int(f, 0);
}
if (preserve_gid) {
int len;
for (list = gidlist; list; list = list->next) {
if (!list->name)
continue;
len = strlen(list->name);
list = gidlist;
while (list) {
int len = strlen(list->name);
write_int(f, list->id);
write_byte(f, len);
write_buf(f, list->name, len);
list = list->next;
}
write_int(f, 0);
}
}
/* recv a complete uid/gid mapping from the peer and map the uid/gid
* in the file list to local names */
in the file list to local names */
void recv_uid_list(int f, struct file_list *flist)
{
int id, i;
char *name;
struct idlist *list;
if (preserve_uid && !numeric_ids) {
if (numeric_ids) return;
if (preserve_uid) {
/* read the uid list */
while ((id = read_int(f)) != 0) {
list = uidlist;
id = read_int(f);
while (id != 0) {
int len = read_byte(f);
name = new_array(char, len+1);
if (!name)
out_of_memory("recv_uid_list");
if (!name) out_of_memory("recv_uid_list");
read_sbuf(f, name, len);
recv_add_uid(id, name); /* node keeps name's memory */
if (!list) {
uidlist = add_list(id, name);
list = uidlist;
} else {
list->next = add_list(id, name);
list = list->next;
}
list->id2 = map_uid(id, name);
free(name);
id = read_int(f);
}
}
if (preserve_gid && !numeric_ids) {
/* read the gid list */
while ((id = read_int(f)) != 0) {
if (preserve_gid) {
/* and the gid list */
list = gidlist;
id = read_int(f);
while (id != 0) {
int len = read_byte(f);
name = new_array(char, len+1);
if (!name)
out_of_memory("recv_uid_list");
if (!name) out_of_memory("recv_uid_list");
read_sbuf(f, name, len);
recv_add_gid(id, name); /* node keeps name's memory */
if (!list) {
gidlist = add_list(id, name);
list = gidlist;
} else {
list->next = add_list(id, name);
list = list->next;
}
list->id2 = map_gid(id, name);
free(name);
id = read_int(f);
}
}
if (!(am_root && preserve_uid) && !preserve_gid) return;
/* now convert the uid/gid of all files in the list to the mapped
* uid/gid */
if (am_root && preserve_uid && !numeric_ids) {
for (i = 0; i < flist->count; i++)
uid/gid */
for (i=0;i<flist->count;i++) {
if (am_root && preserve_uid && flist->files[i]->uid != 0) {
flist->files[i]->uid = match_uid(flist->files[i]->uid);
}
if (preserve_gid && (!am_root || !numeric_ids)) {
for (i = 0; i < flist->count; i++)
}
if (preserve_gid && flist->files[i]->gid != 0) {
flist->files[i]->gid = match_gid(flist->files[i]->gid);
}
}
}

401
util.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.
@@ -22,13 +22,12 @@
/**
* @file
*
* Utilities used in rsync
* Utilities used in rsync
**/
#include "rsync.h"
extern int verbose;
extern struct exclude_list_struct server_exclude_list;
int sanitize_paths = 0;
@@ -68,7 +67,7 @@ void set_blocking(int fd)
/**
* Create a file descriptor pair - like pipe() but use socketpair if
* possible (because of blocking issues on pipes).
*
*
* Always set non-blocking.
*/
int fd_pair(int fd[2])
@@ -112,14 +111,14 @@ void print_child_argv(char **cmd)
void out_of_memory(char *str)
{
rprintf(FERROR, "ERROR: out of memory in %s\n", str);
exit_cleanup(RERR_MALLOC);
rprintf(FERROR,"ERROR: out of memory in %s\n",str);
exit_cleanup(RERR_MALLOC);
}
void overflow(char *str)
{
rprintf(FERROR, "ERROR: buffer overflow in %s\n", str);
exit_cleanup(RERR_MALLOC);
rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
exit_cleanup(RERR_MALLOC);
}
@@ -135,10 +134,10 @@ int set_modtime(char *fname, time_t modtime)
fname, (long) modtime,
asctime(localtime(&modtime)));
}
{
#ifdef HAVE_UTIMBUF
struct utimbuf tbuf;
struct utimbuf tbuf;
tbuf.actime = time(NULL);
tbuf.modtime = modtime;
return utime(fname,&tbuf);
@@ -168,15 +167,13 @@ int create_directory_path(char *fname, int base_umask)
{
char *p;
while (*fname == '/')
fname++;
while (strncmp(fname, "./", 2) == 0)
fname += 2;
while (*fname == '/') fname++;
while (strncmp(fname,"./",2)==0) fname += 2;
p = fname;
while ((p = strchr(p,'/')) != NULL) {
while ((p=strchr(p,'/'))) {
*p = 0;
do_mkdir(fname, 0777 & ~base_umask);
do_mkdir(fname, 0777 & ~base_umask);
*p = '/';
p++;
}
@@ -197,13 +194,15 @@ int create_directory_path(char *fname, int base_umask)
static int full_write(int desc, char *ptr, size_t len)
{
int total_written;
total_written = 0;
while (len > 0) {
int written = write(desc, ptr, len);
int written = write (desc, ptr, len);
if (written < 0) {
#ifdef EINTR
if (errno == EINTR)
continue;
#endif
return written;
}
total_written += written;
@@ -228,14 +227,18 @@ static int full_write(int desc, char *ptr, size_t len)
static int safe_read(int desc, char *ptr, size_t len)
{
int n_chars;
if (len == 0)
return len;
#ifdef EINTR
do {
n_chars = read(desc, ptr, len);
} while (n_chars < 0 && errno == EINTR);
#else
n_chars = read(desc, ptr, len);
#endif
return n_chars;
}
@@ -271,7 +274,7 @@ int copy_file(char *source, char *dest, mode_t mode)
return -1;
}
while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
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));
@@ -317,15 +320,17 @@ int robust_unlink(char *fname)
char path[MAXPATHLEN];
rc = do_unlink(fname);
if (rc == 0 || errno != ETXTBSY)
if ((rc == 0) || (errno != ETXTBSY))
return rc;
if ((pos = strlcpy(path, fname, MAXPATHLEN)) >= MAXPATHLEN)
pos = MAXPATHLEN - 1;
strlcpy(path, fname, MAXPATHLEN);
while (pos > 0 && path[pos-1] != '/')
pos--;
pos += strlcpy(path+pos, ".rsync", MAXPATHLEN-pos);
pos = strlen(path);
while((path[--pos] != '/') && (pos >= 0))
;
++pos;
strlcpy(&path[pos], ".rsync", MAXPATHLEN-pos);
pos += sizeof(".rsync")-1;
if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
errno = ETXTBSY;
@@ -338,12 +343,11 @@ int robust_unlink(char *fname)
sprintf(&path[pos], "%03d", counter);
if (++counter >= MAX_RENAMES)
counter = 1;
} while ((rc = access(path, 0)) == 0 && counter != start);
} while (((rc = access(path, 0)) == 0) && (counter != start));
if (verbose > 0) {
if (verbose > 0)
rprintf(FINFO,"renaming %s to %s because of text busy\n",
fname, path);
}
fname, path);
/* maybe we should return rename()'s exit status? Nah. */
if (do_rename(fname, path) != 0) {
@@ -354,33 +358,18 @@ 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. */
int robust_rename(char *from, char *to, int mode)
int robust_rename(char *from, char *to)
{
int tries = 4;
while (tries--) {
if (do_rename(from, to) == 0)
return 0;
switch (errno) {
#ifdef ETXTBSY
case ETXTBSY:
if (robust_unlink(to) != 0)
return -1;
break;
#ifndef ETXTBSY
return do_rename(from, to);
#else
int rc = do_rename(from, to);
if ((rc == 0) || (errno != ETXTBSY))
return rc;
if (robust_unlink(to) != 0)
return -1;
return do_rename(from, to);
#endif
case EXDEV:
if (copy_file(from, to, mode) != 0)
return -2;
do_unlink(from);
return 0;
default:
return -1;
}
}
return -1;
}
@@ -391,7 +380,7 @@ static int num_pids;
pid_t do_fork(void)
{
pid_t newpid = fork();
if (newpid != 0 && newpid != -1) {
all_pids[num_pids++] = newpid;
}
@@ -465,34 +454,18 @@ int lock_range(int fd, int offset, int len)
lock.l_start = offset;
lock.l_len = len;
lock.l_pid = 0;
return fcntl(fd,F_SETLK,&lock) == 0;
}
static int exclude_server_path(char *arg)
{
char *s;
if (server_exclude_list.head) {
for (s = arg; (s = strchr(s, '/')) != NULL; ) {
*s = '\0';
if (check_exclude(&server_exclude_list, arg, 1) < 0) {
/* We must leave arg truncated! */
return 1;
}
*s++ = '/';
}
}
return 0;
}
static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
{
#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
if (!*s) s = ".";
s = argv[*argc] = strdup(s);
exclude_server_path(s);
argv[*argc] = strdup(s);
(*argc)++;
return;
#else
extern int sanitize_paths;
glob_t globbuf;
@@ -500,60 +473,54 @@ static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
if (!*s) s = ".";
s = argv[*argc] = strdup(s);
argv[*argc] = strdup(s);
if (sanitize_paths) {
sanitize_path(s, NULL);
sanitize_path(argv[*argc], NULL);
}
memset(&globbuf, 0, sizeof globbuf);
if (!exclude_server_path(s))
glob(s, 0, NULL, &globbuf);
memset(&globbuf, 0, sizeof(globbuf));
glob(argv[*argc], 0, NULL, &globbuf);
if (globbuf.gl_pathc == 0) {
(*argc)++;
globfree(&globbuf);
return;
}
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");
for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
if (i == 0) free(argv[*argc]);
argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
if (!argv[(*argc) + i]) out_of_memory("glob_expand");
}
globfree(&globbuf);
*argc += i;
(*argc) += i;
#endif
}
/* This routine is only used in daemon mode. */
void glob_expand(char *base1, char **argv, int *argc, int maxargs)
{
char *s = argv[*argc];
char *p, *q;
char *base = base1;
int base_len = strlen(base);
if (!s || !*s) return;
if (strncmp(s, base, base_len) == 0)
s += base_len;
if (strncmp(s, base, strlen(base)) == 0) {
s += strlen(base);
}
s = strdup(s);
if (!s) 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) {
while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
/* split it at this point */
*p = 0;
glob_expand_one(q, argv, argc, maxargs);
q = p + base_len;
q = p+strlen(base);
}
if (*q && *argc < maxargs)
glob_expand_one(q, argv, argc, maxargs);
if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
free(s);
free(base);
@@ -571,58 +538,6 @@ void strlower(char *s)
}
}
/* Join strings p1 & p2 into "dest" with a guaranteed '/' between them. (If
* p1 ends with a '/', no extra '/' is inserted.) Returns the length of both
* strings + 1 (if '/' was inserted), regardless of whether the null-terminated
* string fits into destsize. */
size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2)
{
size_t len = strlcpy(dest, p1, destsize);
if (len < destsize - 1) {
if (!len || dest[len-1] != '/')
dest[len++] = '/';
if (len < destsize - 1)
len += strlcpy(dest + len, p2, destsize - len);
else {
dest[len] = '\0';
len += strlen(p2);
}
}
else
len += strlen(p2) + 1; /* Assume we'd insert a '/'. */
return len;
}
/* Join any number of strings together, putting them in "dest". The return
* value is the length of all the strings, regardless of whether the null-
* terminated whole fits in destsize. Your list of string pointers must end
* with a NULL to indicate the end of the list. */
size_t stringjoin(char *dest, size_t destsize, ...)
{
va_list ap;
size_t len, ret = 0;
const char *src;
va_start(ap, destsize);
while (1) {
if (!(src = va_arg(ap, const char *)))
break;
len = strlen(src);
ret += len;
if (destsize > 1) {
if (len >= destsize)
len = destsize - 1;
memcpy(dest, src, len);
destsize -= len;
dest += len;
}
}
*dest = '\0';
va_end(ap);
return ret;
}
void clean_fname(char *name)
{
char *p;
@@ -634,7 +549,7 @@ void clean_fname(char *name)
while (modified) {
modified = 0;
if ((p = strstr(name,"/./")) != NULL) {
if ((p=strstr(name,"/./"))) {
modified = 1;
while (*p) {
p[0] = p[2];
@@ -642,7 +557,7 @@ void clean_fname(char *name)
}
}
if ((p = strstr(name,"//")) != NULL) {
if ((p=strstr(name,"//"))) {
modified = 1;
while (*p) {
p[0] = p[1];
@@ -650,14 +565,14 @@ void clean_fname(char *name)
}
}
if (strncmp(p = name, "./", 2) == 0) {
if (strncmp(p=name,"./",2) == 0) {
modified = 1;
do {
p[0] = p[2];
} while (*p++);
}
l = strlen(p = name);
l = strlen(p=name);
if (l > 1 && p[l-1] == '/') {
modified = 1;
p[l-1] = 0;
@@ -716,7 +631,7 @@ void sanitize_path(char *p, char *reldir)
* both p (and sanp if the original had a slash) should
* always be left pointing after a slash
*/
if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
/* skip "." component */
while (*++p == '/') {
/* skip following slashes */
@@ -725,9 +640,10 @@ void sanitize_path(char *p, char *reldir)
continue;
}
allowdotdot = 0;
if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
if ((*p == '.') && (*(p+1) == '.') &&
((*(p+2) == '/') || (*(p+2) == '\0'))) {
/* ".." component followed by slash or end */
if (depth > 0 && sanp == start) {
if ((depth > 0) && (sanp == start)) {
/* allow depth levels of .. at the beginning */
--depth;
allowdotdot = 1;
@@ -738,7 +654,7 @@ void sanitize_path(char *p, char *reldir)
if (sanp != start) {
/* back up sanp one level */
--sanp; /* now pointing at slash */
while (sanp > start && sanp[-1] != '/') {
while ((sanp > start) && (*(sanp - 1) != '/')) {
/* skip back up to slash */
sanp--;
}
@@ -749,7 +665,7 @@ void sanitize_path(char *p, char *reldir)
while (1) {
/* copy one component through next slash */
*sanp++ = *p++;
if (*p == '\0' || p[-1] == '/') {
if ((*p == '\0') || (*(p-1) == '/')) {
while (*p == '/') {
/* skip multiple slashes */
p++;
@@ -762,7 +678,7 @@ void sanitize_path(char *p, char *reldir)
start = sanp;
}
}
if (sanp == start && !allowdotdot) {
if ((sanp == start) && !allowdotdot) {
/* ended up with nothing, so put in "." component */
/*
* note that the !allowdotdot doesn't prevent this from
@@ -775,146 +691,59 @@ void sanitize_path(char *p, char *reldir)
*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;
}
char curr_dir[MAXPATHLEN];
unsigned int curr_dir_len;
static char curr_dir[MAXPATHLEN];
/**
* Like chdir(), but it keeps track of the current directory (in the
* global "curr_dir"), and ensures that the path size doesn't overflow.
* Also cleans the path using the clean_fname() function.
* Like chdir() but can be reversed with pop_dir() if @p save is set.
* It is also much faster as it remembers where we have been.
**/
int push_dir(char *dir)
char *push_dir(char *dir, int save)
{
char *ret = curr_dir;
static int initialised;
unsigned int len;
if (!initialised) {
initialised = 1;
getcwd(curr_dir, sizeof curr_dir - 1);
curr_dir_len = strlen(curr_dir);
getcwd(curr_dir, sizeof(curr_dir)-1);
}
if (!dir) /* this call was probably just to initialize */
return 0;
if (!dir) return NULL; /* this call was probably just to initialize */
len = strlen(dir);
if (len == 1 && *dir == '.')
return 1;
if (chdir(dir)) return NULL;
if ((*dir == '/' ? len : curr_dir_len + 1 + len) >= sizeof curr_dir)
return 0;
if (chdir(dir))
return 0;
if (save) {
ret = strdup(curr_dir);
}
if (*dir == '/') {
memcpy(curr_dir, dir, len + 1);
curr_dir_len = len;
strlcpy(curr_dir, dir, sizeof(curr_dir));
} else {
curr_dir[curr_dir_len++] = '/';
memcpy(curr_dir + curr_dir_len, dir, len + 1);
curr_dir_len += len;
strlcat(curr_dir,"/", sizeof(curr_dir));
strlcat(curr_dir,dir, sizeof(curr_dir));
}
clean_fname(curr_dir);
return 1;
return ret;
}
/**
* Reverse a push_dir() call. You must pass in an absolute path
* that was copied from a prior value of "curr_dir".
**/
/** Reverse a push_dir() call */
int pop_dir(char *dir)
{
if (chdir(dir))
return 0;
int ret;
curr_dir_len = strlcpy(curr_dir, dir, sizeof curr_dir);
if (curr_dir_len >= sizeof curr_dir)
curr_dir_len = sizeof curr_dir - 1;
return 1;
}
/**
* 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)
{
extern int module_id;
static char *result = NULL;
char *m1, *m2, *m3;
char *p1, *p2;
if (result)
free(result);
if (*fn == '/')
p1 = p2 = "";
else {
p1 = curr_dir;
p2 = "/";
ret = chdir(dir);
if (ret) {
free(dir);
return ret;
}
if (module_id >= 0) {
m1 = " (in ";
m2 = lp_name(module_id);
m3 = ")";
if (*p1) {
if (!lp_use_chroot(module_id)) {
char *p = lp_path(module_id);
if (*p != '/' || p[1])
p1 += strlen(p);
}
if (!*p1)
p2++;
else
p1++;
}
else
fn++;
} else
m1 = m2 = m3 = "";
asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3);
strlcpy(curr_dir, dir, sizeof(curr_dir));
return result;
free(dir);
return 0;
}
/** We need to supply our own strcmp function for file list comparisons
@@ -927,7 +756,7 @@ int u_strcmp(const char *cs1, const char *cs2)
while (*s1 && *s2 && (*s1 == *s2)) {
s1++; s2++;
}
return (int)*s1 - (int)*s2;
}
@@ -968,7 +797,7 @@ int unsafe_symlink(const char *dest, const char *src)
/* find out what our safety margin is */
for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
if (strncmp(name, "../", 3) == 0) {
depth = 0;
depth=0;
} else if (strncmp(name, "./", 2) == 0) {
/* nothing */
} else {
@@ -1006,9 +835,9 @@ char *timestring(time_t t)
struct tm *tm = localtime(&t);
#ifdef HAVE_STRFTIME
strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm);
strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
#else
strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf);
strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
#endif
if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
@@ -1027,21 +856,21 @@ char *timestring(time_t t)
**/
int msleep(int t)
{
int tdiff = 0;
struct timeval tval, t1, t2;
int tdiff=0;
struct timeval tval,t1,t2;
gettimeofday(&t1, NULL);
gettimeofday(&t2, NULL);
while (tdiff < t) {
tval.tv_sec = (t-tdiff)/1000;
tval.tv_usec = 1000*((t-tdiff)%1000);
errno = 0;
select(0,NULL,NULL, NULL, &tval);
gettimeofday(&t2, NULL);
tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
(t2.tv_usec - t1.tv_usec)/1000;
}
@@ -1087,7 +916,7 @@ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
int ret;
char *cmd;
asprintf(&cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'",
asprintf(&cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'",
getpid(), getpid(), getpid());
if (!fn) {

View File

@@ -19,6 +19,9 @@ int wildmatch_errors = 0;
typedef char bool;
#define false 0
#define true 1
int output_iterations = 0;
static struct poptOption long_options[] = {
@@ -81,14 +84,8 @@ main(int argc, char **argv)
}
}
argv = (char**)poptGetArgs(pc);
if (!argv || argv[1]) {
fprintf(stderr, "Usage: wildtest TESTFILE\n");
exit(1);
}
if ((fp = fopen(*argv, "r")) == NULL) {
fprintf(stderr, "Unable to open %s\n", *argv);
if ((fp = fopen("wildtest.txt", "r")) == NULL) {
fprintf(stderr, "Unable to open wildtest.txt.\n");
exit(1);
}
@@ -107,8 +104,8 @@ main(int argc, char **argv)
if (*++s != ' ' && *s != '\t')
flag[i] = -1;
if (flag[i] < 0) {
fprintf(stderr, "Invalid flag syntax on line %d of %s:\n%s",
line, *argv, buf);
fprintf(stderr, "Invalid flag syntax on line %d of wildtest.txt:%s\n",
line, buf);
exit(1);
}
while (*++s == ' ' || *s == '\t') {}
@@ -119,16 +116,16 @@ main(int argc, char **argv)
string[i] = s;
while (*s && *s != quote) s++;
if (!*s) {
fprintf(stderr, "Unmatched quote on line %d of %s:\n%s",
line, *argv, buf);
fprintf(stderr, "Unmatched quote on line %d of wildtest.txt:%s\n",
line, buf);
exit(1);
}
end[i] = s;
}
else {
if (!*s || *s == '\n') {
fprintf(stderr, "Not enough strings on line %d of %s:\n%s",
line, *argv, buf);
fprintf(stderr, "Not enough strings on line %d of wildtest.txt:%s\n",
line, buf);
exit(1);
}
string[i] = s;