Compare commits

...

202 Commits

Author SHA1 Message Date
rsync-bugs
86a2dd0a0a preparing for release of 2.2.1 1998-11-25 16:24:56 +00:00
David Dykstra
63f0774f75 Back out change that treated "refuse options = compress" the same as
"dont compress = *", by request of Tridge.  Instead, mention the difference
in the man page.  Also, put in a shortcut in set_compression() to recognize
"*" earlier instead of going through malloc/strtok/fnmatch/free cycle.
1998-11-25 15:37:50 +00:00
David Dykstra
d47741cac6 When "refuse options = compress" is set in rsyncd.conf, silently send files
at compression level 0 instead of printing an error and exitting.  This is
the same effect as "dont compress = *".
1998-11-24 22:03:16 +00:00
David Dykstra
5d5811f7d9 Always include "." when processing exclude lists. This avoids confusion
when people do --exclude "*".  Also, add an example to the man page that
shows explicitly including parent directories when itemizing specific
paths to include followed by --exclude "*".
1998-11-24 21:26:38 +00:00
David Dykstra
dcc3a131d1 Update the README file to reflect current usage options. 1998-11-24 20:54:56 +00:00
David Dykstra
7212be9237 Don't list cleaned-out duplicate file names as "<NULL>" when doing
list_only mode; skip them instead.
1998-11-24 20:51:45 +00:00
David Dykstra
44e2e57837 Change sanitize_path() function to not malloc a copy since it only shrinks
paths and it is only used in places that have already just done a copy.
1998-11-24 20:18:11 +00:00
David Dykstra
d1be231290 Make sure secrets file is not other-accessible, and owned by root if the
daemon is running as root.  Suggested by
    Mike Richardson <mike@quaking.demon.co.uk>
1998-11-24 19:52:35 +00:00
David Dykstra
a926daecbf Always add the O_BINARY flag in do_open if it is defined, for Windows.
Suggestion from Mart.Laak@hansa.ee
1998-11-24 19:10:21 +00:00
David Dykstra
53dd3135f1 Backup deleted files when using --delete and --backup. Based on a
suggested patch from Kanai Makoto (kanai@hallab.co.jp).
1998-11-24 19:01:24 +00:00
David Dykstra
cd64343a7a Add "include" and "include from" rsyncd.conf options. Contributed
by Dennis Gilbert <dennis@oit.pdx.edu>.
1998-11-23 21:54:01 +00:00
Andrew Tridgell
9e3c856a39 updates to reflect new samba.org domain
the main web site is now http://rsync.samba.org/
1998-11-23 00:30:27 +00:00
Andrew Tridgell
1e8ae5ede6 changed an example slightly 1998-11-20 22:46:42 +00:00
Andrew Tridgell
83fff1aa60 added "dont compress" option with the default setting of
*.gz *.tgz *.zip *.z *.rpm *.deb
1998-11-20 22:26:29 +00:00
Andrew Tridgell
055af77666 improved the "refuse options" code a bit 1998-11-19 06:45:21 +00:00
Andrew Tridgell
cd8185f2bd added "refuse options" option 1998-11-19 06:35:49 +00:00
David Dykstra
6bd98f0617 Look for strcasecmp in -lresolv for Unixware. 1998-11-18 17:53:22 +00:00
David Dykstra
14d43f1fcf Minor documentation patches, due mostly to
Jason Henry Parker <henry@freezer.humbug.org.au>
1998-11-18 17:36:36 +00:00
David Dykstra
3a64ad1fd0 Change --log-format documentation to make it clear that it is for the client
logging to stdout.
1998-11-18 16:20:22 +00:00
David Dykstra
5557c8e3e0 Remove a debugging statement I accidentally included in the last commit. 1998-11-18 16:02:23 +00:00
David Dykstra
baf3e5049e Change documentation to explain that a lack of -t in effect causes -I to be
assumed on the next transfer.
1998-11-18 15:54:50 +00:00
David Dykstra
b389939f87 Apply sanitize_paths() to glob expansions when use chroot = no. 1998-11-17 21:56:18 +00:00
Andrew Tridgell
af77cc6b57 don't interpret %h and %a when using --log-format locally 1998-11-16 23:50:28 +00:00
Andrew Tridgell
1309d90dde fixed a bug handling files larger than 2GB 1998-11-16 03:53:43 +00:00
Andrew Tridgell
a9766ef147 log filename(line) in exit_cleanup() to make tracking down problems
easier in rsync daemons.
1998-11-15 01:21:42 +00:00
Andrew Tridgell
5a788adec1 use native strlcat() and strlcpy() if available 1998-11-15 01:04:16 +00:00
Andrew Tridgell
50abd20bb3 compile with optimisation by default on all compilers
(the mdfour code really needs it)
1998-11-14 23:49:08 +00:00
Andrew Tridgell
37f9805dab changed strlcat() and strlcpy() to have the same semantics as the
OpenBSD functions of the same name.

changed slprintf() to take buffer length rather than buffer length -1
1998-11-14 23:31:58 +00:00
David Dykstra
b5f9e67d57 Change sanitize_path() to not use clean_fname() because it removes the
trailing slash.  This caused a problem when using "use chroot" and sources
that contained a trailing slash (which prevents the last filename component
of the source from being included in the destination).  Instead, have
sanitize_path() remove "." components and duplicated slashes ("//") itself.
1998-11-06 17:07:07 +00:00
Andrew Tridgell
ed06894a01 fixed typo 1998-11-06 10:37:10 +00:00
David Dykstra
d532c0f569 Add comment before call to mktemp saying it is deliberately chosen over
mkstemp.
1998-11-05 14:33:38 +00:00
David Dykstra
ec9df38086 Fix confusion between RERR_NOSUPPORT and RERR_UNSUPPORTED for exit codes
that indicate a feature is not supported.  Two places that are normally
ifdefed out used RERR_UNSUPPORTED whereas one other place and errcode.h
used RERR_NOSUPPORT.  Changed them all to consistently use RERR_UNSUPPORTED.
The two things that had the bad values were #ifndef SUPPORT_LINKS and
#ifdef NO_INT64.  The former is probably for non-Unix operating systems
and the latter was at least on the default Unixware compiler.
1998-11-04 16:47:33 +00:00
Andrew Tridgell
81791cfccb added timeout option in rsyncd.conf 1998-11-04 03:14:22 +00:00
Andrew Tridgell
2fb27e9146 use macros to make mdfour faster on systems that don't do inlining
well. Also helps when optimisation level is low.
1998-11-04 02:35:18 +00:00
David Dykstra
946347b8ff Remove statement in rsync.1 that a rsync:// URL can only be used if
a username is not needed.
1998-11-03 22:30:52 +00:00
rsync-bugs
c239825783 preparing for release of 2.2.0 1998-11-03 22:00:59 +00:00
David Dykstra
33e817e37e Document the fact that you can use [USER@] in an rsync URL.
Note: the same thing works for ftp and http URLs in netscape.
1998-11-03 21:58:08 +00:00
David Dykstra
1b8e662a24 Call clean_fname() in sanitize_path() to catch some more strange but
legal file name syntaxes.
1998-11-03 21:49:38 +00:00
David Dykstra
2acf81eb00 Add support for optional ":PORT" in rsync URL. 1998-11-03 21:17:40 +00:00
Andrew Tridgell
654175798b patch from Alberto Accomazzi <aaccomazzi@cfa.harvard.edu> to add
different exit codes for different conditions.
1998-11-03 07:08:27 +00:00
Andrew Tridgell
3e578a1909 documented --delete disabling on IO errors 1998-11-03 05:14:41 +00:00
Andrew Tridgell
b606265491 added the --log-format option to allow users to request arbitrary
per-file logging of interactive rsync sessions.
1998-11-03 03:48:47 +00:00
Andrew Tridgell
263cf2ed55 remove double / from filenames in display 1998-11-02 07:26:36 +00:00
Andrew Tridgell
ab7104da8f the logging wasn't showing the full prefix for filenames 1998-11-02 06:40:11 +00:00
Andrew Tridgell
1b7c47cb55 Jason told me that's its very important for his site to log exactly
how many bytes were needed to be transferred for each file. I added %b
and %c log format options to cover this. See the man page for details.
1998-11-02 04:17:56 +00:00
Andrew Tridgell
039faa8660 - document the rsync:// URL format 1998-11-02 00:55:21 +00:00
Andrew Tridgell
f7632fc60d if no local destination is provided for the transfer then provide
a "ls -l" style listing of the files that would be transferred
1998-11-02 00:52:01 +00:00
Andrew Tridgell
2f098547ea added copyright notice from Patrick Powell 1998-10-31 04:35:44 +00:00
Andrew Tridgell
c7c056410c get the date comparison the right way around 1998-10-31 00:12:59 +00:00
Andrew Tridgell
e803090538 use the orig_umask when choosing perms for the log file. 1998-10-30 23:50:12 +00:00
Andrew Tridgell
6265551a5a fixed perms on rsyncd log file 1998-10-30 23:03:08 +00:00
Andrew Tridgell
958f373550 move the time init before the logfile opening. 1998-10-30 11:18:38 +00:00
Andrew Tridgell
2c51d5deec added a perl script to summarise the rsyncd log format 1998-10-30 06:12:14 +00:00
Andrew Tridgell
97cb8dc29b added %m, %P and %u options to logging 1998-10-30 05:53:05 +00:00
Andrew Tridgell
cd957c70c4 need BIG_ENDIAN test for inet_ntoa replacement 1998-10-30 02:52:42 +00:00
Andrew Tridgell
7b3d425783 check for a broken inet_ntoa() on IRIX 1998-10-30 02:50:02 +00:00
Andrew Tridgell
b24203b323 get null termination right in logging 1998-10-30 02:43:10 +00:00
Andrew Tridgell
3472009789 get null termination right in logging 1998-10-30 02:36:05 +00:00
Andrew Tridgell
f27b53f5b5 hopefuly fix logging of "transfer interrupted" messages 1998-10-30 02:32:29 +00:00
Andrew Tridgell
e08bfe1248 added "log format" option to allow admins to choose the format for
rsyncd log file entries
1998-10-30 02:24:47 +00:00
Andrew Tridgell
74e708d85a hanle null strings in -vvv output 1998-10-30 02:23:01 +00:00
Andrew Tridgell
7597e1a96a fixed cacheing of some values (using code from Samba) 1998-10-29 23:44:30 +00:00
David Dykstra
692da0b555 Fix for systems such as Unixware that have a cc that does not support -o
with -c.
1998-10-29 22:28:56 +00:00
Andrew Tridgell
67ea0d4844 put the pid on each line of the log file to facilitate
auto-parsing. Requested by Jarkko Hietaniemi (jhi@iki.fi)
1998-10-29 11:16:51 +00:00
Andrew Tridgell
9b73d1c0e9 put the pid on each line of the log file to facilitate
auto-parsing. Requested by Jarkko Hietaniemi (jhi@iki.fi)
1998-10-29 11:11:38 +00:00
Andrew Tridgell
f3737e0648 some minor optimisations 1998-10-29 06:39:43 +00:00
Andrew Tridgell
19a013837e a change I made yesterday corrupted the displayed filename in some
cases. cosmetic fix.
1998-10-29 06:10:31 +00:00
Andrew Tridgell
d730b113f4 final change needed to get rsync working on a CRAY J90 1998-10-29 05:48:11 +00:00
Andrew Tridgell
7ae359c331 kfixed char* casts 1998-10-29 05:06:51 +00:00
Andrew Tridgell
8de330a387 changes to get rsync working on a CRAY J90. This machine doesn't have
a 4 byte integer type (short is 8 bytes). I needed to use a new md4
implementation (I used the portable one I wrote for Samba).
1998-10-29 05:01:47 +00:00
Andrew Tridgell
27d3cdbc94 syslog support in rsync daemon has been broken since I added the "log
file" option. I wonder why noone reported it? Or did everyone just use
"log file" ?
1998-10-28 10:43:31 +00:00
Andrew Tridgell
106005004e fixed handling of %.0f in replacement snprintf.c 1998-10-28 04:06:43 +00:00
Andrew Tridgell
92ad2c90c4 fixed a typo 1998-10-28 03:37:53 +00:00
Andrew Tridgell
11a5a3c704 and I thought I wasn't going to do any rsync coding for a while ...
Jason Andrade convinced me to add ftpd style logging of transfers,
enabled with a "transfer logging" option in rsyncd.conf

you can customise the format in log.c
1998-10-28 03:28:30 +00:00
David Dykstra
8bb5aa8fe8 Document the fact that --numeric-ids is implied if the source system is
a daemon using chroot.
1998-10-27 17:30:28 +00:00
David Dykstra
4040be4d60 - Define bindir and mandir as per gnu makefile standards
- Add install-strip target as per gnu makefile standards
Contributed by Fred Sanchez <wsanchez@apple.com>
1998-10-27 16:07:51 +00:00
Andrew Tridgell
a9685611e2 fixed a typecast 1998-10-27 14:19:35 +00:00
Andrew Tridgell
b280a1f47e handle OSes (such as Unicos) which use a different value for S_IFLNK 1998-10-27 14:09:28 +00:00
Andrew Tridgell
f8be5ef4cb added a vsnprintf() implementation from cvslock. See the notes on the
license at the top of lib/snprintf.c
1998-10-26 23:23:45 +00:00
David Dykstra
587cb08dc4 Fix bug in --include and --include-from which didn't work as advertised;
could only include files before if "+ " was explicitly prefixed on files
from any exclude or include option.  Also simplified the code by removing
the "orig" exclude_struct element, and reduced the number of bytes
transferred from client to server by never including "- " prefixes in the
transmitted exclude list because exclusion is the default.
1998-10-26 22:03:18 +00:00
David Dykstra
8638dd48f7 Add "use chroot" and "pid file" rsyncd.conf options. The former allows one
to disable the use of chroot so rsync --daemon can be run as a non-root
user (if a non-privileged --port is used).  The latter allows one to
specify a file in which to write the process id of the daemon, which is
useful when rsync --daemon is not run from inetd.
1998-10-26 21:51:47 +00:00
David Dykstra
2bca43f627 Optimize server for special case of a long list of includes ("+") followed
by a match-all exclude "- *".
1998-10-26 21:45:23 +00:00
David Dykstra
375a4556c7 Add --compare-dest option which enables specifying an additional destination
for comparisons when syncing.  Useful for syncing into a scratch area and
doing a flash-cutover when it is completed.
1998-10-26 21:42:38 +00:00
rsync-bugs
b41c3f9273 preparing for release of 2.1.1 1998-09-09 07:07:11 +00:00
Andrew Tridgell
35bdd146e4 fixed timestring() bug 1998-09-09 07:06:44 +00:00
Andrew Tridgell
8d249b635c don't complain about not setting times on directories
because some filesystems can't do it
1998-09-09 06:37:13 +00:00
Andrew Tridgell
932be9aa52 handle sstem (sco 3) with glob but not glob.h 1998-09-09 06:31:13 +00:00
Andrew Tridgell
c6b81a9865 handle OSes where you can't rename a open file in the cleanup code. 1998-09-09 06:23:27 +00:00
Andrew Tridgell
e0414f4202 put the time in when using log file. 1998-09-09 06:06:08 +00:00
Andrew Tridgell
6e4fb64e61 added finddead target, removed dead code and made some functions
static
1998-09-09 05:57:34 +00:00
Andrew Tridgell
37863201ad doc updates 1998-09-09 05:52:25 +00:00
Andrew Tridgell
4f6325c362 added "log file" option for those systems with broken syslog (like
AIX)
1998-09-09 05:51:42 +00:00
Andrew Tridgell
f98df1d9b7 wanr people who use path names to rsync :: 1998-09-09 05:51:08 +00:00
Andrew Tridgell
3d913675a1 fixed a small memory leak when using -C
thanks to kalt@research.bell-labs.com for this fix.
1998-08-27 05:17:21 +00:00
Andrew Tridgell
2f9af90118 removed the limit on the read buffer size until I fully understand the
interactions with ssh. The old ssh freezes have shown up again and
some debugging (with help from James Welborn) showed that the cause
was the read buffer hitting maximum size. I think this means that ssh
must be misbehaving about blocking IO.

This change gets rid of the freezes at the expense of memory
usage. Where it would have frozen it uses more memory instead.
1998-08-27 05:07:52 +00:00
Andrew Tridgell
3eb388185b a couple of changes to where the nonblocking settings are called. 1998-08-27 05:05:14 +00:00
Andrew Tridgell
858fb9ebad fix PATTERN/FILE in --help output 1998-07-25 09:20:33 +00:00
Andrew Tridgell
2f03f956f4 rsync.c was getting a bit unwieldy so I split the code into 3 modules,
for the 3 logical stages of rsync; generator, sender and receiver.
1998-07-25 02:25:22 +00:00
Andrew Tridgell
0199b05f25 fixed the relative paths bug pointed out by Alberto Accomazzi 1998-07-23 03:09:14 +00:00
rsync-bugs
e2d1033d5d preparing for release of 2.1.0 1998-07-20 05:43:51 +00:00
Andrew Tridgell
c46ded4621 I think I might havefinally fixed the rsync hanging bug. It was caused
by a read during an io_flush() triggered during a readfd(). A simple
logic bug in the io code :(
1998-07-20 05:36:25 +00:00
Andrew Tridgell
8cd9fd4e8c always use a timeout to select, even if --timeout is not
specified. This makes things easier to debug.
1998-07-19 10:51:26 +00:00
Andrew Tridgell
41979ff87c - defer the error message from the options parsing until after the
socket is multiplexed. This allows clients sending new options which
the remote server doesn't understand to get a sensible error message.
1998-07-19 05:22:05 +00:00
Andrew Tridgell
b11ed3b150 - close stdout and stderr and reopen then as /dev/null when running as
a daemon. This prevents library functions (such as getopt) stuffing up
our protocol stream when errors are detected.

- defer the error message from the options parsing until after the
socket is multiplexed. This allows clients sending new options which
the remote server doesn't understand to get a sensible error message.
1998-07-19 04:50:48 +00:00
rsync-bugs
42245f1b56 preparing for release of 2.0.19 1998-07-17 14:53:00 +00:00
Andrew Tridgell
c29ee43dbd handle hard links on systems with 16 bit ino_t 1998-07-17 14:42:59 +00:00
Andrew Tridgell
d310a212f7 added a bit in the man page about the clean shell error 1998-07-17 14:25:14 +00:00
Andrew Tridgell
ca6c93f817 check whether there is a / before a : in the rsync command line. If
there is then assume that the : is from a filename, not a host:dir
separator. This allows you to copy files with a : in them. (suggestion
from pfeifer@wait.de)
1998-07-17 14:05:57 +00:00
Andrew Tridgell
72914a606e make rsync behave more like GNU cp with regard to file permissions
when -p (preserve permissions) isn't set.

It works by taking the sending file permissions and masking them with
the umask to create the destination file permissions. (There is really
no "correct" way of doing this but at least we now behave like GNU cp
which fits the principle of least surprise.)

also fixed a race condition in copy_file()
1998-07-17 13:18:32 +00:00
Andrew Tridgell
4b957c2238 added the --safe-links option to disallow symlinks outside the
destination tree
1998-07-17 10:00:48 +00:00
Andrew Tridgell
d853783f21 added the --safe-links option to disallow symlinks outside the
destination tree
1998-07-17 10:00:43 +00:00
Andrew Tridgell
298c10d5bb some code reformatting 1998-07-17 07:42:04 +00:00
Andrew Tridgell
6608462cac removed old "make dist" target 1998-07-17 07:26:08 +00:00
Andrew Tridgell
ca8e96946e changed wording of an error message 1998-07-17 07:25:42 +00:00
Andrew Tridgell
6ed67e6dd5 moved getopt.h above unistd.h to prevent problems with uwin on NT 1998-07-17 07:17:11 +00:00
Andrew Tridgell
1f658d4207 fixed a problem with rsync buffering the debug output when redirected
to a file.
1998-07-17 07:07:23 +00:00
Andrew Tridgell
d3bc0b68ab make a function static 1998-07-17 05:38:51 +00:00
Andrew Tridgell
1a0de6c68b remove a useless debug message 1998-07-17 05:38:21 +00:00
Andrew Tridgell
eb601ffeb8 code style change 1998-07-17 05:37:56 +00:00
Andrew Tridgell
8d72ef6e52 use error to detect lockfile open failures vs. max connections reached
and report an appropriate error message
1998-07-17 05:37:18 +00:00
Andrew Tridgell
bcf5b1335d - use explicit flushes instead of setlinebuf. I've had reports of
verbose info not being line buffered to files.

- add a call to localtime() in open_log() in order to prime the C
  libraries timezone cache before the chroot(). This should fix the
  problem of rsyncd log entries being in GMT time.
1998-07-02 10:57:20 +00:00
Andrew Tridgell
bd7e05d799 remove a redundent continue statement 1998-07-02 03:02:14 +00:00
Andrew Tridgell
c95f1aa9d3 prioritise reading over writing in the select loop. (this is another
ssh-friendly attempt)
1998-07-02 02:59:04 +00:00
Andrew Tridgell
86ffe37f11 fix the problem of --timeout waiting for twice the specified time. 1998-07-02 02:48:09 +00:00
Andrew Tridgell
b536f47e3c - don't show "created directory" message unless verbose is selected
- check for null buf in show_progress
1998-07-02 02:08:55 +00:00
Andrew Tridgell
43b06eeae9 output progress % every 1k instead of every 1%, this is better for
large files.
1998-07-02 01:28:39 +00:00
Andrew Tridgell
067857e0ac the recv_generator can be static 1998-07-02 01:27:51 +00:00
Andrew Tridgell
b3e10ed75b enable output buffering in the recv generator. This makes a
significant difference when the transport is ssh as ssh will otherwise
output a complete frame for each checksum record, which increases the
checksum data in size by a factor of around 4.
1998-07-02 01:27:14 +00:00
Andrew Tridgell
a353d56337 don't need to send --progress option to server as the server never
prints progress info.
1998-07-02 00:48:20 +00:00
Andrew Tridgell
eb86d661d7 added --progress option which shows the progress of transfers. This
gives bored users something to watch.
1998-07-02 00:47:13 +00:00
Andrew Tridgell
fe055c718a - only keep a partial file if some literal data has been transferred,
this prevents a second interrupted transfer from reducing the size of
the transferred file.

- set SIGUSR1 to SIG_IGN early to prevent a race condition that
prevents the --partial code from working properly
1998-07-01 11:03:50 +00:00
Andrew Tridgell
31f440e68b I've had reports of rsyncd leaving zombies under digital unix. This
patch tries to address the problem in two ways:

1) reinstall the SIGCHLD handler before each fork
2) reap any children not caught by the handler using waitpid with
WNOHANG.

I expect this will fix the problem.
1998-07-01 05:10:42 +00:00
Andrew Tridgell
c95da96a0c added a --partial option which tells rsync to keep partially
transferred files if the transfer is interrupted.

added a "options summary" section to the man page
1998-07-01 03:36:03 +00:00
Andrew Tridgell
bf9f01689f if we get EWOULDBLOCK on a write then reduce the amount of data we are
trying to write. This guarantees that the maximum amount of data that
can be written at any one time is written.
1998-06-19 00:55:19 +00:00
Andrew Tridgell
da81e21536 use LDFLAGS in Makefile.in (fix from arndt@schoenewald.de) 1998-06-18 14:15:16 +00:00
Andrew Tridgell
46831d6fcf fixed chmod bug pointed out by Han Holl <jeholl@euronet.nl> 1998-06-18 13:26:10 +00:00
rsync-bugs
b58ad6c569 preparing for release of 2.0.18 1998-06-18 13:06:00 +00:00
Andrew Tridgell
22b1933287 fixed a race condition in rsync that opened a security hole. The
temporary files were being created with the same permissions as the
original file. So if the file was setuid but not owned by the user
doing the transfer then there was a window of opportunity for a
malicious user to execute it with the wrong permissions while it was
being transferred.

Thanks to snabb@epipe.fi for pointing this out.
1998-06-18 12:17:23 +00:00
rsync-bugs
5a03f68a5a preparing for release of 2.0.17 1998-06-18 10:30:48 +00:00
Andrew Tridgell
e81da93e86 if as non-root we failed to update the group of a file then don't
print the file name.
1998-06-18 10:03:44 +00:00
Andrew Tridgell
f578043391 for consistency use memcpy/memset everywhere instead of bcopy/bzero 1998-06-18 09:51:44 +00:00
Andrew Tridgell
e8f5b936ad move include of compat.h after other includes. 1998-06-18 09:37:21 +00:00
Andrew Tridgell
667e72a195 change the order of chmod and chown calls so that setuid bits don't
get removed by chown calls.
1998-06-18 09:36:24 +00:00
Andrew Tridgell
e1b3d5c4be set network file descriptors non-blocking before starting main rsync
algorithm.
1998-06-18 09:34:56 +00:00
Andrew Tridgell
f7b9377863 handle non-blocking file descriptors for both read and write. Add a
workaround for buggy systems that say there is space to write when
there isn't.
1998-06-18 09:33:46 +00:00
Andrew Tridgell
a5343e765b put set_nonblocking() code back in. 1998-06-18 09:32:45 +00:00
Andrew Tridgell
704f908eae --help changes suggested by Francois 1998-06-18 09:31:42 +00:00
Andrew Tridgell
de2fd20eb7 manpage updates, mostly suggested by Francois 1998-06-18 09:30:51 +00:00
Andrew Tridgell
100e5241b0 the tag table should be of type int* not tag*.
This bug resulted in rsync being much less efficient that it could be
for files with more than 64k blocks. With the adaptive block size code
giving a maximum block size of 16k this means that files larger than
1GB were handled very inefficiently. The transfer was still accurate,
just slow.
1998-06-03 02:47:52 +00:00
Andrew Tridgell
ddecf7060b if the user passes a block size on the command line then don't adapt
the block size.
1998-06-03 02:35:51 +00:00
Andrew Tridgell
56cdbccb92 added note to docs saying that --stats doesn't work unless -v is used 1998-06-02 12:50:23 +00:00
Andrew Tridgell
fc8a6b9705 added some fflush() calls to make sure the statistics lines are
printed when redirecting output to a file.
1998-06-02 12:46:46 +00:00
rsync-bugs
143384f367 preparing for release of 2.0.16 1998-06-01 13:49:12 +00:00
Andrew Tridgell
8c3b04730b added some notes to test.sh 1998-06-01 13:44:06 +00:00
Andrew Tridgell
aa9b77a56c replace calls to strcmp() with a u_strcmp() function that uses only
unsigned comparisons. Transferring files between two machines that
treated strcmp() differently led to the files being given the wrong
name at the destination if the filenames had characters > 128 (such as
Kanji characters) and the source and destination machines treated
strcmp() differently (ie. one treated strings as signed and the other
as unsigned).

We now treat all string comparisons for file list sorting as unsigned.
1998-06-01 13:39:54 +00:00
Andrew Tridgell
b72f24c719 updated the usage info 1998-06-01 10:38:24 +00:00
Andrew Tridgell
a800434a82 added --stats option for verbose stats on the file transfer 1998-06-01 03:42:14 +00:00
rsync-bugs
3b3c3d4390 preparing for release of 2.0.15 1998-05-30 02:10:18 +00:00
Andrew Tridgell
d846b09874 replace BAD with zBAD so it compiles on AIX 1998-05-30 02:07:36 +00:00
Andrew Tridgell
1d3754aede cosmetic fix.
reset offset to 0 at the start of each loop so the filenames get
printed correctly when sending directories followed by local names.
1998-05-30 02:03:29 +00:00
Andrew Tridgell
e44f9a12c4 make sure that io_flush() doesn't call writefd_unbuffered from within
a writefd_unbuffered call!

this should fix the "decompressor lost sync" bug
1998-05-30 02:02:23 +00:00
Andrew Tridgell
5243c216d6 replaced chdir and getcwd calls with push_dir/pop_dir functions. These
are faster and don't cause problems in a chrooted environment on any
systems.
1998-05-29 14:36:39 +00:00
rsync-bugs
79a51e7ee6 preparing for release of 2.0.14 1998-05-29 02:29:33 +00:00
Andrew Tridgell
cad2bba7d8 fixed a bug in the flist sending code that caused the flist sending to
get out of sync.
1998-05-29 02:28:33 +00:00
Andrew Tridgell
fe8c0a9824 use Realloc instead of realloc 1998-05-28 06:40:25 +00:00
Andrew Tridgell
6cdc6b1344 fix realloc call for systems that don't handle realloc(NULL, ...) 1998-05-28 06:29:57 +00:00
Andrew Tridgell
05848a2cc7 don't do recursive deletion if the recurse option is not selected. 1998-05-28 05:05:26 +00:00
Andrew Tridgell
528bfcd79a cosmetic fix. don't display a EOF error when displaying just the motd
from a rsync server
1998-05-28 01:58:33 +00:00
rsync-bugs
a1e13a937c preparing for release of 2.0.13 1998-05-27 13:54:41 +00:00
Andrew Tridgell
e3fe383aaa reduce IO_BUFFER_SIZE by 4 bytes so when then length word gets added
it is a power of 2.
1998-05-27 13:47:34 +00:00
Andrew Tridgell
43bd68e5dd added new include/exclude options to man page 1998-05-27 13:39:40 +00:00
Andrew Tridgell
ea2111d10a - always flush the IO write buffer when reading
- handle start of line in exclude properly
1998-05-27 13:05:05 +00:00
Andrew Tridgell
4c36ddbeec heaps of cleanup in the io code.
we no longer use non-blocking IO, instead it uses select a lot more,
being careful to always allow for reading whenever a valid read fd is
available and chcking timeouts.

also split the file io calls into fileio.c
1998-05-27 12:37:22 +00:00
Andrew Tridgell
2b6b4d539b added support for --include, --include-from and the +/- syntax 1998-05-27 11:02:33 +00:00
Andrew Tridgell
35f69d8ad9 new test code from Phil 1998-05-27 06:31:37 +00:00
Andrew Tridgell
7b1ce0d746 fixed a race condition in the --delete handling code. The bug led to
spurious error messages about not be able to delete some files.

this fix also makes --delete processing more efficient
1998-05-27 06:30:50 +00:00
rsync-bugs
54816348d1 preparing for release of 2.0.12 1998-05-26 14:45:05 +00:00
Andrew Tridgell
49d11b78c1 fixed a bug in the handling of very long filenames (longer than 255
chars) where two neighboring filenames share more than 255 characters
at the start of their names.
1998-05-26 14:39:18 +00:00
Andrew Tridgell
bb0f7089fe check for munmap as well as mmap. NextStep only has mmap in standard
libs
1998-05-26 14:18:59 +00:00
Andrew Tridgell
1ff5450d31 formatting changes 1998-05-26 14:17:27 +00:00
Andrew Tridgell
2f7512b006 error formatting changes 1998-05-26 14:16:20 +00:00
Andrew Tridgell
943882a289 - don't allow chown for the group of a file if running as a daemon and
uid!=0

- reset am_root after startup as a daemon
1998-05-23 05:57:08 +00:00
Andrew Tridgell
6c82f74b6f don't treat intermediate link directories as links in the relative
path code
1998-05-23 03:13:46 +00:00
Andrew Tridgell
8a5b8b263b need strchr check in configure.in 1998-05-22 14:22:41 +00:00
Andrew Tridgell
d47a7fcf0f use a simpler mmap() test in autoconf as we don't need all the
features of mmap that the standard test uses, and it reports Ultrix as
having no working mmap() when in fact any mmap will do what we want
for rsync.
1998-05-22 14:03:30 +00:00
Andrew Tridgell
e24c850818 need a ifdef around some mmap code 1998-05-22 13:51:26 +00:00
rsync-bugs
6c612747e3 preparing for release of 2.0.11 1998-05-22 13:46:30 +00:00
Andrew Tridgell
505c7ea2bc add a cast to initialisation of mask 1998-05-22 13:27:55 +00:00
Andrew Tridgell
9add51f18e change WRAP to ZWRAP so it doesn't conflict with IRIX includes 1998-05-22 13:02:22 +00:00
Andrew Tridgell
f7bd44eb32 added a README.rsync to explain what we have changed in zlib and to
tell people that any bugs are our responsibility.
1998-05-22 12:20:07 +00:00
Andrew Tridgell
e3ac52f2e1 no longer needed 1998-05-22 12:13:07 +00:00
Andrew Tridgell
06e27ef78e - fix redefinition of MAX
- fix shadow of variable "overflow"
1998-05-22 12:08:49 +00:00
Andrew Tridgell
23e43fceeb fix shadowed variable 1998-05-22 12:07:23 +00:00
Andrew Tridgell
f900f5fe71 removing an unused variable 1998-05-22 12:06:25 +00:00
Andrew Tridgell
db199cfae0 don't need two AC_OUTPUT lines in configure.in 1998-05-22 12:05:53 +00:00
Paul Mackerras
5914bf15d2 Update to use the new zlib-1.1.2 code.
The compressed token code now handles the null (-2)
token from the match logic.
1998-05-22 06:58:52 +00:00
Andrew Tridgell
45f133b976 this fixes two problems:
1) handle 64 bit file offsets in the token code. I wonder how large
bit files worked up till now?

2) send a null token when we have passed over a large lump of data
without finding a token match. This reduces the number of IOs
considerably as it removes the need for seeks/reads on the checksum
calculation and literal send code. This is not enabled yet for the
compressed case as the deflate token code can't handle it yet.
1998-05-22 01:53:02 +00:00
Andrew Tridgell
c5eb365011 formatting changes. committed separately so they don't mask the coming
token changes.
1998-05-21 05:57:15 +00:00
Andrew Tridgell
2f326946a1 now that we slide the mmap window we can use a smaller MAX_MAP_SIZE
and thus consume less virtual memory on the sending side.
1998-05-21 05:55:33 +00:00
Andrew Tridgell
754d120c98 use mmap() for files of any size. This should be much more buffer
cache friendly.
1998-05-21 05:52:37 +00:00
Andrew Tridgell
8e9871303b someone didn't realise that you need rsync at both ends! 1998-05-21 05:32:36 +00:00
Andrew Tridgell
de5fb3744d added DNS spoofing test to host access control 1998-05-20 00:20:12 +00:00
59 changed files with 8356 additions and 8288 deletions

View File

@@ -3,8 +3,8 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
INSTALL_BIN=$(exec_prefix)/bin
INSTALL_MAN=$(prefix)/man
bindir=@bindir@
mandir=@mandir@
LIBS=@LIBS@
CC=@CC@
@@ -12,38 +12,46 @@ CFLAGS=@CFLAGS@
INSTALLCMD=@INSTALL@
VPATH=@srcdir@
srcdir=@srcdir@
VPATH=$(srcdir)
SHELL=/bin/sh
.SUFFIXES:
.SUFFIXES: .c .o
LIBOBJ=lib/getopt.o lib/fnmatch.o lib/zlib.o lib/compat.o
OBJS1=rsync.o exclude.o util.o md4.o main.o checksum.o match.o syscall.o log.o
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o
LIBOBJ=lib/getopt.o lib/fnmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o
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
OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o main.o checksum.o match.o syscall.o log.o
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o fileio.o
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
OBJS=$(OBJS1) $(OBJS2) $(DAEMON_OBJ) $(LIBOBJ)
OBJS=$(OBJS1) $(OBJS2) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ)
# note that the -I. is needed to handle config.h when using VPATH
.c.o:
$(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@
@OBJ_SAVE@
$(CC) -I. -I$(srcdir) $(CFLAGS) -c $< @CC_SHOBJ_FLAG@
@OBJ_RESTORE@
all: rsync
man: rsync.1 rsyncd.conf.5
install: all
-mkdir -p ${INSTALL_BIN}
${INSTALLCMD} -m 755 rsync ${INSTALL_BIN}
-mkdir -p ${INSTALL_MAN}/man1
-mkdir -p ${INSTALL_MAN}/man5
${INSTALLCMD} -m 644 $(srcdir)/rsync.1 ${INSTALL_MAN}/man1
${INSTALLCMD} -m 644 $(srcdir)/rsyncd.conf.5 ${INSTALL_MAN}/man5
-mkdir -p ${bindir}
${INSTALLCMD} -m 755 rsync ${bindir}
-mkdir -p ${mandir}/man1
-mkdir -p ${mandir}/man5
${INSTALLCMD} -m 644 $(srcdir)/rsync.1 ${mandir}/man1
${INSTALLCMD} -m 644 $(srcdir)/rsyncd.conf.5 ${mandir}/man5
install-strip:
$(MAKE) INSTALLCMD='$(INSTALLCMD) -s' install
rsync: $(OBJS)
$(CC) $(CFLAGS) -o rsync $(OBJS) $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o rsync $(OBJS) $(LIBS)
rsync.1: rsync.yo
yodl2man -o rsync.1 rsync.yo
@@ -55,12 +63,13 @@ proto:
cat *.c | awk -f mkproto.awk > proto.h
clean:
rm -f *~ $(OBJS) rsync config.cache config.log config.status
rm -f *~ $(OBJS) rsync
dist:
tar --exclude-from .ignore -czf dist.tar.gz .
-mkdir rsync-$(VERSION)
(cd rsync-$(VERSION) ; tar xzf ../dist.tar.gz)
tar -czf rsync-$(VERSION).tar.gz rsync-$(VERSION)
rm -f dist.tar.gz
echo rsync-$(VERSION) >> .cvsignore
# this target is really just for my use. It only works on a limited
# range of machines and is used to produce a list of potentially
# dead (ie. unused) functions in the code. (tridge)
finddead:
nm *.o */*.o |grep 'U ' | awk '{print $$2}' | sort -u > nmused.txt
nm *.o */*.o |grep 'T ' | awk '{print $$3}' | sort -u > nmfns.txt
comm -13 nmused.txt nmfns.txt

125
README
View File

@@ -20,53 +20,69 @@ USAGE
Basically you use rsync just like rcp, but rsync has many additional options.
Here is a brief description of available options:
Here is a brief description of rsync usage:
Options:
-v, --verbose increase verbosity
-c, --checksum always checksum
-a, --archive archive mode (same as -rlptDog)
-r, --recursive recurse into directories
-R, --relative use relative path names
-b, --backup make backups (default ~ extension)
-u, --update update only (don't overwrite newer files)
-l, --links preserve soft links
-L, --copy-links treat soft links like regular files
-H, --hard-links preserve hard links
-p, --perms preserve permissions
-o, --owner preserve owner (root only)
-g, --group preserve group
-D, --devices preserve devices (root only)
-t, --times preserve times
-S, --sparse handle sparse files efficiently
-n, --dry-run show what would have been transferred
-W, --whole-file copy whole files, no incremental checks
-x, --one-file-system don't cross filesystem boundaries
-B, --block-size SIZE checksum blocking size
-e, --rsh COMMAND specify rsh replacement
--rsync-path PATH specify path to rsync on the remote machine
-C, --cvs-exclude auto ignore files in the same way CVS does
--delete delete files that don't exist on the sending side
--force force deletion of directories even if not empty
--numeric-ids don't map uid/gid values by user/group name
--timeout TIME set IO timeout in seconds
-I, --ignore-times don't exclude files that match length and time
-T --temp-dir DIR create temporary files in directory DIR
-z, --compress compress file data
--exclude FILE exclude file FILE
--exclude-from FILE exclude files listed in FILE
--suffix SUFFIX override backup suffix
--version print version number
--daemon run as a rsync daemon
--config FILE specify alternate rsyncd.conf file
--port PORT specify alternate rsyncd port number
Usage: rsync [OPTION]... SRC [USER@]HOST:DEST
or rsync [OPTION]... [USER@]HOST:SRC DEST
or rsync [OPTION]... SRC DEST
or rsync [OPTION]... [USER@]HOST::SRC [DEST]
or rsync [OPTION]... SRC [USER@]HOST::DEST
or rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]
Options
-v, --verbose increase verbosity
-c, --checksum always checksum
-a, --archive archive mode
-r, --recursive recurse into directories
-R, --relative use relative path names
-b, --backup make backups (default ~ extension)
-u, --update update only (don't overwrite newer files)
-l, --links preserve soft links
-L, --copy-links treat soft links like regular files
--safe-links ignore links outside the destination tree
-H, --hard-links preserve hard links
-p, --perms preserve permissions
-o, --owner preserve owner (root only)
-g, --group preserve group
-D, --devices preserve devices (root only)
-t, --times preserve times
-S, --sparse handle sparse files efficiently
-n, --dry-run show what would have been transferred
-W, --whole-file copy whole files, no incremental checks
-x, --one-file-system don't cross filesystem boundaries
-B, --block-size=SIZE checksum blocking size
-e, --rsh=COMMAND specify rsh replacement
--rsync-path=PATH specify path to rsync on the remote machine
-C, --cvs-exclude auto ignore files in the same way CVS does
--delete delete files that don't exist on the sending side
--partial keep partially transferred files
--force force deletion of directories even if not empty
--numeric-ids don't map uid/gid values by user/group name
--timeout=TIME set IO timeout in seconds
-I, --ignore-times don't exclude files that match length and time
-T --temp-dir=DIR create temporary files in directory DIR
--compare-dest=DIR also compare destination files relative to DIR
-z, --compress compress file data
--exclude=PATTERN exclude files matching PATTERN
--exclude-from=FILE exclude patterns listed in FILE
--include=PATTERN don't exclude files matching PATTERN
--include-from=FILE don't exclude patterns listed in FILE
--suffix=SUFFIX override backup suffix
--version print version number
--daemon run as a rsync daemon
--config=FILE specify alternate rsyncd.conf file
--port=PORT specify alternate rsyncd port number
--stats give some file transfer stats
--progress show progress during transfer
--log-format=FORMAT log file transfers using specified format
-h, --help show this help screen
SETUP
-----
Rsync uses rsh or ssh for communication. It does not need to be setuid
and requires no special privilages for installation. It does not
and requires no special privileges for installation. It does not
require a inetd entry or a daemon. You must, however, have a working
rsh or ssh system. Using ssh is recommended for its security
features.
@@ -88,7 +104,7 @@ RSYNC SERVERS
-------------
rsync can also talk to "rsync servers" which can provide anonymous or
authenticated rsync. See the rsync.conf(5) man page for details on how
authenticated rsync. See the rsyncd.conf(5) man page for details on how
to setup a rsync server. See the rsync(1) man page for info on how to
connect to a rsync server.
@@ -100,25 +116,25 @@ There is a mailing list for the discussion of rsync and its
applications. It is open to anyone to join. I will announce new
versions on this list.
To join the mailing list send mail to listproc@samba.anu.edu.au with
To join the mailing list send mail to listproc@samba.org with
no subject and a body of "subscribe rsync Your Name".
To send mail to everyone on the list send it to rsync@samba.anu.edu.au
To send mail to everyone on the list send it to rsync@samba.org
BUG REPORTS
-----------
If you have web access then please look at
http://samba.anu.edu.au/rsync/
http://rsync.samba.org/rsync/
This will give you access to the bug tracking system used by the
developers of rsync and will allow you to look at other bug reports or
submit a new bug report.
If you don't have web access then mail bug reports to
rsync-bugs@samba.anu.edu.au or (if you think it will be of interest to
lots of people) send it to rsync@samba.anu.edu.au
rsync-bugs@samba.org or (if you think it will be of interest to lots
of people) send it to rsync@samba.org
CVS TREE
@@ -128,10 +144,10 @@ If you want to get the very latest version of rsync direct from the
source code repository then you can use anonymous cvs. You will need a
recent version of cvs then use the following commands:
cvs -d :pserver:cvs@samba.anu.edu.au:/cvsroot login
cvs -d :pserver:cvs@cvs.samba.org:/cvsroot login
Password: cvs
cvs -d :pserver:cvs@samba.anu.edu.au:/cvsroot co rsync
cvs -d :pserver:cvs@cvs.samba.org:/cvsroot co rsync
Look at the cvs documentation for more details.
@@ -142,18 +158,13 @@ COPYRIGHT
Rsync was written by Andrew Tridgell and Paul Mackerras, and is
available under the Gnu Public License.
tridge@samba.anu.edu.au
tridge@samba.org
paulus@cs.anu.edu.au
AVAILABILITY
------------
The main ftp site for rsync is ftp://samba.anu.edu.au/pub/rsync
This is also available as rsync://samba.anu.edu.au/rsyncftp/
Mirrors are available at:
ftp://sunsite.auc.dk/pub/unix/rsync
ftp://ftp.sunet.se/pub/unix/admin/rsync
ftp://ftp.fu-berlin.de/pub/unix/network/rsync/
The main web site for rsync is http://rsync.samba.org/
The main ftp site is ftp://rsync.samba.org/pub/rsync/
This is also available as rsync://rsync.samba.org/rsyncftp/

View File

@@ -34,7 +34,7 @@ static int match_hostname(char *host, char *tok)
static int match_address(char *addr, char *tok)
{
char *p;
unsigned long a, t, mask = ~0;
unsigned long a, t, mask = (unsigned long)~0;
if (!addr || !*addr) return 0;

View File

@@ -7,3 +7,5 @@
#undef HAVE_UTIMBUF
#undef ino_t
#undef HAVE_CONNECT
#undef HAVE_SHORT_INO_T
#undef REPLACE_INET_NTOA

23
aclocal.m4 vendored Normal file
View File

@@ -0,0 +1,23 @@
dnl AC_VALIDATE_CACHE_SYSTEM_TYPE[(cmd)]
dnl if the cache file is inconsistent with the current host,
dnl target and build system types, execute CMD or print a default
dnl error message.
AC_DEFUN(AC_VALIDATE_CACHE_SYSTEM_TYPE, [
AC_REQUIRE([AC_CANONICAL_SYSTEM])
AC_MSG_CHECKING([config.cache system type])
if { test x"${ac_cv_host_system_type+set}" = x"set" &&
test x"$ac_cv_host_system_type" != x"$host"; } ||
{ test x"${ac_cv_build_system_type+set}" = x"set" &&
test x"$ac_cv_build_system_type" != x"$build"; } ||
{ test x"${ac_cv_target_system_type+set}" = x"set" &&
test x"$ac_cv_target_system_type" != x"$target"; }; then
AC_MSG_RESULT([different])
ifelse($#, 1, [$1],
[AC_MSG_ERROR(["you must remove config.cache and restart configure"])])
else
AC_MSG_RESULT([same])
fi
ac_cv_host_system_type="$host"
ac_cv_build_system_type="$build"
ac_cv_target_system_type="$target"
])

View File

@@ -55,7 +55,7 @@ static void gen_challenge(char *addr, char *challenge)
memset(input, 0, sizeof(input));
strlcpy((char *)input, addr, 16);
strlcpy((char *)input, addr, 17);
gettimeofday(&tv, NULL);
SIVAL(input, 16, tv.tv_sec);
SIVAL(input, 20, tv.tv_usec);
@@ -75,12 +75,31 @@ static int get_secret(int module, char *user, char *secret, int len)
int fd, found=0;
char line[MAXPATHLEN];
char *p, *pass=NULL;
STRUCT_STAT st;
int ok = 1;
extern int am_root;
if (!fname || !*fname) return 0;
fd = open(fname,O_RDONLY);
if (fd == -1) return 0;
if (do_stat(fname, &st) == -1) {
rprintf(FERROR,"stat(%s) : %s\n", fname, strerror(errno));
ok = 0;
} else if ((st.st_mode & 06) != 0) {
rprintf(FERROR,"secrets file must not be other-accessible\n");
ok = 0;
} else if (am_root && (st.st_uid != 0)) {
rprintf(FERROR,"secrets file must be owned by root when running as root\n");
ok = 0;
}
if (!ok) {
rprintf(FERROR,"continuing without secrets file\n");
close(fd);
return 0;
}
while (!found) {
int i = 0;
memset(line, 0, sizeof(line));
@@ -112,7 +131,7 @@ static int get_secret(int module, char *user, char *secret, int len)
}
/* generate a 16 byte hash from a password and challenge */
void generate_hash(char *in, char *challenge, char *out)
static void generate_hash(char *in, char *challenge, char *out)
{
char buf[16];

View File

@@ -49,82 +49,71 @@ uint32 get_checksum1(char *buf1,int len)
}
static void sum_put(MDstruct *md,char *sum)
{
SIVAL(sum,0,md->buffer[0]);
if (csum_length <= 4) return;
SIVAL(sum,4,md->buffer[1]);
if (csum_length <= 8) return;
SIVAL(sum,8,md->buffer[2]);
if (csum_length <= 12) return;
SIVAL(sum,12,md->buffer[3]);
}
void get_checksum2(char *buf,int len,char *sum)
{
int i;
MDstruct MD;
static char *buf1;
static int len1;
int i;
static char *buf1;
static int len1;
struct mdfour m;
if (len > len1) {
if (buf1) free(buf1);
buf1 = (char *)malloc(len+4);
len1 = len;
if (!buf1) out_of_memory("get_checksum2");
}
MDbegin(&MD);
bcopy(buf,buf1,len);
if (checksum_seed) {
SIVAL(buf1,len,checksum_seed);
len += 4;
}
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
MDupdate(&MD, buf1+i, CSUM_CHUNK*8);
}
if (len - i > 0)
MDupdate(&MD, buf1+i, (len-i)*8);
sum_put(&MD,sum);
if (len > len1) {
if (buf1) free(buf1);
buf1 = (char *)malloc(len+4);
len1 = len;
if (!buf1) out_of_memory("get_checksum2");
}
mdfour_begin(&m);
memcpy(buf1,buf,len);
if (checksum_seed) {
SIVAL(buf1,len,checksum_seed);
len += 4;
}
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
}
if (len - i > 0) {
mdfour_update(&m, (uchar *)(buf1+i), (len-i));
}
mdfour_result(&m, (uchar *)sum);
}
void file_checksum(char *fname,char *sum,OFF_T size)
{
OFF_T i;
MDstruct MD;
struct map_struct *buf;
int fd;
OFF_T len = size;
char tmpchunk[CSUM_CHUNK];
OFF_T i;
struct map_struct *buf;
int fd;
OFF_T len = size;
char tmpchunk[CSUM_CHUNK];
struct mdfour m;
memset(sum,0,csum_length);
fd = open(fname,O_RDONLY);
if (fd == -1) return;
buf = map_file(fd,size);
mdfour_begin(&m);
bzero(sum,csum_length);
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
memcpy(tmpchunk, map_ptr(buf,i,CSUM_CHUNK), CSUM_CHUNK);
mdfour_update(&m, (uchar *)tmpchunk, CSUM_CHUNK);
}
fd = open(fname,O_RDONLY);
if (fd == -1) return;
if (len - i > 0) {
memcpy(tmpchunk, map_ptr(buf,i,len-i), len-i);
mdfour_update(&m, (uchar *)tmpchunk, (len-i));
}
buf = map_file(fd,size);
mdfour_result(&m, (uchar *)sum);
MDbegin(&MD);
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
bcopy(map_ptr(buf,i,CSUM_CHUNK),tmpchunk,CSUM_CHUNK);
MDupdate(&MD, tmpchunk, CSUM_CHUNK*8);
}
if (len - i > 0) {
bcopy(map_ptr(buf,i,len-i),tmpchunk,len-i);
MDupdate(&MD, tmpchunk, (len-i)*8);
}
sum_put(&MD,sum);
close(fd);
unmap_file(buf);
close(fd);
unmap_file(buf);
}
@@ -138,58 +127,54 @@ void checksum_init(void)
static MDstruct sumMD;
static int sumresidue;
static char sumrbuf[CSUM_CHUNK];
static struct mdfour md;
void sum_init(void)
{
char s[4];
MDbegin(&sumMD);
sumresidue=0;
SIVAL(s,0,checksum_seed);
sum_update(s,4);
char s[4];
mdfour_begin(&md);
sumresidue=0;
SIVAL(s,0,checksum_seed);
sum_update(s,4);
}
void sum_update(char *p,int len)
{
int i;
if (len + sumresidue < CSUM_CHUNK) {
bcopy(p,sumrbuf+sumresidue,len);
sumresidue += len;
return;
}
int i;
if (len + sumresidue < CSUM_CHUNK) {
memcpy(sumrbuf+sumresidue, p, len);
sumresidue += len;
return;
}
if (sumresidue) {
i = MIN(CSUM_CHUNK-sumresidue,len);
bcopy(p,sumrbuf+sumresidue,i);
MDupdate(&sumMD, sumrbuf, (i+sumresidue)*8);
len -= i;
p += i;
}
if (sumresidue) {
i = MIN(CSUM_CHUNK-sumresidue,len);
memcpy(sumrbuf+sumresidue,p,i);
mdfour_update(&md, (uchar *)sumrbuf, (i+sumresidue));
len -= i;
p += i;
}
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
bcopy(p+i,sumrbuf,CSUM_CHUNK);
MDupdate(&sumMD, sumrbuf, CSUM_CHUNK*8);
}
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
memcpy(sumrbuf,p+i,CSUM_CHUNK);
mdfour_update(&md, (uchar *)sumrbuf, CSUM_CHUNK);
}
if (len - i > 0) {
sumresidue = len-i;
bcopy(p+i,sumrbuf,sumresidue);
} else {
sumresidue = 0;
}
if (len - i > 0) {
sumresidue = len-i;
memcpy(sumrbuf,p+i,sumresidue);
} else {
sumresidue = 0;
}
}
void sum_end(char *sum)
{
if (sumresidue)
MDupdate(&sumMD, sumrbuf, sumresidue*8);
if (sumresidue) {
mdfour_update(&md, (uchar *)sumrbuf, sumresidue);
}
SIVAL(sum,0,sumMD.buffer[0]);
SIVAL(sum,4,sumMD.buffer[1]);
SIVAL(sum,8,sumMD.buffer[2]);
SIVAL(sum,12,sumMD.buffer[3]);
mdfour_result(&md, (uchar *)sum);
}

87
cleanup.c Normal file
View File

@@ -0,0 +1,87 @@
/*
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.
*/
#include "rsync.h"
/* handling the cleanup when a transfer is interrupted is tricky when
--partial is selected. We need to ensure that the partial file is
kept if any real data has been transferred */
int cleanup_got_literal=0;
static char *cleanup_fname;
static char *cleanup_new_fname;
static struct file_struct *cleanup_file;
static int cleanup_fd1, cleanup_fd2;
static struct map_struct *cleanup_buf;
static int cleanup_pid = 0;
void _exit_cleanup(int code, const char *file, int line)
{
extern int keep_partial;
signal(SIGUSR1, SIG_IGN);
if (cleanup_got_literal && cleanup_fname && keep_partial) {
char *fname = cleanup_fname;
cleanup_fname = NULL;
if (cleanup_buf) unmap_file(cleanup_buf);
if (cleanup_fd1 != -1) close(cleanup_fd1);
if (cleanup_fd2 != -1) close(cleanup_fd2);
finish_transfer(cleanup_new_fname, fname, cleanup_file);
}
io_flush();
if (cleanup_fname)
do_unlink(cleanup_fname);
if (code) {
kill_all(SIGUSR1);
}
if ((cleanup_pid != 0) && (cleanup_pid == (int) getpid())) {
char *pidf = lp_pid_file();
if (pidf && *pidf) {
unlink(lp_pid_file());
}
}
if (code) log_exit(code, file, line);
exit(code);
}
void cleanup_disable(void)
{
cleanup_fname = NULL;
cleanup_got_literal = 0;
}
void cleanup_set(char *fnametmp, char *fname, struct file_struct *file,
struct map_struct *buf, int fd1, int fd2)
{
cleanup_fname = fnametmp;
cleanup_new_fname = fname;
cleanup_file = file;
cleanup_buf = buf;
cleanup_fd1 = fd1;
cleanup_fd2 = fd2;
}
void cleanup_set_pid(int pid)
{
cleanup_pid = pid;
}

View File

@@ -24,6 +24,7 @@ extern int module_id;
extern int read_only;
extern int verbose;
extern int rsync_port;
char *auth_user;
int start_socket_client(char *host, char *path, int argc, char *argv[])
{
@@ -36,6 +37,11 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
extern int am_client;
extern int am_sender;
if (*path == '/') {
rprintf(FERROR,"ERROR: The remote path must start with a module name\n");
return -1;
}
p = strchr(host, '@');
if (p) {
user = host;
@@ -50,7 +56,7 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
fd = open_socket_out(host, rsync_port);
if (fd == -1) {
exit_cleanup(1);
exit_cleanup(RERR_SOCKETIO);
}
server_options(sargs,&sargc);
@@ -116,11 +122,13 @@ static int rsync_module(int fd, int i)
char *addr = client_addr(fd);
char *host = client_name(fd);
char *name = lp_name(i);
char *user;
int use_chroot = lp_use_chroot(i);
int start_glob=0;
int ret;
char *request=NULL;
extern int am_sender;
extern int remote_version;
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",
@@ -131,16 +139,23 @@ static int rsync_module(int fd, int i)
}
if (!claim_connection(lp_lock_file(), lp_max_connections())) {
rprintf(FERROR,"max connections (%d) reached\n",
lp_max_connections());
io_printf(fd,"@ERROR: max connections (%d) reached - try again later\n", lp_max_connections());
if (errno) {
rprintf(FERROR,"failed to open lock file %s : %s\n",
lp_lock_file(), strerror(errno));
io_printf(fd,"@ERROR: failed to open lock file %s : %s\n",
lp_lock_file(), strerror(errno));
} else {
rprintf(FERROR,"max connections (%d) reached\n",
lp_max_connections());
io_printf(fd,"@ERROR: max connections (%d) reached - try again later\n", lp_max_connections());
}
return -1;
}
user = auth_server(fd, i, addr, "@RSYNCD: AUTHREQD ");
auth_user = auth_server(fd, i, addr, "@RSYNCD: AUTHREQD ");
if (!user) {
if (!auth_user) {
rprintf(FERROR,"auth failed on module %s from %s (%s)\n",
name, client_name(fd), client_addr(fd));
io_printf(fd,"@ERROR: auth failed on module %s\n",name);
@@ -172,37 +187,54 @@ static int rsync_module(int fd, int i)
gid = atoi(p);
}
p = lp_include_from(i);
add_exclude_file(p, 1, 1);
p = lp_include(i);
add_include_line(p);
p = lp_exclude_from(i);
add_exclude_file(p, 1);
add_exclude_file(p, 1, 0);
p = lp_exclude(i);
add_exclude_line(p);
log_open();
if (chroot(lp_path(i))) {
rprintf(FERROR,"chroot %s failed\n", lp_path(i));
io_printf(fd,"@ERROR: chroot failed\n");
return -1;
if (use_chroot) {
if (chroot(lp_path(i))) {
rprintf(FERROR,"chroot %s failed\n", lp_path(i));
io_printf(fd,"@ERROR: chroot failed\n");
return -1;
}
if (chdir("/")) {
rprintf(FERROR,"chdir %s failed\n", lp_path(i));
io_printf(fd,"@ERROR: chdir failed\n");
return -1;
}
if (setgid(gid) || getgid() != gid) {
rprintf(FERROR,"setgid %d failed\n", gid);
io_printf(fd,"@ERROR: setgid failed\n");
return -1;
}
if (setuid(uid) || getuid() != uid) {
rprintf(FERROR,"setuid %d failed\n", uid);
io_printf(fd,"@ERROR: setuid failed\n");
return -1;
}
} else {
if (!push_dir(lp_path(i), 0)) {
rprintf(FERROR,"chdir %s failed\n", lp_path(i));
io_printf(fd,"@ERROR: chdir failed\n");
return -1;
}
}
if (chdir("/")) {
rprintf(FERROR,"chdir %s failed\n", lp_path(i));
io_printf(fd,"@ERROR: chdir failed\n");
return -1;
}
if (setgid(gid) || getgid() != gid) {
rprintf(FERROR,"setgid %d failed\n", gid);
io_printf(fd,"@ERROR: setgid failed\n");
return -1;
}
if (setuid(uid) || getuid() != uid) {
rprintf(FERROR,"setuid %d failed\n", uid);
io_printf(fd,"@ERROR: setuid failed\n");
return -1;
}
am_root = (getuid() == 0);
io_printf(fd,"@RSYNCD: OK\n");
@@ -227,7 +259,7 @@ static int rsync_module(int fd, int i)
request = strdup(p);
start_glob++;
}
glob_expand(name, argv, &argc, MAX_ARGS);
glob_expand(name, argv, &argc, MAX_ARGS, !use_chroot);
} else {
argc++;
}
@@ -241,13 +273,26 @@ static int rsync_module(int fd, int i)
}
}
parse_arguments(argc, argv);
if (!use_chroot) {
/*
* 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]);
}
}
ret = parse_arguments(argc, argv);
if (request) {
if (*user) {
if (*auth_user) {
rprintf(FINFO,"rsync %s %s from %s@%s (%s)\n",
am_sender?"on":"to",
request, user, host, addr);
request, auth_user, host, addr);
} else {
rprintf(FINFO,"rsync %s %s from %s (%s)\n",
am_sender?"on":"to",
@@ -256,8 +301,10 @@ static int rsync_module(int fd, int i)
free(request);
}
#if !TRIDGE
/* don't allow the logs to be flooded too fast */
if (verbose > 1) verbose = 1;
#endif
argc -= optind;
argp = argv + optind;
@@ -266,6 +313,15 @@ static int rsync_module(int fd, int i)
if (remote_version > 17 && am_sender)
io_start_multiplex_out(fd);
if (!ret) {
option_error();
}
if (lp_timeout(i)) {
extern int io_timeout;
io_timeout = lp_timeout(i);
}
start_server(fd, fd, argc, argp);
return 0;
@@ -295,7 +351,7 @@ static int start_daemon(int fd)
extern int remote_version;
if (!lp_load(config_file, 0)) {
exit_cleanup(1);
exit_cleanup(RERR_SYNTAX);
}
set_socket_options(fd,"SO_KEEPALIVE");
@@ -305,7 +361,7 @@ static int start_daemon(int fd)
io_printf(fd,"@RSYNCD: %d\n", PROTOCOL_VERSION);
motd = lp_motd_file();
if (*motd) {
if (motd && *motd) {
FILE *f = fopen(motd,"r");
while (f && !feof(f)) {
int len = fread(line, 1, sizeof(line)-1, f);
@@ -358,9 +414,26 @@ static int start_daemon(int fd)
int daemon_main(void)
{
extern char *config_file;
char *pid_file;
/* this ensures that we don't call getcwd after the chroot,
which doesn't work on platforms that use popen("pwd","r")
for getcwd */
push_dir("/", 0);
if (is_a_socket(STDIN_FILENO)) {
/* we are running via inetd */
int i;
/* we are running via inetd - close off stdout and
stderr so that library functions (and getopt) don't
try to use them. Redirect them to /dev/null */
for (i=1;i<3;i++) {
close(i);
open("/dev/null", O_RDWR);
}
set_nonblocking(STDIN_FILENO);
return start_daemon(STDIN_FILENO);
}
@@ -368,13 +441,26 @@ int daemon_main(void)
if (!lp_load(config_file, 1)) {
fprintf(stderr,"failed to load config file %s\n", config_file);
exit_cleanup(1);
exit_cleanup(RERR_SYNTAX);
}
log_open();
rprintf(FINFO,"rsyncd version %s starting\n",VERSION);
if (((pid_file = lp_pid_file()) != NULL) && (*pid_file != '\0')) {
FILE *f;
int pid = (int) getpid();
cleanup_set_pid(pid);
if ((f = fopen(lp_pid_file(), "w")) == NULL) {
cleanup_set_pid(0);
fprintf(stderr,"failed to create pid file %s\n", pid_file);
exit_cleanup(RERR_FILEIO);
}
fprintf(f, "%d\n", pid);
fclose(f);
}
start_accept_loop(rsync_port, start_daemon);
return -1;
}

View File

@@ -44,10 +44,8 @@ void setup_protocol(int f_out,int f_in)
if (am_server) {
remote_version = read_int(f_in);
write_int(f_out,PROTOCOL_VERSION);
write_flush(f_out);
} else {
write_int(f_out,PROTOCOL_VERSION);
write_flush(f_out);
remote_version = read_int(f_in);
}
}
@@ -55,7 +53,8 @@ void setup_protocol(int f_out,int f_in)
if (remote_version < MIN_PROTOCOL_VERSION ||
remote_version > MAX_PROTOCOL_VERSION) {
rprintf(FERROR,"protocol version mismatch - is your shell clean?\n");
exit_cleanup(1);
rprintf(FERROR,"(see the rsync man page for an explanation)\n");
exit_cleanup(RERR_PROTOCOL);
}
if (verbose > 2)

627
config.guess vendored Executable file
View File

@@ -0,0 +1,627 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright (C) 1992, 93, 94, 95, 1996 Free Software Foundation, Inc.
#
# 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
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Written by Per Bothner <bothner@cygnus.com>.
# The master version of this file is at the FSF in /home/gd/gnu/lib.
#
# This script attempts to guess a canonical system name similar to
# config.sub. If it succeeds, it prints the system name on stdout, and
# exits with 0. Otherwise, it exits with 1.
#
# The plan is that this can be called by configure scripts if you
# don't specify an explicit system type (host/target name).
#
# Only a few systems have been added to this list; please add others
# (but try to keep the structure clean).
#
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 8/24/94.)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
PATH=$PATH:/.attbin ; export PATH
fi
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
# Note: order is significant - the case branches are not exclusive.
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
news*:NEWS-OS:6.*:*)
echo mips-sony-newsos6
exit 0 ;;
alpha:OSF1:*:*)
# 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.
echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//'`
exit 0 ;;
21064:Windows_NT:50:3)
echo alpha-dec-winnt3.5
exit 0 ;;
Amiga*:UNIX_System_V:4.0:*)
echo m68k-cbm-sysv4
exit 0;;
amiga:NetBSD:*:*)
echo m68k-cbm-netbsd${UNAME_RELEASE}
exit 0 ;;
amiga:OpenBSD:*:*)
echo m68k-cbm-openbsd${UNAME_RELEASE}
exit 0 ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
exit 0;;
Pyramid*:OSx*:*:*)
if test "`(/bin/universe) 2>/dev/null`" = att ; then
echo pyramid-pyramid-sysv3
else
echo pyramid-pyramid-bsd
fi
exit 0 ;;
sun4*:SunOS:5.*:*)
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit 0 ;;
i86pc:SunOS:5.*:*)
echo i386-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit 0 ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit 0 ;;
sun4*:SunOS:*:*)
case "`/usr/bin/arch -k`" in
Series*|S4*)
UNAME_RELEASE=`uname -v`
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
exit 0 ;;
sun3*:SunOS:*:*)
echo m68k-sun-sunos${UNAME_RELEASE}
exit 0 ;;
atari*:NetBSD:*:*)
echo m68k-atari-netbsd${UNAME_RELEASE}
exit 0 ;;
atari*:OpenBSD:*:*)
echo m68k-atari-openbsd${UNAME_RELEASE}
exit 0 ;;
sun3*:NetBSD:*:*)
echo m68k-sun-netbsd${UNAME_RELEASE}
exit 0 ;;
sun3*:OpenBSD:*:*)
echo m68k-sun-openbsd${UNAME_RELEASE}
exit 0 ;;
mac68k:NetBSD:*:*)
echo m68k-apple-netbsd${UNAME_RELEASE}
exit 0 ;;
mac68k:OpenBSD:*:*)
echo m68k-apple-openbsd${UNAME_RELEASE}
exit 0 ;;
RISC*:ULTRIX:*:*)
echo mips-dec-ultrix${UNAME_RELEASE}
exit 0 ;;
VAX*:ULTRIX*:*:*)
echo vax-dec-ultrix${UNAME_RELEASE}
exit 0 ;;
mips:*:4*:UMIPS)
echo mips-mips-riscos4sysv
exit 0 ;;
mips:*:5*:RISCos)
echo mips-mips-riscos${UNAME_RELEASE}
exit 0 ;;
Night_Hawk:Power_UNIX:*:*)
echo powerpc-harris-powerunix
exit 0 ;;
m88k:CX/UX:7*:*)
echo m88k-harris-cxux7
exit 0 ;;
m88k:*:4*:R4*)
echo m88k-motorola-sysv4
exit 0 ;;
m88k:*:3*:R3*)
echo m88k-motorola-sysv3
exit 0 ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
-o ${TARGET_BINARY_INTERFACE}x = x ] ; then
echo m88k-dg-dgux${UNAME_RELEASE}
else
echo m88k-dg-dguxbcs${UNAME_RELEASE}
fi
else echo i586-dg-dgux${UNAME_RELEASE}
fi
exit 0 ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
exit 0 ;;
M88*:*:R3*:*)
# Delta 88k system running SVR3
echo m88k-motorola-sysv3
exit 0 ;;
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
echo m88k-tektronix-sysv3
exit 0 ;;
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
echo m68k-tektronix-bsd
exit 0 ;;
*:IRIX*:*:*)
echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
exit 0 ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
i[34]86:AIX:*:*)
echo i386-ibm-aix
exit 0 ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
sed 's/^ //' << EOF >dummy.c
#include <sys/systemcfg.h>
main()
{
if (!__power_pc())
exit(1);
puts("powerpc-ibm-aix3.2.5");
exit(0);
}
EOF
${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
rm -f dummy.c dummy
echo rs6000-ibm-aix3.2.5
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
echo rs6000-ibm-aix3.2.4
else
echo rs6000-ibm-aix3.2
fi
exit 0 ;;
*:AIX:*:4)
if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
IBM_ARCH=rs6000
else
IBM_ARCH=powerpc
fi
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
else
IBM_REV=4.${UNAME_RELEASE}
fi
echo ${IBM_ARCH}-ibm-aix${IBM_REV}
exit 0 ;;
*:AIX:*:*)
echo rs6000-ibm-aix
exit 0 ;;
ibmrt:4.4BSD:*|romp-ibm:BSD:*)
echo romp-ibm-bsd4.4
exit 0 ;;
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
exit 0 ;; # report: romp-ibm BSD 4.3
*:BOSX:*:*)
echo rs6000-bull-bosx
exit 0 ;;
DPX/2?00:B.O.S.:*:*)
echo m68k-bull-sysv3
exit 0 ;;
9000/[34]??:4.3bsd:1.*:*)
echo m68k-hp-bsd
exit 0 ;;
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
echo m68k-hp-bsd4.4
exit 0 ;;
9000/[3478]??:HP-UX:*:*)
case "${UNAME_MACHINE}" in
9000/31? ) HP_ARCH=m68000 ;;
9000/[34]?? ) HP_ARCH=m68k ;;
9000/7?? | 9000/8?[679] ) HP_ARCH=hppa1.1 ;;
9000/8?? ) HP_ARCH=hppa1.0 ;;
esac
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
exit 0 ;;
3050*:HI-UX:*:*)
sed 's/^ //' << EOF >dummy.c
#include <unistd.h>
int
main ()
{
long cpu = sysconf (_SC_CPU_VERSION);
/* The order matters, because CPU_IS_HP_MC68K erroneously returns
true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
results, however. */
if (CPU_IS_PA_RISC (cpu))
{
switch (cpu)
{
case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
default: puts ("hppa-hitachi-hiuxwe2"); break;
}
}
else if (CPU_IS_HP_MC68K (cpu))
puts ("m68k-hitachi-hiuxwe2");
else puts ("unknown-hitachi-hiuxwe2");
exit (0);
}
EOF
${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
rm -f dummy.c dummy
echo unknown-hitachi-hiuxwe2
exit 0 ;;
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
echo hppa1.1-hp-bsd
exit 0 ;;
9000/8??:4.3bsd:*:*)
echo hppa1.0-hp-bsd
exit 0 ;;
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
echo hppa1.1-hp-osf
exit 0 ;;
hp8??:OSF1:*:*)
echo hppa1.0-hp-osf
exit 0 ;;
parisc*:Lites*:*:*)
echo hppa1.1-hp-lites
exit 0 ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
exit 0 ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
exit 0 ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
echo c34-convex-bsd
exit 0 ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
echo c38-convex-bsd
exit 0 ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
exit 0 ;;
CRAY*T3E:*:*:*)
echo t3e-cray-unicos_mk
exit 0 ;;
CRAY*X-MP:*:*:*)
echo xmp-cray-unicos
exit 0 ;;
CRAY*Y-MP:*:*:*)
echo ymp-cray-unicos${UNAME_RELEASE}
exit 0 ;;
CRAY*C90:*:*:*)
echo c90-cray-unicos${UNAME_RELEASE}
exit 0 ;;
CRAY*TS:*:*:*)
echo t90-cray-unicos${UNAME_RELEASE}
exit 0 ;;
CRAY-2:*:*:*)
echo cray2-cray-unicos
exit 0 ;;
hp3[0-9][05]:NetBSD:*:*)
echo m68k-hp-netbsd${UNAME_RELEASE}
exit 0 ;;
hp3[0-9][05]:OpenBSD:*:*)
echo m68k-hp-openbsd${UNAME_RELEASE}
exit 0 ;;
i[34]86:BSD/386:*:* | *:BSD/OS:*:*)
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit 0 ;;
*:FreeBSD:*:*)
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit 0 ;;
*:NetBSD:*:*)
echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
exit 0 ;;
*:OpenBSD:*:*)
echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
exit 0 ;;
i*:CYGWIN*:*)
echo i386-unknown-cygwin32
exit 0 ;;
p*:CYGWIN*:*)
echo powerpcle-unknown-cygwin32
exit 0 ;;
prep*:SunOS:5.*:*)
echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit 0 ;;
*:GNU:*:*)
echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
exit 0 ;;
*:Linux:*:*)
# The BFD linker knows what the default object file format is, so
# first see if it will tell us.
ld_help_string=`ld --help 2>&1`
if echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf_i[345]86"; then
echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i[345]86linux"; then
echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i[345]86coff"; then
echo "${UNAME_MACHINE}-unknown-linuxcoff" ; exit 0
elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68kelf"; then
echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68klinux"; then
echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
elif test "${UNAME_MACHINE}" = "alpha" ; then
echo alpha-unknown-linux ; exit 0
else
# Either a pre-BFD a.out linker (linuxoldld) or one that does not give us
# useful --help. Gcc wants to distinguish between linuxoldld and linuxaout.
test ! -d /usr/lib/ldscripts/. \
&& echo "${UNAME_MACHINE}-unknown-linuxoldld" && exit 0
# Determine whether the default compiler is a.out or elf
cat >dummy.c <<EOF
main(argc, argv)
int argc;
char *argv[];
{
#ifdef __ELF__
printf ("%s-unknown-linux\n", argv[1]);
#else
printf ("%s-unknown-linuxaout\n", argv[1]);
#endif
return 0;
}
EOF
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
rm -f dummy.c dummy
fi ;;
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
# are messed up and put the nodename in both sysname and nodename.
i[34]86:DYNIX/ptx:4*:*)
echo i386-sequent-sysv4
exit 0 ;;
i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
else
echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
fi
exit 0 ;;
i[34]86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
echo ${UNAME_MACHINE}-unknown-isc$UNAME_REL
elif /bin/uname -X 2>/dev/null >/dev/null ; then
UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
&& UNAME_MACHINE=i586
echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
else
echo ${UNAME_MACHINE}-unknown-sysv32
fi
exit 0 ;;
Intel:Mach:3*:*)
echo i386-unknown-mach3
exit 0 ;;
paragon:*:*:*)
echo i860-intel-osf1
exit 0 ;;
i860:*:4.*:*) # i860-SVR4
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
else # Add other i860-SVR4 vendors below as they are discovered.
echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
fi
exit 0 ;;
mini*:CTIX:SYS*5:*)
# "miniframe"
echo m68010-convergent-sysv
exit 0 ;;
M680[234]0:*:R3V[567]*:*)
test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
uname -p 2>/dev/null | grep 86 >/dev/null \
&& echo i486-ncr-sysv4.3 && exit 0 ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
uname -p 2>/dev/null | grep 86 >/dev/null \
&& echo i486-ncr-sysv4 && exit 0 ;;
m680[234]0:LynxOS:2.[23]*:*)
echo m68k-lynx-lynxos${UNAME_RELEASE}
exit 0 ;;
mc68030:UNIX_System_V:4.*:*)
echo m68k-atari-sysv4
exit 0 ;;
i[34]86:LynxOS:2.[23]*:*)
echo i386-lynx-lynxos${UNAME_RELEASE}
exit 0 ;;
TSUNAMI:LynxOS:2.[23]*:*)
echo sparc-lynx-lynxos${UNAME_RELEASE}
exit 0 ;;
rs6000:LynxOS:2.[23]*:*)
echo rs6000-lynx-lynxos${UNAME_RELEASE}
exit 0 ;;
RM*:SINIX-*:*:*)
echo mips-sni-sysv4
exit 0 ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null`
echo ${UNAME_MACHINE}-sni-sysv4
else
echo ns32k-sni-sysv
fi
exit 0 ;;
mc68*:A/UX:*:*)
echo m68k-apple-aux${UNAME_RELEASE}
exit 0 ;;
R3000:*System_V*:*:*)
if [ -d /usr/nec ]; then
echo mips-nec-sysv${UNAME_RELEASE}
else
echo mips-unknown-sysv${UNAME_RELEASE}
fi
exit 0 ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
cat >dummy.c <<EOF
#ifdef _SEQUENT_
# include <sys/types.h>
# include <sys/utsname.h>
#endif
main ()
{
#if defined (sony)
#if defined (MIPSEB)
/* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
I don't know.... */
printf ("mips-sony-bsd\n"); exit (0);
#else
#include <sys/param.h>
printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
"4"
#else
""
#endif
); exit (0);
#endif
#endif
#if defined (__arm) && defined (__acorn) && defined (__unix)
printf ("arm-acorn-riscix"); exit (0);
#endif
#if defined (hp300) && !defined (hpux)
printf ("m68k-hp-bsd\n"); exit (0);
#endif
#if defined (NeXT)
#if !defined (__ARCHITECTURE__)
#define __ARCHITECTURE__ "m68k"
#endif
int version;
version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
printf ("%s-next-nextstep%s\n", __ARCHITECTURE__, version==2 ? "2" : "3");
exit (0);
#endif
#if defined (MULTIMAX) || defined (n16)
#if defined (UMAXV)
printf ("ns32k-encore-sysv\n"); exit (0);
#else
#if defined (CMU)
printf ("ns32k-encore-mach\n"); exit (0);
#else
printf ("ns32k-encore-bsd\n"); exit (0);
#endif
#endif
#endif
#if defined (__386BSD__)
printf ("i386-unknown-bsd\n"); exit (0);
#endif
#if defined (sequent)
#if defined (i386)
printf ("i386-sequent-dynix\n"); exit (0);
#endif
#if defined (ns32000)
printf ("ns32k-sequent-dynix\n"); exit (0);
#endif
#endif
#if defined (_SEQUENT_)
struct utsname un;
uname(&un);
if (strncmp(un.version, "V2", 2) == 0) {
printf ("i386-sequent-ptx2\n"); exit (0);
}
if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
printf ("i386-sequent-ptx1\n"); exit (0);
}
printf ("i386-sequent-ptx\n"); exit (0);
#endif
#if defined (vax)
#if !defined (ultrix)
printf ("vax-dec-bsd\n"); exit (0);
#else
printf ("vax-dec-ultrix\n"); exit (0);
#endif
#endif
#if defined (alliant) && defined (i860)
printf ("i860-alliant-bsd\n"); exit (0);
#endif
exit (1);
}
EOF
${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
rm -f dummy.c dummy
# Apollos put the system type in the environment.
test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
# Convex versions that predate uname can use getsysinfo(1)
if [ -x /usr/convex/getsysinfo ]
then
case `getsysinfo -f cpu_type` in
c1*)
echo c1-convex-bsd
exit 0 ;;
c2*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
exit 0 ;;
c34*)
echo c34-convex-bsd
exit 0 ;;
c38*)
echo c38-convex-bsd
exit 0 ;;
c4*)
echo c4-convex-bsd
exit 0 ;;
esac
fi
#echo '(Unable to guess system type)' 1>&2
exit 1

1099
config.sub vendored Executable file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,12 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(byteorder.h)
AC_CONFIG_HEADER(config.h)
# compile with optimisation and without debugging by default
CFLAGS=${CFLAGS-"-O"}
AC_CANONICAL_SYSTEM
AC_VALIDATE_CACHE_SYSTEM_TYPE
dnl Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
@@ -10,12 +16,14 @@ AC_SUBST(SHELL)
AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0)
AC_DEFINE_UNQUOTED(HAVE_REMSH, $HAVE_REMSH)
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)
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)
AC_CHECK_HEADERS(glob.h)
AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(long)
@@ -32,17 +40,19 @@ AC_TYPE_PID_T
AC_STRUCT_ST_RDEV
AC_CHECK_TYPE(ino_t,unsigned)
echo $ac_n "checking for errno in errno.h... $ac_c"
AC_TRY_COMPILE([#include <errno.h>],[int i = errno],
echo yes; AC_DEFINE(HAVE_ERRNO_DECL),
echo no)
AC_CACHE_CHECK([for errno in errno.h],rsync_cv_errno, [
AC_TRY_COMPILE([#include <errno.h>],[int i = errno],
rsync_cv_errno=yes,rsync_cv_have_errno_decl=no)])
if test x"$rsync_cv_errno" = x"yes"; then
AC_DEFINE(HAVE_ERRNO_DECL)
fi
AC_FUNC_MEMCMP
AC_FUNC_MMAP
AC_FUNC_UTIME_NULL
AC_CHECK_FUNCS(waitpid strtok pipe getcwd mkdir strdup strerror chown chmod mknod)
AC_CHECK_FUNCS(fchmod fstat strchr bcopy bzero readlink link utime utimes)
AC_CHECK_FUNCS(memmove getopt_long lchown setlinebuf vsnprintf setsid glob)
AC_CHECK_FUNCS(mmap munmap waitpid getcwd strdup strerror chown chmod mknod)
AC_CHECK_FUNCS(fchmod fstat strchr readlink link utime utimes strftime)
AC_CHECK_FUNCS(memmove getopt_long lchown vsnprintf snprintf setsid glob strpbrk)
AC_CHECK_FUNCS(strlcat strlcpy)
echo $ac_n "checking for working fnmatch... $ac_c"
AC_TRY_RUN([#include <fnmatch.h>
@@ -50,40 +60,73 @@ main() { exit(fnmatch("*.o", "x.o", 0) == 0? 0: 1); }],
echo yes;AC_DEFINE(HAVE_FNMATCH),
echo no)
echo $ac_n "checking for long long ... $ac_c"
AC_CACHE_CHECK([for long long],rsync_cv_have_longlong,[
AC_TRY_RUN([#include <stdio.h>
main() { long long x = 1000000; x *= x; exit(((x/1000000) == 1000000)? 0: 1); }],
echo yes;AC_DEFINE(HAVE_LONGLONG),
echo no)
rsync_cv_have_longlong=yes,rsync_cv_have_longlong=no,rsync_cv_have_longlong=cross)])
if test x"$rsync_cv_have_longlong" = x"yes"; then
AC_DEFINE(HAVE_LONGLONG)
fi
echo $ac_n "checking for off64_t ... $ac_c"
AC_CACHE_CHECK([for off64_t],rsync_cv_HAVE_OFF64_T,[
AC_TRY_RUN([#include <stdio.h>
#include <sys/stat.h>
main() { struct stat64 st; off64_t s; if (sizeof(off_t) == sizeof(off64_t)) return 1; exit((lstat64("/dev/null", &st)==0)?0:1); }],
echo yes;AC_DEFINE(HAVE_OFF64_T),
main() { struct stat64 st; off64_t s; if (sizeof(off_t) == sizeof(off64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }],
rsync_cv_HAVE_OFF64_T=yes,rsync_cv_HAVE_OFF64_T=no,rsync_cv_HAVE_OFF64_T=cross)])
if test x"$rsync_cv_HAVE_OFF64_T" = x"yes"; then
AC_DEFINE(HAVE_OFF64_T)
fi
echo $ac_n "checking for short ino_t ... $ac_c"
AC_TRY_RUN([#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
main() { if (sizeof(ino_t) < sizeof(unsigned int)) return 0; return 1; }],
echo yes;AC_DEFINE(HAVE_SHORT_INO_T),
echo no)
echo $ac_n "checking for unsigned char ... $ac_c"
AC_CACHE_CHECK([for unsigned char],rsync_cv_HAVE_UNSIGNED_CHAR,[
AC_TRY_RUN([#include <stdio.h>
main() { char c; c=250; exit((c > 0)?0:1); }],
echo yes;AC_DEFINE(HAVE_UNSIGNED_CHAR),
echo no)
rsync_cv_HAVE_UNSIGNED_CHAR=yes,rsync_cv_HAVE_UNSIGNED_CHAR=no,rsync_cv_HAVE_UNSIGNED_CHAR=cross)])
if test x"$rsync_cv_HAVE_UNSIGNED_CHAR" = x"yes"; then
AC_DEFINE(HAVE_UNSIGNED_CHAR)
fi
echo $ac_n "checking for broken readdir ... $ac_c"
AC_CACHE_CHECK([for broken readdir],rsync_cv_HAVE_BROKEN_READDIR,[
AC_TRY_RUN([#include <sys/types.h>
#include <dirent.h>
main() { struct dirent *di; DIR *d = opendir("."); di = readdir(d);
if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 &&
di->d_name[0] == 0) return 0; return 1;} ],
echo yes - you are using the broken /usr/ucb/cc;AC_DEFINE(HAVE_BROKEN_READDIR),
echo no)
di->d_name[0] == 0) exit(0); exit(1);} ],
rsync_cv_HAVE_BROKEN_READDIR=yes,rsync_cv_HAVE_BROKEN_READDIR=no,rsync_cv_HAVE_BROKEN_READDIR=cross)])
if test x"$rsync_cv_HAVE_BROKEN_READDIR" = x"yes"; then
AC_DEFINE(HAVE_BROKEN_READDIR)
fi
echo $ac_n "checking for utimbuf ... $ac_c"
AC_CACHE_CHECK([for utimbuf],rsync_cv_HAVE_UTIMBUF,[
AC_TRY_COMPILE([#include <sys/types.h>
#include <utime.h>],
[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; return utime("foo.c",&tbuf);],
echo yes;AC_DEFINE(HAVE_UTIMBUF),
echo no)
[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(utime("foo.c",&tbuf));],
rsync_cv_HAVE_UTIMBUF=yes,rsync_cv_HAVE_UTIMBUF=no,rsync_cv_HAVE_UTIMBUF=cross)])
if test x"$rsync_cv_HAVE_UTIMBUF" = x"yes"; then
AC_DEFINE(HAVE_UTIMBUF)
fi
AC_CACHE_CHECK([for broken inet_ntoa],rsync_cv_REPLACE_INET_NTOA,[
AC_TRY_RUN([
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#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(0); }
exit(1);}],
rsync_cv_REPLACE_INET_NTOA=yes,rsync_cv_REPLACE_INET_NTOA=no,rsync_cv_REPLACE_INET_NTOA=cross)])
if test x"$rsync_cv_REPLACE_INET_NTOA" = x"yes"; then
AC_DEFINE(REPLACE_INET_NTOA)
fi
# The following test taken from the cvs sources
# If we can't find connect, try looking in -lsocket, -lnsl, and -linet.
@@ -91,30 +134,66 @@ echo no)
# libsocket.so which has a bad implementation of gethostbyname (it
# only looks in /etc/hosts), so we only look for -lsocket if we need
# it.
AC_CHECK_FUNC(connect, :,
[case "$LIBS" in
*-lnsl*) ;;
*) AC_CHECK_LIB(nsl_s, printf) ;;
esac
case "$LIBS" in
*-lnsl*) ;;
*) AC_CHECK_LIB(nsl, printf) ;;
esac
case "$LIBS" in
*-lsocket*) ;;
*) AC_CHECK_LIB(socket, connect) ;;
esac
case "$LIBS" in
*-linet*) ;;
*) AC_CHECK_LIB(inet, connect) ;;
esac
dnl We can't just call AC_CHECK_FUNCS(connect) here, because the value
dnl has been cached.
if test "$ac_cv_lib_socket_connect" = "yes" ||
test "$ac_cv_lib_inet_connect" = "yes"; then
ac_cv_func_connect=yes
AC_DEFINE(HAVE_CONNECT)
fi])
AC_CHECK_FUNCS(connect)
if test x"$ac_cv_func_connect" = x"no"; then
case "$LIBS" in
*-lnsl*) ;;
*) AC_CHECK_LIB(nsl_s, printf) ;;
esac
case "$LIBS" in
*-lnsl*) ;;
*) AC_CHECK_LIB(nsl, printf) ;;
esac
case "$LIBS" in
*-lsocket*) ;;
*) AC_CHECK_LIB(socket, connect) ;;
esac
case "$LIBS" in
*-linet*) ;;
*) AC_CHECK_LIB(inet, connect) ;;
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" ||
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
AC_DEFINE(HAVE_CONNECT)
fi
fi
#
# if we can't find strcasecmp, look in -lresolv (for Unixware at least)
#
AC_CHECK_FUNCS(strcasecmp)
if test x"$ac_cv_func_strcasecmp" = x"no"; then
AC_CHECK_LIB(resolv, strcasecmp)
fi
#
# The following test was mostly taken from the tcl/tk plus patches
#
echo $ac_n "checking whether -c -o works ... $ac_c"
rm -rf conftest*
cat > conftest.$ac_ext <<EOF
int main() { return 0; }
EOF
${CC-cc} -c -o conftest..o conftest.$ac_ext
if test -f conftest..o; then
OBJ_SAVE="#"
OBJ_RESTORE="#"
CC_SHOBJ_FLAG='-o $@'
echo yes
else
OBJ_SAVE=' @b=`basename $@ .o`;rm -f $$b.o.sav;if test -f $$b.o; then mv $$b.o $$b.o.sav;fi;'
OBJ_RESTORE=' @b=`basename $@ .o`;if test "$$b.o" != "$@"; then mv $$b.o $@; if test -f $$b.o.sav; then mv $$b.o.sav $$b.o; fi; fi'
CC_SHOBJ_FLAG=""
echo no
fi
rm -rf conftest*
AC_SUBST(OBJ_SAVE)
AC_SUBST(OBJ_RESTORE)
AC_SUBST(CC_SHOBJ_FLAG)
AC_OUTPUT(Makefile lib/dummy)
AC_OUTPUT(Makefile lib/dummy zlib/dummy)

View File

@@ -29,7 +29,7 @@ int claim_connection(char *fname,int max_connections)
if (max_connections <= 0)
return 1;
fd = open(fname,O_RDWR|O_CREAT, 0600);
if (fd == -1) {
@@ -41,6 +41,9 @@ int claim_connection(char *fname,int max_connections)
if (lock_range(fd, i*4, 4)) return 1;
}
/* only interested in open failures */
errno = 0;
close(fd);
return 0;
}

18
errcode.h Normal file
View File

@@ -0,0 +1,18 @@
/* error codes returned by rsync */
#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_SOCKETIO 10 /* error in socket IO */
#define RERR_FILEIO 11 /* error in file IO */
#define RERR_STREAMIO 12 /* error in rsync protocol data stream */
#define RERR_MESSAGEIO 13 /* errors with program diagnostics */
#define RERR_IPC 14 /* error in IPC code */
#define RERR_SIGNAL 20 /* status returned when sent SIGUSR1, SIGINT */
#define RERR_WAITCHILD 21 /* some error returned by waitpid() */
#define RERR_MALLOC 22 /* error allocating core memory buffers */
#define RERR_TIMEOUT 30 /* timeout in data send/receive */

379
exclude.c
View File

@@ -17,160 +17,280 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
a lot of this stuff was derived from GNU tar
*/
/* a lot of this stuff was originally derived from GNU tar, although
it has now changed so much that it is hard to tell :) */
#include "rsync.h"
extern int verbose;
static char **exclude_list;
static struct exclude_struct **exclude_list;
static int is_regex(char *str)
/*
* Optimization for special case when all included files are explicitly
* listed without wildcards in the "exclude" list followed by a "- *"
* to exclude the rest.
* Contributed by Dave Dykstra <dwd@bell-labs.com>
*/
static int only_included_files = 1;
static struct exclude_struct *exclude_the_rest;
int send_included_file_names(int f,struct file_list *flist)
{
return strchr(str, '*') || strchr(str, '[') || strchr(str, '?');
}
struct exclude_struct *ex, **ex_list;
int n;
char *p;
if (!only_included_files || (exclude_the_rest == NULL))
return 0;
static int check_one_exclude(char *name,char *pattern)
{
char *p;
if (verbose > 1) {
rprintf(FINFO,"(using include-only optimization) ");
}
if (!strchr(pattern,'/') && (p=strrchr(name,'/')))
name = p+1;
if (!name[0]) return 0;
if (*pattern == '/' && *name != '/') pattern++;
if (is_regex(pattern)) {
if (fnmatch(pattern, name, 0) == 0)
return 1;
} else {
int l1 = strlen(name);
int l2 = strlen(pattern);
if (l2 <= l1 &&
strcmp(name+(l1-l2),pattern) == 0 &&
(l1==l2 || name[l1-(l2+1)] == '/'))
return 1;
}
return 0;
}
int check_exclude(char *name,char **local_exclude_list)
{
int n;
if (exclude_list) {
for (n=0; exclude_list[n]; n++)
if (check_one_exclude(name,exclude_list[n]))
/* set exclude_list to NULL temporarily so check_exclude */
/* will always return true */
ex_list = exclude_list;
exclude_list = NULL;
for (n=0; (ex = ex_list[n]) != NULL; n++) {
if (ex == exclude_the_rest)
break;
p = ex->pattern;
while (*p == '/') {
/* skip the allowed beginning slashes */
p++;
}
send_file_name(f,flist,p,0,0);
}
exclude_list = ex_list;
return 1;
}
if (local_exclude_list) {
for (n=0; local_exclude_list[n]; n++)
if (check_one_exclude(name,local_exclude_list[n]))
return 1;
}
return 0;
}
void add_exclude_list(char *pattern,char ***list)
/* build an exclude structure given a exclude pattern */
static struct exclude_struct *make_exclude(char *pattern, int include)
{
int len=0;
if (list && *list)
for (; (*list)[len]; len++) ;
struct exclude_struct *ret;
if (strcmp(pattern,"!") == 0) {
if (verbose > 2)
rprintf(FINFO,"clearing exclude list\n");
while ((len)--)
free((*list)[len]);
free((*list));
*list = NULL;
return;
}
ret = (struct exclude_struct *)malloc(sizeof(*ret));
if (!ret) out_of_memory("make_exclude");
if (!*list) {
*list = (char **)malloc(sizeof(char *)*2);
} else {
*list = (char **)realloc(*list,sizeof(char *)*(len+2));
}
memset(ret, 0, sizeof(*ret));
if (!*list || !((*list)[len] = strdup(pattern)))
out_of_memory("add_exclude");
if (strncmp(pattern,"- ",2) == 0) {
pattern += 2;
} else if (strncmp(pattern,"+ ",2) == 0) {
ret->include = 1;
pattern += 2;
} else {
ret->include = include;
}
if (verbose > 2)
rprintf(FINFO,"add_exclude(%s)\n",pattern);
(*list)[len+1] = NULL;
ret->pattern = strdup(pattern);
if (!ret->pattern) out_of_memory("make_exclude");
if (strpbrk(pattern, "*[?")) {
if (!ret->include && (*pattern == '*') && (*(pattern+1) == '\0')) {
exclude_the_rest = ret;
} else {
only_included_files = 0;
}
ret->regular_exp = 1;
} else if (!ret->include) {
only_included_files = 0;
}
if (strlen(pattern) > 1 && pattern[strlen(pattern)-1] == '/') {
ret->pattern[strlen(pattern)-1] = 0;
ret->directory = 1;
}
if (!strchr(ret->pattern,'/')) {
ret->local = 1;
}
return ret;
}
void add_exclude(char *pattern)
static void free_exclude(struct exclude_struct *ex)
{
add_exclude_list(pattern,&exclude_list);
free(ex->pattern);
memset(ex,0,sizeof(*ex));
free(ex);
}
char **make_exclude_list(char *fname,char **list1,int fatal)
static int check_one_exclude(char *name,struct exclude_struct *ex,
STRUCT_STAT *st)
{
char **list=list1;
FILE *f = fopen(fname,"r");
char line[MAXPATHLEN];
if (!f) {
if (fatal) {
rprintf(FERROR,"%s : %s\n",fname,strerror(errno));
exit_cleanup(1);
}
return list;
}
char *p;
int match_start=0;
char *pattern = ex->pattern;
while (fgets(line,MAXPATHLEN,f)) {
int l = strlen(line);
if (l && line[l-1] == '\n') l--;
line[l] = 0;
if (line[0]) add_exclude_list(line,&list);
}
fclose(f);
return list;
if (ex->local && (p=strrchr(name,'/')))
name = p+1;
if (!name[0]) return 0;
if (ex->directory && !S_ISDIR(st->st_mode)) return 0;
if (*pattern == '/' && *name != '/') {
match_start = 1;
pattern++;
}
if (ex->regular_exp) {
if (fnmatch(pattern, name, 0) == 0)
return 1;
} else {
int l1 = strlen(name);
int l2 = strlen(pattern);
if (l2 <= l1 &&
strcmp(name+(l1-l2),pattern) == 0 &&
(l1==l2 || (!match_start && name[l1-(l2+1)] == '/')))
return 1;
}
return 0;
}
void add_exclude_file(char *fname,int fatal)
int check_exclude(char *name,struct exclude_struct **local_exclude_list,
STRUCT_STAT *st)
{
int n;
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++)
if (check_one_exclude(name,exclude_list[n],st))
return !exclude_list[n]->include;
}
if (local_exclude_list) {
for (n=0; local_exclude_list[n]; n++)
if (check_one_exclude(name,local_exclude_list[n],st))
return !local_exclude_list[n]->include;
}
return 0;
}
void add_exclude_list(char *pattern,struct exclude_struct ***list, int include)
{
int len=0;
if (list && *list)
for (; (*list)[len]; len++) ;
if (strcmp(pattern,"!") == 0) {
if (verbose > 2)
rprintf(FINFO,"clearing exclude list\n");
while ((len)--) {
free_exclude((*list)[len]);
}
free((*list));
*list = NULL;
only_included_files = 1;
exclude_the_rest = NULL;
return;
}
*list = (struct exclude_struct **)Realloc(*list,sizeof(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)\n",pattern);
(*list)[len+1] = NULL;
}
void add_exclude(char *pattern, int include)
{
add_exclude_list(pattern,&exclude_list, include);
}
struct exclude_struct **make_exclude_list(char *fname,
struct exclude_struct **list1,
int fatal, int include)
{
struct exclude_struct **list=list1;
FILE *f = fopen(fname,"r");
char line[MAXPATHLEN];
if (!f) {
if (fatal) {
rprintf(FERROR,"%s : %s\n",fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
return list;
}
while (fgets(line,MAXPATHLEN,f)) {
int l = strlen(line);
if (l && line[l-1] == '\n') l--;
line[l] = 0;
if (line[0]) add_exclude_list(line,&list,include);
}
fclose(f);
return list;
}
void add_exclude_file(char *fname,int fatal,int include)
{
if (!fname || !*fname) return;
exclude_list = make_exclude_list(fname,exclude_list,fatal);
exclude_list = make_exclude_list(fname,exclude_list,fatal,include);
}
void send_exclude_list(int f)
{
int i;
if (exclude_list)
for (i=0;exclude_list[i];i++) {
int l = strlen(exclude_list[i]);
if (l == 0) continue;
write_int(f,l);
write_buf(f,exclude_list[i],l);
}
write_int(f,0);
int i;
extern int remote_version;
if (!exclude_list) {
write_int(f,0);
return;
}
for (i=0;exclude_list[i];i++) {
char *pattern = exclude_list[i]->pattern;
int l;
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];
int l;
while ((l=read_int(f))) {
if (l >= MAXPATHLEN) overflow("recv_exclude_list");
read_sbuf(f,line,l);
add_exclude(line);
}
char line[MAXPATHLEN];
int l;
while ((l=read_int(f))) {
if (l >= MAXPATHLEN) overflow("recv_exclude_list");
read_sbuf(f,line,l);
add_exclude(line,0);
}
}
@@ -181,7 +301,18 @@ void add_exclude_line(char *p)
p = strdup(p);
if (!p) out_of_memory("add_exclude_line");
for (tok=strtok(p," "); tok; tok=strtok(NULL," "))
add_exclude(tok);
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=strtok(p," "); tok; tok=strtok(NULL," "))
add_exclude(tok, 1);
free(p);
}
@@ -197,17 +328,17 @@ static char *cvs_ignore_list[] = {
void add_cvs_excludes(void)
{
char fname[MAXPATHLEN];
char *p;
int i;
char fname[MAXPATHLEN];
char *p;
int i;
for (i=0; cvs_ignore_list[i]; i++)
add_exclude(cvs_ignore_list[i]);
for (i=0; cvs_ignore_list[i]; i++)
add_exclude(cvs_ignore_list[i], 0);
if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
slprintf(fname,sizeof(fname)-1, "%s/.cvsignore",p);
add_exclude_file(fname,0);
}
if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
slprintf(fname,sizeof(fname), "%s/.cvsignore",p);
add_exclude_file(fname,0,0);
}
add_exclude_line(getenv("CVSIGNORE"));
add_exclude_line(getenv("CVSIGNORE"));
}

218
fileio.c Normal file
View File

@@ -0,0 +1,218 @@
/*
Copyright (C) Andrew Tridgell 1998
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
*/
#include "rsync.h"
static char last_byte;
static int last_sparse;
extern int sparse_files;
int sparse_end(int f)
{
if (last_sparse) {
do_lseek(f,-1,SEEK_CUR);
return (write(f,&last_byte,1) == 1 ? 0 : -1);
}
last_sparse = 0;
return 0;
}
static int write_sparse(int f,char *buf,int len)
{
int l1=0,l2=0;
int ret;
for (l1=0;l1<len && buf[l1]==0;l1++) ;
for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
last_byte = buf[len-1];
if (l1 == len || l2 > 0)
last_sparse=1;
if (l1 > 0)
do_lseek(f,l1,SEEK_CUR);
if (l1 == len)
return len;
if ((ret=write(f,buf+l1,len-(l1+l2))) != len-(l1+l2)) {
if (ret == -1 || ret == 0) return ret;
return (l1+ret);
}
if (l2 > 0)
do_lseek(f,l2,SEEK_CUR);
return len;
}
int write_file(int f,char *buf,int len)
{
int ret = 0;
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;
}
len -= r1;
buf += r1;
ret += r1;
}
return ret;
}
struct map_struct *map_file(int fd,OFF_T len)
{
struct map_struct *ret;
ret = (struct map_struct *)malloc(sizeof(*ret));
if (!ret) out_of_memory("map_file");
ret->map = NULL;
ret->fd = fd;
ret->size = len;
ret->p = NULL;
ret->p_size = 0;
ret->p_offset = 0;
ret->p_len = 0;
#ifdef USE_MMAP
len = MIN(len, MAX_MAP_SIZE);
ret->map = (char *)do_mmap(NULL,len,PROT_READ,MAP_SHARED,fd,0);
if (ret->map == (char *)-1) {
ret->map = NULL;
} else {
ret->p_len = len;
}
#endif
return ret;
}
char *map_ptr(struct map_struct *map,OFF_T offset,int len)
{
int nread;
if (len == 0)
return NULL;
if (len > (map->size-offset))
len = map->size-offset;
#ifdef USE_MMAP
if (map->map) {
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
return (map->map + (offset - map->p_offset));
}
if (munmap(map->map, map->p_len) != 0) {
rprintf(FERROR,"munmap failed : %s\n", strerror(errno));
exit_cleanup(RERR_MALLOC);
}
/* align the mmap region on a nice boundary back a bit from
where it is asked for to allow for some seeking */
if (offset > 2*CHUNK_SIZE) {
map->p_offset = offset - 2*CHUNK_SIZE;
map->p_offset &= ~((OFF_T)(CHUNK_SIZE-1));
} else {
map->p_offset = 0;
}
/* map up to MAX_MAP_SIZE */
map->p_len = MAX(len, MAX_MAP_SIZE);
map->p_len = MIN(map->p_len, map->size - map->p_offset);
map->map = (char *)do_mmap(NULL,map->p_len,PROT_READ,
MAP_SHARED,map->fd,map->p_offset);
if (map->map == (char *)-1) {
map->map = NULL;
map->p_len = 0;
map->p_offset = 0;
} else {
return (map->map + (offset - map->p_offset));
}
}
#endif
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
return (map->p + (offset - map->p_offset));
}
len = MAX(len,CHUNK_SIZE);
if (len > (map->size-offset))
len = map->size-offset;
if (len > map->p_size) {
if (map->p) free(map->p);
map->p = (char *)malloc(len);
if (!map->p) out_of_memory("map_ptr");
map->p_size = len;
}
map->p_offset = offset;
map->p_len = len;
if (do_lseek(map->fd,offset,SEEK_SET) != offset) {
rprintf(FERROR,"lseek failed in map_ptr\n");
exit_cleanup(RERR_FILEIO);
}
if ((nread=read(map->fd,map->p,len)) != len) {
if (nread < 0) nread = 0;
/* the best we can do is zero the buffer - the file
has changed mid transfer! */
memset(map->p+nread, 0, len - nread);
}
return map->p;
}
void unmap_file(struct map_struct *map)
{
#ifdef USE_MMAP
if (map->map) {
munmap(map->map,map->p_len);
map->map = NULL;
}
#endif
if (map->p) {
free(map->p);
map->p = NULL;
}
memset(map, 0, sizeof(*map));
free(map);
}

558
flist.c
View File

@@ -21,12 +21,13 @@
#include "rsync.h"
extern struct stats stats;
extern int csum_length;
extern int verbose;
extern int am_server;
extern int always_checksum;
extern int64 total_size;
extern int cvs_exclude;
@@ -46,7 +47,43 @@ extern int copy_links;
extern int remote_version;
extern int io_error;
static char **local_exclude_list;
static struct exclude_struct **local_exclude_list;
static void clean_flist(struct file_list *flist, int strip_root);
static void list_file_entry(struct file_struct *f)
{
char perms[11] = "----------";
char *perm_map = "rwxrwxrwx";
int i;
if (!f->basename)
/* this can happen if duplicate names were removed */
return;
for (i=0;i<9;i++) {
if (f->mode & (1<<i)) perms[9-i] = perm_map[8-i];
}
if (S_ISLNK(f->mode)) perms[0] = 'l';
if (S_ISDIR(f->mode)) perms[0] = 'd';
if (S_ISBLK(f->mode)) perms[0] = 'b';
if (S_ISCHR(f->mode)) perms[0] = 'c';
if (S_ISSOCK(f->mode)) perms[0] = 's';
if (S_ISFIFO(f->mode)) perms[0] = 'p';
if (preserve_links && S_ISLNK(f->mode)) {
rprintf(FINFO,"%s %11.0f %s %s -> %s\n",
perms,
(double)f->length, timestring(f->modtime),
f_name(f), f->link);
} else {
rprintf(FINFO,"%s %11.0f %s %s\n",
perms,
(double)f->length, timestring(f->modtime), f_name(f));
}
}
int link_stat(const char *Path, STRUCT_STAT *Buffer)
{
@@ -67,7 +104,7 @@ int link_stat(const char *Path, STRUCT_STAT *Buffer)
*/
static int match_file_name(char *fname,STRUCT_STAT *st)
{
if (check_exclude(fname,local_exclude_list)) {
if (check_exclude(fname,local_exclude_list,st)) {
if (verbose > 2)
rprintf(FINFO,"excluding file %s\n",fname);
return 0;
@@ -86,140 +123,119 @@ static void set_filesystem(char *fname)
}
static int to_wire_mode(mode_t mode)
{
if (S_ISLNK(mode) && (S_IFLNK != 0120000)) {
return (mode & ~(_S_IFMT)) | 0120000;
}
return (int)mode;
}
static mode_t from_wire_mode(int mode)
{
if ((mode & (_S_IFMT)) == 0120000 && (S_IFLNK != 0120000)) {
return (mode & ~(_S_IFMT)) | S_IFLNK;
}
return (mode_t)mode;
}
static void send_directory(int f,struct file_list *flist,char *dir);
static char *flist_dir;
static void clean_fname(char *name)
static void send_file_entry(struct file_struct *file,int f,unsigned base_flags)
{
char *p;
int l;
int modified = 1;
unsigned char flags;
static time_t last_time;
static mode_t last_mode;
static dev_t last_rdev;
static uid_t last_uid;
static gid_t last_gid;
static char lastname[MAXPATHLEN];
char *fname;
int l1,l2;
if (!name) return;
if (f == -1) return;
while (modified) {
modified = 0;
if (!file) {
write_byte(f,0);
return;
}
if ((p=strstr(name,"/./"))) {
modified = 1;
while (*p) {
p[0] = p[2];
p++;
}
}
fname = f_name(file);
if ((p=strstr(name,"//"))) {
modified = 1;
while (*p) {
p[0] = p[1];
p++;
}
}
flags = base_flags;
if (strncmp(p=name,"./",2) == 0) {
modified = 1;
do {
p[0] = p[2];
} while (*p++);
}
if (file->mode == last_mode) flags |= SAME_MODE;
if (file->rdev == last_rdev) flags |= SAME_RDEV;
if (file->uid == last_uid) flags |= SAME_UID;
if (file->gid == last_gid) flags |= SAME_GID;
if (file->modtime == last_time) flags |= SAME_TIME;
l = strlen(p=name);
if (l > 1 && p[l-1] == '/') {
modified = 1;
p[l-1] = 0;
}
}
}
for (l1=0;lastname[l1] && (fname[l1] == lastname[l1]) && (l1 < 255);l1++) ;
l2 = strlen(fname) - l1;
if (l1 > 0) flags |= SAME_NAME;
if (l2 > 255) flags |= LONG_NAME;
/* we must make sure we don't send a zero flags byte or the other
end will terminate the flist transfer */
if (flags == 0 && !S_ISDIR(file->mode)) flags |= FLAG_DELETE;
if (flags == 0) flags |= LONG_NAME;
void send_file_entry(struct file_struct *file,int f,unsigned base_flags)
{
unsigned char flags;
static time_t last_time;
static mode_t last_mode;
static dev_t last_rdev;
static uid_t last_uid;
static gid_t last_gid;
static char lastname[MAXPATHLEN];
char *fname;
int l1,l2;
write_byte(f,flags);
if (flags & SAME_NAME)
write_byte(f,l1);
if (flags & LONG_NAME)
write_int(f,l2);
else
write_byte(f,l2);
write_buf(f,fname+l1,l2);
if (f == -1) return;
if (!file) {
write_byte(f,0);
return;
}
fname = f_name(file);
flags = base_flags;
if (file->mode == last_mode) flags |= SAME_MODE;
if (file->rdev == last_rdev) flags |= SAME_RDEV;
if (file->uid == last_uid) flags |= SAME_UID;
if (file->gid == last_gid) flags |= SAME_GID;
if (file->modtime == last_time) flags |= SAME_TIME;
for (l1=0;lastname[l1] && fname[l1] == lastname[l1];l1++) ;
l2 = strlen(fname) - l1;
if (l1 > 0) flags |= SAME_NAME;
if (l2 > 255) flags |= LONG_NAME;
write_byte(f,flags);
if (flags & SAME_NAME)
write_byte(f,l1);
if (flags & LONG_NAME)
write_int(f,l2);
else
write_byte(f,l2);
write_buf(f,fname+l1,l2);
write_longint(f,file->length);
if (!(flags & SAME_TIME))
write_int(f,(int)file->modtime);
if (!(flags & SAME_MODE))
write_int(f,(int)file->mode);
if (preserve_uid && !(flags & SAME_UID)) {
add_uid(file->uid);
write_int(f,(int)file->uid);
}
if (preserve_gid && !(flags & SAME_GID)) {
add_gid(file->gid);
write_int(f,(int)file->gid);
}
if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_RDEV))
write_int(f,(int)file->rdev);
write_longint(f,file->length);
if (!(flags & SAME_TIME))
write_int(f,(int)file->modtime);
if (!(flags & SAME_MODE))
write_int(f,to_wire_mode(file->mode));
if (preserve_uid && !(flags & SAME_UID)) {
add_uid(file->uid);
write_int(f,(int)file->uid);
}
if (preserve_gid && !(flags & SAME_GID)) {
add_gid(file->gid);
write_int(f,(int)file->gid);
}
if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_RDEV))
write_int(f,(int)file->rdev);
#if SUPPORT_LINKS
if (preserve_links && S_ISLNK(file->mode)) {
write_int(f,strlen(file->link));
write_buf(f,file->link,strlen(file->link));
}
if (preserve_links && S_ISLNK(file->mode)) {
write_int(f,strlen(file->link));
write_buf(f,file->link,strlen(file->link));
}
#endif
#if SUPPORT_HARD_LINKS
if (preserve_hard_links && S_ISREG(file->mode)) {
write_int(f,(int)file->dev);
write_int(f,(int)file->inode);
}
if (preserve_hard_links && S_ISREG(file->mode)) {
write_int(f,(int)file->dev);
write_int(f,(int)file->inode);
}
#endif
if (always_checksum) {
write_buf(f,file->sum,csum_length);
}
if (always_checksum) {
write_buf(f,file->sum,csum_length);
}
last_mode = file->mode;
last_rdev = file->rdev;
last_uid = file->uid;
last_gid = file->gid;
last_time = file->modtime;
last_mode = file->mode;
last_rdev = file->rdev;
last_uid = file->uid;
last_gid = file->gid;
last_time = file->modtime;
strlcpy(lastname,fname,MAXPATHLEN-1);
lastname[MAXPATHLEN-1] = 0;
strlcpy(lastname,fname,MAXPATHLEN);
lastname[MAXPATHLEN-1] = 0;
}
@@ -227,101 +243,102 @@ void send_file_entry(struct file_struct *file,int f,unsigned base_flags)
static void receive_file_entry(struct file_struct **fptr,
unsigned flags,int f)
{
static time_t last_time;
static mode_t last_mode;
static dev_t last_rdev;
static uid_t last_uid;
static gid_t last_gid;
static char lastname[MAXPATHLEN];
char thisname[MAXPATHLEN];
int l1=0,l2=0;
char *p;
struct file_struct *file;
static time_t last_time;
static mode_t last_mode;
static dev_t last_rdev;
static uid_t last_uid;
static gid_t last_gid;
static char lastname[MAXPATHLEN];
char thisname[MAXPATHLEN];
int l1=0,l2=0;
char *p;
struct file_struct *file;
if (flags & SAME_NAME)
l1 = read_byte(f);
if (flags & SAME_NAME)
l1 = read_byte(f);
if (flags & LONG_NAME)
l2 = read_int(f);
else
l2 = read_byte(f);
if (flags & LONG_NAME)
l2 = read_int(f);
else
l2 = read_byte(f);
file = (struct file_struct *)malloc(sizeof(*file));
if (!file) out_of_memory("receive_file_entry");
bzero((char *)file,sizeof(*file));
(*fptr) = file;
file = (struct file_struct *)malloc(sizeof(*file));
if (!file) out_of_memory("receive_file_entry");
memset((char *)file, 0, sizeof(*file));
(*fptr) = file;
if (l2 >= MAXPATHLEN-l1) overflow("receive_file_entry");
if (l2 >= MAXPATHLEN-l1) overflow("receive_file_entry");
strlcpy(thisname,lastname,l1);
read_sbuf(f,&thisname[l1],l2);
thisname[l1+l2] = 0;
strlcpy(thisname,lastname,l1+1);
read_sbuf(f,&thisname[l1],l2);
thisname[l1+l2] = 0;
strlcpy(lastname,thisname,MAXPATHLEN-1);
lastname[MAXPATHLEN-1] = 0;
strlcpy(lastname,thisname,MAXPATHLEN);
lastname[MAXPATHLEN-1] = 0;
clean_fname(thisname);
clean_fname(thisname);
if (relative_paths && thisname[0] == '/') {
/* strip / off absolute paths in destination */
memmove(thisname, thisname+1, strlen(thisname));
if (!thisname[0]) strcpy(thisname,".");
}
if ((p = strrchr(thisname,'/'))) {
static char *lastdir;
*p = 0;
if (lastdir && strcmp(thisname, lastdir)==0) {
file->dirname = lastdir;
} else {
file->dirname = strdup(thisname);
lastdir = file->dirname;
}
file->basename = strdup(p+1);
} else {
file->dirname = NULL;
file->basename = strdup(thisname);
}
if ((p = strrchr(thisname,'/'))) {
static char *lastdir;
*p = 0;
if (lastdir && strcmp(thisname, lastdir)==0) {
file->dirname = lastdir;
} else {
file->dirname = strdup(thisname);
lastdir = file->dirname;
}
file->basename = strdup(p+1);
} else {
file->dirname = NULL;
file->basename = strdup(thisname);
}
if (!file->basename) out_of_memory("receive_file_entry 1");
if (!file->basename) out_of_memory("receive_file_entry 1");
file->flags = flags;
file->length = read_longint(f);
file->modtime = (flags & SAME_TIME) ? last_time : (time_t)read_int(f);
file->mode = (flags & SAME_MODE) ? last_mode : (mode_t)read_int(f);
if (preserve_uid)
file->uid = (flags & SAME_UID) ? last_uid : (uid_t)read_int(f);
if (preserve_gid)
file->gid = (flags & SAME_GID) ? last_gid : (gid_t)read_int(f);
if (preserve_devices && IS_DEVICE(file->mode))
file->rdev = (flags & SAME_RDEV) ? last_rdev : (dev_t)read_int(f);
file->flags = flags;
file->length = read_longint(f);
file->modtime = (flags & SAME_TIME) ? last_time : (time_t)read_int(f);
file->mode = (flags & SAME_MODE) ? last_mode : from_wire_mode(read_int(f));
if (preserve_uid)
file->uid = (flags & SAME_UID) ? last_uid : (uid_t)read_int(f);
if (preserve_gid)
file->gid = (flags & SAME_GID) ? last_gid : (gid_t)read_int(f);
if (preserve_devices && IS_DEVICE(file->mode))
file->rdev = (flags & SAME_RDEV) ? last_rdev : (dev_t)read_int(f);
if (preserve_links && S_ISLNK(file->mode)) {
int l = read_int(f);
file->link = (char *)malloc(l+1);
if (!file->link) out_of_memory("receive_file_entry 2");
read_sbuf(f,file->link,l);
}
if (preserve_links && S_ISLNK(file->mode)) {
int l = read_int(f);
file->link = (char *)malloc(l+1);
if (!file->link) out_of_memory("receive_file_entry 2");
read_sbuf(f,file->link,l);
}
#if SUPPORT_HARD_LINKS
if (preserve_hard_links && S_ISREG(file->mode)) {
file->dev = read_int(f);
file->inode = read_int(f);
}
if (preserve_hard_links && S_ISREG(file->mode)) {
file->dev = read_int(f);
file->inode = read_int(f);
}
#endif
if (always_checksum) {
file->sum = (char *)malloc(MD4_SUM_LENGTH);
if (!file->sum) out_of_memory("md4 sum");
read_buf(f,file->sum,csum_length);
}
if (always_checksum) {
file->sum = (char *)malloc(MD4_SUM_LENGTH);
if (!file->sum) out_of_memory("md4 sum");
read_buf(f,file->sum,csum_length);
}
last_mode = file->mode;
last_rdev = file->rdev;
last_uid = file->uid;
last_gid = file->gid;
last_time = file->modtime;
last_mode = file->mode;
last_rdev = file->rdev;
last_uid = file->uid;
last_gid = file->gid;
last_time = file->modtime;
if (!preserve_perms) {
extern int orig_umask;
/* set an appropriate set of permissions based on original
permissions and umask. This emulates what GNU cp does */
file->mode &= ~orig_umask;
}
}
@@ -357,12 +374,12 @@ static struct file_struct *make_file(char *fname)
char *p;
char cleaned_name[MAXPATHLEN];
strlcpy(cleaned_name, fname, MAXPATHLEN-1);
strlcpy(cleaned_name, fname, MAXPATHLEN);
cleaned_name[MAXPATHLEN-1] = 0;
clean_fname(cleaned_name);
fname = cleaned_name;
bzero(sum,SUM_LENGTH);
memset(sum,0,SUM_LENGTH);
if (link_stat(fname,&st) != 0) {
io_error = 1;
@@ -389,7 +406,7 @@ static struct file_struct *make_file(char *fname)
file = (struct file_struct *)malloc(sizeof(*file));
if (!file) out_of_memory("make_file");
bzero((char *)file,sizeof(*file));
memset((char *)file,0,sizeof(*file));
if ((p = strrchr(fname,'/'))) {
static char *lastdir;
@@ -459,14 +476,14 @@ static struct file_struct *make_file(char *fname)
}
if (!S_ISDIR(st.st_mode))
total_size += st.st_size;
stats.total_size += st.st_size;
return file;
}
static void send_file_name(int f,struct file_list *flist,char *fname,
void send_file_name(int f,struct file_list *flist,char *fname,
int recursive, unsigned base_flags)
{
struct file_struct *file;
@@ -493,10 +510,10 @@ static void send_file_name(int f,struct file_list *flist,char *fname,
}
if (S_ISDIR(file->mode) && recursive) {
char **last_exclude_list = local_exclude_list;
send_directory(f,flist,f_name(file));
local_exclude_list = last_exclude_list;
return;
struct exclude_struct **last_exclude_list = local_exclude_list;
send_directory(f,flist,f_name(file));
local_exclude_list = last_exclude_list;
return;
}
}
@@ -513,12 +530,12 @@ static void send_directory(int f,struct file_list *flist,char *dir)
d = opendir(dir);
if (!d) {
io_error = 1;
rprintf(FERROR,"%s: %s\n",
rprintf(FERROR,"opendir(%s): %s\n",
dir,strerror(errno));
return;
}
strlcpy(fname,dir,MAXPATHLEN-1);
strlcpy(fname,dir,MAXPATHLEN);
l = strlen(fname);
if (fname[l-1] != '/') {
if (l == MAXPATHLEN-1) {
@@ -527,15 +544,17 @@ static void send_directory(int f,struct file_list *flist,char *dir)
closedir(d);
return;
}
strlcat(fname,"/", MAXPATHLEN-1);
strlcat(fname,"/", MAXPATHLEN);
l++;
}
p = fname + strlen(fname);
local_exclude_list = NULL;
if (cvs_exclude) {
if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN-1) {
strcpy(p,".cvsignore");
local_exclude_list = make_exclude_list(fname,NULL,0);
local_exclude_list = make_exclude_list(fname,NULL,0,0);
} else {
io_error = 1;
rprintf(FINFO,"cannot cvs-exclude in long-named directory %s\n",fname);
@@ -547,8 +566,12 @@ static void send_directory(int f,struct file_list *flist,char *dir)
if (strcmp(dname,".")==0 ||
strcmp(dname,"..")==0)
continue;
strlcpy(p,dname,MAXPATHLEN-(l+1));
send_file_name(f,flist,fname,recurse,FLAG_DELETE);
strlcpy(p,dname,MAXPATHLEN-l);
send_file_name(f,flist,fname,recurse,0);
}
if (local_exclude_list) {
add_exclude_list("!", &local_exclude_list, 0);
}
closedir(d);
@@ -560,16 +583,18 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
{
int i,l;
STRUCT_STAT st;
char *p,*dir;
char dbuf[MAXPATHLEN];
char *p,*dir,*olddir;
char lastpath[MAXPATHLEN]="";
struct file_list *flist;
int64 start_write;
if (verbose && recurse && !am_server && f != -1) {
rprintf(FINFO,"building file list ... ");
rflush(FINFO);
}
start_write = stats.total_written;
flist = (struct file_list *)malloc(sizeof(flist[0]));
if (!flist) out_of_memory("send_file_list");
@@ -587,11 +612,11 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
char fname2[MAXPATHLEN];
char *fname = fname2;
strlcpy(fname,argv[i],MAXPATHLEN-1);
strlcpy(fname,argv[i],MAXPATHLEN);
l = strlen(fname);
if (l != 1 && fname[l-1] == '/') {
strlcat(fname,".",MAXPATHLEN-1);
strlcat(fname,".",MAXPATHLEN);
}
if (link_stat(fname,&st) != 0) {
@@ -606,6 +631,7 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
}
dir = NULL;
olddir = NULL;
if (!relative_paths) {
p = strrchr(fname,'/');
@@ -622,11 +648,14 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
thus getting their permissions right */
*p = 0;
if (strcmp(lastpath,fname)) {
strlcpy(lastpath, fname, sizeof(lastpath)-1);
strlcpy(lastpath, fname, sizeof(lastpath));
*p = '/';
for (p=fname+1; (p=strchr(p,'/')); p++) {
int copy_links_saved = copy_links;
*p = 0;
copy_links = 0;
send_file_name(f, flist, fname, 0, 0);
copy_links = copy_links_saved;
*p = '/';
}
} else {
@@ -638,32 +667,32 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
fname = ".";
if (dir && *dir) {
if (getcwd(dbuf,MAXPATHLEN-1) == NULL) {
rprintf(FERROR,"getwd : %s\n",strerror(errno));
exit_cleanup(1);
}
if (chdir(dir) != 0) {
olddir = push_dir(dir, 1);
if (!olddir) {
io_error=1;
rprintf(FERROR,"chdir %s : %s\n",
rprintf(FERROR,"push_dir %s : %s\n",
dir,strerror(errno));
continue;
}
flist_dir = dir;
if (one_file_system)
set_filesystem(fname);
send_file_name(f,flist,fname,recurse,FLAG_DELETE);
flist_dir = NULL;
if (chdir(dbuf) != 0) {
rprintf(FERROR,"chdir %s : %s\n",
dbuf,strerror(errno));
exit_cleanup(1);
}
continue;
}
if (one_file_system)
set_filesystem(fname);
send_file_name(f,flist,fname,recurse,FLAG_DELETE);
if (!recurse || !send_included_file_names(f,flist))
send_file_name(f,flist,fname,recurse,FLAG_DELETE);
if (olddir != NULL) {
flist_dir = NULL;
if (pop_dir(olddir) != 0) {
rprintf(FERROR,"pop_dir %s : %s\n",
dir,strerror(errno));
exit_cleanup(RERR_FILESELECT);
}
}
}
if (f != -1) {
@@ -673,7 +702,7 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
if (verbose && recurse && !am_server && f != -1)
rprintf(FINFO,"done\n");
clean_flist(flist);
clean_flist(flist, 0);
/* now send the uid/gid list. This was introduced in protocol
version 15 */
@@ -688,7 +717,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
if (f != -1) {
io_end_buffering(f);
write_flush(f);
stats.flist_size = stats.total_written - start_write;
stats.num_files = flist->count;
}
if (verbose > 2)
@@ -702,12 +732,16 @@ struct file_list *recv_file_list(int f)
{
struct file_list *flist;
unsigned char flags;
int64 start_read;
extern int list_only;
if (verbose && recurse && !am_server) {
rprintf(FINFO,"receiving file list ... ");
rflush(FINFO);
}
start_read = stats.total_read;
flist = (struct file_list *)malloc(sizeof(flist[0]));
if (!flist)
goto oom;
@@ -738,7 +772,7 @@ struct file_list *recv_file_list(int f)
receive_file_entry(&flist->files[i],flags,f);
if (S_ISREG(flist->files[i]->mode))
total_size += flist->files[i]->length;
stats.total_size += flist->files[i]->length;
flist->count++;
@@ -750,7 +784,7 @@ struct file_list *recv_file_list(int f)
if (verbose > 2)
rprintf(FINFO,"received %d names\n",flist->count);
clean_flist(flist);
clean_flist(flist, relative_paths);
if (verbose && recurse && !am_server) {
rprintf(FINFO,"done\n");
@@ -766,9 +800,20 @@ struct file_list *recv_file_list(int f)
io_error |= read_int(f);
}
if (list_only) {
int i;
for (i=0;i<flist->count;i++) {
list_file_entry(flist->files[i]);
}
}
if (verbose > 2)
rprintf(FINFO,"recv_file_list done\n");
stats.flist_size = stats.total_read - start_read;
stats.num_files = flist->count;
return flist;
oom:
@@ -783,8 +828,8 @@ int file_compare(struct file_struct **f1,struct file_struct **f2)
if (!(*f1)->basename) return -1;
if (!(*f2)->basename) return 1;
if ((*f1)->dirname == (*f2)->dirname)
return strcmp((*f1)->basename, (*f2)->basename);
return strcmp(f_name(*f1),f_name(*f2));
return u_strcmp((*f1)->basename, (*f2)->basename);
return u_strcmp(f_name(*f1),f_name(*f2));
}
@@ -820,7 +865,7 @@ static void free_file(struct file_struct *file)
if (file->basename) free(file->basename);
if (file->link) free(file->link);
if (file->sum) free(file->sum);
bzero((char *)file, sizeof(*file));
memset((char *)file, 0, sizeof(*file));
}
@@ -834,9 +879,9 @@ void flist_free(struct file_list *flist)
free_file(flist->files[i]);
free(flist->files[i]);
}
bzero((char *)flist->files, sizeof(flist->files[0])*flist->count);
memset((char *)flist->files, 0, sizeof(flist->files[0])*flist->count);
free(flist->files);
bzero((char *)flist, sizeof(*flist));
memset((char *)flist, 0, sizeof(*flist));
free(flist);
}
@@ -845,7 +890,7 @@ void flist_free(struct file_list *flist)
* This routine ensures we don't have any duplicate names in our file list.
* duplicate names can cause corruption because of the pipelining
*/
void clean_flist(struct file_list *flist)
static void clean_flist(struct file_list *flist, int strip_root)
{
int i;
@@ -867,6 +912,37 @@ void clean_flist(struct file_list *flist)
free_file(flist->files[i]);
}
}
if (strip_root) {
/* we need to strip off the root directory in the case
of relative paths, but this must be done _after_
the sorting phase */
for (i=0;i<flist->count;i++) {
if (flist->files[i]->dirname &&
flist->files[i]->dirname[0] == '/') {
memmove(&flist->files[i]->dirname[0],
&flist->files[i]->dirname[1],
strlen(flist->files[i]->dirname));
}
if (flist->files[i]->dirname &&
!flist->files[i]->dirname[0]) {
flist->files[i]->dirname = NULL;
}
}
}
if (verbose <= 3) return;
for (i=0;i<flist->count;i++) {
rprintf(FINFO,"[%d] i=%d %s %s mode=0%o len=%d\n",
getpid(), i,
NS(flist->files[i]->dirname),
NS(flist->files[i]->basename),
flist->files[i]->mode,
(int)flist->files[i]->length);
}
}
@@ -884,9 +960,11 @@ char *f_name(struct file_struct *f)
n = (n+1)%10;
if (f->dirname) {
slprintf(p, MAXPATHLEN-1, "%s/%s", f->dirname, f->basename);
strlcpy(p, f->dirname, MAXPATHLEN);
strlcat(p, "/", MAXPATHLEN);
strlcat(p, f->basename, MAXPATHLEN);
} else {
strlcpy(p, f->basename, MAXPATHLEN-1);
strlcpy(p, f->basename, MAXPATHLEN);
}
return p;

420
generator.c Normal file
View File

@@ -0,0 +1,420 @@
/*
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.
*/
#include "rsync.h"
extern int verbose;
extern int dry_run;
extern int relative_paths;
extern int preserve_links;
extern int am_root;
extern int preserve_devices;
extern int preserve_hard_links;
extern int update_only;
extern int whole_file;
extern int block_size;
extern int csum_length;
extern int ignore_times;
extern int io_timeout;
extern int remote_version;
extern int always_checksum;
/* choose whether to skip a particular file */
static int skip_file(char *fname,
struct file_struct *file, STRUCT_STAT *st)
{
if (st->st_size != file->length) {
return 0;
}
/* if always checksum is set then we use the checksum instead
of the file time to determine whether to sync */
if (always_checksum && S_ISREG(st->st_mode)) {
char sum[MD4_SUM_LENGTH];
file_checksum(fname,sum,st->st_size);
return (memcmp(sum,file->sum,csum_length) == 0);
}
if (ignore_times) {
return 0;
}
return (st->st_mtime == file->modtime);
}
/* use a larger block size for really big files */
static int adapt_block_size(struct file_struct *file, int bsize)
{
int ret;
if (bsize != BLOCK_SIZE) return bsize;
ret = file->length / (10000); /* rough heuristic */
ret = ret & ~15; /* multiple of 16 */
if (ret < bsize) ret = bsize;
if (ret > CHUNK_SIZE/2) ret = CHUNK_SIZE/2;
return ret;
}
/*
send a sums struct down a fd
*/
static void send_sums(struct sum_struct *s,int f_out)
{
int i;
/* tell the other guy how many we are going to be doing and how many
bytes there are in the last chunk */
write_int(f_out,s?s->count:0);
write_int(f_out,s?s->n:block_size);
write_int(f_out,s?s->remainder:0);
if (s)
for (i=0;i<s->count;i++) {
write_int(f_out,s->sums[i].sum1);
write_buf(f_out,s->sums[i].sum2,csum_length);
}
}
/*
generate a stream of signatures/checksums that describe a buffer
generate approximately one checksum every n bytes
*/
static struct sum_struct *generate_sums(struct map_struct *buf,OFF_T len,int n)
{
int i;
struct sum_struct *s;
int count;
int block_len = n;
int remainder = (len%block_len);
OFF_T offset = 0;
count = (len+(block_len-1))/block_len;
s = (struct sum_struct *)malloc(sizeof(*s));
if (!s) out_of_memory("generate_sums");
s->count = count;
s->remainder = remainder;
s->n = n;
s->flength = len;
if (count==0) {
s->sums = NULL;
return s;
}
if (verbose > 3)
rprintf(FINFO,"count=%d rem=%d n=%d flength=%d\n",
s->count,s->remainder,s->n,(int)s->flength);
s->sums = (struct sum_buf *)malloc(sizeof(s->sums[0])*s->count);
if (!s->sums) out_of_memory("generate_sums");
for (i=0;i<count;i++) {
int n1 = MIN(len,n);
char *map = map_ptr(buf,offset,n1);
s->sums[i].sum1 = get_checksum1(map,n1);
get_checksum2(map,n1,s->sums[i].sum2);
s->sums[i].offset = offset;
s->sums[i].len = n1;
s->sums[i].i = i;
if (verbose > 3)
rprintf(FINFO,"chunk[%d] offset=%d len=%d sum1=%08x\n",
i,(int)s->sums[i].offset,s->sums[i].len,s->sums[i].sum1);
len -= n1;
offset += n1;
}
return s;
}
void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
{
int fd;
STRUCT_STAT st;
struct map_struct *buf;
struct sum_struct *s;
int statret;
struct file_struct *file = flist->files[i];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
extern char *compare_dest;
extern int list_only;
if (list_only) return;
if (verbose > 2)
rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
statret = link_stat(fname,&st);
if (S_ISDIR(file->mode)) {
if (dry_run) return;
if (statret == 0 && !S_ISDIR(st.st_mode)) {
if (do_unlink(fname) != 0) {
rprintf(FERROR,"unlink %s : %s\n",fname,strerror(errno));
return;
}
statret = -1;
}
if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
if (!(relative_paths && errno==ENOENT &&
create_directory_path(fname)==0 &&
do_mkdir(fname,file->mode)==0)) {
rprintf(FERROR,"mkdir %s : %s (2)\n",
fname,strerror(errno));
}
}
if (set_perms(fname,file,NULL,0) && verbose)
rprintf(FINFO,"%s/\n",fname);
return;
}
if (preserve_links && S_ISLNK(file->mode)) {
#if SUPPORT_LINKS
char lnk[MAXPATHLEN];
int l;
extern int safe_symlinks;
if (safe_symlinks && unsafe_symlink(file->link, fname)) {
if (verbose) {
rprintf(FINFO,"ignoring unsafe symlink %s -> %s\n",
fname,file->link);
}
return;
}
if (statret == 0) {
l = readlink(fname,lnk,MAXPATHLEN-1);
if (l > 0) {
lnk[l] = 0;
if (strcmp(lnk,file->link) == 0) {
set_perms(fname,file,&st,1);
return;
}
}
}
delete_file(fname);
if (do_symlink(file->link,fname) != 0) {
rprintf(FERROR,"link %s -> %s : %s\n",
fname,file->link,strerror(errno));
} else {
set_perms(fname,file,NULL,0);
if (verbose) {
rprintf(FINFO,"%s -> %s\n",
fname,file->link);
}
}
#endif
return;
}
#ifdef HAVE_MKNOD
if (am_root && preserve_devices && IS_DEVICE(file->mode)) {
if (statret != 0 ||
st.st_mode != file->mode ||
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->rdev);
if (do_mknod(fname,file->mode,file->rdev) != 0) {
rprintf(FERROR,"mknod %s : %s\n",fname,strerror(errno));
} else {
set_perms(fname,file,NULL,0);
if (verbose)
rprintf(FINFO,"%s\n",fname);
}
} else {
set_perms(fname,file,&st,1);
}
return;
}
#endif
if (preserve_hard_links && check_hard_link(file)) {
if (verbose > 1)
rprintf(FINFO,"%s is a hard link\n",f_name(file));
return;
}
if (!S_ISREG(file->mode)) {
rprintf(FINFO,"skipping non-regular file %s\n",fname);
return;
}
fnamecmp = fname;
if ((statret == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
int saveerrno = errno;
slprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",compare_dest,fname);
statret = link_stat(fnamecmpbuf,&st);
if (!S_ISREG(st.st_mode))
statret = -1;
if (statret == -1)
errno = saveerrno;
else
fnamecmp = fnamecmpbuf;
}
if (statret == -1) {
if (errno == ENOENT) {
write_int(f_out,i);
if (!dry_run) send_sums(NULL,f_out);
} else {
if (verbose > 1)
rprintf(FERROR,"recv_generator failed to open %s\n",fname);
}
return;
}
if (!S_ISREG(st.st_mode)) {
if (delete_file(fname) != 0) {
return;
}
/* now pretend the file didn't exist */
write_int(f_out,i);
if (!dry_run) send_sums(NULL,f_out);
return;
}
if (update_only && st.st_mtime > file->modtime && fnamecmp == fname) {
if (verbose > 1)
rprintf(FINFO,"%s is newer\n",fname);
return;
}
if (skip_file(fname, file, &st)) {
set_perms(fname,file,&st,1);
return;
}
if (dry_run) {
write_int(f_out,i);
return;
}
if (whole_file) {
write_int(f_out,i);
send_sums(NULL,f_out);
return;
}
/* open the file */
fd = open(fnamecmp,O_RDONLY);
if (fd == -1) {
rprintf(FERROR,"failed to open %s : %s\n",fnamecmp,strerror(errno));
rprintf(FERROR,"skipping %s\n",fname);
return;
}
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 %d\n",fnamecmp,(int)st.st_size);
s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));
if (verbose > 2)
rprintf(FINFO,"sending sums for %d\n",i);
write_int(f_out,i);
send_sums(s,f_out);
close(fd);
if (buf) unmap_file(buf);
free_sums(s);
}
void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
{
int i;
int phase=0;
if (verbose > 2)
rprintf(FINFO,"generator starting pid=%d count=%d\n",
(int)getpid(),flist->count);
for (i = 0; i < flist->count; i++) {
struct file_struct *file = flist->files[i];
mode_t saved_mode = file->mode;
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; /* user write */
}
recv_generator(local_name?local_name:f_name(file),
flist,i,f);
file->mode = saved_mode;
}
phase++;
csum_length = SUM_LENGTH;
ignore_times=1;
if (verbose > 2)
rprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
/* we expect to just sit around now, so don't exit on a
timeout. If we really get a timeout then the other process should
exit */
io_timeout = 0;
if (remote_version >= 13) {
/* in newer versions of the protocol the files can cycle through
the system more than once to catch initial checksum errors */
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(file),
flist,i,f);
}
phase++;
if (verbose > 2)
rprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
}
}

View File

@@ -56,7 +56,7 @@ void init_hard_links(struct file_list *flist)
out_of_memory("init_hard_links");
for (i = 0; i < flist->count; i++)
bcopy(flist->files[i], &hlink_list[i], sizeof(hlink_list[0]));
memcpy(&hlink_list[i], flist->files[i], sizeof(hlink_list[0]));
qsort(hlink_list,flist->count,
sizeof(hlink_list[0]),

469
io.c
View File

@@ -24,34 +24,23 @@
*/
#include "rsync.h"
static int64 total_written;
static int64 total_read;
/* if no timeout is specified then use a 60 second select timeout */
#define SELECT_TIMEOUT 60
static int io_multiplexing_out;
static int io_multiplexing_in;
static int multiplex_in_fd;
static int multiplex_out_fd;
static time_t last_io;
static int eof_error=1;
extern int verbose;
extern int sparse_files;
extern int io_timeout;
int64 write_total(void)
{
return total_written;
}
int64 read_total(void)
{
return total_read;
}
extern struct stats stats;
static int buffer_f_in = -1;
void setup_nonblocking(int f_in,int f_out)
void setup_readbuffer(int f_in)
{
set_blocking(f_out,0);
buffer_f_in = f_in;
}
@@ -68,10 +57,10 @@ static void check_timeout(void)
t = time(NULL);
if (last_io && io_timeout && (t-last_io)>io_timeout) {
rprintf(FERROR,"read timeout after %d second - exiting\n",
if (last_io && io_timeout && (t-last_io) >= io_timeout) {
rprintf(FERROR,"io timeout after %d second - exiting\n",
(int)(t-last_io));
exit_cleanup(1);
exit_cleanup(RERR_TIMEOUT);
}
}
@@ -80,45 +69,87 @@ static char *read_buffer;
static char *read_buffer_p;
static int read_buffer_len;
static int read_buffer_size;
static int no_flush;
static int no_flush_read;
/* read from a socket with IO timeout. return the number of
bytes read. If no bytes can be read then exit, never return
a number <= 0 */
static int read_timeout(int fd, char *buf, int len)
{
int n, ret=0;
no_flush_read++;
io_flush();
no_flush_read--;
while (ret == 0) {
fd_set fds;
struct timeval tv;
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) != 1) {
check_timeout();
continue;
}
n = read(fd, buf, len);
if (n > 0) {
buf += n;
len -= n;
ret += n;
if (io_timeout)
last_io = time(NULL);
continue;
}
if (n == -1 && errno == EINTR) {
continue;
}
if (n == -1 &&
(errno == EAGAIN || errno == EWOULDBLOCK)) {
/* this shouldn't happen, if it does then
sleep for a short time to prevent us
chewing too much CPU */
u_sleep(100);
continue;
}
if (n == 0) {
if (eof_error) {
rprintf(FERROR,"unexpected EOF in read_timeout\n");
}
exit_cleanup(RERR_STREAMIO);
}
rprintf(FERROR,"read error: %s\n", strerror(errno));
exit_cleanup(RERR_STREAMIO);
}
return ret;
}
/* continue trying to read len bytes - don't return until len
has been read */
static void read_loop(int fd, char *buf, int len)
{
while (len) {
int n = read(fd, buf, len);
if (n > 0) {
buf += n;
len -= n;
}
if (n == 0) {
rprintf(FERROR,"EOF in read_loop\n");
exit_cleanup(1);
}
if (n == -1) {
fd_set fds;
struct timeval tv;
int n = read_timeout(fd, buf, len);
if (errno != EAGAIN && errno != EWOULDBLOCK) {
rprintf(FERROR,"io error: %s\n",
strerror(errno));
exit_cleanup(1);
}
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = io_timeout;
tv.tv_usec = 0;
if (select(fd+1, &fds, NULL, NULL,
io_timeout?&tv:NULL) != 1) {
check_timeout();
}
}
buf += n;
len -= n;
}
}
/* read from the file descriptor handling multiplexing -
return number of bytes read
never return <= 0 */
static int read_unbuffered(int fd, char *buf, int len)
{
static int remaining;
@@ -127,7 +158,7 @@ static int read_unbuffered(int fd, char *buf, int len)
char line[1024];
if (!io_multiplexing_in || fd != multiplex_in_fd)
return read(fd, buf, len);
return read_timeout(fd, buf, len);
while (ret == 0) {
if (remaining) {
@@ -150,13 +181,13 @@ static int read_unbuffered(int fd, char *buf, int len)
if (tag != FERROR && tag != FINFO) {
rprintf(FERROR,"unexpected tag %d\n", tag);
exit_cleanup(1);
exit_cleanup(RERR_STREAMIO);
}
if (remaining > sizeof(line)-1) {
rprintf(FERROR,"multiplexing overflow %d\n\n",
remaining);
exit_cleanup(1);
exit_cleanup(RERR_STREAMIO);
}
read_loop(fd, line, remaining);
@@ -170,12 +201,13 @@ static int read_unbuffered(int fd, char *buf, int len)
}
/* This function was added to overcome a deadlock problem when using
* ssh. It looks like we can't allow our receive queue to get full or
* ssh will clag up. Uggh. */
static void read_check(int f)
{
int n;
int n = 8192;
if (f == -1) return;
@@ -183,12 +215,6 @@ static void read_check(int f)
read_buffer_p = read_buffer;
}
if ((n=num_waiting(f)) <= 0)
return;
/* things could deteriorate if we read in really small chunks */
if (n < 10) n = 1024;
if (n > MAX_READ_BUFFER/4)
n = MAX_READ_BUFFER/4;
@@ -199,28 +225,26 @@ static void read_check(int f)
if (n > (read_buffer_size - read_buffer_len)) {
read_buffer_size += n;
if (!read_buffer)
read_buffer = (char *)malloc(read_buffer_size);
else
read_buffer = (char *)realloc(read_buffer,read_buffer_size);
read_buffer = (char *)Realloc(read_buffer,read_buffer_size);
if (!read_buffer) out_of_memory("read check");
read_buffer_p = read_buffer;
}
n = read_unbuffered(f,read_buffer+read_buffer_len,n);
if (n > 0) {
read_buffer_len += n;
}
read_buffer_len += n;
}
static int readfd(int fd,char *buffer,int N)
/* do a buffered read from fd. don't return until all N bytes
have been read. If all N can't be read then exit with an error */
static void readfd(int fd,char *buffer,int N)
{
int ret;
int total=0;
struct timeval tv;
if (read_buffer_len < N)
if ((read_buffer_len < N) && (N < 1024)) {
read_check(buffer_f_in);
}
while (total < N) {
if (read_buffer_len > 0 && buffer_f_in == fd) {
@@ -232,47 +256,27 @@ static int readfd(int fd,char *buffer,int N)
continue;
}
no_flush_read++;
io_flush();
no_flush_read--;
while ((ret = read_unbuffered(fd,buffer + total,N-total)) == -1) {
fd_set fds;
if (errno != EAGAIN && errno != EWOULDBLOCK)
return -1;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = io_timeout;
tv.tv_usec = 0;
if (select(fd+1, &fds, NULL, NULL,
io_timeout?&tv:NULL) != 1) {
check_timeout();
}
}
if (ret <= 0)
return total;
ret = read_unbuffered(fd,buffer + total,N-total);
total += ret;
}
if (io_timeout)
last_io = time(NULL);
return total;
stats.total_read += total;
}
int32 read_int(int f)
{
int ret;
char b[4];
if ((ret=readfd(f,b,4)) != 4) {
if (verbose > 1)
rprintf(FERROR,"(%d) read_int: Error reading %d bytes : %s\n",
getpid(),4,ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_read += 4;
return IVAL(b,0);
char b[4];
int32 ret;
readfd(f,b,4);
ret = IVAL(b,0);
if (ret == (int32)0xffffffff) return -1;
return ret;
}
int64 read_longint(int f)
@@ -282,20 +286,16 @@ int64 read_longint(int f)
char b[8];
ret = read_int(f);
if ((int32)ret != (int32)0xffffffff) return ret;
if ((int32)ret != (int32)0xffffffff) {
return ret;
}
#ifdef NO_INT64
rprintf(FERROR,"Integer overflow - attempted 64 bit offset\n");
exit_cleanup(1);
exit_cleanup(RERR_UNSUPPORTED);
#else
if (remote_version >= 16) {
if ((ret=readfd(f,b,8)) != 8) {
if (verbose > 1)
rprintf(FERROR,"(%d) read_longint: Error reading %d bytes : %s\n",
getpid(),8,ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_read += 8;
readfd(f,b,8);
ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
}
#endif
@@ -305,14 +305,7 @@ int64 read_longint(int f)
void read_buf(int f,char *buf,int len)
{
int ret;
if ((ret=readfd(f,buf,len)) != len) {
if (verbose > 1)
rprintf(FERROR,"(%d) read_buf: Error reading %d bytes : %s\n",
getpid(),len,ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_read += len;
readfd(f,buf,len);
}
void read_sbuf(int f,char *buf,int len)
@@ -323,149 +316,88 @@ void read_sbuf(int f,char *buf,int len)
unsigned char read_byte(int f)
{
unsigned char c;
read_buf(f,(char *)&c,1);
return c;
}
static char last_byte;
static int last_sparse;
int sparse_end(int f)
{
if (last_sparse) {
do_lseek(f,-1,SEEK_CUR);
return (write(f,&last_byte,1) == 1 ? 0 : -1);
}
last_sparse = 0;
return 0;
}
static int write_sparse(int f,char *buf,int len)
{
int l1=0,l2=0;
int ret;
for (l1=0;l1<len && buf[l1]==0;l1++) ;
for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
last_byte = buf[len-1];
if (l1 == len || l2 > 0)
last_sparse=1;
if (l1 > 0)
do_lseek(f,l1,SEEK_CUR);
if (l1 == len)
return len;
if ((ret=write(f,buf+l1,len-(l1+l2))) != len-(l1+l2)) {
if (ret == -1 || ret == 0) return ret;
return (l1+ret);
}
if (l2 > 0)
do_lseek(f,l2,SEEK_CUR);
return len;
unsigned char c;
read_buf(f,(char *)&c,1);
return c;
}
int write_file(int f,char *buf,int len)
{
int ret = 0;
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;
}
len -= r1;
buf += r1;
ret += r1;
}
return ret;
}
static int writefd_unbuffered(int fd,char *buf,int len)
/* write len bytes to fd, possibly reading from buffer_f_in if set
in order to unclog the pipe. don't return until all len
bytes have been written */
static void writefd_unbuffered(int fd,char *buf,int len)
{
int total = 0;
fd_set w_fds, r_fds;
int fd_count, count, got_select=0;
int fd_count, count;
struct timeval tv;
int reading=0;
int blocked=0;
no_flush++;
while (total < len) {
int ret = write(fd,buf+total,len-total);
if (ret == 0) return total;
if (ret == -1 && !(errno == EWOULDBLOCK || errno == EAGAIN))
return -1;
if (ret == -1 && got_select) {
/* hmmm, we got a write select on the fd and
then failed to write. Why doesn't that
mean that the fd is dead? It doesn't on
some systems it seems (eg. IRIX) */
u_sleep(1000);
}
got_select = 0;
if (ret != -1) {
total += ret;
continue;
}
if (read_buffer_len < MAX_READ_BUFFER && buffer_f_in != -1)
read_check(buffer_f_in);
fd_count = fd+1;
FD_ZERO(&w_fds);
FD_ZERO(&r_fds);
FD_SET(fd,&w_fds);
if (buffer_f_in != -1) {
fd_count = fd+1;
if (!no_flush_read) {
reading = (buffer_f_in != -1);
}
if (reading) {
FD_SET(buffer_f_in,&r_fds);
if (buffer_f_in > fd)
fd_count = buffer_f_in+1;
}
tv.tv_sec = BLOCKING_TIMEOUT;
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
tv.tv_usec = 0;
count = select(fd_count,buffer_f_in == -1? NULL: &r_fds,
&w_fds,NULL,&tv);
if (count == -1 && errno != EINTR) {
if (verbose > 1)
rprintf(FERROR,"select error: %s\n", strerror(errno));
exit_cleanup(1);
}
if (count == 0) {
count = select(fd_count,
reading?&r_fds:NULL,
&w_fds,NULL,
&tv);
if (count <= 0) {
check_timeout();
continue;
}
if (reading && FD_ISSET(buffer_f_in, &r_fds)) {
read_check(buffer_f_in);
}
if (FD_ISSET(fd, &w_fds)) {
got_select = 1;
int n = (len-total)>>blocked;
int ret = write(fd,buf+total,n?n:1);
if (ret == -1 && errno == EINTR) {
continue;
}
if (ret == -1 &&
(errno == EAGAIN || errno == EWOULDBLOCK)) {
blocked++;
continue;
}
if (ret <= 0) {
rprintf(FERROR,"erroring writing %d bytes - exiting\n", len);
exit_cleanup(RERR_STREAMIO);
}
blocked = 0;
total += ret;
if (io_timeout)
last_io = time(NULL);
}
}
if (io_timeout)
last_io = time(NULL);
return total;
no_flush--;
}
@@ -487,21 +419,13 @@ void io_start_buffering(int fd)
void io_flush(void)
{
int fd = multiplex_out_fd;
if (!io_buffer_count) return;
if (!io_buffer_count || no_flush) return;
if (io_multiplexing_out) {
SIVAL(io_buffer-4, 0, (MPLEX_BASE<<24) + io_buffer_count);
if (writefd_unbuffered(fd, io_buffer-4, io_buffer_count+4) !=
io_buffer_count+4) {
rprintf(FERROR,"write failed\n");
exit_cleanup(1);
}
writefd_unbuffered(fd, io_buffer-4, io_buffer_count+4);
} else {
if (writefd_unbuffered(fd, io_buffer, io_buffer_count) !=
io_buffer_count) {
rprintf(FERROR,"write failed\n");
exit_cleanup(1);
}
writefd_unbuffered(fd, io_buffer, io_buffer_count);
}
io_buffer_count = 0;
}
@@ -515,11 +439,14 @@ void io_end_buffering(int fd)
}
}
static int writefd(int fd,char *buf,int len1)
static void writefd(int fd,char *buf,int len)
{
int len = len1;
stats.total_written += len;
if (!io_buffer) return writefd_unbuffered(fd, buf, len);
if (!io_buffer) {
writefd_unbuffered(fd, buf, len);
return;
}
while (len) {
int n = MIN(len, IO_BUFFER_SIZE-io_buffer_count);
@@ -532,60 +459,40 @@ static int writefd(int fd,char *buf,int len1)
if (io_buffer_count == IO_BUFFER_SIZE) io_flush();
}
return len1;
}
void write_int(int f,int32 x)
{
int ret;
char b[4];
SIVAL(b,0,x);
if ((ret=writefd(f,b,4)) != 4) {
rprintf(FERROR,"write_int failed : %s\n",
ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_written += 4;
writefd(f,b,4);
}
void write_longint(int f, int64 x)
{
extern int remote_version;
char b[8];
int ret;
if (remote_version < 16 || x <= 0x7FFFFFFF) {
write_int(f, (int)x);
return;
}
write_int(f, -1);
write_int(f, (int32)0xFFFFFFFF);
SIVAL(b,0,(x&0xFFFFFFFF));
SIVAL(b,4,((x>>32)&0xFFFFFFFF));
if ((ret=writefd(f,b,8)) != 8) {
rprintf(FERROR,"write_longint failed : %s\n",
ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_written += 8;
writefd(f,b,8);
}
void write_buf(int f,char *buf,int len)
{
int ret;
if ((ret=writefd(f,buf,len)) != len) {
rprintf(FERROR,"write_buf failed : %s\n",
ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_written += len;
writefd(f,buf,len);
}
/* write a string to the connection */
void write_sbuf(int f,char *buf)
static void write_sbuf(int f,char *buf)
{
write_buf(f, buf, strlen(buf));
}
@@ -596,15 +503,14 @@ void write_byte(int f,unsigned char c)
write_buf(f,(char *)&c,1);
}
void write_flush(int f)
{
}
int read_line(int f, char *buf, int maxlen)
{
eof_error = 0;
while (maxlen) {
buf[0] = 0;
read_buf(f, buf, 1);
if (buf[0] == 0) return 0;
if (buf[0] == '\n') {
buf[0] = 0;
break;
@@ -618,6 +524,9 @@ int read_line(int f, char *buf, int maxlen)
*buf = 0;
return 0;
}
eof_error = 1;
return 1;
}
@@ -629,10 +538,10 @@ void io_printf(int fd, const char *format, ...)
int len;
va_start(ap, format);
len = vslprintf(buf, sizeof(buf)-1, format, ap);
len = vslprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (len < 0) exit_cleanup(1);
if (len < 0) exit_cleanup(RERR_STREAMIO);
write_sbuf(fd, buf);
}
@@ -654,7 +563,7 @@ void io_start_multiplex_in(int fd)
io_flush();
if (read_buffer_len) {
fprintf(stderr,"ERROR: data in read buffer at mplx start\n");
exit_cleanup(1);
exit_cleanup(RERR_STREAMIO);
}
io_multiplexing_in = 1;
@@ -670,6 +579,8 @@ int io_multiplex_write(int f, char *buf, int len)
SIVAL(io_buffer-4, 0, ((MPLEX_BASE + f)<<24) + len);
memcpy(io_buffer, buf, len);
stats.total_written += (len+4);
writefd_unbuffered(multiplex_out_fd, io_buffer-4, len+4);
return 1;
}

View File

@@ -36,7 +36,7 @@
#endif
#ifndef HAVE_GETCWD
char *getcwd(char *buf, int size)
char *getcwd(char *buf, int size)
{
return getwd(buf);
}
@@ -44,7 +44,7 @@ char *getcwd(char *buf, int size)
#ifndef HAVE_WAITPID
pid_t waitpid(pid_t pid, int *statptr, int options)
pid_t waitpid(pid_t pid, int *statptr, int options)
{
return wait4(pid, statptr, options, NULL);
}
@@ -52,9 +52,78 @@ pid_t waitpid(pid_t pid, int *statptr, int options)
#ifndef HAVE_MEMMOVE
void *memmove(void *dest, const void *src, size_t n)
void *memmove(void *dest, const void *src, size_t n)
{
bcopy(src, dest, n);
memcpy(dest, src, n);
return dest;
}
#endif
#ifndef HAVE_STRPBRK
/* Find the first ocurrence in S of any character in ACCEPT.
derived from glibc
*/
char *strpbrk(const char *s, const char *accept)
{
while (*s != '\0') {
const char *a = accept;
while (*a != '\0') {
if (*a++ == *s) return (char *)s;
}
++s;
}
return NULL;
}
#endif
#ifdef REPLACE_INET_NTOA
char *rep_inet_ntoa(struct in_addr ip)
{
unsigned char *p = (unsigned char *)&ip.s_addr;
static char buf[18];
#if WORDS_BIGENDIAN
slprintf(buf, 18, "%d.%d.%d.%d",
(int)p[0], (int)p[1], (int)p[2], (int)p[3]);
#else
slprintf(buf, 18, "%d.%d.%d.%d",
(int)p[3], (int)p[2], (int)p[1], (int)p[0]);
#endif
return buf;
}
#endif
#ifndef HAVE_STRLCPY
/* like strncpy but does not 0 fill the buffer and always null
terminates. bufsize is the size of the destination buffer */
size_t strlcpy(char *d, const char *s, size_t bufsize)
{
size_t len = strlen(s);
size_t ret = len;
if (len >= bufsize) len = bufsize-1;
memcpy(d, s, len);
d[len] = 0;
return ret;
}
#endif
#ifndef HAVE_STRLCAT
/* like strncat but does not 0 fill the buffer and always null
terminates. bufsize is the length of the buffer, which should
be one more than the maximum resulting string length */
size_t strlcat(char *d, const char *s, size_t bufsize)
{
size_t len1 = strlen(d);
size_t len2 = strlen(s);
size_t ret = len1 + len2;
if (len1+len2 >= bufsize) {
len2 = bufsize - (len1+1);
}
if (len2 > 0) {
memcpy(d+len1, s, len2);
d[len1+len2] = 0;
}
return ret;
}
#endif

266
lib/mdfour.c Normal file
View File

@@ -0,0 +1,266 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
a implementation of MD4 designed for use in the SMB authentication protocol
Copyright (C) Andrew Tridgell 1997-1998.
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.
*/
#include "rsync.h"
/* NOTE: This code makes no attempt to be fast!
It assumes that a int is at least 32 bits long
*/
static struct mdfour *m;
#define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z)))
#define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)))
#define H(X,Y,Z) ((X)^(Y)^(Z))
#ifdef LARGE_INT32
#define lshift(x,s) ((((x)<<(s))&0xFFFFFFFF) | (((x)>>(32-(s)))&0xFFFFFFFF))
#else
#define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s))))
#endif
#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s)
#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s)
/* this applies md4 to 64 byte chunks */
static void mdfour64(uint32 *M)
{
int j;
uint32 AA, BB, CC, DD;
uint32 X[16];
uint32 A,B,C,D;
for (j=0;j<16;j++)
X[j] = M[j];
A = m->A; B = m->B; C = m->C; D = m->D;
AA = A; BB = B; CC = C; DD = D;
ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
A += AA; B += BB; C += CC; D += DD;
#ifdef LARGE_INT32
A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
#endif
for (j=0;j<16;j++)
X[j] = 0;
m->A = A; m->B = B; m->C = C; m->D = D;
}
static void copy64(uint32 *M, unsigned char *in)
{
int i;
for (i=0;i<16;i++)
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
(in[i*4+1]<<8) | (in[i*4+0]<<0);
}
static void copy4(unsigned char *out,uint32 x)
{
out[0] = x&0xFF;
out[1] = (x>>8)&0xFF;
out[2] = (x>>16)&0xFF;
out[3] = (x>>24)&0xFF;
}
void mdfour_begin(struct mdfour *md)
{
md->A = 0x67452301;
md->B = 0xefcdab89;
md->C = 0x98badcfe;
md->D = 0x10325476;
md->totalN = 0;
}
static void mdfour_tail(unsigned char *in, int n)
{
unsigned char buf[128];
uint32 M[16];
uint32 b;
m->totalN += n;
b = m->totalN * 8;
memset(buf, 0, 128);
if (n) memcpy(buf, in, n);
buf[n] = 0x80;
if (n <= 55) {
copy4(buf+56, b);
copy64(M, buf);
mdfour64(M);
} else {
copy4(buf+120, b);
copy64(M, buf);
mdfour64(M);
copy64(M, buf+64);
mdfour64(M);
}
}
void mdfour_update(struct mdfour *md, unsigned char *in, int n)
{
uint32 M[16];
if (n == 0) mdfour_tail(in, n);
m = md;
while (n >= 64) {
copy64(M, in);
mdfour64(M);
in += 64;
n -= 64;
m->totalN += 64;
}
if (n) mdfour_tail(in, n);
}
void mdfour_result(struct mdfour *md, unsigned char *out)
{
m = md;
copy4(out, m->A);
copy4(out+4, m->B);
copy4(out+8, m->C);
copy4(out+12, m->D);
}
void mdfour(unsigned char *out, unsigned char *in, int n)
{
struct mdfour md;
mdfour_begin(&md);
mdfour_update(&md, in, n);
mdfour_result(&md, out);
}
#ifdef TEST_MDFOUR
static void file_checksum1(char *fname)
{
int fd, i;
struct mdfour md;
unsigned char buf[64*1024], sum[16];
fd = open(fname,O_RDONLY);
if (fd == -1) {
perror("fname");
exit(1);
}
mdfour_begin(&md);
while (1) {
int n = read(fd, buf, sizeof(buf));
if (n <= 0) break;
mdfour_update(&md, buf, n);
}
close(fd);
mdfour_result(&md, sum);
for (i=0;i<16;i++)
printf("%02X", sum[i]);
printf("\n");
}
#if 0
#include "../md4.h"
static void file_checksum2(char *fname)
{
int fd, i;
MDstruct md;
unsigned char buf[64], sum[16];
fd = open(fname,O_RDONLY);
if (fd == -1) {
perror("fname");
exit(1);
}
MDbegin(&md);
while (1) {
int n = read(fd, buf, sizeof(buf));
if (n <= 0) break;
MDupdate(&md, buf, n*8);
}
if (!md.done) {
MDupdate(&md, buf, 0);
}
close(fd);
memcpy(sum, md.buffer, 16);
for (i=0;i<16;i++)
printf("%02X", sum[i]);
printf("\n");
}
#endif
int main(int argc, char *argv[])
{
file_checksum1(argv[1]);
#if 0
file_checksum2(argv[1]);
#endif
return 0;
}
#endif

34
lib/mdfour.h Normal file
View File

@@ -0,0 +1,34 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
a implementation of MD4 designed for use in the SMB authentication protocol
Copyright (C) Andrew Tridgell 1997-1998.
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.
*/
struct mdfour {
uint32 A, B, C, D;
uint32 totalN;
};
void mdfour_begin(struct mdfour *md);
void mdfour_update(struct mdfour *md, unsigned char *in, int n);
void mdfour_result(struct mdfour *md, unsigned char *out);
void mdfour(unsigned char *out, unsigned char *in, int n);

820
lib/snprintf.c Normal file
View File

@@ -0,0 +1,820 @@
/*
* Copyright Patrick Powell 1995
* This code is based on code written by Patrick Powell (papowell@astart.com)
* It may be used for any purpose as long as this notice remains intact
* on all source code distributions
*/
/**************************************************************
* Original:
* Patrick Powell Tue Apr 11 09:48:21 PDT 1995
* A bombproof version of doprnt (dopr) included.
* Sigh. This sort of thing is always nasty do deal with. Note that
* the version here does not include floating point...
*
* snprintf() is used instead of sprintf() as it does limit checks
* for string length. This covers a nasty loophole.
*
* The other functions are there to prevent NULL pointers from
* causing nast effects.
*
* More Recently:
* Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
* This was ugly. It is still ugly. I opted out of floating point
* numbers, but the formatter understands just about everything
* from the normal C string format, at least as far as I can tell from
* the Solaris 2.5 printf(3S) man page.
*
* Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
* Ok, added some minimal floating point support, which means this
* probably requires libm on most operating systems. Don't yet
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
* was pretty badly broken, it just wasn't being exercised in ways
* which showed it, so that's been fixed. Also, formated the code
* to mutt conventions, and removed dead code left over from the
* original. Also, there is now a builtin-test, just compile with:
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
* and run snprintf for results.
*
* Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
* The PGP code was using unsigned hexadecimal formats.
* Unfortunately, unsigned formats simply didn't work.
*
* Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
* The original code assumed that both snprintf() and vsnprintf() were
* missing. Some systems only have snprintf() but not vsnprintf(), so
* the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
*
* Andrew Tridgell (tridge@samba.org) Oct 1998
* fixed handling of %.0f
* added test for HAVE_LONG_DOUBLE
*
**************************************************************/
#include "config.h"
#include <string.h>
# include <ctype.h>
#include <sys/types.h>
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
/* Define this as a fall through, HAVE_STDARG_H is probably already set */
#define HAVE_VARARGS_H
/* varargs declarations: */
#if defined(HAVE_STDARG_H)
# include <stdarg.h>
# define HAVE_STDARGS /* let's hope that works everywhere (mj) */
# define VA_LOCAL_DECL va_list ap
# define VA_START(f) va_start(ap, f)
# define VA_SHIFT(v,t) ; /* no-op for ANSI */
# define VA_END va_end(ap)
#else
# if defined(HAVE_VARARGS_H)
# include <varargs.h>
# undef HAVE_STDARGS
# define VA_LOCAL_DECL va_list ap
# define VA_START(f) va_start(ap) /* f is ignored! */
# define VA_SHIFT(v,t) v = va_arg(ap,t)
# define VA_END va_end(ap)
# else
/*XX ** NO VARARGS ** XX*/
# endif
#endif
#ifdef HAVE_LONG_DOUBLE
#define LDOUBLE long double
#else
#define LDOUBLE double
#endif
/*int snprintf (char *str, size_t count, const char *fmt, ...);*/
/*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/
static void dopr (char *buffer, size_t maxlen, const char *format,
va_list args);
static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max);
static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags);
static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags);
static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
/*
* dopr(): poor man's version of doprintf
*/
/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS 1
#define DP_S_MIN 2
#define DP_S_DOT 3
#define DP_S_MAX 4
#define DP_S_MOD 5
#define DP_S_CONV 6
#define DP_S_DONE 7
/* format flags - Bits */
#define DP_F_MINUS (1 << 0)
#define DP_F_PLUS (1 << 1)
#define DP_F_SPACE (1 << 2)
#define DP_F_NUM (1 << 3)
#define DP_F_ZERO (1 << 4)
#define DP_F_UP (1 << 5)
#define DP_F_UNSIGNED (1 << 6)
/* Conversion Flags */
#define DP_C_SHORT 1
#define DP_C_LONG 2
#define DP_C_LDOUBLE 3
#define char_to_int(p) (p - '0')
#define MAX(p,q) ((p >= q) ? p : q)
static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
{
char ch;
long value;
LDOUBLE fvalue;
char *strvalue;
int min;
int max;
int state;
int flags;
int cflags;
size_t currlen;
state = DP_S_DEFAULT;
currlen = flags = cflags = min = 0;
max = -1;
ch = *format++;
while (state != DP_S_DONE)
{
if ((ch == '\0') || (currlen >= maxlen))
state = DP_S_DONE;
switch(state)
{
case DP_S_DEFAULT:
if (ch == '%')
state = DP_S_FLAGS;
else
dopr_outch (buffer, &currlen, maxlen, ch);
ch = *format++;
break;
case DP_S_FLAGS:
switch (ch)
{
case '-':
flags |= DP_F_MINUS;
ch = *format++;
break;
case '+':
flags |= DP_F_PLUS;
ch = *format++;
break;
case ' ':
flags |= DP_F_SPACE;
ch = *format++;
break;
case '#':
flags |= DP_F_NUM;
ch = *format++;
break;
case '0':
flags |= DP_F_ZERO;
ch = *format++;
break;
default:
state = DP_S_MIN;
break;
}
break;
case DP_S_MIN:
if (isdigit((unsigned char)ch))
{
min = 10*min + char_to_int (ch);
ch = *format++;
}
else if (ch == '*')
{
min = va_arg (args, int);
ch = *format++;
state = DP_S_DOT;
}
else
state = DP_S_DOT;
break;
case DP_S_DOT:
if (ch == '.')
{
state = DP_S_MAX;
ch = *format++;
}
else
state = DP_S_MOD;
break;
case DP_S_MAX:
if (isdigit((unsigned char)ch))
{
if (max < 0)
max = 0;
max = 10*max + char_to_int (ch);
ch = *format++;
}
else if (ch == '*')
{
max = va_arg (args, int);
ch = *format++;
state = DP_S_MOD;
}
else
state = DP_S_MOD;
break;
case DP_S_MOD:
/* Currently, we don't support Long Long, bummer */
switch (ch)
{
case 'h':
cflags = DP_C_SHORT;
ch = *format++;
break;
case 'l':
cflags = DP_C_LONG;
ch = *format++;
break;
case 'L':
cflags = DP_C_LDOUBLE;
ch = *format++;
break;
default:
break;
}
state = DP_S_CONV;
break;
case DP_S_CONV:
switch (ch)
{
case 'd':
case 'i':
if (cflags == DP_C_SHORT)
value = va_arg (args, short int);
else if (cflags == DP_C_LONG)
value = va_arg (args, long int);
else
value = va_arg (args, int);
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
break;
case 'o':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned short int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
break;
case 'u':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned short int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
break;
case 'X':
flags |= DP_F_UP;
case 'x':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned short int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
break;
case 'f':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
/* um, floating point? */
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
break;
case 'E':
flags |= DP_F_UP;
case 'e':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
break;
case 'G':
flags |= DP_F_UP;
case 'g':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
break;
case 'c':
dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
break;
case 's':
strvalue = va_arg (args, char *);
if (max < 0)
max = maxlen; /* ie, no max */
fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
break;
case 'p':
strvalue = va_arg (args, void *);
fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
break;
case 'n':
if (cflags == DP_C_SHORT)
{
short int *num;
num = va_arg (args, short int *);
*num = currlen;
}
else if (cflags == DP_C_LONG)
{
long int *num;
num = va_arg (args, long int *);
*num = (long int)currlen;
}
else
{
int *num;
num = va_arg (args, int *);
*num = currlen;
}
break;
case '%':
dopr_outch (buffer, &currlen, maxlen, ch);
break;
case 'w':
/* not supported yet, treat as next char */
ch = *format++;
break;
default:
/* Unknown, skip */
break;
}
ch = *format++;
state = DP_S_DEFAULT;
flags = cflags = min = 0;
max = -1;
break;
case DP_S_DONE:
break;
default:
/* hmm? */
break; /* some picky compilers need this */
}
}
if (currlen < maxlen - 1)
buffer[currlen] = '\0';
else
buffer[maxlen - 1] = '\0';
}
static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max)
{
int padlen, strln; /* amount to pad */
int cnt = 0;
if (value == 0)
{
value = "<NULL>";
}
for (strln = 0; value[strln]; ++strln); /* strlen */
padlen = min - strln;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justify */
while ((padlen > 0) && (cnt < max))
{
dopr_outch (buffer, currlen, maxlen, ' ');
--padlen;
++cnt;
}
while (*value && (cnt < max))
{
dopr_outch (buffer, currlen, maxlen, *value++);
++cnt;
}
while ((padlen < 0) && (cnt < max))
{
dopr_outch (buffer, currlen, maxlen, ' ');
++padlen;
++cnt;
}
}
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags)
{
int signvalue = 0;
unsigned long uvalue;
char convert[20];
int place = 0;
int spadlen = 0; /* amount to space pad */
int zpadlen = 0; /* amount to zero pad */
int caps = 0;
if (max < 0)
max = 0;
uvalue = value;
if(!(flags & DP_F_UNSIGNED))
{
if( value < 0 ) {
signvalue = '-';
uvalue = -value;
}
else
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
signvalue = '+';
else
if (flags & DP_F_SPACE)
signvalue = ' ';
}
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
do {
convert[place++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")
[uvalue % (unsigned)base ];
uvalue = (uvalue / (unsigned)base );
} while(uvalue && (place < 20));
if (place == 20) place--;
convert[place] = 0;
zpadlen = max - place;
spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
if (zpadlen < 0) zpadlen = 0;
if (spadlen < 0) spadlen = 0;
if (flags & DP_F_ZERO)
{
zpadlen = MAX(zpadlen, spadlen);
spadlen = 0;
}
if (flags & DP_F_MINUS)
spadlen = -spadlen; /* Left Justifty */
#ifdef DEBUG_SNPRINTF
printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
zpadlen, spadlen, min, max, place);
#endif
/* Spaces */
while (spadlen > 0)
{
dopr_outch (buffer, currlen, maxlen, ' ');
--spadlen;
}
/* Sign */
if (signvalue)
dopr_outch (buffer, currlen, maxlen, signvalue);
/* Zeros */
if (zpadlen > 0)
{
while (zpadlen > 0)
{
dopr_outch (buffer, currlen, maxlen, '0');
--zpadlen;
}
}
/* Digits */
while (place > 0)
dopr_outch (buffer, currlen, maxlen, convert[--place]);
/* Left Justified spaces */
while (spadlen < 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
++spadlen;
}
}
static LDOUBLE abs_val (LDOUBLE value)
{
LDOUBLE result = value;
if (value < 0)
result = -value;
return result;
}
static LDOUBLE pow10 (int exp)
{
LDOUBLE result = 1;
while (exp)
{
result *= 10;
exp--;
}
return result;
}
static long round (LDOUBLE value)
{
long intpart;
intpart = (long)value;
value = value - intpart;
if (value >= 0.5)
intpart++;
return intpart;
}
static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags)
{
int signvalue = 0;
LDOUBLE ufvalue;
char iconvert[20];
char fconvert[20];
int iplace = 0;
int fplace = 0;
int padlen = 0; /* amount to pad */
int zpadlen = 0;
int caps = 0;
long intpart;
long fracpart;
/*
* AIX manpage says the default is 0, but Solaris says the default
* is 6, and sprintf on AIX defaults to 6
*/
if (max < 0)
max = 6;
ufvalue = abs_val (fvalue);
if (fvalue < 0)
signvalue = '-';
else
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
signvalue = '+';
else
if (flags & DP_F_SPACE)
signvalue = ' ';
#if 0
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
#endif
intpart = (long)ufvalue;
/*
* Sorry, we only support 9 digits past the decimal because of our
* conversion method
*/
if (max > 9)
max = 9;
/* We "cheat" by converting the fractional part to integer by
* multiplying by a factor of 10
*/
fracpart = round ((pow10 (max)) * (ufvalue - intpart));
if (fracpart >= pow10 (max))
{
intpart++;
fracpart -= pow10 (max);
}
#ifdef DEBUG_SNPRINTF
printf("fmtfp: %g %d.%d min=%d max=%d\n",
(double)fvalue, intpart, fracpart, min, max);
#endif
/* Convert integer part */
do {
iconvert[iplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
intpart = (intpart / 10);
} while(intpart && (iplace < 20));
if (iplace == 20) iplace--;
iconvert[iplace] = 0;
/* Convert fractional part */
do {
fconvert[fplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
fracpart = (fracpart / 10);
} while(fracpart && (fplace < 20));
if (fplace == 20) fplace--;
fconvert[fplace] = 0;
/* -1 for decimal point, another -1 if we are printing a sign */
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
zpadlen = max - fplace;
if (zpadlen < 0)
zpadlen = 0;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justifty */
if ((flags & DP_F_ZERO) && (padlen > 0))
{
if (signvalue)
{
dopr_outch (buffer, currlen, maxlen, signvalue);
--padlen;
signvalue = 0;
}
while (padlen > 0)
{
dopr_outch (buffer, currlen, maxlen, '0');
--padlen;
}
}
while (padlen > 0)
{
dopr_outch (buffer, currlen, maxlen, ' ');
--padlen;
}
if (signvalue)
dopr_outch (buffer, currlen, maxlen, signvalue);
while (iplace > 0)
dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
#ifdef DEBUG_SNPRINTF
printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
#endif
/*
* Decimal point. This should probably use locale to find the correct
* char to print out.
*/
if (max > 0) {
dopr_outch (buffer, currlen, maxlen, '.');
while (fplace > 0)
dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
}
while (zpadlen > 0)
{
dopr_outch (buffer, currlen, maxlen, '0');
--zpadlen;
}
while (padlen < 0)
{
dopr_outch (buffer, currlen, maxlen, ' ');
++padlen;
}
}
static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
{
if (*currlen < maxlen)
buffer[(*currlen)++] = c;
}
#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
#ifndef HAVE_VSNPRINTF
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{
str[0] = 0;
dopr(str, count, fmt, args);
return(strlen(str));
}
#endif /* !HAVE_VSNPRINTF */
#ifndef HAVE_SNPRINTF
/* VARARGS3 */
#ifdef HAVE_STDARGS
int snprintf (char *str,size_t count,const char *fmt,...)
#else
int snprintf (va_alist) va_dcl
#endif
{
#ifndef HAVE_STDARGS
char *str;
size_t count;
char *fmt;
#endif
VA_LOCAL_DECL;
VA_START (fmt);
VA_SHIFT (str, char *);
VA_SHIFT (count, size_t );
VA_SHIFT (fmt, char *);
(void) vsnprintf(str, count, fmt, ap);
VA_END;
return(strlen(str));
}
#else
/* keep compilers happy about empty files */
void dummy_snprintf(void) {}
#endif /* !HAVE_SNPRINTF */
#ifdef TEST_SNPRINTF
#ifndef LONG_STRING
#define LONG_STRING 1024
#endif
int main (void)
{
char buf1[LONG_STRING];
char buf2[LONG_STRING];
char *fp_fmt[] = {
"%-1.5f",
"%1.5f",
"%123.9f",
"%10.5f",
"% 10.5f",
"%+22.9f",
"%+4.9f",
"%01.3f",
"%4f",
"%3.1f",
"%3.2f",
"%.0f",
"%.1f",
NULL
};
double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
0.9996, 1.996, 4.136, 0};
char *int_fmt[] = {
"%-1.5d",
"%1.5d",
"%123.9d",
"%5.5d",
"%10.5d",
"% 10.5d",
"%+22.33d",
"%01.3d",
"%4d",
NULL
};
long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
int x, y;
int fail = 0;
int num = 0;
printf ("Testing snprintf format codes against system sprintf...\n");
for (x = 0; fp_fmt[x] != NULL ; x++)
for (y = 0; fp_nums[y] != 0 ; y++)
{
snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
sprintf (buf2, fp_fmt[x], fp_nums[y]);
if (strcmp (buf1, buf2))
{
printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
fp_fmt[x], buf1, buf2);
fail++;
}
num++;
}
for (x = 0; int_fmt[x] != NULL ; x++)
for (y = 0; int_nums[y] != 0 ; y++)
{
snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
sprintf (buf2, int_fmt[x], int_nums[y]);
if (strcmp (buf1, buf2))
{
printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
int_fmt[x], buf1, buf2);
fail++;
}
num++;
}
printf ("%d tests failed out of %d.\n", fail, num);
}
#endif /* SNPRINTF_TEST */

4601
lib/zlib.c
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,632 +0,0 @@
/* $Id$ */
/*
* This file is derived from zlib.h and zconf.h from the zlib-0.95
* distribution by Jean-loup Gailly and Mark Adler, with some additions
* by Paul Mackerras to aid in implementing Deflate compression and
* decompression for PPP packets.
*/
/* zlib.h -- interface of the 'zlib' general purpose compression library
version 0.95, Aug 16th, 1995.
Copyright (C) 1995 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
gzip@prep.ai.mit.edu madler@alumni.caltech.edu
*/
#ifndef _ZLIB_H
#define _ZLIB_H
/* #include "zconf.h" */ /* included directly here */
/* zconf.h -- configuration of the zlib compression library
* Copyright (C) 1995 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
/*
The library does not install any signal handler. It is recommended to
add at least a handler for SIGSEGV when decompressing; the library checks
the consistency of the input data whenever possible but may go nuts
for some forms of corrupted input.
*/
/*
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
* than 64k bytes at a time (needed on systems with 16-bit int).
* Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
* at addresses which are not a multiple of their size.
* Under DOS, -DFAR=far or -DFAR=__far may be needed.
*/
#ifndef STDC
# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
# define STDC
# endif
#endif
#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
# include <unix.h>
#endif
/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
# ifdef MAXSEG_64K
# define MAX_MEM_LEVEL 8
# else
# define MAX_MEM_LEVEL 9
# endif
#endif
#ifndef FAR
# define FAR
#endif
/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
#ifndef MAX_WBITS
# define MAX_WBITS 15 /* 32K LZ77 window */
#endif
/* The memory requirements for deflate are (in bytes):
1 << (windowBits+2) + 1 << (memLevel+9)
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
plus a few kilobytes for small objects. For example, if you want to reduce
the default memory requirements from 256K to 128K, compile with
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
Of course this will generally degrade compression (there's no free lunch).
The memory requirements for inflate are (in bytes) 1 << windowBits
that is, 32K for windowBits=15 (default value) plus a few kilobytes
for small objects.
*/
/* Type declarations */
#ifndef OF /* function prototypes */
# ifdef STDC
# define OF(args) args
# else
# define OF(args) ()
# endif
#endif
typedef unsigned char Byte; /* 8 bits */
typedef unsigned int uInt; /* 16 bits or more */
typedef int32 Long; /* 32 bits or more */
typedef uint32 uLong; /* 32 bits or more */
typedef Byte FAR Bytef;
typedef char FAR charf;
typedef int FAR intf;
typedef uInt FAR uIntf;
typedef uLong FAR uLongf;
#ifdef STDC
typedef void FAR *voidpf;
typedef void *voidp;
#else
typedef Byte FAR *voidpf;
typedef Byte *voidp;
#endif
/* end of original zconf.h */
#define ZLIB_VERSION "0.95P"
/*
The 'zlib' compression library provides in-memory compression and
decompression functions, including integrity checks of the uncompressed
data. This version of the library supports only one compression method
(deflation) but other algorithms may be added later and will have the same
stream interface.
For compression the application must provide the output buffer and
may optionally provide the input buffer for optimization. For decompression,
the application must provide the input buffer and may optionally provide
the output buffer for optimization.
Compression can be done in a single step if the buffers are large
enough (for example if an input file is mmap'ed), or can be done by
repeated calls of the compression function. In the latter case, the
application must provide more input and/or consume the output
(providing more output space) before each call.
*/
typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes));
struct internal_state;
typedef struct z_stream_s {
Bytef *next_in; /* next input byte */
uInt avail_in; /* number of bytes available at next_in */
uLong total_in; /* total nb of input bytes read so far */
Bytef *next_out; /* next output byte should be put there */
uInt avail_out; /* remaining free space at next_out */
uLong total_out; /* total nb of bytes output so far */
char *msg; /* last error message, NULL if no error */
struct internal_state FAR *state; /* not visible by applications */
alloc_func zalloc; /* used to allocate the internal state */
free_func zfree; /* used to free the internal state */
voidp opaque; /* private data object passed to zalloc and zfree */
Byte data_type; /* best guess about the data type: ascii or binary */
} z_stream;
/*
The application must update next_in and avail_in when avail_in has
dropped to zero. It must update next_out and avail_out when avail_out
has dropped to zero. The application must initialize zalloc, zfree and
opaque before calling the init function. All other fields are set by the
compression library and must not be updated by the application.
The opaque value provided by the application will be passed as the first
parameter for calls of zalloc and zfree. This can be useful for custom
memory management. The compression library attaches no meaning to the
opaque value.
zalloc must return Z_NULL if there is not enough memory for the object.
On 16-bit systems, the functions zalloc and zfree must be able to allocate
exactly 65536 bytes, but will not be required to allocate more than this
if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
pointers returned by zalloc for objects of exactly 65536 bytes *must*
have their offset normalized to zero. The default allocation function
provided by this library ensures this (see zutil.c). To reduce memory
requirements and avoid any allocation of 64K objects, at the expense of
compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
The fields total_in and total_out can be used for statistics or
progress reports. After compression, total_in holds the total size of
the uncompressed data and may be saved for use in the decompressor
(particularly if the decompressor wants to decompress everything in
a single step).
*/
/* constants */
#define Z_NO_FLUSH 0
#define Z_PARTIAL_FLUSH 1
#define Z_FULL_FLUSH 2
#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */
#define Z_FINISH 4
#define Z_PACKET_FLUSH 5
#define Z_INSERT_ONLY 6 /* update hash table etc., produce no output */
/* See deflate() below for the usage of these constants */
#define Z_OK 0
#define Z_STREAM_END 1
#define Z_ERRNO (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR (-3)
#define Z_MEM_ERROR (-4)
#define Z_BUF_ERROR (-5)
/* error codes for the compression/decompression functions */
#define Z_BEST_SPEED 1
#define Z_BEST_COMPRESSION 9
#define Z_DEFAULT_COMPRESSION (-1)
/* compression levels */
#define Z_FILTERED 1
#define Z_HUFFMAN_ONLY 2
#define Z_DEFAULT_STRATEGY 0
#define Z_BINARY 0
#define Z_ASCII 1
#define Z_UNKNOWN 2
/* Used to set the data_type field */
#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
extern char *zlib_version;
/* The application can compare zlib_version and ZLIB_VERSION for consistency.
If the first character differs, the library code actually used is
not compatible with the zlib.h header file used by the application.
*/
/* basic functions */
extern int deflateInit OF((z_stream *strm, int level));
/*
Initializes the internal stream state for compression. The fields
zalloc, zfree and opaque must be initialized before by the caller.
If zalloc and zfree are set to Z_NULL, deflateInit updates them to
use default allocation functions.
The compression level must be Z_DEFAULT_COMPRESSION, or between 1 and 9:
1 gives best speed, 9 gives best compression. Z_DEFAULT_COMPRESSION requests
a default compromise between speed and compression (currently equivalent
to level 6).
deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_STREAM_ERROR if level is not a valid compression level.
msg is set to null if there is no error message. deflateInit does not
perform any compression: this will be done by deflate().
*/
extern int deflate OF((z_stream *strm, int flush));
/*
Performs one or both of the following actions:
- Compress more input starting at next_in and update next_in and avail_in
accordingly. If not all input can be processed (because there is not
enough room in the output buffer), next_in and avail_in are updated and
processing will resume at this point for the next call of deflate().
- Provide more output starting at next_out and update next_out and avail_out
accordingly. This action is forced if the parameter flush is non zero.
Forcing flush frequently degrades the compression ratio, so this parameter
should be set only when necessary (in interactive applications).
Some output may be provided even if flush is not set.
Before the call of deflate(), the application should ensure that at least
one of the actions is possible, by providing more input and/or consuming
more output, and updating avail_in or avail_out accordingly; avail_out
should never be zero before the call. The application can consume the
compressed output when it wants, for example when the output buffer is full
(avail_out == 0), or after each call of deflate().
If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
block is terminated and flushed to the output buffer so that the
decompressor can get all input data available so far. For method 9, a future
variant on method 8, the current block will be flushed but not terminated.
If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
special marker is output and the compression dictionary is discarded; this
is useful to allow the decompressor to synchronize if one compressed block
has been damaged (see inflateSync below). Flushing degrades compression and
so should be used only when necessary. Using Z_FULL_FLUSH too often can
seriously degrade the compression. If deflate returns with avail_out == 0,
this function must be called again with the same value of the flush
parameter and more output space (updated avail_out), until the flush is
complete (deflate returns with non-zero avail_out).
If the parameter flush is set to Z_PACKET_FLUSH, the compression
block is terminated, and a zero-length stored block is output,
omitting the length bytes (the effect of this is that the 3-bit type
code 000 for a stored block is output, and the output is then
byte-aligned). This is designed for use at the end of a PPP packet.
In addition, if the current compression block contains all the data
since the last Z_PACKET_FLUSH, it is never output as a stored block.
If the current compression block output as a static or dynamic block
would not be at least `minCompression' bytes smaller than the
original data, then nothing is output for that block. (The type
code for the zero-length stored block is still output, resulting in
a single zero byte being output for the whole packet.)
`MinCompression' is a parameter to deflateInit2, or 0 if deflateInit
is used.
If the parameter flush is set to Z_FINISH, all pending input is processed,
all pending output is flushed and deflate returns with Z_STREAM_END if there
was enough output space; if deflate returns with Z_OK, this function must be
called again with Z_FINISH and more output space (updated avail_out) but no
more input data, until it returns with Z_STREAM_END or an error. After
deflate has returned Z_STREAM_END, the only possible operations on the
stream are deflateReset or deflateEnd.
Z_FINISH can be used immediately after deflateInit if all the compression
is to be done in a single step. In this case, avail_out must be at least
0.1% larger than avail_in plus 12 bytes. If deflate does not return
Z_STREAM_END, then it must be called again as described above.
deflate() may update data_type if it can make a good guess about
the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
binary. This field is only for information purposes and does not affect
the compression algorithm in any manner.
deflate() returns Z_OK if some progress has been made (more input
processed or more output produced), Z_STREAM_END if all input has been
consumed and all output has been produced (only when flush is set to
Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
*/
extern int deflateEnd OF((z_stream *strm));
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any
pending output.
deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
stream state was inconsistent. In the error case, msg may be set
but then points to a static string (which must not be deallocated).
*/
extern int inflateInit OF((z_stream *strm));
/*
Initializes the internal stream state for decompression. The fields
zalloc and zfree must be initialized before by the caller. If zalloc and
zfree are set to Z_NULL, inflateInit updates them to use default allocation
functions.
inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory. msg is set to null if there is no error message.
inflateInit does not perform any decompression: this will be done by
inflate().
*/
extern int inflate OF((z_stream *strm, int flush));
/*
Performs one or both of the following actions:
- Decompress more input starting at next_in and update next_in and avail_in
accordingly. If not all input can be processed (because there is not
enough room in the output buffer), next_in is updated and processing
will resume at this point for the next call of inflate().
- Provide more output starting at next_out and update next_out and avail_out
accordingly. inflate() always provides as much output as possible
(until there is no more input data or no more space in the output buffer).
Before the call of inflate(), the application should ensure that at least
one of the actions is possible, by providing more input and/or consuming
more output, and updating the next_* and avail_* values accordingly.
The application can consume the uncompressed output when it wants, for
example when the output buffer is full (avail_out == 0), or after each
call of inflate().
If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
inflate flushes as much output as possible to the output buffer. The
flushing behavior of inflate is not specified for values of the flush
parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
current implementation actually flushes as much output as possible
anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
has been consumed, it is expecting to see the length field of a stored
block; if not, it returns Z_DATA_ERROR.
inflate() should normally be called until it returns Z_STREAM_END or an
error. However if all decompression is to be performed in a single step
(a single call of inflate), the parameter flush should be set to
Z_FINISH. In this case all pending input is processed and all pending
output is flushed; avail_out must be large enough to hold all the
uncompressed data. (The size of the uncompressed data may have been saved
by the compressor for this purpose.) The next operation on this stream must
be inflateEnd to deallocate the decompression state. The use of Z_FINISH
is never required, but can be used to inform inflate that a faster routine
may be used for the single inflate() call.
inflate() returns Z_OK if some progress has been made (more input
processed or more output produced), Z_STREAM_END if the end of the
compressed data has been reached and all uncompressed output has been
produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
the stream structure was inconsistent (for example if next_in or next_out
was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
progress is possible or if there was not enough room in the output buffer
when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
call inflateSync to look for a good compression block. */
extern int inflateEnd OF((z_stream *strm));
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any
pending output.
inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
was inconsistent. In the error case, msg may be set but then points to a
static string (which must not be deallocated).
*/
/* advanced functions */
/*
The following functions are needed only in some special applications.
*/
extern int deflateInit2 OF((z_stream *strm,
int level,
int method,
int windowBits,
int memLevel,
int strategy));
/*
This is another version of deflateInit with more compression options. The
fields next_in, zalloc and zfree must be initialized before by the caller.
The method parameter is the compression method. It must be 8 in this
version of the library. (Method 9 will allow a 64K history buffer and
partial block flushes.)
The windowBits parameter is the base two logarithm of the window size
(the size of the history buffer). It should be in the range 8..15 for this
version of the library (the value 16 will be allowed for method 9). Larger
values of this parameter result in better compression at the expense of
memory usage. The default value is 15 if deflateInit is used instead.
The memLevel parameter specifies how much memory should be allocated
for the internal compression state. memLevel=1 uses minimum memory but
is slow and reduces compression ratio; memLevel=9 uses maximum memory
for optimal speed. The default value is 8. See zconf.h for total memory
usage as a function of windowBits and memLevel.
The strategy parameter is used to tune the compression algorithm. Use
the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data
produced by a filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman
encoding only (no string match). Filtered data consists mostly of small
values with a somewhat random distribution. In this case, the
compression algorithm is tuned to compress them better. The strategy
parameter only affects the compression ratio but not the correctness of
the compressed output even if it is not set appropriately.
The minCompression parameter specifies the minimum reduction in size
required for a compressed block to be output when Z_PACKET_FLUSH is
used (see the description of deflate above).
If next_in is not null, the library will use this buffer to hold also
some history information; the buffer must either hold the entire input
data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
is null, the library will allocate its own history buffer (and leave next_in
null). next_out need not be provided here but must be provided by the
application for the next call of deflate().
If the history buffer is provided by the application, next_in must
must never be changed by the application since the compressor maintains
information inside this buffer from call to call; the application
must provide more input only by increasing avail_in. next_in is always
reset by the library in this case.
deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
an invalid method). msg is set to null if there is no error message.
deflateInit2 does not perform any compression: this will be done by
deflate().
*/
extern int deflateCopy OF((z_stream *dest,
z_stream *source));
/*
Sets the destination stream as a complete copy of the source stream. If
the source stream is using an application-supplied history buffer, a new
buffer is allocated for the destination stream. The compressed output
buffer is always application-supplied. It's the responsibility of the
application to provide the correct values of next_out and avail_out for the
next call of deflate.
This function is useful when several compression strategies will be
tried, for example when there are several ways of pre-processing the input
data with a filter. The streams that will be discarded should then be freed
by calling deflateEnd. Note that deflateCopy duplicates the internal
compression state which can be quite large, so this strategy is slow and
can consume lots of memory.
deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
(such as zalloc being NULL). msg is left unchanged in both source and
destination.
*/
extern int deflateReset OF((z_stream *strm));
/*
This function is equivalent to deflateEnd followed by deflateInit,
but does not free and reallocate all the internal compression state.
The stream will keep the same compression level and any other attributes
that may have been set by deflateInit2.
deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being NULL).
*/
extern int inflateInit2 OF((z_stream *strm,
int windowBits));
/*
This is another version of inflateInit with more compression options. The
fields next_out, zalloc and zfree must be initialized before by the caller.
The windowBits parameter is the base two logarithm of the maximum window
size (the size of the history buffer). It should be in the range 8..15 for
this version of the library (the value 16 will be allowed soon). The
default value is 15 if inflateInit is used instead. If a compressed stream
with a larger window size is given as input, inflate() will return with
the error code Z_DATA_ERROR instead of trying to allocate a larger window.
If next_out is not null, the library will use this buffer for the history
buffer; the buffer must either be large enough to hold the entire output
data, or have at least 1<<windowBits bytes. If next_out is null, the
library will allocate its own buffer (and leave next_out null). next_in
need not be provided here but must be provided by the application for the
next call of inflate().
If the history buffer is provided by the application, next_out must
never be changed by the application since the decompressor maintains
history information inside this buffer from call to call; the application
can only reset next_out to the beginning of the history buffer when
avail_out is zero and all output has been consumed.
inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
windowBits < 8). msg is set to null if there is no error message.
inflateInit2 does not perform any decompression: this will be done by
inflate().
*/
extern int inflateSync OF((z_stream *strm));
/*
Skips invalid compressed data until the special marker (see deflate()
above) can be found, or until all available input is skipped. No output
is provided.
inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
if no more input was provided, Z_DATA_ERROR if no marker has been found,
or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
case, the application may save the current current value of total_in which
indicates where valid compressed data was found. In the error case, the
application may repeatedly call inflateSync, providing more input each time,
until success or end of the input data.
*/
extern int inflateReset OF((z_stream *strm));
/*
This function is equivalent to inflateEnd followed by inflateInit,
but does not free and reallocate all the internal decompression state.
The stream will keep attributes that may have been set by inflateInit2.
inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being NULL).
*/
extern int inflateIncomp OF((z_stream *strm));
/*
This function adds the data at next_in (avail_in bytes) to the output
history without performing any output. There must be no pending output,
and the decompressor must be expecting to see the start of a block.
Calling this function is equivalent to decompressing a stored block
containing the data at next_in (except that the data is not output).
*/
/* checksum functions */
/*
This function is not related to compression but is exported
anyway because it might be useful in applications using the
compression library.
*/
extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
/*
Update a running Adler-32 checksum with the bytes buf[0..len-1] and
return the updated checksum. If buf is NULL, this function returns
the required initial value for the checksum.
An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
much faster. Usage example:
uLong adler = adler32(0L, Z_NULL, 0);
while (read_buffer(buffer, length) != EOF) {
adler = adler32(adler, buffer, length);
}
if (adler != original_adler) error();
*/
#ifndef _Z_UTIL_H
struct internal_state {int dummy;}; /* hack for buggy compilers */
#endif
#endif /* _ZLIB_H */

View File

@@ -47,12 +47,11 @@
#define BOOL int
#define False 0
#define True 1
#define Realloc realloc
#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
#define strequal(a,b) (strcasecmp(a,b)==0)
#define BOOLSTR(b) ((b) ? "Yes" : "No")
typedef char pstring[1024];
#define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring)-1)
#define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring))
/* the following are used by loadparm for option lists */
typedef enum
@@ -99,6 +98,8 @@ typedef struct
{
char *motd_file;
char *lock_file;
char *log_file;
char *pid_file;
int syslog_facility;
int max_connections;
char *socket_options;
@@ -118,6 +119,8 @@ typedef struct
char *comment;
BOOL read_only;
BOOL list;
BOOL use_chroot;
BOOL transfer_logging;
char *uid;
char *gid;
char *hosts_allow;
@@ -126,6 +129,12 @@ typedef struct
char *secrets_file;
char *exclude;
char *exclude_from;
char *include;
char *include_from;
char *log_format;
char *refuse_options;
char *dont_compress;
int timeout;
} service;
@@ -137,6 +146,8 @@ static service sDefault =
NULL, /* comment */
True, /* read only */
True, /* list */
True, /* use chroot */
False, /* transfer logging */
"nobody",/* uid */
"nobody",/* gid */
NULL, /* hosts allow */
@@ -145,6 +156,12 @@ static service sDefault =
NULL, /* secrets file */
NULL, /* exclude */
NULL, /* exclude from */
NULL, /* include */
NULL, /* include from */
"%o %h [%a] %m (%u) %f %l", /* log format */
NULL, /* refuse options */
"*.gz *.tgz *.zip *.z *.rpm *.deb", /* dont compress */
0 /* timeout */
};
@@ -232,12 +249,16 @@ static struct parm_struct parm_table[] =
{"lock file", P_STRING, P_GLOBAL, &Globals.lock_file, NULL, 0},
{"syslog facility", P_ENUM, P_GLOBAL, &Globals.syslog_facility, enum_facilities,0},
{"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},
{"timeout", P_INTEGER, P_LOCAL, &sDefault.timeout, NULL, 0},
{"name", P_STRING, P_LOCAL, &sDefault.name, NULL, 0},
{"comment", P_STRING, P_LOCAL, &sDefault.comment, 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},
{"uid", P_STRING, P_LOCAL, &sDefault.uid, NULL, 0},
{"gid", P_STRING, P_LOCAL, &sDefault.gid, NULL, 0},
{"hosts allow", P_STRING, P_LOCAL, &sDefault.hosts_allow, NULL, 0},
@@ -246,6 +267,12 @@ static struct parm_struct parm_table[] =
{"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file,NULL, 0},
{"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL, 0},
{"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from,NULL, 0},
{"include", P_STRING, P_LOCAL, &sDefault.include, NULL, 0},
{"include from", P_STRING, P_LOCAL, &sDefault.include_from,NULL, 0},
{"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging,NULL,0},
{"log format", P_STRING, P_LOCAL, &sDefault.log_format, NULL, 0},
{"refuse options", P_STRING, P_LOCAL, &sDefault.refuse_options,NULL, 0},
{"dont compress", P_STRING, P_LOCAL, &sDefault.dont_compress,NULL, 0},
{NULL, P_BOOL, P_NONE, NULL, NULL, 0}
};
@@ -296,6 +323,8 @@ static void init_locals(void)
FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
FN_GLOBAL_STRING(lp_lock_file, &Globals.lock_file)
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_max_connections, &Globals.max_connections)
FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
@@ -305,6 +334,8 @@ FN_LOCAL_STRING(lp_comment, comment)
FN_LOCAL_STRING(lp_path, path)
FN_LOCAL_BOOL(lp_read_only, read_only)
FN_LOCAL_BOOL(lp_list, list)
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
FN_LOCAL_STRING(lp_uid, uid)
FN_LOCAL_STRING(lp_gid, gid)
FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
@@ -313,6 +344,12 @@ FN_LOCAL_STRING(lp_auth_users, auth_users)
FN_LOCAL_STRING(lp_secrets_file, secrets_file)
FN_LOCAL_STRING(lp_exclude, exclude)
FN_LOCAL_STRING(lp_exclude_from, exclude_from)
FN_LOCAL_STRING(lp_include, include)
FN_LOCAL_STRING(lp_include_from, include_from)
FN_LOCAL_STRING(lp_log_format, log_format)
FN_LOCAL_STRING(lp_refuse_options, refuse_options)
FN_LOCAL_STRING(lp_dont_compress, dont_compress)
FN_LOCAL_INTEGER(lp_timeout, timeout)
/* local prototypes */
static int strwicmp( char *psz1, char *psz2 );
@@ -330,7 +367,7 @@ initialise a service to the defaults
***************************************************************************/
static void init_service(service *pservice)
{
bzero((char *)pservice,sizeof(service));
memset((char *)pservice,0,sizeof(service));
copy_service(pservice,&sDefault);
}
@@ -341,7 +378,7 @@ static void string_set(char **s, char *v)
return;
}
*s = strdup(v);
if (!*s) exit_cleanup(1);
if (!*s) exit_cleanup(RERR_MALLOC);
}
@@ -368,6 +405,7 @@ static int add_a_service(service *pservice, char *name)
i = iNumServices;
ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
if (ServicePtrs)
pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
@@ -430,7 +468,7 @@ static int map_parameter(char *parmname)
if (strwicmp(parm_table[iIndex].label, parmname) == 0)
return(iIndex);
rprintf(FERROR, "Unknown parameter encountered: \"%s\"\n", parmname);
rprintf(FERROR, "Unknown Parameter encountered: \"%s\"\n", parmname);
return(-1);
}
@@ -542,7 +580,7 @@ static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
if (parmnum < 0)
{
rprintf(FERROR, "Ignoring unknown parameter \"%s\"\n", parmname);
rprintf(FERROR, "IGNORING unknown parameter \"%s\"\n", parmname);
return(True);
}
@@ -588,7 +626,7 @@ static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
break;
case P_GSTRING:
strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring)-1);
strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring));
break;
case P_ENUM:

226
log.c
View File

@@ -23,15 +23,46 @@
*/
#include "rsync.h"
static FILE *logfile;
static void logit(int priority, char *buf)
{
if (logfile) {
fprintf(logfile,"%s [%d] %s",
timestring(time(NULL)), (int)getpid(), buf);
fflush(logfile);
} else {
syslog(priority, "%s", buf);
}
}
void log_open(void)
{
static int initialised;
int options = LOG_PID;
time_t t;
char *logf;
if (initialised) return;
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 */
t = time(NULL);
localtime(&t);
/* optionally use a log file instead of syslog */
logf = lp_log_file();
if (logf && *logf) {
extern int orig_umask;
int old_umask = umask(022 | orig_umask);
logfile = fopen(logf, "a");
umask(old_umask);
return;
}
#ifdef LOG_NDELAY
options |= LOG_NDELAY;
#endif
@@ -43,13 +74,13 @@ void log_open(void)
#endif
#ifndef LOG_NDELAY
syslog(LOG_INFO,"rsyncd started\n");
logit(LOG_INFO,"rsyncd started\n");
#endif
}
/* this is the rsync debugging function. Call it with FINFO or FERROR */
void rprintf(int fd, const char *format, ...)
/* this is the rsync debugging function. Call it with FINFO, FERROR or FLOG */
void rprintf(int fd, const char *format, ...)
{
va_list ap;
char buf[1024];
@@ -57,29 +88,34 @@ void rprintf(int fd, const char *format, ...)
FILE *f=NULL;
extern int am_daemon;
/* recursion can happen with certain fatal conditions */
static int depth;
if (depth) return;
depth++;
va_start(ap, format);
len = vslprintf(buf, sizeof(buf)-1, format, ap);
len = vslprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (len < 0) exit_cleanup(1);
if (len < 0) exit_cleanup(RERR_MESSAGEIO);
if (len > sizeof(buf)-1) exit_cleanup(1);
if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
buf[len] = 0;
if (fd == FLOG) {
if (am_daemon) logit(LOG_INFO, buf);
return;
}
if (am_daemon) {
static int depth;
int priority = LOG_INFO;
if (fd == FERROR) priority = LOG_WARNING;
if (depth) return;
depth++;
log_open();
if (!io_multiplex_write(fd, buf, strlen(buf))) {
syslog(priority, "%s", buf);
logit(priority, buf);
}
depth--;
@@ -98,11 +134,11 @@ void rprintf(int fd, const char *format, ...)
f = stdout;
}
if (!f) exit_cleanup(1);
if (!f) exit_cleanup(RERR_MESSAGEIO);
if (fwrite(buf, len, 1, f) != 1) exit_cleanup(1);
if (fwrite(buf, len, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO);
depth--;
if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
}
void rflush(int fd)
@@ -114,6 +150,10 @@ void rflush(int fd)
return;
}
if (fd == FLOG) {
return;
}
if (fd == FERROR) {
f = stderr;
}
@@ -126,7 +166,161 @@ void rflush(int fd)
f = stdout;
}
if (!f) exit_cleanup(1);
if (!f) exit_cleanup(RERR_MESSAGEIO);
fflush(f);
}
/* a generic logging routine for send/recv, with parameter
substitiution */
static void log_formatted(int fd,
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;
int l;
extern struct stats stats;
extern int am_sender;
extern int am_daemon;
int64 b;
strlcpy(buf, format, sizeof(buf));
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':
slprintf(buf2,sizeof(buf2),"%.0f",
(double)file->length);
n = buf2;
break;
case 'p':
slprintf(buf2,sizeof(buf2),"%d",
(int)getpid());
n = buf2;
break;
case 'o': n = op; break;
case 'f':
slprintf(buf2, sizeof(buf2), "%s/%s",
file->basedir?file->basedir:"",
f_name(file));
clean_fname(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':
if (am_sender) {
b = stats.total_written -
initial_stats->total_written;
} else {
b = stats.total_read -
initial_stats->total_read;
}
slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
n = buf2;
break;
case 'c':
if (!am_sender) {
b = stats.total_written -
initial_stats->total_written;
} else {
b = stats.total_read -
initial_stats->total_read;
}
slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
n = buf2;
break;
}
if (!n) continue;
l = strlen(n);
if ((l-1) + ((int)(s - &buf[0])) > sizeof(buf)) {
rprintf(FERROR,"buffer overflow expanding %%%c - exiting\n",
p[0]);
exit_cleanup(RERR_MESSAGEIO);
}
if (l != 2) {
memmove(s+(l-1), s+1, strlen(s+1)+1);
}
memcpy(p, n, l);
s = p+l;
}
rprintf(fd,"%s\n", buf);
}
/* 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) {
log_formatted(FINFO, log_format, "send", file, 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), "send", file, initial_stats);
} else if (log_format && !am_server) {
log_formatted(FINFO, log_format, "send", file, initial_stats);
}
}
/* called when the transfer is interrupted for some reason */
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 {
rprintf(FLOG,"transfer interrupted (code %d) at %s(%d)\n",
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
it i 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);
}

253
main.c
View File

@@ -20,7 +20,8 @@
#include "rsync.h"
time_t starttime = 0;
int64 total_size = 0;
struct stats stats;
extern int csum_length;
@@ -28,16 +29,14 @@ extern int verbose;
static void report(int f)
{
int64 in,out,tsize;
time_t t = time(NULL);
extern int am_server;
extern int am_sender;
extern int am_daemon;
extern int do_stats;
if (am_daemon) {
syslog(LOG_INFO,"wrote %.0f bytes read %.0f bytes total size %.0f\n",
(double)write_total(),(double)read_total(),
(double)total_size);
log_exit(0, __FILE__, __LINE__);
if (f == -1 || !am_sender) return;
}
@@ -46,27 +45,49 @@ static void report(int f)
if (am_server && !am_sender) return;
if (am_server && am_sender) {
write_longint(f,read_total());
write_longint(f,write_total());
write_longint(f,total_size);
write_flush(f);
write_longint(f,stats.total_read);
write_longint(f,stats.total_written);
write_longint(f,stats.total_size);
return;
}
if (am_sender) {
in = read_total();
out = write_total();
tsize = total_size;
} else {
out = read_longint(f);
in = read_longint(f);
tsize = read_longint(f);
if (!am_sender) {
int64 r;
stats.total_written = read_longint(f);
r = read_longint(f);
stats.total_size = read_longint(f);
stats.total_read = r;
}
if (do_stats) {
rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
rprintf(FINFO,"Number of files transferred: %d\n",
stats.num_transferred_files);
rprintf(FINFO,"Total file size: %.0f bytes\n",
(double)stats.total_size);
rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
(double)stats.total_transferred_size);
rprintf(FINFO,"Literal data: %.0f bytes\n",
(double)stats.literal_data);
rprintf(FINFO,"Matched data: %.0f bytes\n",
(double)stats.matched_data);
rprintf(FINFO,"File list size: %d\n", stats.flist_size);
rprintf(FINFO,"Total bytes written: %.0f\n",
(double)stats.total_written);
rprintf(FINFO,"Total bytes read: %.0f\n\n",
(double)stats.total_read);
}
printf("wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
(double)out,(double)in,(in+out)/(0.5 + (t-starttime)));
printf("total size is %.0f speedup is %.2f\n",
(double)tsize,(1.0*tsize)/(in+out));
rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
(double)stats.total_written,
(double)stats.total_read,
(stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
(double)stats.total_size,
(1.0*stats.total_size)/(stats.total_written+stats.total_read));
fflush(stdout);
fflush(stderr);
}
@@ -148,40 +169,47 @@ static char *get_local_name(struct file_list *flist,char *name)
STRUCT_STAT st;
extern int orig_umask;
if (do_stat(name,&st) == 0) {
if (S_ISDIR(st.st_mode)) {
if (chdir(name) != 0) {
rprintf(FERROR,"chdir %s : %s (1)\n",name,strerror(errno));
exit_cleanup(1);
}
return NULL;
}
if (flist->count > 1) {
rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
exit_cleanup(1);
}
return name;
}
if (verbose > 2)
rprintf(FINFO,"get_local_name count=%d %s\n",
flist->count, name);
if (flist->count == 1)
return name;
if (do_stat(name,&st) == 0) {
if (S_ISDIR(st.st_mode)) {
if (!push_dir(name, 0)) {
rprintf(FERROR,"push_dir %s : %s (1)\n",
name,strerror(errno));
exit_cleanup(RERR_FILESELECT);
}
return NULL;
}
if (flist->count > 1) {
rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
exit_cleanup(RERR_FILESELECT);
}
return name;
}
if (!name)
return NULL;
if (flist->count == 1)
return name;
if (do_mkdir(name,0777 & ~orig_umask) != 0) {
rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
exit_cleanup(1);
} else {
rprintf(FINFO,"created directory %s\n",name);
}
if (!name)
return NULL;
if (chdir(name) != 0) {
rprintf(FERROR,"chdir %s : %s (2)\n",name,strerror(errno));
exit_cleanup(1);
}
if (do_mkdir(name,0777 & ~orig_umask) != 0) {
rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
exit_cleanup(RERR_FILEIO);
} else {
if (verbose > 0)
rprintf(FINFO,"created directory %s\n",name);
}
return NULL;
if (!push_dir(name, 0)) {
rprintf(FERROR,"push_dir %s : %s (2)\n",
name,strerror(errno));
exit_cleanup(RERR_FILESELECT);
}
return NULL;
}
@@ -198,9 +226,9 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
if (verbose > 2)
rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
if (!relative_paths && chdir(dir) != 0) {
rprintf(FERROR,"chdir %s: %s (3)\n",dir,strerror(errno));
exit_cleanup(1);
if (!relative_paths && !push_dir(dir, 0)) {
rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
exit_cleanup(RERR_FILESELECT);
}
argc--;
argv++;
@@ -219,6 +247,10 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
argv[0] = ".";
}
set_nonblocking(f_out);
if (f_in != f_out)
set_nonblocking(f_in);
flist = send_file_list(f_out,argc,argv);
if (!flist || flist->count == 0) {
exit_cleanup(0);
@@ -243,7 +275,7 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
if (pipe(recv_pipe) < 0) {
rprintf(FERROR,"pipe failed in do_recv\n");
exit_cleanup(1);
exit_cleanup(RERR_SOCKETIO);
}
io_flush();
@@ -252,12 +284,12 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
close(recv_pipe[0]);
if (f_in != f_out) close(f_out);
set_nonblocking(f_in);
set_nonblocking(recv_pipe[1]);
recv_files(f_in,flist,local_name,recv_pipe[1]);
report(f_in);
if (verbose > 3)
rprintf(FINFO,"do_recv waiting on %d\n",pid);
io_flush();
_exit(0);
}
@@ -265,6 +297,12 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
close(recv_pipe[1]);
io_close_input(f_in);
if (f_in != f_out) close(f_in);
set_nonblocking(f_out);
set_nonblocking(recv_pipe[0]);
io_start_buffering(f_out);
generate_files(f_out,flist,local_name,recv_pipe[0]);
io_flush();
@@ -289,10 +327,10 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
dir = argv[0];
argc--;
argv++;
if (!am_daemon && chdir(dir) != 0) {
rprintf(FERROR,"chdir %s : %s (4)\n",
if (!am_daemon && !push_dir(dir, 0)) {
rprintf(FERROR,"push_dir %s : %s (4)\n",
dir,strerror(errno));
exit_cleanup(1);
exit_cleanup(RERR_FILESELECT);
}
}
@@ -302,7 +340,7 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
flist = recv_file_list(f_in);
if (!flist || flist->count == 0) {
rprintf(FERROR,"server_recv: nothing to do\n");
exit_cleanup(1);
exit_cleanup(RERR_FILESELECT);
}
if (argc > 0) {
@@ -323,8 +361,12 @@ void start_server(int f_in, int f_out, int argc, char *argv[])
extern int cvs_exclude;
extern int am_sender;
set_nonblocking(f_out);
if (f_in != f_out)
set_nonblocking(f_in);
setup_protocol(f_out, f_in);
if (am_sender) {
recv_exclude_list(f_in);
if (cvs_exclude)
@@ -342,6 +384,7 @@ int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
int status = 0, status2 = 0;
char *local_name = NULL;
extern int am_sender;
extern int list_only;
setup_protocol(f_out,f_in);
@@ -355,6 +398,11 @@ int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
flist = send_file_list(f_out,argc,argv);
if (verbose > 3)
rprintf(FINFO,"file list sent\n");
set_nonblocking(f_out);
if (f_in != f_out)
set_nonblocking(f_in);
send_files(flist,f_out,f_in);
if (pid != -1) {
if (verbose > 3)
@@ -365,6 +413,8 @@ int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
report(-1);
exit_cleanup(status);
}
if (argc == 0) list_only = 1;
send_exclude_list(f_out);
@@ -388,20 +438,54 @@ int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
return status | status2;
}
static char *find_colon(char *s)
{
char *p, *p2;
int start_client(int argc, char *argv[])
p = strchr(s,':');
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;
return p;
}
static int start_client(int argc, char *argv[])
{
char *p;
char *shell_machine = NULL;
char *shell_path = NULL;
char *shell_user = NULL;
int pid;
int pid, ret;
int f_in,f_out;
extern int local_server;
extern int am_sender;
extern char *shell_cmd;
extern int rsync_port;
p = strchr(argv[0],':');
if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
char *host, *path;
host = argv[0] + strlen(URL_PREFIX);
p = strchr(host,'/');
if (p) {
*p = 0;
path = p+1;
} else {
path="";
}
p = strchr(host,':');
if (p) {
rsync_port = atoi(p+1);
*p = 0;
}
return start_socket_client(host, path, argc-1, argv+1);
}
p = find_colon(argv[0]);
if (p) {
if (p[1] == ':') {
@@ -409,9 +493,9 @@ int start_client(int argc, char *argv[])
return start_socket_client(argv[0], p+2, argc-1, argv+1);
}
if (argc < 2) {
if (argc < 1) {
usage(FERROR);
exit_cleanup(1);
exit_cleanup(RERR_SYNTAX);
}
am_sender = 0;
@@ -423,7 +507,7 @@ int start_client(int argc, char *argv[])
} else {
am_sender = 1;
p = strchr(argv[argc-1],':');
p = find_colon(argv[argc-1]);
if (!p) {
local_server = 1;
} else if (p[1] == ':') {
@@ -433,7 +517,7 @@ int start_client(int argc, char *argv[])
if (argc < 2) {
usage(FERROR);
exit_cleanup(1);
exit_cleanup(RERR_SYNTAX);
}
if (local_server) {
@@ -464,24 +548,24 @@ int start_client(int argc, char *argv[])
shell_path?shell_path:"");
}
if (!am_sender && argc != 1) {
if (!am_sender && argc > 1) {
usage(FERROR);
exit_cleanup(1);
exit_cleanup(RERR_SYNTAX);
}
pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
#if HAVE_SETLINEBUF
setlinebuf(stdout);
setlinebuf(stderr);
#endif
ret = client_run(f_in, f_out, pid, argc, argv);
return client_run(f_in, f_out, pid, argc, argv);
fflush(stdout);
fflush(stderr);
return ret;
}
RETSIGTYPE sigusr1_handler(int val) {
exit_cleanup(1);
static RETSIGTYPE sigusr1_handler(int val) {
exit_cleanup(RERR_SIGNAL);
}
int main(int argc,char *argv[])
@@ -497,16 +581,20 @@ int main(int argc,char *argv[])
starttime = time(NULL);
am_root = (getuid() == 0);
memset(&stats, 0, sizeof(stats));
if (argc < 2) {
usage(FERROR);
exit_cleanup(1);
exit_cleanup(RERR_SYNTAX);
}
/* we set a 0 umask so that correct file permissions can be
carried across */
orig_umask = (int)umask(0);
parse_arguments(argc, argv);
if (!parse_arguments(argc, argv)) {
exit_cleanup(RERR_SYNTAX);
}
argc -= optind;
argv += optind;
@@ -516,6 +604,7 @@ int main(int argc,char *argv[])
signal(SIGINT,SIGNAL_CAST sig_int);
signal(SIGPIPE,SIGNAL_CAST sig_int);
signal(SIGHUP,SIGNAL_CAST sig_int);
signal(SIGTERM,SIGNAL_CAST sig_int);
if (am_daemon) {
return daemon_main();
@@ -523,7 +612,7 @@ int main(int argc,char *argv[])
if (argc < 1) {
usage(FERROR);
exit_cleanup(1);
exit_cleanup(RERR_SYNTAX);
}
if (dry_run)
@@ -532,7 +621,7 @@ int main(int argc,char *argv[])
#ifndef SUPPORT_LINKS
if (!am_server && preserve_links) {
rprintf(FERROR,"ERROR: symbolic links not supported\n");
exit_cleanup(1);
exit_cleanup(RERR_UNSUPPORTED);
}
#endif

51
match.c
View File

@@ -29,18 +29,18 @@ extern int remote_version;
typedef unsigned short tag;
#define TABLESIZE (1<<16)
#define NULL_TAG ((tag)-1)
#define NULL_TAG (-1)
static int false_alarms;
static int tag_hits;
static int matches;
static int data_transfer;
static int64 data_transfer;
static int total_false_alarms;
static int total_tag_hits;
static int total_matches;
static int64 total_data_transfer;
extern struct stats stats;
struct target {
tag t;
@@ -49,7 +49,7 @@ struct target {
static struct target *targets;
static tag *tag_table;
static int *tag_table;
#define gettag2(s1,s2) (((s1) + (s2)) & 0xFFFF)
#define gettag(sum) gettag2((sum)&0xFFFF,(sum)>>16)
@@ -65,7 +65,7 @@ static void build_hash_table(struct sum_struct *s)
int i;
if (!tag_table)
tag_table = (tag *)malloc(sizeof(tag)*TABLESIZE);
tag_table = (int *)malloc(sizeof(tag_table[0])*TABLESIZE);
targets = (struct target *)malloc(sizeof(targets[0])*s->count);
if (!tag_table || !targets)
@@ -94,20 +94,19 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
OFF_T offset,int i)
{
OFF_T n = offset - last_match;
int j;
OFF_T j;
if (verbose > 2 && i >= 0)
rprintf(FINFO,"match at %d last_match=%d j=%d len=%d n=%d\n",
(int)offset,(int)last_match,i,(int)s->sums[i].len,(int)n);
send_token(f,i,buf,last_match,n,i==-1?0:s->sums[i].len);
send_token(f,i,buf,last_match,n,i<0?0:s->sums[i].len);
data_transfer += n;
if (n > 0)
write_flush(f);
if (i >= 0)
if (i >= 0) {
stats.matched_data += s->sums[i].len;
n += s->sums[i].len;
}
for (j=0;j<n;j+=CHUNK_SIZE) {
int n1 = MIN(CHUNK_SIZE,n-j);
@@ -119,6 +118,11 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
last_match = offset + s->sums[i].len;
else
last_match = offset;
if (buf)
show_progress(last_match, buf->size);
if (i == -1) end_progress();
}
@@ -212,7 +216,17 @@ static void hash_search(int f,struct sum_struct *s,
} else {
--k;
}
/* By matching early we avoid re-reading the
data 3 times in the case where a token
match comes a long way after last
match. The 3 reads are caused by the
running match, the checksum update and the
literal send. */
if (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);
@@ -243,6 +257,12 @@ void match_sums(int f,struct sum_struct *s,struct map_struct *buf,OFF_T len)
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) {
int n1 = MIN(CHUNK_SIZE,(len-CHUNK_SIZE)-j);
matched(f,s,buf,j+n1,-2);
}
matched(f,s,buf,len,-1);
}
@@ -266,7 +286,7 @@ void match_sums(int f,struct sum_struct *s,struct map_struct *buf,OFF_T len)
total_tag_hits += tag_hits;
total_false_alarms += false_alarms;
total_matches += matches;
total_data_transfer += data_transfer;
stats.literal_data += data_transfer;
}
void match_report(void)
@@ -275,7 +295,8 @@ void match_report(void)
return;
rprintf(FINFO,
"total: matches=%d tag_hits=%d false_alarms=%d data=%ld\n",
"total: matches=%d tag_hits=%d false_alarms=%d data=%.0f\n",
total_matches,total_tag_hits,
total_false_alarms,(long)total_data_transfer);
total_false_alarms,
(double)stats.literal_data);
}

4
md4.c
View File

@@ -102,7 +102,7 @@
** Assumes X is an array of 16 ints.
** The macro revx reverses the byte-ordering of the next word of X.
*/
void MDreverse(X)
static void MDreverse(X)
unsigned int32 *X;
{ register unsigned int32 t;
register unsigned int i;
@@ -225,7 +225,7 @@
/* Process data */
if (count == 512)
{ /* Full block of data to handle */
MDblock(MDp,(unsigned int *)X);
MDblock(MDp,(unsigned int32 *)X);
}
else if (count > 512) /* Check for count too large */
{ rprintf(FERROR,"\nError: MDupdate called with illegal count value %d."

View File

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

759
options.c
View File

@@ -55,74 +55,101 @@ int am_sender=0;
int recurse = 0;
int am_daemon=0;
int am_client=0;
int do_stats=0;
int do_progress=0;
int keep_partial=0;
int safe_symlinks=0;
int block_size=BLOCK_SIZE;
char *backup_suffix = BACKUP_SUFFIX;
char *tmpdir = NULL;
char *compare_dest = NULL;
char *config_file = RSYNCD_CONF;
char *shell_cmd = NULL;
char *log_format = NULL;
char *rsync_path = RSYNC_NAME;
int rsync_port = RSYNC_PORT;
int verbose = 0;
int always_checksum = 0;
int list_only = 0;
void usage(int F)
{
rprintf(F,"rsync version %s Copyright Andrew Tridgell and Paul Mackerras\n\n",
VERSION);
rprintf(F,"Usage:\t%s [options] src user@host:dest\nOR",RSYNC_NAME);
rprintf(F,"\t%s [options] user@host:src dest\n\n",RSYNC_NAME);
rprintf(F,"Options:\n");
rprintf(F,"-v, --verbose increase verbosity\n");
rprintf(F,"-c, --checksum always checksum\n");
rprintf(F,"-a, --archive archive mode (same as -rlptDog)\n");
rprintf(F,"-r, --recursive recurse into directories\n");
rprintf(F,"-R, --relative use relative path names\n");
rprintf(F,"-b, --backup make backups (default ~ extension)\n");
rprintf(F,"-u, --update update only (don't overwrite newer files)\n");
rprintf(F,"-l, --links preserve soft links\n");
rprintf(F,"-L, --copy-links treat soft links like regular files\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");
rprintf(F,"-g, --group preserve group\n");
rprintf(F,"-D, --devices preserve devices (root only)\n");
rprintf(F,"-t, --times preserve times\n");
rprintf(F,"-S, --sparse handle sparse files efficiently\n");
rprintf(F,"-n, --dry-run show what would have been transferred\n");
rprintf(F,"-W, --whole-file copy whole files, no incremental checks\n");
rprintf(F,"-x, --one-file-system don't cross filesystem boundaries\n");
rprintf(F,"-B, --block-size SIZE checksum blocking size\n");
rprintf(F,"-e, --rsh COMMAND specify rsh replacement\n");
rprintf(F," --rsync-path PATH specify path to rsync on the remote machine\n");
rprintf(F,"-C, --cvs-exclude auto ignore files in the same way CVS does\n");
rprintf(F," --delete delete files that don't exist on the sending side\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 IO timeout in seconds\n");
rprintf(F,"-I, --ignore-times don't exclude files that match length and time\n");
rprintf(F,"-T --temp-dir DIR create temporary files in directory DIR\n");
rprintf(F,"-z, --compress compress file data\n");
rprintf(F," --exclude FILE exclude file FILE\n");
rprintf(F," --exclude-from FILE exclude files listed in FILE\n");
rprintf(F," --suffix SUFFIX override backup suffix\n");
rprintf(F," --version print version number\n");
rprintf(F," --daemon run as a rsync daemon\n");
rprintf(F," --config FILE specify alternate rsyncd.conf file\n");
rprintf(F," --port PORT specify alternate rsyncd port number\n");
rprintf(F,"rsync is a file transfer program capable of efficient remote update\nvia a fast differencing algorithm.\n\n");
rprintf(F,"Usage: rsync [OPTION]... SRC [USER@]HOST:DEST\n");
rprintf(F," or rsync [OPTION]... [USER@]HOST:SRC DEST\n");
rprintf(F," or rsync [OPTION]... SRC DEST\n");
rprintf(F," or rsync [OPTION]... [USER@]HOST::SRC [DEST]\n");
rprintf(F," or rsync [OPTION]... SRC [USER@]HOST::DEST\n");
rprintf(F," or rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]\n");
rprintf(F,"\nOptions\n");
rprintf(F," -v, --verbose increase verbosity\n");
rprintf(F," -c, --checksum always checksum\n");
rprintf(F," -a, --archive archive mode\n");
rprintf(F," -r, --recursive recurse into directories\n");
rprintf(F," -R, --relative use relative path names\n");
rprintf(F," -b, --backup make backups (default ~ extension)\n");
rprintf(F," -u, --update update only (don't overwrite newer files)\n");
rprintf(F," -l, --links preserve soft links\n");
rprintf(F," -L, --copy-links treat soft links like regular files\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");
rprintf(F," -g, --group preserve group\n");
rprintf(F," -D, --devices preserve devices (root only)\n");
rprintf(F," -t, --times preserve times\n");
rprintf(F," -S, --sparse handle sparse files efficiently\n");
rprintf(F," -n, --dry-run show what would have been transferred\n");
rprintf(F," -W, --whole-file copy whole files, no incremental checks\n");
rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n");
rprintf(F," -B, --block-size=SIZE checksum blocking size\n");
rprintf(F," -e, --rsh=COMMAND specify rsh replacement\n");
rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n");
rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
rprintf(F," --delete delete files that don't exist on the sending side\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 IO timeout in seconds\n");
rprintf(F," -I, --ignore-times don't exclude files that match length and time\n");
rprintf(F," -T --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
rprintf(F," -z, --compress compress file data\n");
rprintf(F," --exclude=PATTERN exclude files matching PATTERN\n");
rprintf(F," --exclude-from=FILE exclude patterns listed in FILE\n");
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," --suffix=SUFFIX override backup suffix\n");
rprintf(F," --version print version number\n");
rprintf(F," --daemon run as a rsync daemon\n");
rprintf(F," --config=FILE specify alternate rsyncd.conf file\n");
rprintf(F," --port=PORT specify alternate rsyncd port number\n");
rprintf(F," --stats give some file transfer stats\n");
rprintf(F," --progress show progress during transfer\n");
rprintf(F," --log-format=FORMAT log file transfers using specified format\n");
rprintf(F," -h, --help show this help screen\n");
rprintf(F,"\n");
rprintf(F,"the backup suffix defaults to %s\n",BACKUP_SUFFIX);
rprintf(F,"the block size defaults to %d\n",BLOCK_SIZE);
rprintf(F,"\nPlease see the rsync(1) and rsyncd.conf(5) man pages for full documentation\n");
rprintf(F,"See http://rsync.samba.org/ for updates and bug reports\n");
}
enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE,
OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH,
OPT_FORCE,OPT_TIMEOUT,OPT_DAEMON,OPT_CONFIG,OPT_PORT};
OPT_FORCE,OPT_TIMEOUT,OPT_DAEMON,OPT_CONFIG,OPT_PORT,
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS, OPT_PARTIAL, OPT_PROGRESS,
OPT_SAFE_LINKS, OPT_COMPARE_DEST, OPT_LOG_FORMAT};
static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z";
@@ -135,6 +162,8 @@ static struct option long_options[] = {
{"numeric-ids", 0, 0, OPT_NUMERIC_IDS},
{"exclude", 1, 0, OPT_EXCLUDE},
{"exclude-from",1, 0, OPT_EXCLUDE_FROM},
{"include", 1, 0, OPT_INCLUDE},
{"include-from",1, 0, OPT_INCLUDE_FROM},
{"rsync-path", 1, 0, OPT_RSYNC_PATH},
{"one-file-system",0, 0, 'x'},
{"ignore-times",0, 0, 'I'},
@@ -153,6 +182,7 @@ static struct option long_options[] = {
{"perms", 0, 0, 'p'},
{"links", 0, 0, 'l'},
{"copy-links", 0, 0, 'L'},
{"safe-links", 0, 0, OPT_SAFE_LINKS},
{"whole-file", 0, 0, 'W'},
{"hard-links", 0, 0, 'H'},
{"owner", 0, 0, 'o'},
@@ -163,300 +193,405 @@ static struct option long_options[] = {
{"block-size", 1, 0, 'B'},
{"timeout", 1, 0, OPT_TIMEOUT},
{"temp-dir", 1, 0, 'T'},
{"compare-dest", 1, 0, OPT_COMPARE_DEST},
{"compress", 0, 0, 'z'},
{"daemon", 0, 0, OPT_DAEMON},
{"stats", 0, 0, OPT_STATS},
{"progress", 0, 0, OPT_PROGRESS},
{"partial", 0, 0, OPT_PARTIAL},
{"config", 1, 0, OPT_CONFIG},
{"port", 1, 0, OPT_PORT},
{"log-format", 1, 0, OPT_LOG_FORMAT},
{0,0,0,0}};
void parse_arguments(int argc, char *argv[])
static char err_buf[100];
void option_error(void)
{
int opt;
int option_index;
while ((opt = getopt_long(argc, argv,
short_options, long_options, &option_index))
!= -1) {
switch (opt)
{
case OPT_VERSION:
printf("rsync version %s protocol version %d\n",
VERSION,PROTOCOL_VERSION);
exit_cleanup(0);
case OPT_SUFFIX:
backup_suffix = optarg;
break;
case OPT_RSYNC_PATH:
rsync_path = optarg;
break;
case 'I':
ignore_times = 1;
break;
case 'x':
one_file_system=1;
break;
case OPT_DELETE:
delete_mode = 1;
break;
case OPT_FORCE:
force_delete = 1;
break;
case OPT_NUMERIC_IDS:
numeric_ids = 1;
break;
case OPT_EXCLUDE:
add_exclude(optarg);
break;
case OPT_EXCLUDE_FROM:
add_exclude_file(optarg,1);
break;
case 'h':
usage(FINFO);
exit_cleanup(0);
case 'b':
make_backups=1;
break;
case 'n':
dry_run=1;
break;
case 'S':
sparse_files=1;
break;
case 'C':
cvs_exclude=1;
break;
case 'u':
update_only=1;
break;
case 'l':
preserve_links=1;
break;
case 'L':
copy_links=1;
break;
case 'W':
whole_file=1;
break;
case 'H':
#if SUPPORT_HARD_LINKS
preserve_hard_links=1;
#else
rprintf(FERROR,"ERROR: hard links not supported on this platform\n");
exit_cleanup(1);
#endif
break;
case 'p':
preserve_perms=1;
break;
case 'o':
preserve_uid=1;
break;
case 'g':
preserve_gid=1;
break;
case 'D':
preserve_devices=1;
break;
case 't':
preserve_times=1;
break;
case 'c':
always_checksum=1;
break;
case 'v':
verbose++;
break;
case 'a':
recurse=1;
#if SUPPORT_LINKS
preserve_links=1;
#endif
preserve_perms=1;
preserve_times=1;
preserve_gid=1;
if (am_root) {
preserve_devices=1;
preserve_uid=1;
}
break;
case OPT_SERVER:
am_server = 1;
break;
case OPT_SENDER:
if (!am_server) {
usage(FERROR);
exit_cleanup(1);
}
am_sender = 1;
break;
case 'r':
recurse = 1;
break;
case 'R':
relative_paths = 1;
break;
case 'e':
shell_cmd = optarg;
break;
case 'B':
block_size = atoi(optarg);
break;
case OPT_TIMEOUT:
io_timeout = atoi(optarg);
break;
case 'T':
tmpdir = optarg;
break;
case 'z':
do_compression = 1;
break;
case OPT_DAEMON:
am_daemon = 1;
break;
case OPT_CONFIG:
config_file = optarg;
break;
case OPT_PORT:
rsync_port = atoi(optarg);
break;
default:
/* rprintf(FERROR,"bad option -%c\n",opt); */
exit_cleanup(1);
if (err_buf[0]) {
rprintf(FLOG,"%s", err_buf);
rprintf(FERROR,"%s", err_buf);
} else {
rprintf(FLOG,"Error parsing options - unsupported option?\n");
rprintf(FERROR,"Error parsing options - unsupported option?\n");
}
}
exit_cleanup(RERR_UNSUPPORTED);
}
/* check to see if we should refuse this option */
static int check_refuse_options(char *ref, int opt)
{
int i, len;
char *p;
const char *name;
for (i=0; long_options[i].name; i++) {
if (long_options[i].val == opt) break;
}
if (!long_options[i].name) return 0;
name = long_options[i].name;
len = strlen(name);
while ((p = strstr(ref,name))) {
if ((p==ref || p[-1]==' ') &&
(p[len] == ' ' || p[len] == 0)) {
slprintf(err_buf,sizeof(err_buf),
"The '%s' option is not supported by this server\n", name);
return 1;
}
ref += len;
}
return 0;
}
int parse_arguments(int argc, char *argv[])
{
int opt;
int option_index;
char *ref = lp_refuse_options(module_id);
while ((opt = getopt_long(argc, argv,
short_options, long_options, &option_index))
!= -1) {
if (ref) {
if (check_refuse_options(ref, opt)) return 0;
}
switch (opt) {
case OPT_VERSION:
rprintf(FINFO,"rsync version %s protocol version %d\n\n",
VERSION,PROTOCOL_VERSION);
rprintf(FINFO,"Written by Andrew Tridgell and Paul Mackerras\n");
exit_cleanup(0);
case OPT_SUFFIX:
backup_suffix = optarg;
break;
case OPT_RSYNC_PATH:
rsync_path = optarg;
break;
case 'I':
ignore_times = 1;
break;
case 'x':
one_file_system=1;
break;
case OPT_DELETE:
delete_mode = 1;
break;
case OPT_FORCE:
force_delete = 1;
break;
case OPT_NUMERIC_IDS:
numeric_ids = 1;
break;
case OPT_EXCLUDE:
add_exclude(optarg, 0);
break;
case OPT_INCLUDE:
add_exclude(optarg, 1);
break;
case OPT_EXCLUDE_FROM:
add_exclude_file(optarg,1, 0);
break;
case OPT_INCLUDE_FROM:
add_exclude_file(optarg,1, 1);
break;
case OPT_SAFE_LINKS:
safe_symlinks=1;
break;
case 'h':
usage(FINFO);
exit_cleanup(0);
case 'b':
make_backups=1;
break;
case 'n':
dry_run=1;
break;
case 'S':
sparse_files=1;
break;
case 'C':
cvs_exclude=1;
break;
case 'u':
update_only=1;
break;
case 'l':
preserve_links=1;
break;
case 'L':
copy_links=1;
break;
case 'W':
whole_file=1;
break;
case 'H':
#if SUPPORT_HARD_LINKS
preserve_hard_links=1;
#else
slprintf(err_buf,sizeof(err_buf),"hard links are not supported on this server\n");
rprintf(FERROR,"ERROR: hard links not supported on this platform\n");
return 0;
#endif
break;
case 'p':
preserve_perms=1;
break;
case 'o':
preserve_uid=1;
break;
case 'g':
preserve_gid=1;
break;
case 'D':
preserve_devices=1;
break;
case 't':
preserve_times=1;
break;
case 'c':
always_checksum=1;
break;
case 'v':
verbose++;
break;
case 'a':
recurse=1;
#if SUPPORT_LINKS
preserve_links=1;
#endif
preserve_perms=1;
preserve_times=1;
preserve_gid=1;
if (am_root) {
preserve_devices=1;
preserve_uid=1;
}
break;
case OPT_SERVER:
am_server = 1;
break;
case OPT_SENDER:
if (!am_server) {
usage(FERROR);
exit_cleanup(RERR_SYNTAX);
}
am_sender = 1;
break;
case 'r':
recurse = 1;
break;
case 'R':
relative_paths = 1;
break;
case 'e':
shell_cmd = optarg;
break;
case 'B':
block_size = atoi(optarg);
break;
case OPT_TIMEOUT:
io_timeout = atoi(optarg);
break;
case 'T':
tmpdir = optarg;
break;
case OPT_COMPARE_DEST:
compare_dest = optarg;
break;
case 'z':
do_compression = 1;
break;
case OPT_DAEMON:
am_daemon = 1;
break;
case OPT_STATS:
do_stats = 1;
break;
case OPT_PROGRESS:
do_progress = 1;
break;
case OPT_PARTIAL:
keep_partial = 1;
break;
case OPT_CONFIG:
config_file = optarg;
break;
case OPT_PORT:
rsync_port = atoi(optarg);
break;
case OPT_LOG_FORMAT:
log_format = optarg;
break;
default:
slprintf(err_buf,sizeof(err_buf),"unrecognised option\n");
return 0;
}
}
return 1;
}
void server_options(char **args,int *argc)
{
int ac = *argc;
static char argstr[50];
static char bsize[30];
static char iotime[30];
int i, x;
int ac = *argc;
static char argstr[50];
static char bsize[30];
static char iotime[30];
int i, x;
args[ac++] = "--server";
args[ac++] = "--server";
if (!am_sender)
args[ac++] = "--sender";
if (!am_sender)
args[ac++] = "--sender";
x = 1;
argstr[0] = '-';
for (i=0;i<verbose;i++)
argstr[x++] = 'v';
if (make_backups)
argstr[x++] = 'b';
if (update_only)
argstr[x++] = 'u';
if (dry_run)
argstr[x++] = 'n';
if (preserve_links)
argstr[x++] = 'l';
if (copy_links)
argstr[x++] = 'L';
if (whole_file)
argstr[x++] = 'W';
if (preserve_hard_links)
argstr[x++] = 'H';
if (preserve_uid)
argstr[x++] = 'o';
if (preserve_gid)
argstr[x++] = 'g';
if (preserve_devices)
argstr[x++] = 'D';
if (preserve_times)
argstr[x++] = 't';
if (preserve_perms)
argstr[x++] = 'p';
if (recurse)
argstr[x++] = 'r';
if (always_checksum)
argstr[x++] = 'c';
if (cvs_exclude)
argstr[x++] = 'C';
if (ignore_times)
argstr[x++] = 'I';
if (relative_paths)
argstr[x++] = 'R';
if (one_file_system)
argstr[x++] = 'x';
if (sparse_files)
argstr[x++] = 'S';
if (do_compression)
argstr[x++] = 'z';
argstr[x] = 0;
x = 1;
argstr[0] = '-';
for (i=0;i<verbose;i++)
argstr[x++] = 'v';
if (make_backups)
argstr[x++] = 'b';
if (update_only)
argstr[x++] = 'u';
if (dry_run)
argstr[x++] = 'n';
if (preserve_links)
argstr[x++] = 'l';
if (copy_links)
argstr[x++] = 'L';
if (whole_file)
argstr[x++] = 'W';
if (preserve_hard_links)
argstr[x++] = 'H';
if (preserve_uid)
argstr[x++] = 'o';
if (preserve_gid)
argstr[x++] = 'g';
if (preserve_devices)
argstr[x++] = 'D';
if (preserve_times)
argstr[x++] = 't';
if (preserve_perms)
argstr[x++] = 'p';
if (recurse)
argstr[x++] = 'r';
if (always_checksum)
argstr[x++] = 'c';
if (cvs_exclude)
argstr[x++] = 'C';
if (ignore_times)
argstr[x++] = 'I';
if (relative_paths)
argstr[x++] = 'R';
if (one_file_system)
argstr[x++] = 'x';
if (sparse_files)
argstr[x++] = 'S';
if (do_compression)
argstr[x++] = 'z';
argstr[x] = 0;
if (x != 1) args[ac++] = argstr;
if (x != 1) args[ac++] = argstr;
if (block_size != BLOCK_SIZE) {
sprintf(bsize,"-B%d",block_size);
args[ac++] = bsize;
}
if (block_size != BLOCK_SIZE) {
sprintf(bsize,"-B%d",block_size);
args[ac++] = bsize;
}
if (io_timeout) {
sprintf(iotime,"--timeout=%d",io_timeout);
args[ac++] = iotime;
}
if (io_timeout) {
sprintf(iotime,"--timeout=%d",io_timeout);
args[ac++] = iotime;
}
if (strcmp(backup_suffix, BACKUP_SUFFIX)) {
args[ac++] = "--suffix";
args[ac++] = backup_suffix;
}
if (strcmp(backup_suffix, BACKUP_SUFFIX)) {
args[ac++] = "--suffix";
args[ac++] = backup_suffix;
}
if (delete_mode)
args[ac++] = "--delete";
if (delete_mode)
args[ac++] = "--delete";
if (force_delete)
args[ac++] = "--force";
if (keep_partial)
args[ac++] = "--partial";
if (numeric_ids)
args[ac++] = "--numeric-ids";
if (force_delete)
args[ac++] = "--force";
if (tmpdir) {
args[ac++] = "--temp-dir";
args[ac++] = tmpdir;
}
if (safe_symlinks)
args[ac++] = "--safe-links";
*argc = ac;
if (numeric_ids)
args[ac++] = "--numeric-ids";
if (tmpdir) {
args[ac++] = "--temp-dir";
args[ac++] = tmpdir;
}
if (compare_dest && am_sender) {
/* the server only needs this option if it is not the sender,
* and it may be an older version that doesn't know this
* option, so don't send it if client is the sender.
*/
args[ac++] = "--compare-dest";
args[ac++] = compare_dest;
}
*argc = ac;
}

View File

@@ -1,10 +1,10 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: 2.0.10
Version: 2.2.1
Release: 1
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.0.10.tar.gz
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.2.1.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync

View File

@@ -77,7 +77,6 @@
#define BOOL int
#define False 0
#define True 1
#define Realloc realloc
/* -------------------------------------------------------------------------- **
* Constants...

484
receiver.c Normal file
View File

@@ -0,0 +1,484 @@
/*
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.
*/
#include "rsync.h"
extern int verbose;
extern int recurse;
extern int delete_mode;
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 cvs_exclude;
extern int io_error;
extern char *tmpdir;
extern char *compare_dest;
extern int make_backups;
extern char *backup_suffix;
static struct delete_list {
dev_t dev;
INO_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)
{
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 = (struct delete_list *)Realloc(delete_list, sizeof(delete_list[0])*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 (do_unlink(f_name(f)) != 0) {
rprintf(FERROR,"unlink %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
rprintf(FINFO,"deleting %s\n",f_name(f));
}
} else {
if (do_rmdir(f_name(f)) != 0) {
if (errno != ENOTEMPTY && errno != EEXIST)
rprintf(FERROR,"rmdir %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
rprintf(FINFO,"deleting directory %s\n",f_name(f));
}
}
}
/* 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 */
static void delete_files(struct file_list *flist)
{
struct file_list *local_file_list;
int i, j;
char *name;
if (cvs_exclude)
add_cvs_excludes();
if (io_error) {
rprintf(FINFO,"IO error encountered - skipping file deletion\n");
return;
}
for (j=0;j<flist->count;j++) {
if (!S_ISDIR(flist->files[j]->mode) ||
!(flist->files[j]->flags & FLAG_DELETE)) continue;
if (remote_version < 19 &&
delete_already_done(flist, j)) continue;
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", name);
for (i=local_file_list->count-1;i>=0;i--) {
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]);
int k = strlen(f) - strlen(backup_suffix);
if (make_backups && ((k <= 0) ||
(strcmp(f+k,backup_suffix) != 0))) {
(void) make_backup(f);
} else {
delete_one(local_file_list->files[i]);
}
}
}
flist_free(local_file_list);
free(name);
}
}
static int get_tmpname(char *fnametmp, char *fname)
{
char *f;
/* open tmp file */
if (tmpdir) {
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;
}
slprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f);
return 1;
}
f = strrchr(fname,'/');
if (strlen(fname)+9 > MAXPATHLEN) {
rprintf(FERROR,"filename too long\n");
return 0;
}
if (f) {
*f = 0;
slprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX",
fname,f+1);
*f = '/';
} else {
slprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname);
}
return 1;
}
static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
OFF_T total_size)
{
int i,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;
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)) {
show_progress(offset, total_size);
if (i > 0) {
extern int cleanup_got_literal;
if (verbose > 3) {
rprintf(FINFO,"data recv %d at %d\n",
i,(int)offset);
}
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",fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
offset += i;
continue;
}
i = -(i+1);
offset2 = i*n;
len = n;
if (i == count-1 && remainder != 0)
len = remainder;
stats.matched_data += len;
if (verbose > 3)
rprintf(FINFO,"chunk[%d] of size %d at %d offset=%d\n",
i,len,(int)offset2,(int)offset);
map = map_ptr(buf,offset2,len);
see_token(map, len);
sum_update(map,len);
if (fd != -1 && write_file(fd,map,len) != len) {
rprintf(FERROR,"write failed on %s : %s\n",
fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
offset += len;
}
end_progress();
if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
rprintf(FERROR,"write failed on %s : %s\n",
fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
sum_end(file_sum1);
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;
}
int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
{
int fd1,fd2;
STRUCT_STAT st;
char *fname;
char fnametmp[MAXPATHLEN];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
struct map_struct *buf;
int i;
struct file_struct *file;
int phase=0;
int recv_ok;
extern struct stats stats;
struct stats initial_stats;
if (verbose > 2) {
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
if (recurse && delete_mode && !local_name && flist->count>0) {
delete_files(flist);
}
while (1) {
cleanup_disable();
i = read_int(f_in);
if (i == -1) {
if (phase==0 && remote_version >= 13) {
phase++;
csum_length = SUM_LENGTH;
if (verbose > 2)
rprintf(FINFO,"recv_files phase=%d\n",phase);
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",
i, flist->count);
exit_cleanup(RERR_PROTOCOL);
}
file = flist->files[i];
fname = f_name(file);
stats.num_transferred_files++;
stats.total_transferred_size += file->length;
if (local_name)
fname = local_name;
if (dry_run) {
if (!am_server) {
log_transfer(file, fname);
}
continue;
}
initial_stats = stats;
if (verbose > 2)
rprintf(FINFO,"recv_files(%s)\n",fname);
fnamecmp = fname;
/* open the file */
fd1 = open(fnamecmp,O_RDONLY);
if ((fd1 == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
slprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
compare_dest,fname);
fnamecmp = fnamecmpbuf;
fd1 = open(fnamecmp,O_RDONLY);
}
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
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_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 && st.st_size > 0) {
buf = map_file(fd1,st.st_size);
if (verbose > 2)
rprintf(FINFO,"recv mapped %s of size %d\n",fnamecmp,(int)st.st_size);
} else {
buf = NULL;
}
if (!get_tmpname(fnametmp,fname)) {
if (buf) unmap_file(buf);
if (fd1 != -1) close(fd1);
continue;
}
/* mktemp is deliberately used here instead of mkstemp.
because O_EXCL is used on the open, the race condition
is not a problem or a security hole, and we want to
control the access permissions on the created file. */
if (NULL == do_mktemp(fnametmp)) {
rprintf(FERROR,"mktemp %s failed\n",fnametmp);
receive_data(f_in,buf,-1,NULL,file->length);
if (buf) unmap_file(buf);
if (fd1 != -1) close(fd1);
continue;
}
/* 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 */
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
file->mode & ACCESSPERMS);
if (fd2 == -1 && relative_paths && errno == ENOENT &&
create_directory_path(fnametmp) == 0) {
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
file->mode & ACCESSPERMS);
}
if (fd2 == -1) {
rprintf(FERROR,"open %s : %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);
if (!am_server) {
log_transfer(file, fname);
}
/* recv file data */
recv_ok = receive_data(f_in,buf,fd2,fname,file->length);
log_recv(file, &initial_stats);
if (buf) unmap_file(buf);
if (fd1 != -1) {
close(fd1);
}
close(fd2);
if (verbose > 2)
rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
finish_transfer(fname, fnametmp, file);
cleanup_disable();
if (!recv_ok) {
if (csum_length == SUM_LENGTH) {
rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
fname);
} else {
if (verbose > 1)
rprintf(FINFO,"redoing %s(%d)\n",fname,i);
write_int(f_gen,i);
}
}
}
if (preserve_hard_links)
do_hard_links(flist);
/* 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(f_name(file),flist,i,-1);
}
if (verbose > 2)
rprintf(FINFO,"recv_files finished\n");
return 0;
}

1136
rsync.c
View File

File diff suppressed because it is too large Load Diff

170
rsync.h
View File

@@ -23,6 +23,8 @@
#define RSYNC_NAME "rsync"
#define RSYNCD_CONF "/etc/rsyncd.conf"
#define URL_PREFIX "rsync://"
#define BACKUP_SUFFIX "~"
/* a non-zero CHAR_OFFSET makes the rolling sum stronger, but is
@@ -41,7 +43,7 @@
#define SAME_TIME (1<<7)
/* update this if you make incompatible changes */
#define PROTOCOL_VERSION 18
#define PROTOCOL_VERSION 19
#define MIN_PROTOCOL_VERSION 11
#define MAX_PROTOCOL_VERSION 30
@@ -50,17 +52,18 @@
#define SPARSE_WRITE_SIZE (1024)
#define WRITE_SIZE (32*1024)
#define CHUNK_SIZE (32*1024)
#define MAX_MAP_SIZE (4*1024*1024)
#define IO_BUFFER_SIZE (4096)
#define MAX_MAP_SIZE (1*1024*1024)
#define IO_BUFFER_SIZE (4092)
#define MAX_READ_BUFFER (1024*1024)
#define MAX_ARGS 1000
#define BLOCKING_TIMEOUT 10
#define MPLEX_BASE 7
#define FERROR 1
#define FINFO 2
#define FLOG 3
#include "errcode.h"
#include "config.h"
@@ -71,6 +74,13 @@
#endif
#include <sys/types.h>
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
#include "lib/getopt.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -93,10 +103,6 @@
#include <string.h>
#endif
#ifdef HAVE_COMPAT_H
#include <compat.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
@@ -142,8 +148,9 @@
#endif
#include <errno.h>
#ifdef HAVE_MMAP
#if defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
#include <sys/mman.h>
#define USE_MMAP 1
#endif
#ifdef HAVE_UTIME_H
@@ -167,13 +174,7 @@
#include "lib/fnmatch.h"
#endif
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
#include "lib/getopt.h"
#endif
#ifdef HAVE_GLOB
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
@@ -188,14 +189,26 @@
#include <syslog.h>
#include <sys/file.h>
#ifndef S_IFLNK
#define S_IFLNK 0120000
#if HAVE_DIRENT_H
# include <dirent.h>
#else
# define dirent direct
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
#ifndef S_ISLNK
#define S_ISLNK(mode) (((mode) & S_IFLNK) == S_IFLNK)
#ifdef HAVE_COMPAT_H
#include <compat.h>
#endif
#define BOOL int
#ifndef uchar
@@ -215,6 +228,10 @@
#define int32 long
#elif (SIZEOF_SHORT == 4)
#define int32 short
#else
/* I hope this works */
#define int32 int
#define LARGE_INT32
#endif
#endif
@@ -243,6 +260,12 @@
#define NO_INT64
#endif
#if HAVE_SHORT_INO_T
#define INO_T uint32
#else
#define INO_T ino_t
#endif
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
@@ -268,7 +291,7 @@ struct file_struct {
time_t modtime;
OFF_T length;
mode_t mode;
ino_t inode;
INO_T inode;
dev_t dev;
dev_t rdev;
uid_t uid;
@@ -281,17 +304,17 @@ struct file_struct {
};
struct file_list {
int count;
int malloced;
struct file_struct **files;
int count;
int malloced;
struct file_struct **files;
};
struct sum_buf {
OFF_T offset; /* offset in file of this chunk */
int len; /* length of chunk of file */
int i; /* index of this chunk */
uint32 sum1; /* simple checksum */
char sum2[SUM_LENGTH]; /* checksum */
OFF_T offset; /* offset in file of this chunk */
int len; /* length of chunk of file */
int i; /* index of this chunk */
uint32 sum1; /* simple checksum */
char sum2[SUM_LENGTH]; /* checksum */
};
struct sum_struct {
@@ -308,6 +331,28 @@ struct map_struct {
OFF_T size, p_offset;
};
struct exclude_struct {
char *orig;
char *pattern;
int regular_exp;
int include;
int directory;
int local;
};
struct stats {
int64 total_size;
int64 total_transferred_size;
int64 total_written;
int64 total_read;
int64 literal_data;
int64 matched_data;
int flist_size;
int num_files;
int num_transferred_files;
};
/* we need this function because of the silly way in which duplicate
entries are handled in the file lists - we can't change this
without breaking existing versions */
@@ -317,25 +362,10 @@ static inline int flist_up(struct file_list *flist, int i)
return i;
}
#if HAVE_DIRENT_H
# include <dirent.h>
#else
# define dirent direct
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
#include "byteorder.h"
#include "version.h"
#include "proto.h"
#include "md4.h"
#include "lib/mdfour.h"
#if !HAVE_STRERROR
extern char *sys_errlist[];
@@ -351,14 +381,6 @@ extern char *sys_errlist[];
extern int errno;
#endif
#ifndef HAVE_BCOPY
#define bcopy(src,dest,n) memcpy(dest,src,n)
#endif
#ifndef HAVE_BZERO
#define bzero(buf,n) memset(buf,0,n)
#endif
#define SUPPORT_LINKS HAVE_READLINK
#define SUPPORT_HARD_LINKS HAVE_LINK
@@ -388,6 +410,18 @@ extern int errno;
#define S_IWUSR 0200
#endif
#ifndef _S_IFMT
#define _S_IFMT 0170000
#endif
#ifndef _S_IFLNK
#define _S_IFLNK 0120000
#endif
#ifndef S_ISLNK
#define S_ISLNK(mode) (((mode) & (_S_IFMT)) == (_S_IFLNK))
#endif
#ifndef S_ISBLK
#define S_ISBLK(mode) (((mode) & (_S_IFMT)) == (_S_IFBLK))
#endif
@@ -423,3 +457,31 @@ 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
/* handler for null strings in printf format */
#define NS(s) ((s)?(s):"<NULL>")
/* use magic gcc attributes to catch format errors */
void rprintf(int , const char *, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
;
#ifdef REPLACE_INET_NTOA
#define inet_ntoa rep_inet_ntoa
#endif
#ifndef HAVE_STRLCPY
size_t strlcpy(char *d, const char *s, size_t bufsize);
#endif
#ifndef HAVE_STRLCAT
size_t strlcat(char *d, const char *s, size_t bufsize);
#endif
#define exit_cleanup(code) _exit_cleanup(code, __FILE__, __LINE__)

374
rsync.yo
View File

@@ -1,5 +1,5 @@
mailto(rsync-bugs@samba.anu.edu.au)
manpage(rsync)(1)(13 May 1998)()()
mailto(rsync-bugs@samba.org)
manpage(rsync)(1)(24 Nov 1998)()()
manpagename(rsync)(faster, flexible replacement for rcp)
manpagesynopsis()
@@ -9,9 +9,11 @@ rsync [options] path [user@]host:path
rsync [options] path path
rsync [options] [user@]host::path path
rsync [options] [user@]host::module[/path] path
rsync [options] path [user@]host::path
rsync [options] path [user@]host::module[/path]
rsync [options] rsync://[user@]host[:port]/module/path path
manpagedescription()
@@ -40,7 +42,7 @@ itemize(
manpagesection(GENERAL)
There are five different ways of using rsync. They are:
There are six different ways of using rsync. They are:
itemize(
it() for copying local files. This is invoked when neither
@@ -57,15 +59,19 @@ itemize(
it() for copying from a remote rsync server to the local
machine. This is invoked when the source path contains a ::
separator.
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.
it() for listing files on a remote machine. This is done the
same way as rsync transfers except that you leave off the
local destination.
)
Note that in all cases at least one of the source and destination
paths must be local.
Note that in all cases (other than listing) at least one of the source
and destination paths must be local.
manpagesection(SETUP)
@@ -75,12 +81,15 @@ Once installed you can use rsync to any machine that you can use rsh
to. rsync uses rsh for its communications, unless both the source and
destination are local.
You can also specify a alternative to rsh, by either using the -e
You can also specify an alternative to rsh, by either using the -e
command line option, or by setting the RSYNC_RSH environment variable.
One common substitute is to use ssh, which offers a high degree of
security.
Note that rsync must be installed on both the source and destination
machines.
manpagesection(USAGE)
You use rsync in the same way you use rcp. You must specify a source
@@ -98,18 +107,18 @@ differences. See the tech report for details.
quote(rsync -avz foo:src/bar /data/tmp)
recursively transfer all files from the directory src/bar on the
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
in the transfer. Additionally compression will be used to reduce the
in the transfer. Additionally, compression will be used to reduce the
size of data portions of the transfer.
quote(rsync -avz foo:src/bar/ /data/tmp)
With a trailing slash on the source this behavior changes to transfer
a trailing slash on the source changes this behavior to transfer
all files from the directory src/bar on the machine foo into the
/data/tmp/. With a trailing / on a source name it means "copy the
/data/tmp/. A trailing / on a source name means "copy the
contents of this directory". Without a trailing slash it means "copy
the directory". This difference becomes particularly important when
using the --delete option.
@@ -118,6 +127,11 @@ You can also use rsync in local-only mode, where both the source and
destination don't have a ':' in the name. In this case it behaves like
an improved copy command.
quote(rsync somehost.mydomain.com::)
this would list all the anonymous rsync modules available on the host
somehost.mydomain.com. (See the following section for more details.)
manpagesection(CONNECTING TO AN RSYNC SERVER)
@@ -125,7 +139,7 @@ It is also possible to use rsync without using rsh or ssh as the
transport. In this case you will connect to a remote rsync server
running on TCP port 873.
Using rsync in this was is the same as using it with rsh or ssh except
Using rsync in this way is the same as using it with rsh or ssh except
that:
itemize(
@@ -133,10 +147,13 @@ itemize(
separate the hostname from the path.
it() the remote server may print a message of the day when you
connect
connect.
it() if you specify no path name on the remote server then the
list of accessible paths on the server will be shown.
it() if you specify no local destination then a listing of the
specified files on the remote server is provided.
)
Some paths on the remote server may require authentication. If so then
@@ -154,8 +171,8 @@ manpagesection(EXAMPLES)
Here are some examples of how I use rsync.
To backup my wife's home directory, which consists of large MS word
files and mail folders I use a cron job that runs
To backup my wife's home directory, which consists of large MS Word
files and mail folders, I use a cron job that runs
quote(rsync -Cavz . arvidsjaur:backup)
@@ -184,11 +201,73 @@ quote(rsync -az -e ssh --delete ~ftp/pub/samba/ nimbus:"~ftp/pub/tridge/samba")
this is launched from cron every few hours.
manpagesection(OPTIONS SUMMARY)
Here is a short summary of the options available in rsync. Please refer
to the detailed description below for a complete description.
verb(
Usage: rsync [OPTION]... SRC [USER@]HOST:DEST
or rsync [OPTION]... [USER@]HOST:SRC DEST
or rsync [OPTION]... SRC DEST
or rsync [OPTION]... [USER@]HOST::SRC [DEST]
or rsync [OPTION]... SRC [USER@]HOST::DEST
or rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]
Options
-v, --verbose increase verbosity
-c, --checksum always checksum
-a, --archive archive mode
-r, --recursive recurse into directories
-R, --relative use relative path names
-b, --backup make backups (default ~ extension)
-u, --update update only (don't overwrite newer files)
-l, --links preserve soft links
-L, --copy-links treat soft links like regular files
--safe-links ignore links outside the destination tree
-H, --hard-links preserve hard links
-p, --perms preserve permissions
-o, --owner preserve owner (root only)
-g, --group preserve group
-D, --devices preserve devices (root only)
-t, --times preserve times
-S, --sparse handle sparse files efficiently
-n, --dry-run show what would have been transferred
-W, --whole-file copy whole files, no incremental checks
-x, --one-file-system don't cross filesystem boundaries
-B, --block-size=SIZE checksum blocking size
-e, --rsh=COMMAND specify rsh replacement
--rsync-path=PATH specify path to rsync on the remote machine
-C, --cvs-exclude auto ignore files in the same way CVS does
--delete delete files that don't exist on the sending side
--partial keep partially transferred files
--force force deletion of directories even if not empty
--numeric-ids don't map uid/gid values by user/group name
--timeout=TIME set IO timeout in seconds
-I, --ignore-times don't exclude files that match length and time
-T --temp-dir=DIR create temporary files in directory DIR
--compare-dest=DIR also compare destination files relative to DIR
-z, --compress compress file data
--exclude=PATTERN exclude files matching PATTERN
--exclude-from=FILE exclude files listed in FILE
--include=PATTERN don't exclude files matching PATTERN
--include-from=FILE don't exclude files listed in FILE
--suffix=SUFFIX override backup suffix
--version print version number
--daemon run as a rsync daemon
--config=FILE specify alternate rsyncd.conf file
--port=PORT specify alternate rsyncd port number
--stats give some file transfer stats
--progress show progress during transfer
--log-format=FORMAT log file transfers using specified format
-h, --help show this help screen
)
manpageoptions()
rsync uses the GNU long options package. Many of the command line
options have two variants, one short and one long. These are shown
below separated by commas. Some options only have a long variant.
below, separated by commas. Some options only have a long variant.
startdit()
dit(bf(-h, --help)) Print a short help page describing the options
@@ -197,12 +276,12 @@ available in rsync
dit(bf(--version)) print the rsync version number and exit
dit(bf(-v, --verbose)) This option increases the amount of information you
are given during the transfer. By default rsync works silently. A
are given during the transfer. By default, rsync works silently. A
single -v will give you information about what files are being
transferred and a brief summary at the end. Two -v flags will give you
information on what files are being skipped and slightly more
information at the end. More than two -v flags should only be used if
you are debugging rsync
you are debugging rsync.
dit(bf(-I, --ignore-times)) Normally rsync will skip any files that are
already the same length and have the same time-stamp. This option turns
@@ -214,16 +293,19 @@ 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 skipped. This option can be quite slow.
dit(bf(-a, --archive)) This is equivalent to -rlptDog. It is a quick way
of saying I want recursion and want to preserve everything.
dit(bf(-a, --archive)) This is equivalent to -rlptDg. It is a quick way
of saying you want recursion and want to preserve everything.
dit(bf(-r, --recursive)) This tells rsync to copy directories recursively
Note: if the user launching rsync is root then the -o option (preserve
uid) is also implied.
dit(bf(-r, --recursive)) This tells rsync to copy directories recursively.
dit(bf(-R, --relative)) Use relative paths. This means that the full path
names specified on the command line are sent to the server rather than
just the last parts of the filenames. This is particularly useful when
you want to sent several different directories at the same time. For
example if you used the command
you want to send several different directories at the same time. For
example, if you used the command
verb(rsync foo/bar/foo.c remote:/tmp/)
@@ -245,11 +327,16 @@ file.
dit(bf(-l, --links)) This tells rsync to recreate symbolic links on the
remote system to be the same as the local system. Without this
option all symbolic links are skipped.
option, all symbolic links are skipped.
dit(bf(-L, --copy-links)) This tells rsync to treat symbolic links just
like ordinary files.
dit(bf(--safe-links)) This tells rsync to ignore any symbolic links
which point outside the destination tree. All absolute symlinks are
also ignored. Using this option in conjunction with --relative may
give unexpected results.
dit(bf(-H, --hard-links)) This tells rsync to recreate hard links on
the remote system to be the same as the local system. Without this
option hard links are treated like regular files.
@@ -263,22 +350,37 @@ dit(bf(-W, --whole-file)) With this option the incremental rsync algorithm
is not used and the whole file is sent as-is instead. This may be
useful when using rsync with a local machine.
dit(bf(--partial)) By default, rsync will delete any partially
transferred file if the transfer is interrupted. In some circumstances
it is more desirable to keep partially transferred files. Using the
--partial option tells rsync to keep the partial file which should
make a subsequent transfer of the rest of the file much faster.
dit(bf(-p, --perms)) This option causes rsync to update the remote
permissions to be the same as the local permissions.
dit(bf(-o, --owner)) This option causes rsync to update the remote owner
of the file to be the same as the local owner. This is only available
to the super-user.
to the super-user. Note that if the source system is a daemon using chroot,
the --numeric-ids option is implied because the source system cannot get
access to the usernames.
dit(bf(-g, --group)) This option causes rsync to update the remote group
of the file to be the same as the local group.
of the file to be the same as the local group. Note that if the source
system is a daemon using chroot, the --numeric-ids option is implied because
the source system cannot get access to the group names.
dit(bf(-D, --devices)) This option causes rsync to transfer character and
block device information to the remote system to recreate these
devices. This option is only available to the super-user.
dit(bf(-t, --times)) This tells rsync to transfer modification times along
with the files and update them on the remote system
with the files and update them on the remote system. Note that if this
option is not used, the optimization that excludes files that have not been
modified cannot be effective; in other words, a missing -t or -a will
cause the next transfer to behave as if it used -I, and all files will have
their checksums compared and show up in log messages even if they haven't
changed.
dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers,
instead it will just report the actions it would have taken.
@@ -286,6 +388,10 @@ instead it will just report the actions it would have taken.
dit(bf(-S, --sparse)) Try to handle sparse files efficiently so they take
up less space on the destination.
NOTE: Don't use this option when the destination is a Solaris "tmpfs"
filesystem. It doesn't seem to handle seeks over null regions
correctly and ends up corrupting the files.
dit(bf(-x, --one-file-system)) This tells rsync not to cross filesystem
boundaries when recursing. This is useful for transferring the
contents of only one filesystem.
@@ -307,9 +413,11 @@ Still, it is probably easy to get burnt with this option. The moral
of the story is to use the -n option until you get used to the
behavior of --delete.
NOTE: It also may delete files on the destination if the sending side
can't open them or stat them. This is a bug that hopefully will be
fixed in a future release.
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
destination.
dit(bf(--force)) This options tells rsync to delete directories even if
they are not empty. This applies to both the --delete option and to
@@ -325,32 +433,39 @@ 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. By default rsync will use rsh, but you may
remote copies of rsync. By default, rsync will use rsh, but you may
like to instead use ssh because of its high security.
You can also choose the remote shell program using the RSYNC_RSH
environment variable.
dit(bf(--rsync-path PATH)) Use this to specify the path to the copy of
rsync on the remote machine. Useful when its not in your path.
rsync on the remote machine. Useful when it's not in your path.
dit(bf(--exclude FILE)) This option allows you to selectively exclude
dit(bf(--exclude pattern)) This option allows you to selectively exclude
certain files from the list of files to be transferred. This is most
useful in combination with a recursive transfer.
The option FILE can either be a file name or a shell wildcard
expression. If it is a directory name then rsync will not recurse into
directories of that name.
You may use as many --exclude options on the command line as you like
to build up the list of files to exclude.
If the filename is a single ! then the exclude list is reset.
See the section on exclude patterns 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 filenames listed in the file FILE to
the exclude list.
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 section of exclude patterns for information on the syntax of
this option.
dit(bf(--include-from FILE)) This specifies a list of include patterns
from a file.
dit(bf(-C, --cvs-exclude)) This is a useful shorthand for excluding a
broad range of files that you often don't want to transfer between
systems. It uses the same algorithm that CVS uses to determine if
@@ -375,7 +490,7 @@ dit(bf(--csum-length LENGTH)) By default the primary checksum used in
rsync is a very strong 16 byte MD4 checksum. In most cases you will
find that a truncated version of this checksum is quite efficient, and
this will decrease the size of the checksum data sent over the link,
making things faster.
making things faster.
You can choose the number of bytes in the truncated checksum using the
--csum-length option. Any value less than or equal to 16 is valid.
@@ -385,11 +500,28 @@ with an incorrect target file. The risk with a value of 16 is
microscopic and can be safely ignored (the universe will probably end
before it fails) but with smaller values the risk is higher.
dit(bf(-T, --temp-dir DIR)) This options instructs rsync to use DIR as a
scratch directory when creating a temporary copies of the files
Current versions of rsync actually use an adaptive algorithm for the
checksum length by default, using a 16 byte file checksum to determine
if a 2nd pass is required with a longer block checksum. Only use this
option if you have read the source code and know what you are doing.
dit(bf(-T, --temp-dir DIR)) This option instructs rsync to use DIR as a
scratch directory when creating temporary copies of the files
transferred on the receiving side. The default behavior is to create
the temporary files in the receiving directory.
dit(bf(--compare-dest DIR)) This option instructs rsync to use DIR as an
additional directory to compare destination files against when doing
transfers. This is useful for doing transfers to a new destination while
leaving existing files intact, and then doing a flash-cutover when all
files have been successfully transferred (for example by moving directories
around and removing the old directory, although this requires also doing
the transfer with -I to avoid skipping files that haven't changed). 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.
dit(bf(-z, --compress)) With this option, rsync compresses any data from
the source file(s) which it sends to the destination machine. This
option is useful on slow links. The compression method used is the
@@ -406,15 +538,16 @@ at both ends.
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 and never mapped via user/group names even if the --numeric-ids
0 are never mapped via user/group names even if the --numeric-ids
option is not specified.
If a user or group name does not exist on the destination system then
the numeric id from the source system is used instead.
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)) 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.
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.
dit(bf(--daemon)) This tells rsync that it is to run as a rsync
daemon. If standard input is a socket then rsync will assume that it
@@ -429,7 +562,132 @@ the default /etc/rsyncd.conf. This is only relevant when --daemon is
specified.
dit(bf(--port PORT)) This specifies an alternate TCP port number to use
rather than the default port 873.
rather than the default port 873.
dit(bf(--log-format=FORMAT)) This allows you to specify exactly what the
rsync client logs to stdout on a per-file basis. The log format is
specified using the same format conventions as the log format option in
rsyncd.conf.
dit(bf(--stats)) This tells rsync to print a verbose set of statistics
on the file transfer, allowing you to tell how effective the rsync
algorithm is for your data. This option only works in conjunction with
the -v (verbose) option.
dit(bf(--progress)) This option tells rsync to print information
showing the progress of the transfer. This gives a bored user
something to watch.
enddit()
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 a ordered list of include/exclude options as specified on
the command line. When a filename is encountered, rsync checks the
name against each exclude/include pattern in turn. The first matching
pattern is acted on. If it is an exclude pattern than that file is
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 patterns can take several forms. The rules are:
itemize(
it() if the pattern starts with a / then it is matched against the
start of the filename, otherwise it is matched against the end of
the filename. Thus /foo would match a file called foo
at the base of the tree whereas foo would match any file
called foo anywhere in the tree.
it() if the pattern ends with a / then it will only match a
directory, not a file, link or device.
it() if the pattern contains a wildcard character from the set
*?[ then regular expression matching is applied using the
normal shell filename matching rules. Otherwise a simple string
match is used.
it() if the pattern contains a / (not counting a trailing /) then it
is matched against the full filename, including any leading
directory. If the pattern doesn't contain a / then it is matched
only against the final component of the filename.
it() if the pattern starts with "+ " (a plus followed by a space)
then it is always considered a include pattern, even if specified as
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 a exclude pattern, even if specified as
part of an include option. The "- " part is discarded before matching.
it() if the pattern is a single exclamation mark ! then the current
exclude list is reset, removing all previous exclude patterns.
)
The +/- rules are most useful in exclude lists, allowing you to have a
single exclude list that contains both include and exclude options.
Here are some examples:
itemize(
it() --exclude "*.o" would exclude all filenames matching *.o
it() --exclude "/foo" would exclude a file in the base directory called foo
it() --exclude "foo/" would exclude any directory called foo
it() --include "*/" --include "*.c" --exclude "*" would include all
directories and C source files
it() --include "foo/" --include "foo/bar.c" --exclude "*" would include
only foo/bar.c (the foo/ directory must be explicitly included or
it would be excluded by the "*")
)
manpagesection(DIAGNOSTICS)
rsync occasionally produces error messages that may seem a little
cryptic. The one that seems to cause the most confusion is "protocol
version mismatch - is your shell clean?".
This message is usually caused by your startup scripts or remote shell
facility producing unwanted garbage on the stream that rsync is using
for its transport. The way to diagnose this problem is to run your
remote shell like this:
verb(
rsh remotehost /bin/true > out.dat
)
then look at out.dat. If everything is working correctly then out.dat
should be a zero length file. You you are getting the above error from
rsync then you will probably find that out.dat contains some text or
data. Look at the contents and try to work out what is producing
it. The most common cause is incorrectly configured shell startup
scripts (such as .cshrc or .profile) that contain output statements
for non-interactive logins.
manpagesection(ENVIRONMENT VARIABLES)
startdit()
dit(bf(CVSIGNORE)) The CVSIGNORE environment variable supplements any
ignore patterns in .cvsignore files. See the --cvs-exclude option for
more details.
dit(bf(RSYNC_RSH)) The RSYNC_RSH environment variable allows you to
override the default shell used as the transport for rsync. This can
be used instead of the -e option.
dit(bf(RSYNC_PASSWORD)) Setting RSYNC_PASSWORD to the required
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 a rsync server.
dit(bf(HOME)) The HOME environment variable is used to find the user's
default .cvsignore file.
enddit()
@@ -453,7 +711,7 @@ values
see also the comments on the --delete option
Please report bugs! The rsync bug tracking system is online at
url(http://samba.anu.edu.au/rsync/)(http://samba.anu.edu.au/rsync/)
url(http://rsync.samba.org/rsync/)(http://rsync.samba.org/rsync/)
manpagesection(VERSION)
This man page is current for version 2.0 of rsync
@@ -463,16 +721,16 @@ manpagesection(CREDITS)
rsync is distributed under the GNU public license. See the file
COPYING for details.
The primary ftp site for rsync is
url(ftp://samba.anu.edu.au/pub/rsync)(ftp://samba.anu.edu.au/pub/rsync).
A WEB site is available at
url(http://samba.anu.edu.au/rsync/)(http://samba.anu.edu.au/rsync/)
url(http://rsync.samba.org/)(http://rsync.samba.org/)
The primary ftp site for rsync is
url(ftp://rsync.samba.org/pub/rsync)(ftp://rsync.samba.org/pub/rsync).
We would be delighted to hear from you if you like this program.
This program uses the zlib compression library written by Jean-loup
Gailly and Mark Adler.
This program uses the excellent zlib compression library written by
Jean-loup Gailly and Mark Adler.
manpagesection(THANKS)
@@ -484,6 +742,6 @@ probably missed some people, my apologies if I have.
manpageauthor()
rsync was written by Andrew Tridgell and Paul Mackerras. They may be
contacted via email at tridge@samba.anu.edu.au and
contacted via email at tridge@samba.org and
Paul.Mackerras@cs.anu.edu.au

View File

@@ -1,5 +1,5 @@
mailto(rsync-bugs@samba.anu.edu.au)
manpage(rsyncd.conf)(5)(13 May 1998)()()
mailto(rsync-bugs@samba.org)
manpage(rsyncd.conf)(5)(25 Nov 1998)()()
manpagename(rsyncd.conf)(configuration file for rsync server)
manpagesynopsis()
@@ -46,7 +46,7 @@ manpagesection(LAUNCHING THE RSYNC DAEMON)
The rsync daemon is launched by specifying the --daemon option to
rsync. The daemon must run with root privileges.
You can launch it either via inetd or as a standalone daemon. If run
You can launch it either via inetd or as a stand-alone daemon. If run
as a daemon then just run the command "rsync --daemon" from a suitable
startup script.
@@ -91,6 +91,14 @@ support the "max connections" option. The rsync server uses record
locking on this file to ensure that the max connections limit is not
exceeded. The default is tt(/var/run/rsyncd.lock).
dit(bf(log file)) The "log file" option tells the rsync daemon to log
messages to that file rather than using syslog. This is particularly
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.
dit(bf(syslog facility)) The "syslog facility" option allows you to
specify the syslog facility name to use when logging messages from the
rsync server. You may use any standard syslog facility name which is
@@ -123,9 +131,15 @@ that is displayed next to the module name when clients obtain a list
of available modules. The default is no comment.
dit(bf(path)) The "path" option specifies the directory in the servers
filesystem to make available in this module. The rsync server will
chroot to this path before starting the file transfer with the
client. You must specify this option for each module in tt(/etc/rsyncd.conf).
filesystem to make available in this module. You must specify this option
for each module in tt(/etc/rsyncd.conf).
dit(bf(use chroot)) If "use chroot" is true, the rsync server will chroot
to the "path" before starting the file transfer with the client. This has
the advantage of extra protection against possible implementation security
holes, but it has the disadvantages of requiring super-user privileges and
of not being able to follow symbolic links outside of the new root path.
The default is to use chroot.
dit(bf(read only)) The "read only" option determines whether clients
will be able to upload files or not. If "read only" is true then any
@@ -162,6 +176,20 @@ equivalent to the client specifying the --exclude-from option with a
equivalent file. See also the note about security for the exclude
option above.
dit(bf(include)) The "include" option allows you to specify a space
separated list of patterns which rsync should not exclude. This is
equivalent to the client specifying these patterns with the --include
option. This is useful as it allows you to build up quite complex
exclude/include rules.
See the section of exclude patterns for information on the syntax of
this option.
dit(bf(include from)) The "include from" option specifies a filename
on the server that contains include patterns, one per line. This is
equivalent to the client specifying the --include-from option with a
equivalent file.
dit(bf(auth users)) The "auth users" option specifies a comma
and space separated list of usernames that will be allowed to connect
to this module. The usernames do not need to exist on the local
@@ -225,13 +253,74 @@ connect.
The default is no "hosts allow" option, which means all hosts can connect.
dit(bf(hosts allow)) The "hosts deny" option allows you to specify a
dit(bf(hosts deny)) The "hosts deny" option allows you to specify a
list of patterns that are matched against a connecting clients
hostname and IP address. If the pattern matches then the connection is
rejected. See the "hosts allow" option for more information.
The default is no "hosts deny" option, which means all hosts can connect.
dit(bf(transfer logging)) The "transfer logging" option enables per-file
logging of downloads and uploads in a format somewhat similar to that
used by ftp daemons. If you want to customize the log formats look at
the log format option.
dit(bf(log format)) The "log format" option allows you to specify the
format used for logging file transfers when transfer logging is
enabled. The format is a text string containing embedded single
character escape sequences prefixed with a percent (%) character.
The prefixes that are understood are:
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() %o for the operation, which is either "send" or "recv"
it() %f for the filename
it() %P for the module path
it() %m for the module name
it() %t for the current time
it() %u for the authenticated username (or the null string)
it() %b for the number of bytes actually transferred
it() %c when sending files this gives the number of checksum bytes
received for this file
)
The default log format is "%o %h [%a] %m (%u) %f %l"
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 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
a 10 minute timeout).
dit(bf(refuse options)) The "refuse options" option allows you to
specify a space separated list of rsync command line options that will
be refused by your rsync server. The full names of the options must be
used (i.e., you must use "checksum" not "c" to disable checksumming).
When an option is refused, the server prints an error message and exits.
To prevent all compression, you can use "dont compress = *" (see below)
instead of "refuse options = compress" to avoid returning an error to a
client that requests compression.
dit(bf(dont compress)) The "dont compress" option allows you to select
filenames based on wildcard patterns that should not be compressed
during transfer. Compression is expensive in terms of CPU usage so it
is usually good to not try to compress files that won't compress well,
such as already compressed files.
The "dont compress" option takes a space separated list of
case-insensitive wildcard patterns. Any source filename matching one
of the patterns will not be compressed during transfer.
The default setting is verb(*.gz *.tgz *.zip *.z *.rpm *.deb)
enddit()
manpagesection(AUTHENTICATION STRENGTH)
@@ -239,7 +328,7 @@ manpagesection(AUTHENTICATION STRENGTH)
The authentication protocol used in rsync is a 128 bit MD4 based
challenge response system. Although I believe that no one has ever
demonstrated a brute-force break of this sort of system you should
realise that this is not a "military strength" authentication system.
realize that this is not a "military strength" authentication system.
It should be good enough for most purposes but if you want really top
quality security then I recommend that you run rsync over ssh.
@@ -267,8 +356,10 @@ A more sophisticated example would be:
uid = nobody nl()
gid = nobody nl()
use chroot = no nl()
max connections = 4 nl()
syslog facility = local5 nl()
pid file = /etc/rsyncd.pid
verb([ftp]
path = /var/ftp/pub
@@ -315,7 +406,7 @@ client. this means a client may be mystified as to why a transfer
failed. The error will have been logged by syslog on the server.
Please report bugs! The rsync bug tracking system is online at
url(http://samba.anu.edu.au/rsync/)(http://samba.anu.edu.au/rsync/)
url(http://rsync.samba.org/)(http://rsync.samba.org/)
manpagesection(VERSION)
This man page is current for version 2.0 of rsync
@@ -326,10 +417,10 @@ rsync is distributed under the GNU public license. See the file
COPYING for details.
The primary ftp site for rsync is
url(ftp://samba.anu.edu.au/pub/rsync)(ftp://samba.anu.edu.au/pub/rsync).
url(ftp://rsync.samba.org/pub/rsync)(ftp://rsync.samba.org/pub/rsync).
A WEB site is available at
url(http://samba.anu.edu.au/rsync/)(http://samba.anu.edu.au/rsync/)
url(http://rsync.samba.org/)(http://rsync.samba.org/)
We would be delighted to hear from you if you like this program.
@@ -345,6 +436,6 @@ documentation!
manpageauthor()
rsync was written by Andrew Tridgell and Paul Mackerras. They may be
contacted via email at tridge@samba.anu.edu.au and
contacted via email at tridge@samba.org and
Paul.Mackerras@cs.anu.edu.au

230
sender.c Normal file
View File

@@ -0,0 +1,230 @@
/*
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.
*/
#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;
/*
receive the checksums for a buffer
*/
static struct sum_struct *receive_sums(int f)
{
struct sum_struct *s;
int i;
OFF_T offset = 0;
s = (struct sum_struct *)malloc(sizeof(*s));
if (!s) out_of_memory("receive_sums");
s->count = read_int(f);
s->n = read_int(f);
s->remainder = read_int(f);
s->sums = NULL;
if (verbose > 3)
rprintf(FINFO,"count=%d n=%d rem=%d\n",
s->count,s->n,s->remainder);
if (s->count == 0)
return(s);
s->sums = (struct sum_buf *)malloc(sizeof(s->sums[0])*s->count);
if (!s->sums) out_of_memory("receive_sums");
for (i=0;i<s->count;i++) {
s->sums[i].sum1 = read_int(f);
read_buf(f,s->sums[i].sum2,csum_length);
s->sums[i].offset = offset;
s->sums[i].i = i;
if (i == s->count-1 && s->remainder != 0) {
s->sums[i].len = s->remainder;
} else {
s->sums[i].len = s->n;
}
offset += s->sums[i].len;
if (verbose > 3)
rprintf(FINFO,"chunk[%d] len=%d offset=%d sum1=%08x\n",
i,s->sums[i].len,(int)s->sums[i].offset,s->sums[i].sum1);
}
s->flength = offset;
return s;
}
void send_files(struct file_list *flist,int f_out,int f_in)
{
int fd;
struct sum_struct *s;
struct map_struct *buf;
STRUCT_STAT st;
char fname[MAXPATHLEN];
int i;
struct file_struct *file;
int phase = 0;
extern struct stats stats;
struct stats initial_stats;
if (verbose > 2)
rprintf(FINFO,"send_files starting\n");
setup_readbuffer(f_in);
while (1) {
int offset=0;
i = read_int(f_in);
if (i == -1) {
if (phase==0 && remote_version >= 13) {
phase++;
csum_length = SUM_LENGTH;
write_int(f_out,-1);
if (verbose > 2)
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",
i, flist->count);
exit_cleanup(RERR_PROTOCOL);
}
file = flist->files[i];
stats.num_transferred_files++;
stats.total_transferred_size += file->length;
fname[0] = 0;
if (file->basedir) {
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;
}
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;
}
initial_stats = stats;
s = receive_sums(f_in);
if (!s) {
io_error = 1;
rprintf(FERROR,"receive_sums failed\n");
return;
}
fd = open(fname,O_RDONLY);
if (fd == -1) {
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 = 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);
} else {
buf = NULL;
}
if (verbose > 2)
rprintf(FINFO,"send_files mapped %s of size %d\n",
fname,(int)st.st_size);
write_int(f_out,i);
write_int(f_out,s->count);
write_int(f_out,s->n);
write_int(f_out,s->remainder);
if (verbose > 2)
rprintf(FINFO,"calling match_sums %s\n",fname);
if (!am_server) {
log_transfer(file, fname+offset);
}
set_compression(fname);
match_sums(f_out,s,buf,st.st_size);
log_send(file, &initial_stats);
if (buf) unmap_file(buf);
close(fd);
free_sums(s);
if (verbose > 2)
rprintf(FINFO,"sender finished %s\n",fname);
}
if (verbose > 2)
rprintf(FINFO,"send files finished\n");
match_report();
write_int(f_out,-1);
}

View File

@@ -54,6 +54,8 @@ int open_socket_out(char *host, int port)
return -1;
}
set_nonblocking(res);
return res;
}
@@ -81,7 +83,7 @@ static int open_socket_in(int type, int port)
return -1;
}
bzero((char *)&sock,sizeof(sock));
memset((char *)&sock,0,sizeof(sock));
memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
sock.sin_port = htons(port);
sock.sin_family = hp->h_addrtype;
@@ -110,9 +112,9 @@ determine if a file descriptor is in fact a socket
****************************************************************************/
int is_a_socket(int fd)
{
int v,l;
l = sizeof(int);
return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
int v,l;
l = sizeof(int);
return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
}
@@ -120,17 +122,15 @@ void start_accept_loop(int port, int (*fn)(int ))
{
int s;
signal(SIGCHLD, SIG_IGN);
/* open an incoming socket */
s = open_socket_in(SOCK_STREAM, port);
if (s == -1)
exit_cleanup(1);
exit_cleanup(RERR_SOCKETIO);
/* ready to listen */
if (listen(s, 5) == -1) {
close(s);
exit_cleanup(1);
exit_cleanup(RERR_SOCKETIO);
}
@@ -155,9 +155,20 @@ void start_accept_loop(int port, int (*fn)(int ))
if (fd == -1) continue;
signal(SIGCHLD, SIG_IGN);
/* we shouldn't have any children left hanging around
but I have had reports that on Digital Unix zombies
are produced, so this ensures that they are reaped */
#ifdef WNOHANG
waitpid(-1, NULL, WNOHANG);
#endif
if (fork()==0) {
close(s);
set_nonblocking(fd);
_exit(fn(fd));
}
@@ -274,27 +285,30 @@ become a daemon, discarding the controlling terminal
****************************************************************************/
void become_daemon(void)
{
if (fork())
int i;
if (fork()) {
_exit(0);
}
/* detach from the terminal */
#ifdef HAVE_SETSID
setsid();
#else
#ifdef TIOCNOTTY
{
int i = open("/dev/tty", O_RDWR);
if (i >= 0)
{
ioctl(i, (int) TIOCNOTTY, (char *)0);
close(i);
}
i = open("/dev/tty", O_RDWR);
if (i >= 0) {
ioctl(i, (int) TIOCNOTTY, (char *)0);
close(i);
}
#endif /* TIOCNOTTY */
#endif
close(0);
close(1);
close(2);
/* make sure that stdin, stdout an stderr don't stuff things
up (library functions, for example) */
for (i=0;i<3;i++) {
close(i);
open("/dev/null", O_RDWR);
}
}
/*******************************************************************
@@ -306,13 +320,17 @@ char *client_addr(int fd)
struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
int length = sizeof(sa);
static char addr_buf[100];
static int initialised;
if (initialised) return addr_buf;
initialised = 1;
if (getpeername(fd, &sa, &length)) {
exit_cleanup(1);
exit_cleanup(RERR_SOCKETIO);
}
strlcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr), sizeof(addr_buf)-1);
strlcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr), sizeof(addr_buf));
return addr_buf;
}
@@ -327,18 +345,43 @@ char *client_name(int fd)
int length = sizeof(sa);
static char name_buf[100];
struct hostent *hp;
char **p;
char *def = "UNKNOWN";
static int initialised;
strcpy(name_buf,"UNKNOWN");
if (initialised) return name_buf;
initialised = 1;
strcpy(name_buf,def);
if (getpeername(fd, &sa, &length)) {
exit_cleanup(1);
exit_cleanup(RERR_SOCKETIO);
}
/* Look up the remote host name. */
if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
sizeof(sockin->sin_addr),
AF_INET))) {
strlcpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1);
strlcpy(name_buf,(char *)hp->h_name,sizeof(name_buf));
}
/* do a forward lookup as well to prevent spoofing */
hp = gethostbyname(name_buf);
if (!hp) {
strcpy(name_buf,def);
rprintf(FERROR,"reverse name lookup failed\n");
} else {
for (p=hp->h_addr_list;*p;p++) {
if (memcmp(*p, &sockin->sin_addr, hp->h_length) == 0) {
break;
}
}
if (!*p) {
strcpy(name_buf,def);
rprintf(FERROR,"reverse name lookup mismatch - spoofed address?\n");
}
}
return name_buf;

286
support/rsyncstats Executable file
View File

@@ -0,0 +1,286 @@
#! /usr/bin/perl
# ---------------------------------------------------------------------------
#
# USAGE: rsyncstats <options>
#
# OPTIONS:
# -f <filename> Use <filename> for the log file
# -h include report on hourly traffic
# -d include report on domain traffic
# -t report on total traffic by section
# -D <domain> report only on traffic from <domain>
# -l <depth> Depth of path detail for sections
# -s <section> Section to report on, For example: -s /pub will report
# only on paths under /pub
#
# This script parses the default logfile format produced by rsync when running
# as a daemon with transfer logging enabled. It is derived from the xferstats
# script that comes with wuftpd
#
# Andrew Tridgell, October 1998
# rsync-bugs@samba.org
#
# ---------------------------------------------------------------------------
# edit the next line to customize for your default log file
$usage_file = "/var/adm/rsyncd.log";
# Edit the following lines for default report settings.
# Entries defined here will be over-ridden by the command line.
$opt_h = 1;
$opt_d = 0;
$opt_t = 1;
$opt_l = 2;
require 'getopts.pl';
&Getopts('f:rahdD:l:s:');
if ($opt_r) { $real = 1;}
if ($opt_a) { $anon = 1;}
if ($real == 0 && $anon == 0) { $anon = 1; }
if ($opt_f) {$usage_file = $opt_f;}
open (LOG,$usage_file) || die "Error opening usage log file: $usage_file\n";
if ($opt_D) {print "Transfer Totals include the '$opt_D' domain only.\n";
print "All other domains are filtered out for this report.\n\n";}
if ($opt_s) {print "Transfer Totals include the '$opt_s' section only.\n";
print "All other sections are filtered out for this report.\n\n";}
line: while (<LOG>) {
@line = split;
$day = $line[0];
$time = $line[1];
$pid = $line[2];
$op = $line[3];
$host = $line[4];
$ip = $line[5];
$module = $line[6];
$user = $line[7];
$file = $line[8];
$bytes = $line[9];
next if ($#line != 9);
next if ($op != "send" && $op != "recv");
$daytime = $day;
$hour = substr($time,0,2);
$file = $module . "/" . $file;
$file =~ s|//|/|mg;
@path = split(/\//, $file);
$pathkey = "";
for ($i=0; $i <= $#path && $i <= $opt_l;$i++) {
$pathkey = $pathkey . "/" . $path[$i];
}
next if (substr($pathkey,0,length("$opt_s")) ne "$opt_s");
$host =~ tr/A-Z/a-z/;
@address = split(/\./, $host);
$domain = $address[$#address];
if ( int($address[0]) > 0 || $#address < 2 )
{ $domain = "unresolved"; }
if ($opt_D) {
next unless (substr($domain,0,length("$opt_D")) eq "$opt_D");
}
# printf ("c=%d day=%s bytes=%d file=%s path=%s\n",
# $#line, $daytime, $bytes, $file, $pathkey);
$xferfiles++; # total files sent
$xfertfiles++; # total files sent
$xferfiles{$daytime}++; # files per day
$groupfiles{$pathkey}++; # per-group accesses
$domainfiles{$domain}++;
$xferbytes{$daytime} += $bytes; # bytes per day
$domainbytes{$domain} += $bytes; # xmit bytes to domain
$xferbytes += $bytes; # total bytes sent
$groupbytes{$pathkey} += $bytes; # per-group bytes sent
$xfertfiles{$hour}++; # files per hour
$xfertbytes{$hour} += $bytes; # bytes per hour
$xfertbytes += $bytes; # total bytes sent
}
close LOG;
@syslist = keys(systemfiles);
@dates = sort datecompare keys(xferbytes);
if ($xferfiles == 0) {die "There was no data to process.\n";}
print "TOTALS FOR SUMMARY PERIOD ", $dates[0], " TO ", $dates[$#dates], "\n\n";
printf ("Files Transmitted During Summary Period %12.0f\n", $xferfiles);
printf ("Bytes Transmitted During Summary Period %12.0f\n", $xferbytes);
printf ("Systems Using Archives %12.0f\n\n", $#syslist+1);
printf ("Average Files Transmitted Daily %12.0f\n",
$xferfiles / ($#dates + 1));
printf ("Average Bytes Transmitted Daily %12.0f\n",
$xferbytes / ($#dates + 1));
format top1 =
Daily Transmission Statistics
Number Of Number of Percent Of Percent Of
Date Files Sent MB Sent Files Sent Bytes Sent
--------------- ---------- ----------- ---------- ----------
.
format line1 =
@<<<<<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>> @>>>>>>> @>>>>>>>
$date, $nfiles, $nbytes/(1024*1024), $pctfiles, $pctbytes
.
$^ = top1;
$~ = line1;
foreach $date ( sort datecompare keys(xferbytes) ) {
$nfiles = $xferfiles{$date};
$nbytes = $xferbytes{$date};
$pctfiles = sprintf("%8.2f", 100*$xferfiles{$date} / $xferfiles);
$pctbytes = sprintf("%8.2f", 100*$xferbytes{$date} / $xferbytes);
write;
}
if ($opt_t) {
format top2 =
Total Transfers from each Archive Section (By bytes)
- Percent -
Archive Section NFiles MB Files Bytes
------------------------------------- ------- ----------- ----- -------
.
format line2 =
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>>>>> @>>>>>>>>>> @>>>> @>>>>
$section, $files, $bytes/(1024*1024), $pctfiles, $pctbytes
.
$| = 1;
$- = 0;
$^ = top2;
$~ = line2;
foreach $section ( sort bytecompare keys(groupfiles) ) {
$files = $groupfiles{$section};
$bytes = $groupbytes{$section};
$pctbytes = sprintf("%8.2f", 100 * $groupbytes{$section} / $xferbytes);
$pctfiles = sprintf("%8.2f", 100 * $groupfiles{$section} / $xferfiles);
write;
}
if ( $xferfiles < 1 ) { $xferfiles = 1; }
if ( $xferbytes < 1 ) { $xferbytes = 1; }
}
if ($opt_d) {
format top3 =
Total Transfer Amount By Domain
Number Of Number of Percent Of Percent Of
Domain Name Files Sent MB Sent Files Sent Bytes Sent
----------- ---------- ------------ ---------- ----------
.
format line3 =
@<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>>> @>>>>>>> @>>>>>>>
$domain, $files, $bytes/(1024*1024), $pctfiles, $pctbytes
.
$- = 0;
$^ = top3;
$~ = line3;
foreach $domain ( sort domnamcompare keys(domainfiles) ) {
if ( $domainsecs{$domain} < 1 ) { $domainsecs{$domain} = 1; }
$files = $domainfiles{$domain};
$bytes = $domainbytes{$domain};
$pctfiles = sprintf("%8.2f", 100 * $domainfiles{$domain} / $xferfiles);
$pctbytes = sprintf("%8.2f", 100 * $domainbytes{$domain} / $xferbytes);
write;
}
}
if ($opt_h) {
format top8 =
Hourly Transmission Statistics
Number Of Number of Percent Of Percent Of
Time Files Sent MB Sent Files Sent Bytes Sent
--------------- ---------- ----------- ---------- ----------
.
format line8 =
@<<<<<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>> @>>>>>>> @>>>>>>>
$hour, $nfiles, $nbytes/(1024*1024), $pctfiles, $pctbytes
.
$| = 1;
$- = 0;
$^ = top8;
$~ = line8;
foreach $hour ( sort keys(xfertbytes) ) {
$nfiles = $xfertfiles{$hour};
$nbytes = $xfertbytes{$hour};
$pctfiles = sprintf("%8.2f", 100*$xfertfiles{$hour} / $xferfiles);
$pctbytes = sprintf("%8.2f", 100*$xfertbytes{$hour} / $xferbytes);
write;
}
}
exit(0);
sub datecompare {
$a gt $b;
}
sub domnamcompare {
$sdiff = length($a) - length($b);
($sdiff < 0) ? -1 : ($sdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0;
}
sub bytecompare {
$bdiff = $groupbytes{$b} - $groupbytes{$a};
($bdiff < 0) ? -1 : ($bdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0;
}
sub faccompare {
$fdiff = $fac{$b} - $fac{$a};
($fdiff < 0) ? -1 : ($fdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0;
}

View File

@@ -76,6 +76,10 @@ int do_rmdir(char *pathname)
int do_open(char *pathname, int flags, mode_t mode)
{
if (dry_run) return -1;
#ifdef O_BINARY
/* for Windows */
flags |= O_BINARY;
#endif
CHECK_RO
return open(pathname, flags, mode);
}
@@ -149,6 +153,17 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)
#endif
}
#ifdef USE_MMAP
void *do_mmap(void *start, int len, int prot, int flags, int fd, OFF_T offset)
{
#if HAVE_OFF64_T
return mmap64(start, len, prot, flags, fd, offset);
#else
return mmap(start, len, prot, flags, fd, offset);
#endif
}
#endif
char *d_name(struct dirent *di)
{
#if HAVE_BROKEN_READDIR

View File

@@ -31,7 +31,7 @@ Imagine you have two files, $A$ and $B$, and you wish to update $B$ to be
the same as $A$. The obvious method is to copy $A$ onto $B$.
Now imagine that the two files are on machines connected by a slow
communications link, for example a dial up IP link. If $A$ is large,
communications link, for example a dialup IP link. If $A$ is large,
copying $A$ onto $B$ will be slow. To make it faster you could
compress $A$ before sending it, but that will usually only gain a
factor of 2 to 4.
@@ -133,7 +133,7 @@ possible offsets within a file in a ``rolling'' fashion, with very
little computation at each point.
Despite its simplicity, this checksum was found to be quite adequate as
a first level check for a match of two file blocks. We have found in
a first-level check for a match of two file blocks. We have found in
practice that the probability of this checksum matching when the
blocks are not equal is quite low. This is important because the much
more expensive strong checksum must be calculated for each block where
@@ -158,16 +158,16 @@ contains a null value if no element of the list has that hash value.
At each offset in the file the 32-bit rolling checksum and its 16-bit
hash are calculated. If the hash table entry for that hash value is
not a null value, the second level check is invoked.
not a null value, the second-level check is invoked.
The second level check involves scanning the sorted checksum list
The second-level check involves scanning the sorted checksum list
starting with the entry pointed to by the hash table entry, looking
for an entry whose 32-bit rolling checksum matches the current value.
The scan terminates when it reaches an entry whose 16-bit hash
differs. If this search finds a match, the third level check is
differs. If this search finds a match, the third-level check is
invoked.
The third level check involves calculating the strong checksum for the
The third-level check involves calculating the strong checksum for the
current offset in the file and comparing it with the strong checksum
value in the current list entry. If the two strong checksums match,
we assume that we have found a block of $A$ which matches a block of
@@ -246,14 +246,14 @@ The columns in the table are as follows:
\begin{description}
\item [block size] The size in bytes of the checksummed blocks.
\item [matches] The number of times a block of $B$ was found in $A$.
\item [tag hits] The number of times the 16 bit hash of the rolling
\item [tag hits] The number of times the 16-bit hash of the rolling
checksum matched a hash of one of the checksums from $B$.
\item [false alarms] The number of times the 32 bit rolling checksum
\item [false alarms] The number of times the 32-bit rolling checksum
matched but the strong checksum didn't.
\item [data] The amount of file data transferred verbatim, in bytes.
\item [written] The total number of bytes written by $\alpha$
\item [written] The total number of bytes written by $\alpha$,
including protocol overheads. This is almost all file data.
\item [read] The total number of bytes read by $\alpha$ including
\item [read] The total number of bytes read by $\alpha$, including
protocol overheads. This is almost all checksum information.
\end{description}
@@ -269,7 +269,7 @@ case. Each pair of checksums consumes 20 bytes: 4 bytes for the
rolling checksum plus 16 bytes for the 128-bit MD4 checksum.
The number of false alarms was less than $1/1000$ of the number of
true matches, indicating that the 32 bit rolling checksum is quite
true matches, indicating that the 32-bit rolling checksum is quite
good at screening out false matches.
The number of tag hits indicates that the second level of the
@@ -305,6 +305,6 @@ diff between the two releases is 4155 lines long totalling 120 kB.
An implementation of rsync which provides a convenient interface
similar to the common UNIX command rcp has been written and is
available for download from ftp://samba.anu.edu.au/pub/rsync.
available for download from http://rsync.samba.org/
\end{document}

20
test.sh
View File

@@ -10,6 +10,14 @@
#
#
cat <<EOF
This set of tests is not completely portable. It is intended for developers
not for end users. You may experience failures on some platforms that
do not indicate a problem with rsync.
EOF
export PATH=.:$PATH
TMP=/tmp/rsync-test.$$
FROM=${TMP}/from
@@ -98,14 +106,21 @@ cp ${FROM}/${F1} ${TO}/ThisShouldGo
checkit "rsync --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
5 " --delete"
LONGDIR=${FROM}/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
mkdir -p ${LONGDIR}
date > ${LONGDIR}/1
ls -la / > ${LONGDIR}/2
checkit "rsync --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
6 "long paths"
if type ssh >/dev/null ; then
rm -rf ${TO}
checkit "rsync -avH -e ssh ${FROM}/ localhost:${TO}" ${FROM}/ ${TO} \
6 "ssh: basic test"
7 "ssh: basic test"
mv ${TO}/${F1} ${TO}/ThisShouldGo
checkit "rsync --delete -avH -e ssh ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}\
7 "ssh: renamed file"
8 "ssh: renamed file"
else
echo ""
echo "**** Skipping SSH tests because ssh is not in the path ****"
@@ -113,4 +128,3 @@ else
fi
checkforlogs ${LOG}.?

615
token.c
View File

@@ -18,68 +18,94 @@
*/
#include "rsync.h"
#include "lib/zlib.h"
#include "zlib/zlib.h"
extern int do_compression;
static int compression_level = Z_DEFAULT_COMPRESSION;
/* determine the compression level based on a wildcard filename list */
void set_compression(char *fname)
{
extern int module_id;
char *dont;
char *tok;
if (!do_compression) return;
compression_level = Z_DEFAULT_COMPRESSION;
dont = lp_dont_compress(module_id);
if (!dont || !*dont) return;
if ((dont[0] == '*') && (!dont[1])) {
/* an optimization to skip the rest of this routine */
compression_level = 0;
return;
}
dont = strdup(dont);
fname = strdup(fname);
if (!dont || !fname) return;
strlower(dont);
strlower(fname);
for (tok=strtok(dont," ");tok;tok=strtok(NULL," ")) {
if (fnmatch(tok, fname, 0) == 0) {
compression_level = 0;
break;
}
}
free(dont);
free(fname);
}
/* non-compressing recv token */
static int simple_recv_token(int f,char **data)
{
static int residue;
static char *buf;
int n;
static int residue;
static char *buf;
int n;
if (!buf) {
buf = (char *)malloc(CHUNK_SIZE);
if (!buf) out_of_memory("simple_recv_token");
}
if (!buf) {
buf = (char *)malloc(CHUNK_SIZE);
if (!buf) out_of_memory("simple_recv_token");
}
if (residue == 0) {
int i = read_int(f);
if (i <= 0) return i;
residue = i;
}
if (residue == 0) {
int i = read_int(f);
if (i <= 0) return i;
residue = i;
}
*data = buf;
n = MIN(CHUNK_SIZE,residue);
residue -= n;
read_buf(f,buf,n);
return n;
*data = buf;
n = MIN(CHUNK_SIZE,residue);
residue -= n;
read_buf(f,buf,n);
return n;
}
/* non-compressing send token */
static void simple_send_token(int f,int token,
struct map_struct *buf,int offset,int n)
struct map_struct *buf,OFF_T offset,int n)
{
if (n > 0) {
int l = 0;
while (l < n) {
int n1 = MIN(CHUNK_SIZE,n-l);
write_int(f,n1);
write_buf(f,map_ptr(buf,offset+l,n1),n1);
l += n1;
}
}
write_int(f,-(token+1));
if (n > 0) {
int l = 0;
while (l < n) {
int n1 = MIN(CHUNK_SIZE,n-l);
write_int(f,n1);
write_buf(f,map_ptr(buf,offset+l,n1),n1);
l += n1;
}
}
/* a -2 token means to send data only and no token */
if (token != -2) {
write_int(f,-(token+1));
}
}
/* Memory allocation/freeing routines, called by zlib stuff. */
static void *
z_alloc(void *opaque, uInt items, uInt size)
{
return malloc(items * size);
}
static void
z_free(void *opaque, void *adrs, uInt nbytes)
{
free(adrs);
}
/* Flag bytes in compressed stream are encoded as follows: */
#define END_FLAG 0 /* that's all folks */
#define TOKEN_LONG 0x20 /* followed by 32-bit token number */
@@ -104,102 +130,131 @@ static char *obuf;
/* Send a deflated token */
static void
send_deflated_token(int f, int token,
struct map_struct *buf, int offset, int nb, int toklen)
struct map_struct *buf, OFF_T offset, int nb, int toklen)
{
int n, r;
static int init_done;
int n, r;
static int init_done, flush_pending;
if (last_token == -1) {
/* initialization */
if (!init_done) {
tx_strm.next_in = NULL;
tx_strm.zalloc = z_alloc;
tx_strm.zfree = z_free;
if (deflateInit2(&tx_strm, Z_DEFAULT_COMPRESSION, 8,
-15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
rprintf(FERROR, "compression init failed\n");
exit_cleanup(1);
}
if ((obuf = malloc(MAX_DATA_COUNT+2)) == NULL)
out_of_memory("send_deflated_token");
init_done = 1;
} else
deflateReset(&tx_strm);
run_start = token;
last_run_end = 0;
if (last_token == -1) {
/* initialization */
if (!init_done) {
tx_strm.next_in = NULL;
tx_strm.zalloc = NULL;
tx_strm.zfree = NULL;
if (deflateInit2(&tx_strm, compression_level,
Z_DEFLATED, -15, 8,
Z_DEFAULT_STRATEGY) != Z_OK) {
rprintf(FERROR, "compression init failed\n");
exit_cleanup(RERR_STREAMIO);
}
if ((obuf = malloc(MAX_DATA_COUNT+2)) == NULL)
out_of_memory("send_deflated_token");
init_done = 1;
} else
deflateReset(&tx_strm);
last_run_end = 0;
run_start = token;
flush_pending = 0;
} else if (nb != 0 || token != last_token + 1
|| token >= run_start + 65536) {
/* output previous run */
r = run_start - last_run_end;
n = last_token - run_start;
if (r >= 0 && r <= 63) {
write_byte(f, (n==0? TOKEN_REL: TOKENRUN_REL) + r);
} else {
write_byte(f, (n==0? TOKEN_LONG: TOKENRUN_LONG));
write_int(f, run_start);
}
if (n != 0) {
write_byte(f, n);
write_byte(f, n >> 8);
}
last_run_end = last_token;
run_start = token;
}
} else if (last_token == -2) {
run_start = token;
last_token = token;
if (nb != 0) {
/* deflate the data starting at offset */
tx_strm.avail_in = 0;
tx_strm.avail_out = 0;
do {
if (tx_strm.avail_in == 0 && nb != 0) {
/* give it some more input */
n = MIN(nb, CHUNK_SIZE);
tx_strm.next_in = (Bytef *)map_ptr(buf, offset, n);
tx_strm.avail_in = n;
nb -= n;
offset += n;
}
if (tx_strm.avail_out == 0) {
tx_strm.next_out = (Bytef *)(obuf + 2);
tx_strm.avail_out = MAX_DATA_COUNT;
}
r = deflate(&tx_strm, nb? Z_NO_FLUSH: Z_PACKET_FLUSH);
if (r != Z_OK) {
rprintf(FERROR, "deflate returned %d\n", r);
exit_cleanup(1);
}
if (nb == 0 || tx_strm.avail_out == 0) {
n = MAX_DATA_COUNT - tx_strm.avail_out;
if (n > 0) {
obuf[0] = DEFLATED_DATA + (n >> 8);
obuf[1] = n;
write_buf(f, obuf, n+2);
} else if (nb != 0 || token != last_token + 1
|| token >= run_start + 65536) {
/* output previous run */
r = run_start - last_run_end;
n = last_token - run_start;
if (r >= 0 && r <= 63) {
write_byte(f, (n==0? TOKEN_REL: TOKENRUN_REL) + r);
} else {
write_byte(f, (n==0? TOKEN_LONG: TOKENRUN_LONG));
write_int(f, run_start);
}
}
} while (nb != 0 || tx_strm.avail_out == 0);
}
if (token != -1) {
/* add the data in the current block to the compressor's
history and hash table */
tx_strm.next_in = (Bytef *)map_ptr(buf, offset, toklen);
tx_strm.avail_in = toklen;
tx_strm.next_out = NULL;
tx_strm.avail_out = 2 * toklen;
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",
r, tx_strm.avail_in);
exit_cleanup(1);
if (n != 0) {
write_byte(f, n);
write_byte(f, n >> 8);
}
last_run_end = last_token;
run_start = token;
}
} else {
/* end of file - clean up */
write_byte(f, END_FLAG);
}
last_token = token;
if (nb != 0 || flush_pending) {
/* deflate the data starting at offset */
int flush = Z_NO_FLUSH;
tx_strm.avail_in = 0;
tx_strm.avail_out = 0;
do {
if (tx_strm.avail_in == 0 && nb != 0) {
/* give it some more input */
n = MIN(nb, CHUNK_SIZE);
tx_strm.next_in = (Bytef *)
map_ptr(buf, offset, n);
tx_strm.avail_in = n;
nb -= n;
offset += n;
}
if (tx_strm.avail_out == 0) {
tx_strm.next_out = (Bytef *)(obuf + 2);
tx_strm.avail_out = MAX_DATA_COUNT;
if (flush != Z_NO_FLUSH) {
/*
* We left the last 4 bytes in the
* buffer, in case they are the
* last 4. Move them to the front.
*/
memcpy(tx_strm.next_out,
obuf+MAX_DATA_COUNT-2, 4);
tx_strm.next_out += 4;
tx_strm.avail_out -= 4;
}
}
if (nb == 0 && token != -2)
flush = Z_SYNC_FLUSH;
r = deflate(&tx_strm, flush);
if (r != Z_OK) {
rprintf(FERROR, "deflate returned %d\n", r);
exit_cleanup(RERR_STREAMIO);
}
if (nb == 0 || tx_strm.avail_out == 0) {
n = MAX_DATA_COUNT - tx_strm.avail_out;
if (flush != Z_NO_FLUSH) {
/*
* We have to trim off the last 4
* bytes of output when flushing
* (they are just 0, 0, ff, ff).
*/
n -= 4;
}
if (n > 0) {
obuf[0] = DEFLATED_DATA + (n >> 8);
obuf[1] = n;
write_buf(f, obuf, n+2);
}
}
} while (nb != 0 || tx_strm.avail_out == 0);
flush_pending = token == -2;
}
if (token == -1) {
/* end of file - clean up */
write_byte(f, END_FLAG);
} else if (token != -2) {
/* add the data in the current block to the compressor's
history and hash table */
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 = 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",
r, tx_strm.avail_in);
exit_cleanup(RERR_STREAMIO);
}
}
}
@@ -219,131 +274,171 @@ static int rx_run;
static int
recv_deflated_token(int f, char **data)
{
int n, r, flag;
static int init_done;
static int saved_flag;
int n, r, flag;
static int init_done;
static int saved_flag;
for (;;) {
switch (recv_state) {
case r_init:
if (!init_done) {
rx_strm.next_out = NULL;
rx_strm.zalloc = z_alloc;
rx_strm.zfree = z_free;
if (inflateInit2(&rx_strm, -15) != Z_OK) {
rprintf(FERROR, "inflate init failed\n");
exit_cleanup(1);
}
if ((cbuf = malloc(MAX_DATA_COUNT)) == NULL
|| (dbuf = malloc(CHUNK_SIZE)) == NULL)
out_of_memory("recv_deflated_token");
init_done = 1;
} else {
inflateReset(&rx_strm);
}
recv_state = r_idle;
rx_token = 0;
break;
case r_idle:
case r_inflated:
if (saved_flag) {
flag = saved_flag & 0xff;
saved_flag = 0;
} else
flag = read_byte(f);
if ((flag & 0xC0) == DEFLATED_DATA) {
n = ((flag & 0x3f) << 8) + read_byte(f);
read_buf(f, cbuf, n);
rx_strm.next_in = (Bytef *)cbuf;
rx_strm.avail_in = n;
recv_state = r_inflating;
break;
}
if (recv_state == r_inflated) {
/* check previous inflated stuff ended correctly */
rx_strm.avail_in = 0;
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_PACKET_FLUSH);
n = CHUNK_SIZE - rx_strm.avail_out;
if (r != Z_OK) {
rprintf(FERROR, "inflate flush returned %d (%d bytes)\n",
r, n);
exit_cleanup(1);
}
if (n != 0) {
/* have to return some more data and
save the flag for later. */
saved_flag = flag + 0x10000;
if (rx_strm.avail_out != 0)
for (;;) {
switch (recv_state) {
case r_init:
if (!init_done) {
rx_strm.next_out = NULL;
rx_strm.zalloc = NULL;
rx_strm.zfree = NULL;
if (inflateInit2(&rx_strm, -15) != Z_OK) {
rprintf(FERROR, "inflate init failed\n");
exit_cleanup(RERR_STREAMIO);
}
if ((cbuf = malloc(MAX_DATA_COUNT)) == NULL
|| (dbuf = malloc(CHUNK_SIZE)) == NULL)
out_of_memory("recv_deflated_token");
init_done = 1;
} else {
inflateReset(&rx_strm);
}
recv_state = r_idle;
*data = dbuf;
return n;
rx_token = 0;
break;
case r_idle:
case r_inflated:
if (saved_flag) {
flag = saved_flag & 0xff;
saved_flag = 0;
} else
flag = read_byte(f);
if ((flag & 0xC0) == DEFLATED_DATA) {
n = ((flag & 0x3f) << 8) + read_byte(f);
read_buf(f, cbuf, n);
rx_strm.next_in = (Bytef *)cbuf;
rx_strm.avail_in = n;
recv_state = r_inflating;
break;
}
if (recv_state == r_inflated) {
/* check previous inflated stuff ended correctly */
rx_strm.avail_in = 0;
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_SYNC_FLUSH);
n = CHUNK_SIZE - rx_strm.avail_out;
/*
* Z_BUF_ERROR just means no progress was
* made, i.e. the decompressor didn't have
* any pending output for us.
*/
if (r != Z_OK && r != Z_BUF_ERROR) {
rprintf(FERROR, "inflate flush returned %d (%d bytes)\n",
r, n);
exit_cleanup(RERR_STREAMIO);
}
if (n != 0 && r != Z_BUF_ERROR) {
/* have to return some more data and
save the flag for later. */
saved_flag = flag + 0x10000;
*data = dbuf;
return n;
}
/*
* At this point the decompressor should
* be expecting to see the 0, 0, ff, ff bytes.
*/
if (!inflateSyncPoint(&rx_strm)) {
rprintf(FERROR, "decompressor lost sync!\n");
exit_cleanup(RERR_STREAMIO);
}
rx_strm.avail_in = 4;
rx_strm.next_in = (Bytef *)cbuf;
cbuf[0] = cbuf[1] = 0;
cbuf[2] = cbuf[3] = 0xff;
inflate(&rx_strm, Z_SYNC_FLUSH);
recv_state = r_idle;
}
if (flag == END_FLAG) {
/* that's all folks */
recv_state = r_init;
return 0;
}
/* here we have a token of some kind */
if (flag & TOKEN_REL) {
rx_token += flag & 0x3f;
flag >>= 6;
} else
rx_token = read_int(f);
if (flag & 1) {
rx_run = read_byte(f);
rx_run += read_byte(f) << 8;
recv_state = r_running;
}
return -1 - rx_token;
case r_inflating:
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_NO_FLUSH);
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);
}
if (rx_strm.avail_in == 0)
recv_state = r_inflated;
if (n != 0) {
*data = dbuf;
return n;
}
break;
case r_running:
++rx_token;
if (--rx_run == 0)
recv_state = r_idle;
return -1 - rx_token;
}
recv_state = r_idle;
}
if (flag == END_FLAG) {
/* that's all folks */
recv_state = r_init;
return 0;
}
/* here we have a token of some kind */
if (flag & TOKEN_REL) {
rx_token += flag & 0x3f;
flag >>= 6;
} else
rx_token = read_int(f);
if (flag & 1) {
rx_run = read_byte(f);
rx_run += read_byte(f) << 8;
recv_state = r_running;
}
return -1 - rx_token;
case r_inflating:
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_NO_FLUSH);
n = CHUNK_SIZE - rx_strm.avail_out;
if (r != Z_OK) {
rprintf(FERROR, "inflate returned %d (%d bytes)\n", r, n);
exit_cleanup(1);
}
if (rx_strm.avail_in == 0)
recv_state = r_inflated;
if (n != 0) {
*data = dbuf;
return n;
}
break;
case r_running:
++rx_token;
if (--rx_run == 0)
recv_state = r_idle;
return -1 - rx_token;
}
}
}
/*
* put the data corresponding to a token that we've just returned
* from recv_deflated_token into the decompressor's history buffer.
*/
void
see_deflate_token(char *buf, int len)
static void see_deflate_token(char *buf, int len)
{
int r;
int r, blklen;
unsigned char hdr[5];
rx_strm.next_in = (Bytef *)buf;
rx_strm.avail_in = len;
r = inflateIncomp(&rx_strm);
if (r != Z_OK) {
rprintf(FERROR, "inflateIncomp returned %d\n", r);
exit_cleanup(1);
}
rx_strm.avail_in = 0;
blklen = 0;
hdr[0] = 0;
do {
if (rx_strm.avail_in == 0 && len != 0) {
if (blklen == 0) {
/* Give it a fake stored-block header. */
rx_strm.next_in = (Bytef *)hdr;
rx_strm.avail_in = 5;
blklen = len;
if (blklen > 0xffff)
blklen = 0xffff;
hdr[1] = blklen;
hdr[2] = blklen >> 8;
hdr[3] = ~hdr[1];
hdr[4] = ~hdr[2];
} else {
rx_strm.next_in = (Bytef *)buf;
rx_strm.avail_in = blklen;
len -= blklen;
blklen = 0;
}
}
rx_strm.next_out = (Bytef *)dbuf;
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);
exit_cleanup(RERR_STREAMIO);
}
} while (len || rx_strm.avail_out == 0);
}
/*
@@ -351,14 +446,14 @@ see_deflate_token(char *buf, int len)
* If token == -1 then we have reached EOF
* If n == 0 then don't send a buffer
*/
void send_token(int f,int token,struct map_struct *buf,int offset,
void send_token(int f,int token,struct map_struct *buf,OFF_T offset,
int n,int toklen)
{
if (!do_compression) {
simple_send_token(f,token,buf,offset,n);
} else {
send_deflated_token(f, token, buf, offset, n, toklen);
}
if (!do_compression) {
simple_send_token(f,token,buf,offset,n);
} else {
send_deflated_token(f, token, buf, offset, n, toklen);
}
}
@@ -370,14 +465,14 @@ void send_token(int f,int token,struct map_struct *buf,int offset,
*/
int recv_token(int f,char **data)
{
int tok;
int tok;
if (!do_compression) {
tok = simple_recv_token(f,data);
} else {
tok = recv_deflated_token(f, data);
}
return tok;
if (!do_compression) {
tok = simple_recv_token(f,data);
} else {
tok = recv_deflated_token(f, data);
}
return tok;
}
/*
@@ -385,6 +480,6 @@ int recv_token(int f,char **data)
*/
void see_token(char *data, int toklen)
{
if (do_compression)
see_deflate_token(data, toklen);
if (do_compression)
see_deflate_token(data, toklen);
}

539
util.c
View File

@@ -24,96 +24,30 @@
*/
#include "rsync.h"
int num_waiting(int fd)
/****************************************************************************
Set a fd into nonblocking mode. Uses POSIX O_NONBLOCK if available,
else
if SYSV use O_NDELAY
if BSD use FNDELAY
****************************************************************************/
int set_nonblocking(int fd)
{
int len=0;
ioctl(fd,FIONREAD,&len);
return(len);
}
struct map_struct *map_file(int fd,OFF_T len)
{
struct map_struct *ret;
ret = (struct map_struct *)malloc(sizeof(*ret));
if (!ret) out_of_memory("map_file");
ret->map = NULL;
ret->fd = fd;
ret->size = len;
ret->p = NULL;
ret->p_size = 0;
ret->p_offset = 0;
ret->p_len = 0;
#ifdef HAVE_MMAP
if (len < MAX_MAP_SIZE) {
ret->map = (char *)mmap(NULL,len,PROT_READ,MAP_SHARED,fd,0);
if (ret->map == (char *)-1) {
ret->map = NULL;
}
}
int val;
#ifdef O_NONBLOCK
#define FLAG_TO_SET O_NONBLOCK
#else
#ifdef SYSV
#define FLAG_TO_SET O_NDELAY
#else /* BSD */
#define FLAG_TO_SET FNDELAY
#endif
return ret;
}
char *map_ptr(struct map_struct *map,OFF_T offset,int len)
{
int nread;
if (map->map)
return map->map+offset;
if (len == 0)
return NULL;
if (len > (map->size-offset))
len = map->size-offset;
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
return (map->p + (offset - map->p_offset));
}
len = MAX(len,CHUNK_SIZE);
if (len > (map->size-offset))
len = map->size-offset;
if (len > map->p_size) {
if (map->p) free(map->p);
map->p = (char *)malloc(len);
if (!map->p) out_of_memory("map_ptr");
map->p_size = len;
}
map->p_offset = offset;
map->p_len = len;
if (do_lseek(map->fd,offset,SEEK_SET) != offset) {
rprintf(FERROR,"lseek failed in map_ptr\n");
exit_cleanup(1);
}
if ((nread=read(map->fd,map->p,len)) != len) {
if (nread < 0) nread = 0;
/* the best we can do is zero the buffer - the file
has changed mid transfer! */
memset(map->p+nread, 0, len - nread);
}
return map->p;
}
void unmap_file(struct map_struct *map)
{
#ifdef HAVE_MMAP
if (map->map)
munmap(map->map,map->size);
#endif
if (map->p) free(map->p);
free(map);
if((val = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
val |= FLAG_TO_SET;
return fcntl( fd, F_SETFL, val);
#undef FLAG_TO_SET
}
@@ -127,14 +61,14 @@ int piped_child(char **command,int *f_in,int *f_out)
if (pipe(to_child_pipe) < 0 ||
pipe(from_child_pipe) < 0) {
rprintf(FERROR,"pipe: %s\n",strerror(errno));
exit_cleanup(1);
exit_cleanup(RERR_IPC);
}
pid = do_fork();
if (pid < 0) {
rprintf(FERROR,"fork: %s\n",strerror(errno));
exit_cleanup(1);
exit_cleanup(RERR_IPC);
}
if (pid == 0)
@@ -145,7 +79,7 @@ int piped_child(char **command,int *f_in,int *f_out)
close(from_child_pipe[0]) < 0 ||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
exit_cleanup(1);
exit_cleanup(RERR_IPC);
}
if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
@@ -153,17 +87,20 @@ int piped_child(char **command,int *f_in,int *f_out)
execvp(command[0], command);
rprintf(FERROR,"Failed to exec %s : %s\n",
command[0],strerror(errno));
exit_cleanup(1);
exit_cleanup(RERR_IPC);
}
if (close(from_child_pipe[1]) < 0 ||
close(to_child_pipe[0]) < 0) {
rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
exit_cleanup(1);
exit_cleanup(RERR_IPC);
}
*f_in = from_child_pipe[0];
*f_out = to_child_pipe[1];
set_nonblocking(*f_in);
set_nonblocking(*f_out);
return pid;
}
@@ -177,14 +114,14 @@ int local_child(int argc, char **argv,int *f_in,int *f_out)
if (pipe(to_child_pipe) < 0 ||
pipe(from_child_pipe) < 0) {
rprintf(FERROR,"pipe: %s\n",strerror(errno));
exit_cleanup(1);
exit_cleanup(RERR_IPC);
}
pid = do_fork();
if (pid < 0) {
rprintf(FERROR,"fork: %s\n",strerror(errno));
exit_cleanup(1);
exit_cleanup(RERR_IPC);
}
if (pid == 0) {
@@ -199,7 +136,7 @@ int local_child(int argc, char **argv,int *f_in,int *f_out)
close(from_child_pipe[0]) < 0 ||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
exit_cleanup(1);
exit_cleanup(RERR_IPC);
}
if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
@@ -209,7 +146,7 @@ int local_child(int argc, char **argv,int *f_in,int *f_out)
if (close(from_child_pipe[1]) < 0 ||
close(to_child_pipe[0]) < 0) {
rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
exit_cleanup(1);
exit_cleanup(RERR_IPC);
}
*f_in = from_child_pipe[0];
@@ -223,13 +160,13 @@ int local_child(int argc, char **argv,int *f_in,int *f_out)
void out_of_memory(char *str)
{
rprintf(FERROR,"ERROR: out of memory in %s\n",str);
exit_cleanup(1);
exit_cleanup(RERR_MALLOC);
}
void overflow(char *str)
{
rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
exit_cleanup(1);
exit_cleanup(RERR_MALLOC);
}
@@ -261,36 +198,6 @@ int set_modtime(char *fname,time_t modtime)
}
/****************************************************************************
Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
else
if SYSV use O_NDELAY
if BSD use FNDELAY
****************************************************************************/
int set_blocking(int fd, int set)
{
int val;
#ifdef O_NONBLOCK
#define FLAG_TO_SET O_NONBLOCK
#else
#ifdef SYSV
#define FLAG_TO_SET O_NDELAY
#else /* BSD */
#define FLAG_TO_SET FNDELAY
#endif
#endif
if((val = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
if(set) /* Turn blocking on - ie. clear nonblock flag */
val &= ~FLAG_TO_SET;
else
val |= FLAG_TO_SET;
return fcntl( fd, F_SETFL, val);
#undef FLAG_TO_SET
}
/****************************************************************************
create any necessary directories in fname. Unfortunately we don't know
what perms to give the directory when this is called so we need to rely
@@ -320,7 +227,7 @@ int create_directory_path(char *fname)
derived from GNU C's cccp.c.
*/
int full_write(int desc, char *ptr, int len)
static int full_write(int desc, char *ptr, int len)
{
int total_written;
@@ -346,7 +253,7 @@ int full_write(int desc, char *ptr, int len)
for an error.
derived from GNU C's cccp.c. */
int safe_read(int desc, char *ptr, int len)
static int safe_read(int desc, char *ptr, int len)
{
int n_chars;
@@ -387,7 +294,7 @@ int copy_file(char *source, char *dest, mode_t mode)
}
ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
if (ofd < 0) {
if (ofd == -1) {
rprintf(FERROR,"open %s: %s\n",
dest,strerror(errno));
close(ifd);
@@ -451,31 +358,6 @@ void kill_all(int sig)
}
}
/* like strncpy but does not 0 fill the buffer and always null
terminates (thus it can use maxlen+1 space in d) */
void strlcpy(char *d, char *s, int maxlen)
{
int len = strlen(s);
if (len > maxlen) len = maxlen;
memcpy(d, s, len);
d[len] = 0;
}
/* like strncat but does not 0 fill the buffer and always null
terminates (thus it can use maxlen+1 space in d) */
void strlcat(char *d, char *s, int maxlen)
{
int len1 = strlen(d);
int len2 = strlen(s);
if (len1+len2 > maxlen) {
len2 = maxlen-len1;
}
if (len2 > 0) {
memcpy(d+len1, s, len2);
d[len1+len2] = 0;
}
}
/* turn a user name into a uid */
int name_to_uid(char *name, uid_t *uid)
{
@@ -503,14 +385,6 @@ int name_to_gid(char *name, gid_t *gid)
}
/****************************************************************************
check if a process exists.
****************************************************************************/
int process_exists(int pid)
{
return(kill(pid,0) == 0 || errno != ESRCH);
}
/* lock a byte range in a open file */
int lock_range(int fd, int offset, int len)
{
@@ -526,9 +400,9 @@ int lock_range(int fd, int offset, int len)
}
static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
static void glob_expand_one(char *s, char **argv, int *argc, int maxargs, int sanitize_paths)
{
#ifndef HAVE_GLOB
#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
if (!*s) s = ".";
argv[*argc] = strdup(s);
(*argc)++;
@@ -539,7 +413,9 @@ static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
if (!*s) s = ".";
argv[*argc] = strdup(s);
s = strdup(s);
sanitize_path(s);
argv[*argc] = s;
memset(&globbuf, 0, sizeof(globbuf));
glob(argv[*argc], 0, NULL, &globbuf);
@@ -558,7 +434,7 @@ static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
#endif
}
void glob_expand(char *base1, char **argv, int *argc, int maxargs)
void glob_expand(char *base1, char **argv, int *argc, int maxargs, int sanitize_paths)
{
char *s = argv[*argc];
char *p, *q;
@@ -582,11 +458,11 @@ void glob_expand(char *base1, char **argv, int *argc, int maxargs)
while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
/* split it at this point */
*p = 0;
glob_expand_one(q, argv, argc, maxargs);
glob_expand_one(q, argv, argc, maxargs, sanitize_paths);
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, sanitize_paths);
free(s);
free(base);
@@ -603,55 +479,17 @@ void strlower(char *s)
}
}
/* this is like vsnprintf but the 'n' limit does not include
the terminating null. So if you have a 1024 byte buffer then
pass 1023 for n */
/* this is like vsnprintf but it always null terminates, so you
can fit at most n-1 chars in */
int vslprintf(char *str, int n, const char *format, va_list ap)
{
#ifdef HAVE_VSNPRINTF
int ret = vsnprintf(str, n, format, ap);
if (ret > n || ret < 0) {
str[n] = 0;
if (ret >= n || ret < 0) {
str[n-1] = 0;
return -1;
}
str[ret] = 0;
return ret;
#else
static char *buf;
static int len=MAXPATHLEN*8;
int ret;
/* this code is NOT a proper vsnprintf() implementation. It
relies on the fact that all calls to slprintf() in rsync
pass strings which have already been checked to be less
than MAXPATHLEN in length and never more than 2 strings are
concatenated. This means the above buffer is absolutely
ample and can never be overflowed.
In the future we would like to replace this with a proper
vsnprintf() implementation but right now we need a solution
that is secure and portable. This is it. */
if (!buf) {
buf = malloc(len);
if (!buf) {
/* can't call debug or we would recurse */
exit_cleanup(1);
}
}
vsprintf(buf, format, ap);
ret = strlen(buf);
if (ret > n) {
/* yikes! */
exit_cleanup(1);
}
buf[ret] = 0;
memcpy(str, buf, ret+1);
return ret;
#endif
}
@@ -667,3 +505,280 @@ int slprintf(char *str, int n, char *format, ...)
return ret;
}
void *Realloc(void *p, int size)
{
if (!p) return (void *)malloc(size);
return (void *)realloc(p, size);
}
void clean_fname(char *name)
{
char *p;
int l;
int modified = 1;
if (!name) return;
while (modified) {
modified = 0;
if ((p=strstr(name,"/./"))) {
modified = 1;
while (*p) {
p[0] = p[2];
p++;
}
}
if ((p=strstr(name,"//"))) {
modified = 1;
while (*p) {
p[0] = p[1];
p++;
}
}
if (strncmp(p=name,"./",2) == 0) {
modified = 1;
do {
p[0] = p[2];
} while (*p++);
}
l = strlen(p=name);
if (l > 1 && p[l-1] == '/') {
modified = 1;
p[l-1] = 0;
}
}
}
/*
* Make path appear as if a chroot had occurred:
* 1. remove leading "/" (or replace with "." if at end)
* 2. remove leading ".." components
* 3. delete any other "<dir>/.." (recursively)
* While we're at it, remove double slashes and "." components like
* clean_fname does(), but DON'T remove a trailing slash because that
* is sometimes significant on command line arguments.
* Can only shrink paths, so sanitizes in place.
* Contributed by Dave Dykstra <dwd@bell-labs.com>
*/
void sanitize_path(char *p)
{
char *start, *sanp;
start = p;
sanp = p;
while (*p == '/') {
/* remove leading slashes */
p++;
}
while (*p != '\0') {
/* this loop iterates once per filename component in p.
* both p (and sanp if the original had a slash) should
* always be left pointing after a slash
*/
if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
/* skip "." component */
while (*++p == '/') {
/* skip following slashes */
;
}
} else if ((*p == '.') && (*(p+1) == '.') &&
((*(p+2) == '/') || (*(p+2) == '\0'))) {
/* skip ".." component followed by slash or end */
p += 2;
if (*p == '/')
p++;
if (sanp != start) {
/* back up sanp one level */
--sanp; /* now pointing at slash */
while ((sanp > start) && (*(sanp - 1) != '/')) {
/* skip back up to slash */
sanp--;
}
}
} else {
while (1) {
/* copy one component through next slash */
*sanp++ = *p++;
if ((*p == '\0') || (*(p-1) == '/')) {
while (*p == '/') {
/* skip multiple slashes */
p++;
}
break;
}
}
}
}
if (sanp == start) {
/* ended up with nothing, so put in "." component */
*sanp++ = '.';
}
*sanp = '\0';
}
static char curr_dir[MAXPATHLEN];
/* like chdir() but can be reversed with pop_dir() if save is set. It
is also much faster as it remembers where we have been */
char *push_dir(char *dir, int save)
{
char *ret = curr_dir;
static int initialised;
if (!initialised) {
initialised = 1;
getcwd(curr_dir, sizeof(curr_dir)-1);
}
if (chdir(dir)) return NULL;
if (save) {
ret = strdup(curr_dir);
}
if (*dir == '/') {
strlcpy(curr_dir, dir, sizeof(curr_dir));
} else {
strlcat(curr_dir,"/", sizeof(curr_dir));
strlcat(curr_dir,dir, sizeof(curr_dir));
}
clean_fname(curr_dir);
return ret;
}
/* reverse a push_dir call */
int pop_dir(char *dir)
{
int ret;
ret = chdir(dir);
if (ret) {
free(dir);
return ret;
}
strlcpy(curr_dir, dir, sizeof(curr_dir));
free(dir);
return 0;
}
/* we need to supply our own strcmp function for file list comparisons
to ensure that signed/unsigned usage is consistent between machines. */
int u_strcmp(const char *cs1, const char *cs2)
{
const uchar *s1 = (const uchar *)cs1;
const uchar *s2 = (const uchar *)cs2;
while (*s1 && *s2 && (*s1 == *s2)) {
s1++; s2++;
}
return (int)*s1 - (int)*s2;
}
static OFF_T last_ofs;
void end_progress(void)
{
extern int do_progress, am_server;
if (do_progress && !am_server) {
rprintf(FINFO,"\n");
}
last_ofs = 0;
}
void show_progress(OFF_T ofs, OFF_T size)
{
extern int do_progress, am_server;
if (do_progress && !am_server) {
if (ofs > last_ofs + 1000) {
int pct = (int)((100.0*ofs)/size);
rprintf(FINFO,"%.0f (%d%%)\r", (double)ofs, pct);
last_ofs = ofs;
}
}
}
/* determine if a symlink points outside the current directory tree */
int unsafe_symlink(char *dest, char *src)
{
char *tok;
int depth = 0;
/* all absolute and null symlinks are unsafe */
if (!dest || !(*dest) || (*dest == '/')) return 1;
src = strdup(src);
if (!src) out_of_memory("unsafe_symlink");
/* find out what our safety margin is */
for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
if (strcmp(tok,"..") == 0) {
depth=0;
} else if (strcmp(tok,".") == 0) {
/* nothing */
} else {
depth++;
}
}
free(src);
/* drop by one to account for the filename portion */
depth--;
dest = strdup(dest);
if (!dest) out_of_memory("unsafe_symlink");
for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
if (strcmp(tok,"..") == 0) {
depth--;
} else if (strcmp(tok,".") == 0) {
/* nothing */
} else {
depth++;
}
/* if at any point we go outside the current directory then
stop - it is unsafe */
if (depth < 0) break;
}
free(dest);
return (depth < 0);
}
/****************************************************************************
return the date and time as a string
****************************************************************************/
char *timestring(time_t t)
{
static char TimeBuf[200];
struct tm *tm = localtime(&t);
#ifdef HAVE_STRFTIME
strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
#else
strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
#endif
if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
TimeBuf[strlen(TimeBuf)-1] = 0;
}
return(TimeBuf);
}

View File

@@ -1 +1 @@
#define VERSION "2.0.10"
#define VERSION "2.2.1"

19
zlib/README.rsync Normal file
View File

@@ -0,0 +1,19 @@
zlib has been adapted slightly for use in rsync. Please don't bother
the zlib authors with problems related to the use of zlib in rsync as
any bugs are likely to be our fault and not theirs.
Specific changes that have been made to zlib for rsync include:
- add Z_INSERT_ONLY to allow for efficient history updating without
actually emitting any data. This is used to compress the matched
blocks that don't cross the wire, which gives better compression
ratios on the literal data.
- fixed a number of minor compilation issues. (redefinition of MAX and
other such trivial things)
- include rsync.h to ensure that we get a consistent set of includes
for all C code in rsync and to take advantage of autoconf
--
Paul Mackerras and Andrew Tridgell

View File

@@ -80,7 +80,7 @@ local block_state deflate_slow OF((deflate_state *s, int flush));
local void lm_init OF((deflate_state *s));
local void putShortMSB OF((deflate_state *s, uInt b));
local void flush_pending OF((z_streamp strm));
local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
local int dread_buf OF((z_streamp strm, Bytef *buf, unsigned size));
#ifdef ASMV
void match_init OF((void)); /* asm code initialization */
uInt longest_match OF((deflate_state *s, IPos cur_match));
@@ -411,7 +411,7 @@ local void putShortMSB (s, b)
* Flush as much pending output as possible. All deflate() output goes
* through this function so some applications may wish to modify it
* to avoid allocating a large strm->next_out buffer and copying into it.
* (See also read_buf()).
* (See also dread_buf()).
*/
local void flush_pending(strm)
z_streamp strm;
@@ -441,7 +441,7 @@ int ZEXPORT deflate (strm, flush)
deflate_state *s;
if (strm == Z_NULL || strm->state == Z_NULL ||
flush > Z_FINISH || flush < 0) {
flush > Z_INSERT_ONLY || flush < 0) {
return Z_STREAM_ERROR;
}
s = strm->state;
@@ -657,7 +657,7 @@ int ZEXPORT deflateCopy (dest, source)
* allocating a large strm->next_in buffer and copying from it.
* (See also flush_pending()).
*/
local int read_buf(strm, buf, size)
local int dread_buf(strm, buf, size)
z_streamp strm;
Bytef *buf;
unsigned size;
@@ -1028,7 +1028,7 @@ local void fill_window(s)
*/
Assert(more >= 2, "more < 2");
n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
n = dread_buf(s->strm, s->window + s->strstart + s->lookahead, more);
s->lookahead += n;
/* Initialize the hash value now that we have some input: */
@@ -1162,6 +1162,12 @@ local block_state deflate_fast(s, flush)
INSERT_STRING(s, s->strstart, hash_head);
}
if (flush == Z_INSERT_ONLY) {
s->strstart++;
s->lookahead--;
continue;
}
/* Find the longest match, discarding those <= prev_length.
* At this point we have always match_length < MIN_MATCH
*/
@@ -1221,6 +1227,10 @@ local block_state deflate_fast(s, flush)
}
if (bflush) FLUSH_BLOCK(s, 0);
}
if (flush == Z_INSERT_ONLY) {
s->block_start = s->strstart;
return need_more;
}
FLUSH_BLOCK(s, flush == Z_FINISH);
return flush == Z_FINISH ? finish_done : block_done;
}
@@ -1259,6 +1269,12 @@ local block_state deflate_slow(s, flush)
INSERT_STRING(s, s->strstart, hash_head);
}
if (flush == Z_INSERT_ONLY) {
s->strstart++;
s->lookahead--;
continue;
}
/* Find the longest match, discarding those <= prev_length.
*/
s->prev_length = s->match_length, s->prev_match = s->match_start;
@@ -1337,6 +1353,10 @@ local block_state deflate_slow(s, flush)
s->lookahead--;
}
}
if (flush == Z_INSERT_ONLY) {
s->block_start = s->strstart;
return need_more;
}
Assert (flush != Z_NO_FLUSH, "no flush?");
if (s->match_available) {
Tracevv((stderr,"%c", s->window[s->strstart-1]));

View File

@@ -176,7 +176,7 @@ int r;
break;
case 3: /* illegal */
DUMPBITS(3)
s->mode = BAD;
s->mode = zBAD;
z->msg = (char*)"invalid block type";
r = Z_DATA_ERROR;
LEAVE
@@ -186,7 +186,7 @@ int r;
NEEDBITS(32)
if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
{
s->mode = BAD;
s->mode = zBAD;
z->msg = (char*)"invalid stored block lengths";
r = Z_DATA_ERROR;
LEAVE
@@ -219,7 +219,7 @@ int r;
#ifndef PKZIP_BUG_WORKAROUND
if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
{
s->mode = BAD;
s->mode = zBAD;
z->msg = (char*)"too many length or distance symbols";
r = Z_DATA_ERROR;
LEAVE
@@ -252,7 +252,7 @@ int r;
ZFREE(z, s->sub.trees.blens);
r = t;
if (r == Z_DATA_ERROR)
s->mode = BAD;
s->mode = zBAD;
LEAVE
}
s->sub.trees.index = 0;
@@ -289,7 +289,7 @@ int r;
(c == 16 && i < 1))
{
ZFREE(z, s->sub.trees.blens);
s->mode = BAD;
s->mode = zBAD;
z->msg = (char*)"invalid bit length repeat";
r = Z_DATA_ERROR;
LEAVE
@@ -317,7 +317,7 @@ int r;
if (t != Z_OK)
{
if (t == (uInt)Z_DATA_ERROR)
s->mode = BAD;
s->mode = zBAD;
r = t;
LEAVE
}
@@ -361,7 +361,7 @@ int r;
case DONE:
r = Z_STREAM_END;
LEAVE
case BAD:
case zBAD:
r = Z_DATA_ERROR;
LEAVE
default:

View File

@@ -22,7 +22,7 @@ typedef enum {
CHECK2, /* two check bytes to go */
CHECK1, /* one check byte to go */
DONE, /* finished check, done */
BAD} /* got an error--stay here */
zBAD} /* got an error--stay here */
inflate_mode;
/* inflate private state */
@@ -38,7 +38,7 @@ struct internal_state {
uLong was; /* computed check value */
uLong need; /* stream check value */
} check; /* if CHECK, check values to compare */
uInt marker; /* if BAD, inflateSync's marker bytes count */
uInt marker; /* if zBAD, inflateSync's marker bytes count */
} sub; /* submode */
/* mode independent information */
@@ -164,14 +164,14 @@ int f;
NEEDBYTE
if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->msg = (char*)"unknown compression method";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
}
if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->msg = (char*)"invalid window size";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
@@ -182,7 +182,7 @@ int f;
b = NEXTBYTE;
if (((z->state->sub.method << 8) + b) % 31)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->msg = (char*)"incorrect header check";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
@@ -213,7 +213,7 @@ int f;
z->state->mode = DICT0;
return Z_NEED_DICT;
case DICT0:
z->state->mode = BAD;
z->state->mode = zBAD;
z->msg = (char*)"need dictionary";
z->state->sub.marker = 0; /* can try inflateSync */
return Z_STREAM_ERROR;
@@ -221,7 +221,7 @@ int f;
r = inflate_blocks(z->state->blocks, z, r);
if (r == Z_DATA_ERROR)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->state->sub.marker = 0; /* can try inflateSync */
break;
}
@@ -255,7 +255,7 @@ int f;
if (z->state->sub.check.was != z->state->sub.check.need)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->msg = (char*)"incorrect data check";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
@@ -264,7 +264,7 @@ int f;
z->state->mode = DONE;
case DONE:
return Z_STREAM_END;
case BAD:
case zBAD:
return Z_DATA_ERROR;
default:
return Z_STREAM_ERROR;
@@ -310,9 +310,9 @@ z_streamp z;
/* set up */
if (z == Z_NULL || z->state == Z_NULL)
return Z_STREAM_ERROR;
if (z->state->mode != BAD)
if (z->state->mode != zBAD)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->state->sub.marker = 0;
}
if ((n = z->avail_in) == 0)

View File

@@ -21,7 +21,7 @@ typedef enum {
CODES, /* processing fixed or dynamic block */
DRY, /* output remaining window bytes */
DONE, /* finished last block, done */
BAD} /* got a data error--stuck here */
zBAD} /* got a data error--stuck here */
inflate_block_mode;
/* inflate blocks semi-private state */
@@ -77,9 +77,9 @@ struct inflate_blocks_state {
/* output bytes */
#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
#define ZWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
#define NEEDOUT {if(m==0){ZWRAP if(m==0){FLUSH ZWRAP if(m==0) LEAVE}}r=Z_OK;}
#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
/* load local pointers */
#define LOAD {LOADIN LOADOUT}

View File

@@ -230,7 +230,9 @@ local void send_bits(s, value, length)
#endif /* DEBUG */
#define MAX(a,b) (a >= b ? a : b)
#ifndef MAX
#define MAX(a,b) ((a) >= (b) ? (a) : (b))
#endif
/* the arguments must not have side effects */
/* ===========================================================================
@@ -497,7 +499,7 @@ local void gen_bitlen(s, desc)
int bits; /* bit length */
int xbits; /* extra bits */
ush f; /* frequency */
int overflow = 0; /* number of elements with bit length too large */
int Overflow = 0; /* number of elements with bit length too large */
for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
@@ -509,7 +511,7 @@ local void gen_bitlen(s, desc)
for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
n = s->heap[h];
bits = tree[tree[n].Dad].Len + 1;
if (bits > max_length) bits = max_length, overflow++;
if (bits > max_length) bits = max_length, Overflow++;
tree[n].Len = (ush)bits;
/* We overwrite tree[n].Dad which is no longer needed */
@@ -522,7 +524,7 @@ local void gen_bitlen(s, desc)
s->opt_len += (ulg)f * (bits + xbits);
if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
}
if (overflow == 0) return;
if (Overflow == 0) return;
Trace((stderr,"\nbit length overflow\n"));
/* This happens for example on obj2 and pic of the Calgary corpus */
@@ -537,8 +539,8 @@ local void gen_bitlen(s, desc)
/* The brother of the overflow item also moves one step up,
* but this does not affect bl_count[max_length]
*/
overflow -= 2;
} while (overflow > 0);
Overflow -= 2;
} while (Overflow > 0);
/* Now recompute all bit lengths, scanning in increasing frequency.
* h is still equal to HEAP_SIZE. (It is simpler to reconstruct all

View File

@@ -127,6 +127,7 @@ typedef z_stream FAR *z_streamp;
#define Z_SYNC_FLUSH 2
#define Z_FULL_FLUSH 3
#define Z_FINISH 4
#define Z_INSERT_ONLY 5
/* Allowed flush values; see deflate() below for details */
#define Z_OK 0

View File

@@ -200,11 +200,6 @@ void zcfree (voidpf opaque, voidpf ptr)
#ifndef MY_ZCALLOC /* Any system without a special alloc function */
#ifndef STDC
extern voidp calloc OF((uInt items, uInt size));
extern void free OF((voidpf ptr));
#endif
voidpf zcalloc (opaque, items, size)
voidpf opaque;
unsigned items;

View File

@@ -13,8 +13,10 @@
#ifndef _Z_UTIL_H
#define _Z_UTIL_H
#include "../rsync.h"
#include "zlib.h"
#if 0
#ifdef STDC
# include <stddef.h>
# include <string.h>
@@ -25,6 +27,7 @@
#else
# include <errno.h>
#endif
#endif
#ifndef local
# define local static