Compare commits

..

2 Commits

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

View File

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

19
.ignore Normal file
View File

@@ -0,0 +1,19 @@
.#*
*.log
Makefile
config.h
*.o
CVS
.ignore
.cvsignore
*~
rsync
config.status
config.cache
TAGS
config.log
test
*.gz
rsync-*
*.dvi
*.aux

11
COPYING
View File

@@ -2,7 +2,7 @@
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -279,7 +279,7 @@ POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
Copyright (C) 19yy <name of author>
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
@@ -305,15 +305,14 @@ the "copyright" line and a pointer to where the full notice is found.
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
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.

27
INSTALL
View File

@@ -1,4 +1,4 @@
To build and install rsync:
To build and install rsync
$ ./configure
$ make
@@ -9,15 +9,8 @@ to ./configure. To see them, use:
$ ./configure --help
Configure tries to figure out if the local system uses group "nobody" or
"nogroup" by looking in the /etc/group file. (This is only used for the
default group of an rsync daemon, which attempts to run with "nobody"
user and group permissions.) You can change the default user and group
for the daemon by editing the NOBODY_USER and NOBODY_GROUP defines in
config.h, or just override them in your /etc/rsyncd.conf file.
As of 2.4.7, rsync uses Eric Troan's popt option-parsing library. A
cut-down copy of release 1.6.4 is included in the rsync distribution,
cut-down copy of release 1.5 is included in the rsync distribution,
and will be used if there is no popt library on your build host, or if
the --with-included-popt option is passed to ./configure.
@@ -25,6 +18,7 @@ If you configure using --enable-maintainer-mode, then rsync will try
to pop up an xterm on DISPLAY=:0 if it crashes. You might find this
useful, but it should be turned off for production builds.
RPM NOTES
---------
@@ -43,15 +37,20 @@ fails:
Install gcc or HP's "ANSI/C Compiler".
MAC OSX NOTES
-------------
Some versions of Mac OS X (Darwin) seem to have an IPv6 stack, but do
not completely implement the "New Sockets" API.
Mac OS X (Darwin) seems to have an IPv6 stack, but it does not
completely implement the "New Sockets" API.
<http://www.ipv6.org/impl/mac.html> says that Apple started to support
IPv6 in 10.2 (Jaguar). If your build fails, try again after running
configure with --disable-ipv6.
<http://www.ipv6.org/impl/mac.html> says that Apple do not support
IPv6 yet. If your build fails, try again with --disable-ipv6.
There is an unresolved problem with the OSX implimentation
of setgroups causing rsyncd to fail. The workaround is to
#undef HAVE_SETGROUPS in config.h
IBM AIX NOTES
-------------

View File

@@ -2,7 +2,6 @@
# Makefile
prefix=@prefix@
datarootdir=@datarootdir@
exec_prefix=@exec_prefix@
bindir=@bindir@
mandir=@mandir@
@@ -26,29 +25,30 @@ VERSION=@VERSION@
.SUFFIXES:
.SUFFIXES: .c .o
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h lib/pool_alloc.h
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
lib/permstring.o lib/pool_alloc.o @LIBOBJS@
ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o
lib/permstring.o @LIBOBJS@
ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \
zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
zlib/zutil.o zlib/adler32.o
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 backup.o
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
fileio.o batch.o clientname.o chmod.o
fileio.o batch.o clientname.o
OBJS3=progress.o pipe.o
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
popt/popthelp.o popt/poptparse.o
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o
TLS_OBJ = tls.o syscall.o lib/permstring.o
# Programs we must have to run the test cases
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) \
trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT)
# Objects for CHECK_PROGS to clean
CHECK_OBJS=getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o
CHECK_OBJS=getgroups.o t_stub.o t_unsafe.o trimslash.o wildtest.o
# note that the -I. is needed to handle config.h when using VPATH
.c.o:
@@ -58,16 +58,18 @@ CHECK_OBJS=getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o
all: rsync$(EXEEXT)
man: rsync.1 rsyncd.conf.5
install: all
-mkdir -p ${DESTDIR}${bindir}
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
${INSTALLCMD} ${STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
-mkdir -p ${DESTDIR}${mandir}/man1
-mkdir -p ${DESTDIR}${mandir}/man5
${INSTALLMAN} -m 644 $(srcdir)/rsync.1 ${DESTDIR}${mandir}/man1
${INSTALLMAN} -m 644 $(srcdir)/rsyncd.conf.5 ${DESTDIR}${mandir}/man5
install-strip:
$(MAKE) INSTALL_STRIP='-s' install
$(MAKE) STRIP='-s' install
rsync$(EXEEXT): $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
@@ -80,10 +82,7 @@ tls$(EXEEXT): $(TLS_OBJ)
getgroups$(EXEEXT): getgroups.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getgroups.o $(LIBS)
getfsdev$(EXEEXT): getfsdev.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o
TRIMSLASH_OBJ = trimslash.o syscall.o
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
@@ -91,14 +90,26 @@ T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
gen:
cd $(srcdir) && $(MAKE) -f prepare-source.mak gen
# I don't like these rules because CVS can skew the timestamps and
# produce spurious warnings, and also make "make install" fail if the
# source directory can no longer be found. Since we don't rebuild
# automatically they're kind of lame anyhow.
man:
cd $(srcdir) && $(MAKE) -f prepare-source.mak man
#Makefile: Makefile.in configure config.status
# echo "WARNING: You need to run ./config.status --recheck"
# don't actually run autoconf, just issue a warning
#configure: configure.in
# echo "WARNING: you need to rerun autoconf"
$(srcdir)/rsync.1: $(srcdir)/rsync.yo
yodl2man -o $(srcdir)/rsync.1 $(srcdir)/rsync.yo
$(srcdir)/rsyncd.conf.5: $(srcdir)/rsyncd.conf.yo
yodl2man -o $(srcdir)/rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
proto:
cd $(srcdir) && $(MAKE) -f prepare-source.mak proto.h
cat $(srcdir)/*.c $(srcdir)/lib/compat.c | awk -f $(srcdir)/mkproto.awk > $(srcdir)/proto.h
clean: cleantests
rm -f *~ $(OBJS) $(TLS_OBJ) $(CHECK_PROGS) $(CHECK_OBJS)
@@ -135,6 +146,9 @@ test: check
# There seems to be no standard way to specify some variables as
# exported from a Makefile apart from listing them like this.
# TODO: Tests that depend on built test aide programs like tls need to
# know where the build directory is.
# This depends on building rsync; if we need any helper programs it
# should depend on them too.
@@ -143,11 +157,11 @@ test: check
# might lose in the future where POSIX diverges from old sh.
check: all $(CHECK_PROGS)
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh
POSIXLY_CORRECT=1 TOOLDIR=`pwd` rsync_bin=`pwd`/rsync$(EXEEXT) srcdir="$(srcdir)" $(srcdir)/runtests.sh
wildtest.o: wildtest.c lib/wildmatch.c rsync.h
wildtest$(EXEEXT): wildtest.o lib/compat.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ wildtest.o lib/compat.o @BUILD_POPT@ $(LIBS)
wildtest$(EXEEXT): wildtest.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ wildtest.o @BUILD_POPT@ $(LIBS)
# This does *not* depend on building or installing: you can use it to
# check a version installed from a binary or some other source tree,

217
NEWS
View File

@@ -1,158 +1,99 @@
NEWS for rsync 2.6.9 (6 Nov 2006)
Protocol: 29 (unchanged)
Changes since 2.6.8:
NEWS for rsync version 2.5.7:
BUG FIXES:
SECURITY:
- If rsync is interrupted via a handled signal (such as SIGINT), it will
once again clean-up its temp file from the destination dir.
* Fix buffer handling bugs. (Andrew Tridgell, Martin Pool, Paul
Russell, Andrea Barisani)
- Fixed an overzealous sanitizing bug in the handling of the --link-dest,
--copy-dest, and --compare-dest options to a daemon without chroot: if
the copy's destination dir is deeper than the top of the module's path,
these options now accept a safe number of parent-dir (../) references
(since these options are relative to the destination dir). The old code
incorrectly chopped off all "../" prefixes for these options, no matter
how deep the destination directory was in the module's hierarchy.
- Fixed a bug where a deferred info/error/log message could get sent
directly to the sender instead of being handled by rwrite() in the
generator. This fixes an "unexpected tag 3" fatal error, and should
also fix a potential problem where a deferred info/error message from
the receiver might bypass the log file and get sent only to the client
process. (These problems could only affect an rsync daemon that was
receiving files.)
- Fixed a bug when --inplace was combined with a --*-dest option and we
update a file's data using an alternate basis file. The code now
notices that it needs to copy the matching data from the basis file
instead of (wrongly) assuming that it was already present in the file.
- Fixed a bug where using --dry-run with a --*-dest option with a path
relative to a directory that does not yet exist: the affected option
gets its proper path value so that the output of the dry-run is right.
- Fixed a bug in the %f logfile escape when receiving files: the
destination path is now included in the output (e.g. you can now tell
when a user specifies a subdir inside a module).
- If the receiving side fails to create a directory, it will now skip
trying to update everything that is inside that directory.
- If --link-dest is specified with --checksum but without --times, rsync
will now allow a hard-link to be created to a matching link-dest file
even when the file's modify-time doesn't match the server's file.
- The daemon now calls more timezone-using functions prior to doing a
chroot. This should help some C libraries to generate proper timestamps
from inside a chrooted daemon (and to not try to access /etc/timezone
over and over again).
- Fixed a bug in the handling of an absolute --partial-dir=ABS_PATH option:
it now deletes an alternate basis file from the partial-dir that was used
to successfully update a destination file.
- Fixed a bug in the handling of --delete-excluded when using a per-dir
merge file: the merge file is now honored on the receiving side, and
only its unqualified include/exclude commands are ignored (just as is
done for global include/excludes).
- Fixed a recent bug where --delete was not working when transferring from
the root (/) of the filesystem with --relative enabled.
- Fixed a recent bug where an --exclude='*' could affect the root (/) of
the filesystem with --relative enabled.
- When --inplace creates a file, it is now created with owner read/write
permissions (0600) instead of no permissions at all. This avoids a
problem continuing a transfer that was interrupted (since --inplace
will not update a file that has no write permissions).
- If either --remove-source-files or --remove-sent-files is enabled and we
are unable to remove the source file, rsync now outputs an error.
- Fixed a bug in the daemon's "incoming chmod" rule: newly-created
directories no longer get the 'F' (file) rules applied to them.
- Fixed an infinite loop bug when a filter rule was rejected due to being
overly long.
- When the server receives a --partial-dir option from the client, it no
longer runs the client-side code that adds an assumed filter rule (since
the client will be sending us the rules in the usual manner, and they
may have chosen to override the auto-added rule).
NEWS for rsync version 2.5.6, aka the dwd-between-jobs release
Changes since version 2.5.5:
ENHANCEMENTS:
- Added the --log-file=FILE and --log-file-format=FORMAT options. These
can be used to tell any rsync to output what it is doing to a log file.
They work with a client rsync, a non-daemon server rsync (see the man
page for instructions), and also allows the overriding of rsyncd.conf
settings when starting a daemon.
* The --delete-after option now implies --delete. (Wayne Davison)
- The --log-format option was renamed to be --out-format to avoid confusing
it with affecting the log-file output. (The old option remains as an
alias for the new to preserve backward compatibility.)
* The --suffix option can now be used with --backup-dir. (Michael
Zimmerman)
- Made "log file" and "syslog facility" settable on a per-module basis in
the daemon's config file.
* Combining "::" syntax with the -rsh/-e option now uses the
specified remote-shell as a transport to talk to a (newly-spawned)
server-daemon. This allows someone to use daemon features, such
as modules, over a secure protocol, such as ssh. (JD Paul)
- Added the --remove-source-files option as a replacement for the (now
deprecated) --remove-sent-files option. This new option removes all
non-dirs from the source directories, even if the file was already
up-to-date. This fixes a problem where interrupting an rsync that
was using --remove-sent-files and restarting it could leave behind
a file that the earlier rsync synchronized, but didn't get to remove.
(The deprecated --remove-sent-files is still understood for now, and
still behaves in the same way as before.)
* The rsync:// syntax for daemon connections is now accepted in the
destination field.
- Added the option --no-motd to suppress the message-of-the-day output
from a daemon when doing a copy. (See the manpage for a caveat.)
* If the file name given to --include-from or --exclude-from is "-",
rsync will read from standard input. (J.W. Schultz)
- Added a new environment variable to the pre-/post-xfer exec commands (in
the daemon's config file): RSYNC_PID. This value will be the same in
both the pre- and post-xfer commands, so it can be used if the pre-xfer
command wants to cache some arg/request info for the post-xfer command.
* New option --link-dest which is like --compare-dest except that
unchanged files are hard-linked in to the destination directory.
(J.W. Schultz)
* Don't report an error if an excluded file disappears during an
rsync run. (Eugene Chupriyanov and Bo Kersey)
* Added .svn to --cvs-exclude list to support subversion. (Jon
Middleton)
* Properly support IPv6 addresses in the rsyncd.conf "hosts allow"
and "hosts deny" fields. (Hideaki Yoshifuji)
* Changed exclude file handling to permit DOS or MAC style line
terminations. (J.W. Schultz)
* Ignore errors from chmod when -p/-a/--preserve-perms is not set.
(Dave Dykstra)
BUG FIXES:
* Fix "forward name lookup failed" errors on AIX 4.3.3. (John
L. Allen, Martin Pool)
* Generate each file's rolling-checksum data as we send it, not
in a separate (memory-eating) pass before hand. This prevents
timeout errors on really large files. (Stefan Nehlsen)
* Fix compilation on Tru64. (Albert Chin, Zoong Pham)
* Better handling of some client-server errors. (Martin Pool)
* Fixed a crash that would occur when sending a list of files that
contains a duplicate name (if it sorts to the end of the file
list) and using --delete. (Wayne Davison)
* Fixed the file-name duplicate-removal code when dealing with multiple
dups in a row. (Wayne Davison)
* Fixed a bug that caused rsync to lose the exit status of its child
processes and sometimes return an exit code of 0 instead of showing
an error. (David R. Staples, Dave Dykstra)
* Fixed bug in --copy-unsafe-links that caused it to be completely
broken. (Dave Dykstra)
* Prevent infinite recursion in cleanup code under certain circumstances.
(Sviatoslav Sviridov and Marc Espie)
* Fixed a bug that prevented rsync from creating intervening directories
when --relative-paths/-R is set. (Craig Barratt)
* Prevent "Connection reset by peer" messages from Cygwin. (Randy O'Meara)
INTERNAL:
- Did a code audit using IBM's code-checker program and made several
changes, including: replacing most of the strcpy() and sprintf()
calls with strlcpy(), snprintf(), and memcpy(), adding a 0-value to
an enum that had been intermingling a literal 0 with the defined enum
values, silencing some uninitialized memory checks, marking some
functions with a "noreturn" attribute, and changing an "if" that
could never succeed on some platforms into a pre-processor directive
that conditionally compiles the code.
* Many code cleanups and improved internal documentation. (Martin
Pool, Nelson Beebe)
- Fixed a potential bug in f_name_cmp() when both the args are a
top-level "." dir (which doesn't happen in normal operations).
* Portability fixes. (Dave Dykstra and Wayne Davison)
- Changed exit_cleanup() so that it can never return instead of exit.
The old code might return if it found the exit_cleanup() function
was being called recursively. The new code is segmented so that
any recursive calls move on to the next step of the exit-processing.
* More test cases. (Martin Pool)
- The macro WIFEXITED(stat) will now be defined if the OS didn't already
define it.
* Some test-case fixes. (Brian Poole, Wayne Davison)
DEVELOPER RELATED:
* Updated included popt to the latest vendor drop, version 1.6.4.
(Jos Backus)
- The acls.diff and xattrs.diff patches have received a bunch of work to
make them much closer to being acceptable in the main distribution.
The xattrs patch also has some preliminary Mac OS X compatibility code
that allows Macs and non-macs to exchange extended attributes.
- A new diff in the patches dir, fake-root.diff, allows rsync to
maintain a backup hierarchy with full owner, group, and device info
without actually running as root. It does this using a special
extended attribute, so it depends on xattrs.diff (which depends on
acls.diff).
- The rsync.yo and rsyncd.conf.yo files have been updated to work
better with the latest yodl 2.x releases.
- Updated config.guess and config.sub to their 2006-02-23 version.
- Updated various files to include the latest FSF address and to have
consistent opening comments.
* Updated config.guess and config.sub to latest versions; this
means rsync should build on more platforms. (Paul Green)

1927
OLDNEWS
View File

File diff suppressed because it is too large Load Diff

17
README
View File

@@ -1,7 +1,7 @@
WHAT IS RSYNC?
--------------
rsync is a replacement for scp/rcp that has many more features.
rsync is a replacement for rcp that has many more features.
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
@@ -29,9 +29,9 @@ and see the manual for more information.
SETUP
-----
Rsync normally uses ssh or rsh for communication. It does not need to
Rsync normally uses rsh or ssh for communication. It does not need to
be setuid and requires no special privileges for installation. You
must, however, have a working ssh or rsh system. Using ssh is
must, however, have a working rsh or ssh system. Using ssh is
recommended for its security features.
Alternatively, rsync can run in `daemon' mode, listening on a socket.
@@ -77,7 +77,7 @@ BUG REPORTS
If you have web access then please look at
http://rsync.samba.org/
http://rsync.samba.org
That page contains links to the current bug list, and information on
how to report a bug well. You might also like to try searching the
@@ -86,11 +86,9 @@ mailing list archives at
http://mail-archive.com/rsync@lists.samba.org/
To send a bug report, follow the instructions on the bug-tracking
page of the web site.
Please send bug reports to
If you don't have web access, email your bug report to
rsync@lists.samba.org.
rsync@lists.samba.org
CVS TREE
@@ -105,7 +103,8 @@ recent version of cvs then use the following commands:
cvs -d :pserver:cvs@pserver.samba.org:/cvsroot co rsync
Look at the cvs documentation for more details.
Look at the cvs documentation, or http://samba.org/cvs.html, for more
details.
COPYRIGHT

924
TODO
View File

File diff suppressed because it is too large Load Diff

135
access.c
View File

@@ -1,30 +1,32 @@
/*
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.
*/
/*
* Routines to authenticate access to a daemon (hosts allow/deny).
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2004, 2005 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
hosts allow/deny code for rsync
*/
#include "rsync.h"
static int match_hostname(char *host, char *tok)
{
if (!host || !*host)
return 0;
if (!host || !*host) return 0;
return wildmatch(tok, host);
}
@@ -32,16 +34,16 @@ static int match_binary(char *b1, char *b2, char *mask, int addrlen)
{
int i;
for (i = 0; i < addrlen; i++) {
if ((b1[i] ^ b2[i]) & mask[i])
for (i=0; i<addrlen; i++) {
if ((b1[i]^b2[i])&mask[i]) {
return 0;
}
}
return 1;
}
static void make_mask(char *mask, int plen, int addrlen)
{
static void make_mask(char *mask, int plen, int addrlen) {
int w, b;
w = plen >> 3;
@@ -73,26 +75,22 @@ static int match_address(char *addr, char *tok)
char *a = NULL, *t = NULL;
unsigned int len;
if (!addr || !*addr)
return 0;
if (!addr || !*addr) return 0;
p = strchr(tok,'/');
if (p) {
*p = '\0';
len = p - tok;
} else
}
else
len = strlen(tok);
/* Fail quietly if tok is a hostname (not an address) */
if (strspn(tok, ".0123456789") != len
#ifdef INET6
&& strchr(tok, ':') == NULL
&& !strchr(tok, ':')
#endif
) {
if (p)
*p = '/';
return 0;
}
) return 0;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
@@ -101,18 +99,17 @@ static int match_address(char *addr, char *tok)
hints.ai_flags = AI_NUMERICHOST;
#endif
if (getaddrinfo(addr, NULL, &hints, &resa) != 0) {
if (p)
*p = '/';
return 0;
}
gai = getaddrinfo(addr, NULL, &hints, &resa);
if (gai) return 0;
gai = getaddrinfo(tok, NULL, &hints, &rest);
if (p)
*p++ = '/';
if (gai != 0) {
rprintf(FLOG, "error matching address %s: %s\n",
tok, gai_strerror(gai));
if (gai) {
rprintf(FERROR,
"error matching address %s: %s\n",
tok,
gai_strerror(gai));
freeaddrinfo(resa);
return 0;
}
@@ -155,7 +152,7 @@ static int match_address(char *addr, char *tok)
}
#endif
default:
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
rprintf(FERROR,"unknown family %u\n", rest->ai_family);
ret = 0;
goto out;
}
@@ -172,14 +169,14 @@ static int match_address(char *addr, char *tok)
#ifdef HAVE_STRTOL
bits = strtol(p, &ep, 10);
if (!*p || *ep) {
rprintf(FLOG, "malformed mask in %s\n", tok);
rprintf(FERROR,"malformed mask in %s\n", tok);
ret = 0;
goto out;
}
#else
for (pp = (unsigned char *)p; *pp; pp++) {
if (!isascii(*pp) || !isdigit(*pp)) {
rprintf(FLOG, "malformed mask in %s\n", tok);
rprintf(FERROR,"malformed mask in %s\n", tok);
ret = 0;
goto out;
}
@@ -191,7 +188,7 @@ static int match_address(char *addr, char *tok)
goto out;
}
if (bits < 0 || bits > (addrlen << 3)) {
rprintf(FLOG, "malformed mask in %s\n", tok);
rprintf(FERROR,"malformed mask in %s\n", tok);
ret = 0;
goto out;
}
@@ -205,7 +202,7 @@ static int match_address(char *addr, char *tok)
ret = match_binary(a, t, mask, addrlen);
out:
out:
freeaddrinfo(resa);
freeaddrinfo(rest);
return ret;
@@ -216,14 +213,12 @@ static int access_match(char *list, char *addr, char *host)
char *tok;
char *list2 = strdup(list);
if (!list2)
out_of_memory("access_match");
if (!list2) out_of_memory("access_match");
strlower(list2);
if (host)
strlower(host);
if (host) strlower(host);
for (tok = strtok(list2, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
for (tok=strtok(list2," ,\t"); tok; tok=strtok(NULL," ,\t")) {
if (match_hostname(host, tok) || match_address(addr, tok)) {
free(list2);
return 1;
@@ -236,25 +231,29 @@ static int access_match(char *list, char *addr, char *host)
int allow_access(char *addr, char *host, char *allow_list, char *deny_list)
{
if (allow_list && !*allow_list)
allow_list = NULL;
if (deny_list && !*deny_list)
deny_list = NULL;
/* if theres no deny list and no allow list then allow access */
if ((!deny_list || !*deny_list) && (!allow_list || !*allow_list))
return 1;
/* If we match an allow-list item, we always allow access. */
if (allow_list) {
if (access_match(allow_list, addr, host))
return 1;
/* For an allow-list w/o a deny-list, disallow non-matches. */
if (!deny_list)
return 0;
}
/* if there is an allow list but no deny list then allow only hosts
on the allow list */
if (!deny_list || !*deny_list)
return(access_match(allow_list, addr, host));
/* If we match a deny-list item (and got past any allow-list
* items), we always disallow access. */
if (deny_list && access_match(deny_list, addr, host))
/* if theres a deny list but no allow list then allow
all hosts not on the deny list */
if (!allow_list || !*allow_list)
return(!access_match(deny_list,addr,host));
/* if there are both type of list then allow all hosts on the
allow list */
if (access_match(allow_list,addr,host))
return 1;
/* if there are both type of list and it's not on the allow then
allow it if its not on the deny */
if (access_match(deny_list,addr,host))
return 0;
/* Allow all other access. */
return 1;
}

11
acconfig.h Normal file
View File

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

View File

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

395
backup.c
View File

@@ -1,280 +1,301 @@
/*
* Backup handling code.
*
* Copyright (C) 1999 Andrew Tridgell
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Copyright (C) Andrew Tridgell 1999
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* backup handling code */
#include "rsync.h"
extern int verbose;
extern int backup_suffix_len;
extern int backup_dir_len;
extern unsigned int backup_dir_remainder;
extern char backup_dir_buf[MAXPATHLEN];
extern char *backup_suffix;
extern char *backup_dir;
extern int am_root;
extern int preserve_devices;
extern int preserve_specials;
extern int preserve_links;
extern int safe_symlinks;
/* make a complete pathname for backup file */
char *get_backup_name(char *fname)
{
if (backup_dir) {
if (stringjoin(backup_dir_buf + backup_dir_len, backup_dir_remainder,
fname, backup_suffix, NULL) < backup_dir_remainder)
return backup_dir_buf;
} else {
if (stringjoin(backup_dir_buf, MAXPATHLEN,
fname, backup_suffix, NULL) < MAXPATHLEN)
return backup_dir_buf;
}
rprintf(FERROR, "backup filename too long\n");
return NULL;
}
extern int preserve_hard_links;
/* simple backup creates a backup with a suffix in the same directory */
static int make_simple_backup(char *fname)
{
int rename_errno;
char *fnamebak = get_backup_name(fname);
if (!fnamebak)
return 0;
while (1) {
if (do_rename(fname, fnamebak) == 0) {
if (verbose > 1) {
rprintf(FINFO, "backed up %s to %s\n",
fname, fnamebak);
}
break;
}
/* cygwin (at least version b19) reports EINVAL */
if (errno == ENOENT || errno == EINVAL)
break;
rename_errno = errno;
if (errno == EISDIR && do_rmdir(fnamebak) == 0)
continue;
if (errno == ENOTDIR && do_unlink(fnamebak) == 0)
continue;
rsyserr(FERROR, rename_errno, "rename %s to backup %s",
fname, fnamebak);
errno = rename_errno;
char fnamebak[MAXPATHLEN];
if (strlen(fname) + backup_suffix_len > MAXPATHLEN-1) {
rprintf(FERROR, "backup filename too long\n");
return 0;
}
snprintf(fnamebak, sizeof(fnamebak), "%s%s", fname, backup_suffix);
if (do_rename(fname, fnamebak) != 0) {
/* cygwin (at least version b19) reports EINVAL */
if (errno != ENOENT && errno != EINVAL) {
rsyserr(FERROR, errno, "rename %s to backup %s", fname, fnamebak);
return 0;
}
} else if (verbose > 1) {
rprintf(FINFO, "backed up %s to %s\n", fname, fnamebak);
}
return 1;
}
/* recursively make a directory path */
static int make_dir(char *name, int mask)
{
char newdir [MAXPATHLEN];
char *p, *d;
/* copy pathname over, look for last '/' */
for (p = d = newdir; *name; *d++ = *name++)
if (*name == '/')
p = d;
if (p == newdir)
return 0;
*p = 0;
/* make the new directory, if that fails then make its parent */
while (do_mkdir (newdir, mask) != 0)
if ((errno != ENOENT) || !make_dir (newdir, mask))
return 0;
return 1;
} /* make_dir */
/****************************************************************************
Create a directory given an absolute path, perms based upon another directory
path
****************************************************************************/
static int make_bak_dir(char *fullpath)
static int make_bak_dir(char *fname, char *bak_path)
{
STRUCT_STAT st;
char *rel = fullpath + backup_dir_len;
char *end = rel + strlen(rel);
char *p = end;
STRUCT_STAT *st2;
char fullpath[MAXPATHLEN];
extern int orig_umask;
char *p;
char *q;
while (strncmp(fullpath, "./", 2) == 0)
fullpath += 2;
while(strncmp(bak_path, "./", 2) == 0) bak_path += 2;
/* Try to find an existing dir, starting from the deepest dir. */
while (1) {
if (--p == fullpath) {
p += strlen(p);
goto failure;
}
if (*p == '/') {
*p = '\0';
if (mkdir_defmode(fullpath) == 0)
break;
if (errno != ENOENT) {
rsyserr(FERROR, errno,
"make_bak_dir mkdir %s failed",
full_fname(fullpath));
goto failure;
}
}
if(bak_path[strlen(bak_path)-1] != '/') {
snprintf(fullpath, sizeof(fullpath), "%s/", bak_path);
} else {
snprintf(fullpath, sizeof(fullpath), "%s", bak_path);
}
p = fullpath;
q = &fullpath[strlen(fullpath)]; /* End of bak_path string */
strcat(fullpath, fname);
/* Make all the dirs that we didn't find on the way here. */
while (1) {
if (p >= rel) {
/* Try to transfer the directory settings of the
* actual dir that the files are coming from. */
if (do_stat(rel, &st) < 0) {
rsyserr(FERROR, errno,
"make_bak_dir stat %s failed",
full_fname(rel));
} else {
do_lchown(fullpath, st.st_uid, st.st_gid);
do_chmod(fullpath, st.st_mode);
/* Make the directories */
while ((p = strchr(p, '/'))) {
*p = 0;
if(do_lstat(fullpath, &st) != 0) {
do_mkdir(fullpath, 0777 & ~orig_umask);
if(p>q) {
if(do_lstat(q, &st) != 0) {
rprintf(FERROR, "make_bak_dir stat %s failed: %s\n",
full_fname(fullpath), strerror(errno));
} else {
st2 = &st;
set_modtime(fullpath, st2->st_mtime);
if(do_lchown(fullpath, st2->st_uid, st2->st_gid) != 0) {
rprintf(FERROR, "make_bak_dir chown %s failed: %s\n",
full_fname(fullpath), strerror(errno));
}
if(do_chmod(fullpath, st2->st_mode) != 0) {
rprintf(FERROR, "make_bak_dir failed to set permissions on %s: %s\n",
full_fname(fullpath), strerror(errno));
}
}
}
}
*p = '/';
p += strlen(p);
if (p == end)
break;
if (mkdir_defmode(fullpath) < 0) {
rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed",
full_fname(fullpath));
goto failure;
}
p++;
}
return 0;
failure:
while (p != end) {
*p = '/';
p += strlen(p);
}
return -1;
}
/* robustly move a file, creating new directory structures if necessary */
static int robust_move(char *src, char *dst)
{
if (robust_rename(src, dst, NULL, 0755) < 0
&& (errno != ENOENT || make_bak_dir(dst) < 0
|| robust_rename(src, dst, NULL, 0755) < 0))
return -1;
return 0;
}
int keep_trying = 4;
int keep_path_extfs = 0;
int failed;
while (keep_trying) {
if (keep_path_extfs) {
failed = copy_file(src, dst, 0755);
if (!failed) {
do_unlink(src);
}
} else {
failed = robust_rename (src, dst);
}
if (failed) {
if (verbose > 2)
rprintf (FERROR, "robust_move failed: %s(%d)\n",
strerror (errno), errno);
switch (errno) {
/* external filesystem */
case EXDEV:
keep_path_extfs = 1;
keep_trying--;
break;
/* no directory to write to */
case ENOENT:
make_dir(dst, 0700);
keep_trying--;
break;
default:
keep_trying = 0;
} /* switch */
} else
keep_trying = 0;
} /* while */
return (!failed);
} /* robust_move */
/* If we have a --backup-dir, then we get here from make_backup().
* We will move the file to be deleted into a parallel directory tree. */
/* if we have a backup_dir, then we get here from make_backup().
We will move the file to be deleted into a parallel directory tree */
static int keep_backup(char *fname)
{
static int initialised;
char keep_name [MAXPATHLEN];
STRUCT_STAT st;
struct file_struct *file;
char *buf;
int kept = 0;
int ret_code;
if (!initialised) {
if (backup_dir_len && backup_dir[backup_dir_len - 1] == '/')
backup_dir[--backup_dir_len] = '\0';
if (verbose > 0)
rprintf (FINFO, "backup_dir is %s\n", backup_dir);
initialised = 1;
}
/* return if no file to keep */
if (do_lstat(fname, &st) < 0)
return 1;
#if SUPPORT_LINKS
if (do_lstat (fname, &st)) return 1;
#else
if (do_stat (fname, &st)) return 1;
#endif
if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
return 1; /* the file could have disappeared */
file = make_file(fname, NULL, NO_EXCLUDES);
if (!(buf = get_backup_name(fname)))
/* the file could have disappeared */
if (!file) return 1;
/* make a complete pathname for backup file */
if (backup_dir_len+strlen(fname)+backup_suffix_len > MAXPATHLEN-1) {
rprintf (FERROR, "keep_backup filename too long\n");
return 0;
}
snprintf(keep_name, sizeof (keep_name), "%s/%s%s",
backup_dir, fname, backup_suffix);
#ifdef HAVE_MKNOD
/* Check to see if this is a device file, or link */
if ((am_root && preserve_devices && IS_DEVICE(file->mode))
|| (preserve_specials && IS_SPECIAL(file->mode))) {
do_unlink(buf);
if (do_mknod(buf, file->mode, file->u.rdev) < 0
&& (errno != ENOENT || make_bak_dir(buf) < 0
|| do_mknod(buf, file->mode, file->u.rdev) < 0)) {
rsyserr(FERROR, errno, "mknod %s failed",
full_fname(buf));
} else if (verbose > 2) {
rprintf(FINFO, "make_backup: DEVICE %s successful.\n",
fname);
if(IS_DEVICE(file->mode)) {
if(am_root && preserve_devices) {
make_bak_dir(fname, backup_dir);
if(do_mknod(keep_name, file->mode, file->rdev) != 0) {
rprintf(FERROR, "mknod %s failed: %s\n",
full_fname(keep_name), strerror(errno));
} else if(verbose>2) {
rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname);
}
}
kept = 1;
do_unlink(fname);
}
#endif
if (!kept && S_ISDIR(file->mode)) {
if(!kept && S_ISDIR(file->mode)) {
/* make an empty directory */
if (do_mkdir(buf, file->mode) < 0
&& (errno != ENOENT || make_bak_dir(buf) < 0
|| do_mkdir(buf, file->mode) < 0)) {
rsyserr(FINFO, errno, "mkdir %s failed",
full_fname(buf));
}
make_bak_dir(fname, backup_dir);
do_mkdir(keep_name, file->mode);
ret_code = do_rmdir(fname);
if (verbose > 2) {
if(verbose>2) {
rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
full_fname(fname), ret_code);
}
kept = 1;
}
#ifdef SUPPORT_LINKS
if (!kept && preserve_links && S_ISLNK(file->mode)) {
if (safe_symlinks && unsafe_symlink(file->u.link, buf)) {
#if SUPPORT_LINKS
if(!kept && preserve_links && S_ISLNK(file->mode)) {
extern int safe_symlinks;
if (safe_symlinks && unsafe_symlink(file->link, keep_name)) {
if (verbose) {
rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
full_fname(buf), file->u.link);
full_fname(keep_name), file->link);
}
kept = 1;
} else {
do_unlink(buf);
if (do_symlink(file->u.link, buf) < 0
&& (errno != ENOENT || make_bak_dir(buf) < 0
|| do_symlink(file->u.link, buf) < 0)) {
rsyserr(FERROR, errno, "link %s -> \"%s\"",
full_fname(buf),
file->u.link);
}
do_unlink(fname);
kept = 1;
}
make_bak_dir(fname, backup_dir);
if(do_symlink(file->link, keep_name) != 0) {
rprintf(FERROR, "link %s -> %s : %s\n",
full_fname(keep_name), file->link, strerror(errno));
}
do_unlink(fname);
kept = 1;
}
#endif
if(!kept && preserve_hard_links && check_hard_link(file)) {
if(verbose > 1)
rprintf(FINFO, "%s is a hard link\n", f_name(file));
}
if (!kept && !S_ISREG(file->mode)) {
if(!kept && !S_ISREG(file->mode)) {
rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
fname);
return 1;
fname);
}
/* move to keep tree if a file */
if (!kept) {
if (robust_move(fname, buf) != 0) {
rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
full_fname(fname), buf);
} else if (st.st_nlink > 1) {
/* If someone has hard-linked the file into the backup
* dir, rename() might return success but do nothing! */
robust_unlink(fname); /* Just in case... */
if(!kept) {
if (!robust_move (fname, keep_name)) {
rprintf(FERROR, "keep_backup failed: %s -> \"%s\": %s\n",
full_fname(fname), keep_name, strerror(errno));
}
}
set_file_attrs(buf, file, NULL, 0);
free(file);
set_perms (keep_name, file, NULL, 0);
free_file (file);
free (file);
if (verbose > 1) {
rprintf(FINFO, "backed up %s to %s\n",
fname, buf);
}
if (verbose > 1)
rprintf (FINFO, "keep_backup %s -> %s\n", fname, keep_name);
return 1;
}
} /* keep_backup */
/* main backup switch routine */
int make_backup(char *fname)
{
if (backup_dir)
return keep_backup(fname);
return make_simple_backup(fname);
return (keep_backup(fname));
else
return (make_simple_backup(fname));
}

786
batch.c
View File

@@ -1,231 +1,605 @@
/*
* Support for the batch-file options.
*
* Copyright (C) 1999 Weiss
* Copyright (C) 2004 Chris Shoemaker
* Copyright (C) 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* -*- c-file-style: "linux" -*-
Weiss 1/1999
Batch utilities for rsync.
*/
#include "rsync.h"
#include "zlib/zlib.h"
#include <time.h>
extern int eol_nulls;
extern int recurse;
extern int xfer_dirs;
extern int preserve_links;
extern int preserve_hard_links;
extern int preserve_devices;
extern int preserve_uid;
extern int preserve_gid;
extern int always_checksum;
extern int do_compression;
extern int def_compress_level;
extern int protocol_version;
extern char *batch_name;
extern char *batch_prefix;
extern struct filter_list_struct filter_list;
struct file_list *batch_flist;
static int tweaked_compress_level;
static char rsync_flist_file[] = ".rsync_flist";
static char rsync_csums_file[] = ".rsync_csums";
static char rsync_delta_file[] = ".rsync_delta";
static char rsync_argvs_file[] = ".rsync_argvs";
static int *flag_ptr[] = {
&recurse, /* 0 */
&preserve_uid, /* 1 */
&preserve_gid, /* 2 */
&preserve_links, /* 3 */
&preserve_devices, /* 4 */
&preserve_hard_links, /* 5 */
&always_checksum, /* 6 */
&xfer_dirs, /* 7 (protocol 29) */
&tweaked_compress_level,/* 8 (protocol 29) */
NULL
};
static int fdb;
static int fdb_delta;
static int fdb_open;
static int fdb_close;
static char *flag_name[] = {
"--recurse (-r)",
"--owner (-o)",
"--group (-g)",
"--links (-l)",
"--devices (-D)",
"--hard-links (-H)",
"--checksum (-c)",
"--dirs (-d)",
"--compress (-z)",
NULL
};
void write_stream_flags(int fd)
void write_batch_flist_file(char *buff, int bytes_to_write)
{
int i, flags;
char filename[MAXPATHLEN];
#if Z_DEFAULT_COMPRESSION == -1
tweaked_compress_level = do_compression ? def_compress_level + 2 : 0;
#else
#error internal logic error! Fix def_compress_level logic above and below too!
#endif
if (fdb_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_flist_file, sizeof(filename));
/* Start the batch file with a bitmap of data-stream-affecting
* flags. */
if (protocol_version < 29)
flag_ptr[7] = NULL;
for (i = 0, flags = 0; flag_ptr[i]; i++) {
if (*flag_ptr[i])
flags |= 1 << i;
}
write_int(fd, flags);
}
void read_stream_flags(int fd)
{
int i, flags;
if (protocol_version < 29)
flag_ptr[7] = NULL;
for (i = 0, flags = read_int(fd); flag_ptr[i]; i++) {
int set = flags & (1 << i) ? 1 : 0;
if (*flag_ptr[i] != set) {
if (verbose) {
rprintf(FINFO,
"%sing the %s option to match the batchfile.\n",
set ? "Sett" : "Clear", flag_name[i]);
}
*flag_ptr[i] = set;
/*
* Open batch flist file for writing;
* create it if it doesn't exist
*/
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
}
if (protocol_version < 29) {
if (recurse)
xfer_dirs |= 1;
else if (xfer_dirs < 2)
xfer_dirs = 0;
fdb_open = 0;
}
if (tweaked_compress_level == 0 || tweaked_compress_level == 2)
do_compression = 0;
else {
do_compression = 1;
def_compress_level = tweaked_compress_level - 2;
}
}
/* Write buffer to batch flist file */
static void write_arg(int fd, char *arg)
{
char *x, *s;
if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
write(fd, arg, x - arg + 1);
arg += x - arg + 1;
}
if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
write(fd, "'", 1);
for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) {
write(fd, s, x - s + 1);
write(fd, "'", 1);
}
write(fd, s, strlen(s));
write(fd, "'", 1);
return;
}
write(fd, arg, strlen(arg));
}
static void write_filter_rules(int fd)
{
struct filter_struct *ent;
write_sbuf(fd, " <<'#E#'\n");
for (ent = filter_list.head; ent; ent = ent->next) {
unsigned int plen;
char *p = get_rule_prefix(ent->match_flags, "- ", 0, &plen);
write_buf(fd, p, plen);
write_sbuf(fd, ent->pattern);
if (ent->match_flags & MATCHFLG_DIRECTORY)
write_byte(fd, '/');
write_byte(fd, eol_nulls ? 0 : '\n');
}
if (eol_nulls)
write_sbuf(fd, ";\n");
write_sbuf(fd, "#E#");
}
/* This routine tries to write out an equivalent --read-batch command
* given the user's --write-batch args. However, it doesn't really
* understand most of the options, so it uses some overly simple
* heuristics to munge the command line into something that will
* (hopefully) work. */
void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
{
int fd, i, len;
char *p, filename[MAXPATHLEN];
stringjoin(filename, sizeof filename,
batch_name, ".sh", NULL);
fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IEXEC);
if (fd < 0) {
rsyserr(FERROR, errno, "Batch file %s open error",
filename);
if (write(fdb, buff, bytes_to_write) == -1) {
rprintf(FERROR, "Batch file %s write error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
/* Write argvs info to BATCH.sh file */
write_arg(fd, argv[0]);
if (filter_list.head) {
if (protocol_version >= 29)
write_sbuf(fd, " --filter=._-");
else
write_sbuf(fd, " --exclude-from=-");
if (fdb_close) {
close(fdb);
}
for (i = 1; i < argc - file_arg_cnt; i++) {
p = argv[i];
if (strncmp(p, "--files-from", 12) == 0
|| strncmp(p, "--filter", 8) == 0
|| strncmp(p, "--include", 9) == 0
|| strncmp(p, "--exclude", 9) == 0) {
if (strchr(p, '=') == NULL)
i++;
continue;
}
void write_batch_flist_info(int flist_count, struct file_struct **fptr)
{
int i;
int bytes_to_write;
/* Write flist info to batch file */
bytes_to_write =
sizeof(unsigned) +
sizeof(time_t) +
sizeof(OFF_T) +
sizeof(mode_t) +
sizeof(INO64_T) +
sizeof(DEV64_T) +
sizeof(DEV64_T) +
sizeof(uid_t) +
sizeof(gid_t);
fdb_open = 1;
fdb_close = 0;
for (i = 0; i < flist_count; i++) {
write_batch_flist_file((char *) fptr[i], bytes_to_write);
write_char_bufs(fptr[i]->basename);
write_char_bufs(fptr[i]->dirname);
write_char_bufs(fptr[i]->basedir);
write_char_bufs(fptr[i]->link);
if (i == flist_count - 1) {
fdb_close = 1;
}
if (strcmp(p, "-f") == 0) {
i++;
continue;
}
write(fd, " ", 1);
if (strncmp(p, "--write-batch", len = 13) == 0
|| strncmp(p, "--only-write-batch", len = 18) == 0) {
write(fd, "--read-batch", 12);
if (p[len] == '=') {
write(fd, "=", 1);
write_arg(fd, p + len + 1);
}
write_char_bufs(fptr[i]->sum);
}
}
void write_char_bufs(char *buf)
{
/* Write the size of the string which will follow */
char b[4];
SIVAL(b, 0, buf != NULL ? strlen(buf) : 0);
write_batch_flist_file(b, sizeof(int));
/* Write the string if there is one */
if (buf != NULL) {
write_batch_flist_file(buf, strlen(buf));
}
}
void write_batch_argvs_file(int argc, char *argv[])
{
int fdb;
int i;
char buff[256]; /* XXX */
char buff2[MAXPATHLEN + 6];
char filename[MAXPATHLEN];
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_argvs_file, sizeof(filename));
/*
* Open batch argvs file for writing;
* create it if it doesn't exist
*/
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE | S_IEXEC);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
buff[0] = '\0';
/* Write argvs info to batch file */
for (i = 0; i < argc; ++i) {
if (i == argc - 2) /* Skip source directory on cmdline */
continue;
/*
* FIXME:
* I think directly manipulating argv[] is probably bogus
*/
if (!strncmp(argv[i], "--write-batch",
strlen("--write-batch"))) {
/* Safer to change it here than script */
/*
* Change to --read-batch=prefix
* to get ready for remote
*/
strlcat(buff, "--read-batch=", sizeof(buff));
strlcat(buff, batch_prefix, sizeof(buff));
} else
write_arg(fd, p);
if (i == argc - 1) {
snprintf(buff2, sizeof(buff2), "${1:-%s}", argv[i]);
strlcat(buff, buff2, sizeof(buff));
}
else {
strlcat(buff, argv[i], sizeof(buff));
}
if (i < (argc - 1)) {
strlcat(buff, " ", sizeof(buff));
}
}
if (!(p = check_for_hostspec(argv[argc - 1], &p, &i)))
p = argv[argc - 1];
write(fd, " ${1:-", 6);
write_arg(fd, p);
write_byte(fd, '}');
if (filter_list.head)
write_filter_rules(fd);
if (write(fd, "\n", 1) != 1 || close(fd) < 0) {
rsyserr(FERROR, errno, "Batch file %s write error",
filename);
strlcat(buff, "\n", sizeof(buff));
if (!write(fdb, buff, strlen(buff))) {
rprintf(FERROR, "Batch file %s write error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
close(fdb);
}
struct file_list *create_flist_from_batch(void)
{
unsigned char flags;
fdb_open = 1;
fdb_close = 0;
batch_flist = new(struct file_list);
if (!batch_flist) {
out_of_memory("create_flist_from_batch");
}
batch_flist->count = 0;
batch_flist->malloced = 1000;
batch_flist->files = new_array(struct file_struct *,
batch_flist->malloced);
if (!batch_flist->files) {
out_of_memory("create_flist_from_batch");
}
for (flags = read_batch_flags(); flags; flags = read_batch_flags()) {
int i = batch_flist->count;
if (i >= batch_flist->malloced) {
if (batch_flist->malloced < 1000)
batch_flist->malloced += 1000;
else
batch_flist->malloced *= 2;
batch_flist->files
= realloc_array(batch_flist->files,
struct file_struct *,
batch_flist->malloced);
if (!batch_flist->files)
out_of_memory("create_flist_from_batch");
}
read_batch_flist_info(&batch_flist->files[i]);
batch_flist->files[i]->flags = flags;
batch_flist->count++;
}
return batch_flist;
}
int read_batch_flist_file(char *buff, int len)
{
int bytes_read;
char filename[MAXPATHLEN];
if (fdb_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_flist_file, sizeof(filename));
/* Open batch flist file for reading */
fdb = do_open(filename, O_RDONLY, 0);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Read flist batch file */
switch (bytes_read = read(fdb, buff, len)) {
case -1:
rprintf(FERROR, "Batch file %s read error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
break;
case 0: /* EOF */
close(fdb);
}
return bytes_read;
}
unsigned char read_batch_flags(void)
{
int flags;
if (read_batch_flist_file((char *) &flags, 4)) {
return 1;
} else {
return 0;
}
}
void read_batch_flist_info(struct file_struct **fptr)
{
int int_str_len;
char char_str_len[4];
char buff[256];
struct file_struct *file;
file = new(struct file_struct);
if (!file)
out_of_memory("read_batch_flist_info");
memset((char *) file, 0, sizeof(*file));
*fptr = file;
/*
* Keep these in sync with bytes_to_write assignment
* in write_batch_flist_info()
*/
read_batch_flist_file((char *) &file->modtime, sizeof(time_t));
read_batch_flist_file((char *) &file->length, sizeof(OFF_T));
read_batch_flist_file((char *) &file->mode, sizeof(mode_t));
read_batch_flist_file((char *) &file->inode, sizeof(INO64_T));
read_batch_flist_file((char *) &file->dev, sizeof(DEV64_T));
read_batch_flist_file((char *) &file->rdev, sizeof(DEV64_T));
read_batch_flist_file((char *) &file->uid, sizeof(uid_t));
read_batch_flist_file((char *) &file->gid, sizeof(gid_t));
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file->basename = strdup(buff);
} else {
file->basename = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].dirname = strdup(buff);
} else {
file[0].dirname = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].basedir = strdup(buff);
} else {
file[0].basedir = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].link = strdup(buff);
} else {
file[0].link = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].sum = strdup(buff);
} else {
file[0].sum = NULL;
}
}
void write_batch_csums_file(void *buff, int bytes_to_write)
{
static int fdb_open = 1;
char filename[MAXPATHLEN];
if (fdb_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_csums_file, sizeof(filename));
/*
* Open batch csums file for writing;
* create it if it doesn't exist
*/
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Write buffer to batch csums file */
if (write(fdb, buff, bytes_to_write) == -1) {
rprintf(FERROR, "Batch file %s write error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
}
void close_batch_csums_file(void)
{
close(fdb);
}
/**
* Write csum info to batch file
*
* @todo This will break if s->count is ever larger than maxint. The
* batch code should probably be changed to consistently use the
* variable-length integer routines, which is probably a compatible
* change.
**/
void write_batch_csum_info(int *flist_entry, int flist_count,
struct sum_struct *s)
{
size_t i;
int int_count;
extern int csum_length;
fdb_open = 1;
write_batch_csums_file(flist_entry, sizeof(int));
int_count = s ? (int) s->count : 0;
write_batch_csums_file(&int_count, sizeof int_count);
if (s) {
for (i = 0; i < s->count; i++) {
write_batch_csums_file(&s->sums[i].sum1, sizeof(uint32));
if ((*flist_entry == flist_count - 1)
&& (i == s->count - 1)) {
fdb_close = 1;
}
write_batch_csums_file(s->sums[i].sum2, csum_length);
}
}
}
int read_batch_csums_file(char *buff, int len)
{
static int fdb_open = 1;
int bytes_read;
char filename[MAXPATHLEN];
if (fdb_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_csums_file, sizeof(filename));
/* Open batch flist file for reading */
fdb = do_open(filename, O_RDONLY, 0);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Read csums batch file */
bytes_read = read(fdb, buff, len);
if (bytes_read == -1) {
rprintf(FERROR, "Batch file %s read error: %s\n",
filename, strerror(errno));
close(fdb);
exit_cleanup(1);
}
return bytes_read;
}
void read_batch_csum_info(int flist_entry, struct sum_struct *s,
int *checksums_match)
{
int i;
int file_flist_entry;
int file_chunk_ct;
uint32 file_sum1;
char file_sum2[SUM_LENGTH];
extern int csum_length;
read_batch_csums_file((char *) &file_flist_entry, sizeof(int));
if (file_flist_entry != flist_entry) {
rprintf(FINFO, "file_flist_entry (%d) != flist_entry (%d)\n",
file_flist_entry, flist_entry);
close(fdb);
exit_cleanup(1);
} else {
read_batch_csums_file((char *) &file_chunk_ct,
sizeof(int));
*checksums_match = 1;
for (i = 0; i < file_chunk_ct; i++) {
read_batch_csums_file((char *) &file_sum1,
sizeof(uint32));
read_batch_csums_file(file_sum2, csum_length);
if ((s->sums[i].sum1 != file_sum1) ||
(memcmp(s->sums[i].sum2, file_sum2, csum_length)
!= 0)) {
*checksums_match = 0;
}
} /* end for */
}
}
void write_batch_delta_file(char *buff, int bytes_to_write)
{
static int fdb_delta_open = 1;
char filename[MAXPATHLEN];
if (fdb_delta_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_delta_file, sizeof(filename));
/*
* Open batch delta file for writing;
* create it if it doesn't exist
*/
fdb_delta = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE);
if (fdb_delta == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
fdb_delta_open = 0;
}
/* Write buffer to batch delta file */
if (write(fdb_delta, buff, bytes_to_write) == -1) {
rprintf(FERROR, "Batch file %s write error: %s\n",
filename, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
}
void close_batch_delta_file(void)
{
close(fdb_delta);
}
int read_batch_delta_file(char *buff, int len)
{
static int fdb_delta_open = 1;
int bytes_read;
char filename[MAXPATHLEN];
if (fdb_delta_open) {
/* Set up file extension */
strlcpy(filename, batch_prefix, sizeof(filename));
strlcat(filename, rsync_delta_file, sizeof(filename));
/* Open batch flist file for reading */
fdb_delta = do_open(filename, O_RDONLY, 0);
if (fdb_delta == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
fdb_delta_open = 0;
}
/* Read delta batch file */
bytes_read = read(fdb_delta, buff, len);
if (bytes_read == -1) {
rprintf(FERROR, "Batch file %s read error: %s\n",
filename, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
return bytes_read;
}
void show_flist(int index, struct file_struct **fptr)
{
/* for debugging show_flist(flist->count, flist->files * */
int i;
for (i = 0; i < index; i++) {
rprintf(FINFO, "flist->flags=%#x\n", fptr[i]->flags);
rprintf(FINFO, "flist->modtime=%#lx\n",
(long unsigned) fptr[i]->modtime);
rprintf(FINFO, "flist->length=%.0f\n",
(double) fptr[i]->length);
rprintf(FINFO, "flist->mode=%#o\n", (int) fptr[i]->mode);
rprintf(FINFO, "flist->basename=%s\n", fptr[i]->basename);
if (fptr[i]->dirname)
rprintf(FINFO, "flist->dirname=%s\n",
fptr[i]->dirname);
if (fptr[i]->basedir)
rprintf(FINFO, "flist->basedir=%s\n",
fptr[i]->basedir);
}
}
void show_argvs(int argc, char *argv[])
{
/* for debugging * */
int i;
rprintf(FINFO, "BATCH.C:show_argvs,argc=%d\n", argc);
for (i = 0; i < argc; i++) {
/* if (argv[i]) */
rprintf(FINFO, "i=%d,argv[i]=%s\n", i, argv[i]);
}
}

View File

@@ -1,26 +1,25 @@
/*
* Simple byteorder handling.
*
* Copyright (C) 1992-1995 Andrew Tridgell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
simple byteorder handling
Copyright (C) Andrew Tridgell 1992-1995
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.
*/
#undef CAREFUL_ALIGNMENT
/* we know that the x86 can handle misalignment and has the "right"
/* we know that the x86 can handle misalignment and has the "right"
byteorder */
#ifdef __i386__
#define CAREFUL_ALIGNMENT 0

View File

@@ -1,80 +0,0 @@
/*
* End-of-run cleanup helper code used by cleanup.c.
*
* Copyright (C) 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* This is included by cleanup.c multiple times, once for every segement in
* the _exit_cleanup() code. This produces the next "case N:" statement in
* sequence and increments the cleanup_step variable by 1. This ensures that
* our case statements never get out of whack due to added/removed steps. */
#if !defined EXIT_CLEANUP_CASE_0
#define EXIT_CLEANUP_CASE_0
case 0:
#elif !defined EXIT_CLEANUP_CASE_1
#define EXIT_CLEANUP_CASE_1
case 1:
#elif !defined EXIT_CLEANUP_CASE_2
#define EXIT_CLEANUP_CASE_2
case 2:
#elif !defined EXIT_CLEANUP_CASE_3
#define EXIT_CLEANUP_CASE_3
case 3:
#elif !defined EXIT_CLEANUP_CASE_4
#define EXIT_CLEANUP_CASE_4
case 4:
#elif !defined EXIT_CLEANUP_CASE_5
#define EXIT_CLEANUP_CASE_5
case 5:
#elif !defined EXIT_CLEANUP_CASE_6
#define EXIT_CLEANUP_CASE_6
case 6:
#elif !defined EXIT_CLEANUP_CASE_7
#define EXIT_CLEANUP_CASE_7
case 7:
#elif !defined EXIT_CLEANUP_CASE_8
#define EXIT_CLEANUP_CASE_8
case 8:
#elif !defined EXIT_CLEANUP_CASE_9
#define EXIT_CLEANUP_CASE_9
case 9:
#elif !defined EXIT_CLEANUP_CASE_10
#define EXIT_CLEANUP_CASE_10
case 10:
#elif !defined EXIT_CLEANUP_CASE_11
#define EXIT_CLEANUP_CASE_11
case 11:
#elif !defined EXIT_CLEANUP_CASE_12
#define EXIT_CLEANUP_CASE_12
case 12:
#elif !defined EXIT_CLEANUP_CASE_13
#define EXIT_CLEANUP_CASE_13
case 13:
#elif !defined EXIT_CLEANUP_CASE_14
#define EXIT_CLEANUP_CASE_14
case 14:
#elif !defined EXIT_CLEANUP_CASE_15
#define EXIT_CLEANUP_CASE_15
case 15:
#elif !defined EXIT_CLEANUP_CASE_16
#define EXIT_CLEANUP_CASE_16
case 16:
#else
#error Need to add more case statements!
#endif
cleanup_step++;

View File

@@ -1,24 +1,21 @@
/*
* Routines to support checksumming of bytes.
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2004, 2005 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
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"
@@ -26,24 +23,24 @@ int csum_length=2; /* initial value */
#define CSUM_CHUNK 64
extern int checksum_seed;
extern int protocol_version;
int checksum_seed = 0;
extern int remote_version;
/*
a simple 32 bit checksum that can be upadted from either end
(inspired by Mark Adler's Adler-32 checksum)
*/
uint32 get_checksum1(char *buf1, int32 len)
uint32 get_checksum1(char *buf1,int len)
{
int32 i;
int i;
uint32 s1, s2;
schar *buf = (schar *)buf1;
s1 = s2 = 0;
for (i = 0; i < (len-4); i+=4) {
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
10*CHAR_OFFSET;
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
}
for (; i < len; i++) {
s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
@@ -52,43 +49,35 @@ uint32 get_checksum1(char *buf1, int32 len)
}
void get_checksum2(char *buf, int32 len, char *sum)
void get_checksum2(char *buf,int len,char *sum)
{
int32 i;
int i;
static char *buf1;
static int32 len1;
static int len1;
struct mdfour m;
if (len > len1) {
if (buf1)
free(buf1);
if (buf1) free(buf1);
buf1 = new_array(char, len+4);
len1 = len;
if (!buf1)
out_of_memory("get_checksum2");
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);
}
/*
* Prior to version 27 an incorrect MD4 checksum was computed
* by failing to call mdfour_tail() for block sizes that
* are multiples of 64. This is fixed by calling mdfour_update()
* even when there are no more bytes.
*/
if (len - i > 0 || protocol_version >= 27) {
if (len - i > 0) {
mdfour_update(&m, (uchar *)(buf1+i), (len-i));
}
mdfour_result(&m, (uchar *)sum);
}
@@ -99,29 +88,27 @@ void file_checksum(char *fname,char *sum,OFF_T size)
struct map_struct *buf;
int fd;
OFF_T len = size;
char tmpchunk[CSUM_CHUNK];
struct mdfour m;
memset(sum,0,MD4_SUM_LENGTH);
fd = do_open(fname, O_RDONLY, 0);
if (fd == -1)
return;
buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK);
if (fd == -1) return;
buf = map_file(fd,size);
mdfour_begin(&m);
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
CSUM_CHUNK);
memcpy(tmpchunk, map_ptr(buf,i,CSUM_CHUNK), CSUM_CHUNK);
mdfour_update(&m, (uchar *)tmpchunk, CSUM_CHUNK);
}
/* Prior to version 27 an incorrect MD4 checksum was computed
* by failing to call mdfour_tail() for block sizes that
* are multiples of 64. This is fixed by calling mdfour_update()
* even when there are no more bytes. */
if (len - i > 0 || protocol_version >= 27)
mdfour_update(&m, (uchar *)map_ptr(buf, i, len-i), len-i);
if (len - i > 0) {
memcpy(tmpchunk, map_ptr(buf,i,len-i), len-i);
mdfour_update(&m, (uchar *)tmpchunk, (len-i));
}
mdfour_result(&m, (uchar *)sum);
@@ -130,17 +117,27 @@ void file_checksum(char *fname,char *sum,OFF_T size)
}
static int32 sumresidue;
void checksum_init(void)
{
if (remote_version >= 14)
csum_length = 2; /* adaptive */
else
csum_length = SUM_LENGTH;
}
static int sumresidue;
static char sumrbuf[CSUM_CHUNK];
static struct mdfour md;
void sum_init(int seed)
void sum_init(void)
{
char s[4];
mdfour_begin(&md);
sumresidue = 0;
SIVAL(s, 0, seed);
sum_update(s, 4);
sumresidue=0;
SIVAL(s,0,checksum_seed);
sum_update(s,4);
}
/**
@@ -151,37 +148,41 @@ void sum_init(int seed)
* @todo Perhaps get rid of md and just pass in the address each time.
* Very slightly clearer and slower.
**/
void sum_update(char *p, int32 len)
void sum_update(char *p, int len)
{
int i;
if (len + sumresidue < CSUM_CHUNK) {
memcpy(sumrbuf + sumresidue, p, len);
memcpy(sumrbuf+sumresidue, p, len);
sumresidue += len;
return;
}
if (sumresidue) {
int32 i = CSUM_CHUNK - sumresidue;
memcpy(sumrbuf + sumresidue, p, i);
mdfour_update(&md, (uchar *)sumrbuf, CSUM_CHUNK);
i = MIN(CSUM_CHUNK-sumresidue,len);
memcpy(sumrbuf+sumresidue,p,i);
mdfour_update(&md, (uchar *)sumrbuf, (i+sumresidue));
len -= i;
p += i;
}
while (len >= CSUM_CHUNK) {
mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
len -= CSUM_CHUNK;
p += CSUM_CHUNK;
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
memcpy(sumrbuf,p+i,CSUM_CHUNK);
mdfour_update(&md, (uchar *)sumrbuf, CSUM_CHUNK);
}
sumresidue = len;
if (sumresidue)
memcpy(sumrbuf, p, sumresidue);
if (len - i > 0) {
sumresidue = len-i;
memcpy(sumrbuf,p+i,sumresidue);
} else {
sumresidue = 0;
}
}
void sum_end(char *sum)
{
if (sumresidue || protocol_version >= 27)
if (sumresidue) {
mdfour_update(&md, (uchar *)sumrbuf, sumresidue);
}
mdfour_result(&md, (uchar *)sum);
}

226
chmod.c
View File

@@ -1,226 +0,0 @@
/*
* Implement the core of the --chmod option.
*
* Copyright (C) 2002 Scott Howard
* Copyright (C) 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "rsync.h"
extern mode_t orig_umask;
#define FLAG_X_KEEP (1<<0)
#define FLAG_DIRS_ONLY (1<<1)
#define FLAG_FILES_ONLY (1<<2)
struct chmod_mode_struct {
struct chmod_mode_struct *next;
int ModeAND, ModeOR;
char flags;
};
#define CHMOD_ADD 1
#define CHMOD_SUB 2
#define CHMOD_EQ 3
#define STATE_ERROR 0
#define STATE_1ST_HALF 1
#define STATE_2ND_HALF 2
/* Parse a chmod-style argument, and break it down into one or more AND/OR
* pairs in a linked list. We return a pointer to new items on succcess
* (appending the items to the specified list), or NULL on error. */
struct chmod_mode_struct *parse_chmod(const char *modestr,
struct chmod_mode_struct **root_mode_ptr)
{
int state = STATE_1ST_HALF;
int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, flags = 0;
struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL,
*prev_mode = NULL;
while (state != STATE_ERROR) {
if (!*modestr || *modestr == ',') {
int bits;
if (!op) {
state = STATE_ERROR;
break;
}
prev_mode = curr_mode;
curr_mode = new_array(struct chmod_mode_struct, 1);
if (prev_mode)
prev_mode->next = curr_mode;
else
first_mode = curr_mode;
curr_mode->next = NULL;
if (where)
bits = where * what;
else {
where = 0111;
bits = (where * what) & ~orig_umask;
}
switch (op) {
case CHMOD_ADD:
curr_mode->ModeAND = CHMOD_BITS;
curr_mode->ModeOR = bits + topoct;
break;
case CHMOD_SUB:
curr_mode->ModeAND = CHMOD_BITS - bits - topoct;
curr_mode->ModeOR = 0;
break;
case CHMOD_EQ:
curr_mode->ModeAND = CHMOD_BITS - (where * 7) - (topoct ? topbits : 0);
curr_mode->ModeOR = bits + topoct;
break;
}
curr_mode->flags = flags;
if (!*modestr)
break;
modestr++;
state = STATE_1ST_HALF;
where = what = op = topoct = topbits = flags = 0;
}
if (state != STATE_2ND_HALF) {
switch (*modestr) {
case 'D':
if (flags & FLAG_FILES_ONLY)
state = STATE_ERROR;
flags |= FLAG_DIRS_ONLY;
break;
case 'F':
if (flags & FLAG_DIRS_ONLY)
state = STATE_ERROR;
flags |= FLAG_FILES_ONLY;
break;
case 'u':
where |= 0100;
topbits |= 04000;
break;
case 'g':
where |= 0010;
topbits |= 02000;
break;
case 'o':
where |= 0001;
break;
case 'a':
where |= 0111;
break;
case '+':
op = CHMOD_ADD;
state = STATE_2ND_HALF;
break;
case '-':
op = CHMOD_SUB;
state = STATE_2ND_HALF;
break;
case '=':
op = CHMOD_EQ;
state = STATE_2ND_HALF;
break;
default:
state = STATE_ERROR;
break;
}
} else {
switch (*modestr) {
case 'r':
what |= 4;
break;
case 'w':
what |= 2;
break;
case 'X':
flags |= FLAG_X_KEEP;
/* FALL THROUGH */
case 'x':
what |= 1;
break;
case 's':
if (topbits)
topoct |= topbits;
else
topoct = 04000;
break;
case 't':
topoct |= 01000;
break;
default:
state = STATE_ERROR;
break;
}
}
modestr++;
}
if (state == STATE_ERROR) {
free_chmod_mode(first_mode);
return NULL;
}
if (!(curr_mode = *root_mode_ptr))
*root_mode_ptr = first_mode;
else {
while (curr_mode->next)
curr_mode = curr_mode->next;
curr_mode->next = first_mode;
}
return first_mode;
}
/* Takes an existing file permission and a list of AND/OR changes, and
* create a new permissions. */
int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes)
{
int IsX = mode & 0111;
int NonPerm = mode & ~CHMOD_BITS;
for ( ; chmod_modes; chmod_modes = chmod_modes->next) {
if ((chmod_modes->flags & FLAG_DIRS_ONLY) && !S_ISDIR(NonPerm))
continue;
if ((chmod_modes->flags & FLAG_FILES_ONLY) && S_ISDIR(NonPerm))
continue;
mode &= chmod_modes->ModeAND;
if ((chmod_modes->flags & FLAG_X_KEEP) && !IsX && !S_ISDIR(NonPerm))
mode |= chmod_modes->ModeOR & ~0111;
else
mode |= chmod_modes->ModeOR;
}
return mode | NonPerm;
}
/* Free the linked list created by parse_chmod. */
int free_chmod_mode(struct chmod_mode_struct *chmod_modes)
{
struct chmod_mode_struct *next;
while (chmod_modes) {
next = chmod_modes->next;
free(chmod_modes);
chmod_modes = next;
}
return 0;
}

232
cleanup.c
View File

@@ -1,40 +1,26 @@
/*
* End-of-run cleanup routines.
*
* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* -*- c-file-style: "linux" -*-
Copyright (C) 1996-2000 by Andrew Tridgell
Copyright (C) Paul Mackerras 1996
Copyright (C) 2002 by Martin Pool
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rsync.h"
extern int am_server;
extern int am_daemon;
extern int io_error;
extern int keep_partial;
extern int log_got_error;
extern char *partial_dir;
extern char *logfile_name;
#ifdef HAVE_SIGACTION
static struct sigaction sigact;
#endif
/**
* Close all open sockets and files, allowing a (somewhat) graceful
* shutdown() of socket connections. This eliminates the abortive
@@ -46,13 +32,15 @@ void close_all(void)
int max_fd;
int fd;
int ret;
STRUCT_STAT st;
struct stat st;
max_fd = sysconf(_SC_OPEN_MAX) - 1;
for (fd = max_fd; fd >= 0; fd--) {
if ((ret = do_fstat(fd, &st)) == 0) {
if (is_a_socket(fd))
ret = fstat(fd,&st);
if (fstat(fd,&st) == 0) {
if (is_a_socket(fd)) {
ret = shutdown(fd, 2);
}
ret = close(fd);
}
}
@@ -77,13 +65,15 @@ void close_all(void)
* --partial is selected. We need to ensure that the partial file is
* kept if any real data has been transferred.
**/
int cleanup_got_literal = 0;
int cleanup_got_literal=0;
static char *cleanup_fname;
static char *cleanup_new_fname;
static struct file_struct *cleanup_file;
static int cleanup_fd_r, cleanup_fd_w;
static pid_t cleanup_pid = 0;
static int cleanup_fd1, cleanup_fd2;
static struct map_struct *cleanup_buf;
static int cleanup_pid = 0;
extern int io_error;
pid_t cleanup_child_pid = -1;
@@ -92,132 +82,88 @@ pid_t cleanup_child_pid = -1;
*
* @param code one of the RERR_* codes from errcode.h.
**/
NORETURN void _exit_cleanup(int code, const char *file, int line)
void _exit_cleanup(int code, const char *file, int line)
{
static int cleanup_step = 0;
static int exit_code = 0;
static int unmodified_code = 0;
int ocode = code;
extern int keep_partial;
extern int log_got_error;
static int inside_cleanup = 0;
SIGACTION(SIGUSR1, SIG_IGN);
SIGACTION(SIGUSR2, SIG_IGN);
if (inside_cleanup > 10) {
/* prevent the occasional infinite recursion */
return;
}
inside_cleanup++;
if (exit_code) /* Preserve first error code when recursing. */
code = exit_code;
signal(SIGUSR1, SIG_IGN);
signal(SIGUSR2, SIG_IGN);
/* Some of our actions might cause a recursive call back here, so we
* keep track of where we are in the cleanup and never repeat a step. */
switch (cleanup_step) {
#include "case_N.h" /* case 0: cleanup_step++; */
if (verbose > 3)
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
code, file, line);
exit_code = unmodified_code = code;
if (verbose > 3) {
rprintf(FINFO,
"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
code, file, line);
if (cleanup_child_pid != -1) {
int status;
if (waitpid(cleanup_child_pid, &status, WNOHANG) == cleanup_child_pid) {
status = WEXITSTATUS(status);
if (status > code) code = status;
}
/* FALLTHROUGH */
#include "case_N.h"
if (cleanup_child_pid != -1) {
int status;
int pid = wait_process(cleanup_child_pid, &status, WNOHANG);
if (pid == cleanup_child_pid) {
status = WEXITSTATUS(status);
if (status > code)
code = exit_code = status;
}
}
/* FALLTHROUGH */
#include "case_N.h"
if (cleanup_got_literal && cleanup_fname && cleanup_new_fname
&& keep_partial && handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) {
char *fname = cleanup_fname;
cleanup_fname = NULL;
if (cleanup_fd_r != -1)
close(cleanup_fd_r);
if (cleanup_fd_w != -1) {
flush_write_file(cleanup_fd_w);
close(cleanup_fd_w);
}
finish_transfer(cleanup_new_fname, fname, NULL,
cleanup_file, 0, !partial_dir);
}
/* FALLTHROUGH */
#include "case_N.h"
io_flush(FULL_FLUSH);
/* FALLTHROUGH */
#include "case_N.h"
if (cleanup_fname)
do_unlink(cleanup_fname);
if (code)
kill_all(SIGUSR1);
if (cleanup_pid && cleanup_pid == getpid()) {
char *pidf = lp_pid_file();
if (pidf && *pidf)
unlink(lp_pid_file());
}
if (code == 0) {
if (io_error & IOERR_DEL_LIMIT)
code = exit_code = RERR_DEL_LIMIT;
if (io_error & IOERR_VANISHED)
code = exit_code = RERR_VANISHED;
if (io_error & IOERR_GENERAL || log_got_error)
code = exit_code = RERR_PARTIAL;
}
if (code || am_daemon || (logfile_name && (am_server || !verbose)))
log_exit(code, file, line);
/* FALLTHROUGH */
#include "case_N.h"
if (verbose > 2) {
rprintf(FINFO,
"_exit_cleanup(code=%d, file=%s, line=%d): "
"about to call exit(%d)\n",
unmodified_code, file, line, code);
}
/* FALLTHROUGH */
#include "case_N.h"
close_all();
/* FALLTHROUGH */
default:
break;
}
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 == 0 && (io_error || log_got_error)) {
code = RERR_PARTIAL;
}
if (code) log_exit(code, file, line);
if (verbose > 2)
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
ocode, file, line, code);
close_all();
exit(code);
}
void cleanup_disable(void)
{
cleanup_fname = cleanup_new_fname = NULL;
cleanup_fname = NULL;
cleanup_got_literal = 0;
}
void cleanup_set(char *fnametmp, char *fname, struct file_struct *file,
int fd_r, int fd_w)
struct map_struct *buf, int fd1, int fd2)
{
cleanup_fname = fnametmp;
cleanup_new_fname = fname; /* can be NULL on a partial-dir failure */
cleanup_new_fname = fname;
cleanup_file = file;
cleanup_fd_r = fd_r;
cleanup_fd_w = fd_w;
cleanup_buf = buf;
cleanup_fd1 = fd1;
cleanup_fd2 = fd2;
}
void cleanup_set_pid(pid_t pid)
void cleanup_set_pid(int pid)
{
cleanup_pid = pid;
}

View File

@@ -1,63 +1,71 @@
/*
/* -*- c-file-style: "linux" -*-
rsync -- fast file replication program
Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* @file clientname.c
*
* Functions for looking up the remote name or addr of a socket.
*
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2002, 2003, 2004 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* This file is now converted to use the new-style getaddrinfo()
* interface, which supports IPv6 but is also supported on recent
* IPv4-only machines. On systems that don't have that interface, we
* emulate it using the KAME implementation.
*/
**/
#include "rsync.h"
static const char default_name[] = "UNKNOWN";
extern int am_daemon;
extern int am_server;
/**
* Return the IP addr of the client as a string
* Return the IP addr of the client as a string
**/
char *client_addr(int fd)
{
static char addr_buf[100];
static int initialised;
struct sockaddr_storage ss;
socklen_t length = sizeof ss;
char *ssh_info, *p;
char *ssh_client, *p;
int len;
static char addr_buf[100];
static int initialised;
if (initialised)
return addr_buf;
if (initialised) return addr_buf;
initialised = 1;
if (am_server) { /* daemon over --rsh mode */
strlcpy(addr_buf, "0.0.0.0", sizeof addr_buf);
if ((ssh_info = getenv("SSH_CONNECTION")) != NULL
|| (ssh_info = getenv("SSH_CLIENT")) != NULL
|| (ssh_info = getenv("SSH2_CLIENT")) != NULL) {
strlcpy(addr_buf, ssh_info, sizeof addr_buf);
/* Truncate the value to just the IP address. */
if ((p = strchr(addr_buf, ' ')) != NULL)
*p = '\0';
if (am_server) {
/* daemon over --rsh mode */
strcpy(addr_buf, "0.0.0.0");
if ((ssh_client = getenv("SSH_CLIENT")) != NULL) {
/* truncate SSH_CLIENT to just IP address */
p = strchr(ssh_client, ' ');
if (p) {
len = MIN((unsigned int) (p - ssh_client),
sizeof(addr_buf) - 1);
strncpy(addr_buf, ssh_client, len);
*(addr_buf + len) = '\0';
}
}
} else {
client_sockaddr(fd, &ss, &length);
@@ -93,58 +101,58 @@ char *client_name(int fd)
static char name_buf[100];
static char port_buf[100];
static int initialised;
struct sockaddr_storage ss;
struct sockaddr_storage ss, *ssp;
struct sockaddr_in sin;
#ifdef INET6
struct sockaddr_in6 sin6;
#endif
socklen_t ss_len;
if (initialised)
return name_buf;
if (initialised) return name_buf;
strlcpy(name_buf, default_name, sizeof name_buf);
strcpy(name_buf, default_name);
initialised = 1;
memset(&ss, 0, sizeof ss);
if (am_server) {
/* daemon over --rsh mode */
if (am_server) { /* daemon over --rsh mode */
char *addr = client_addr(fd);
struct addrinfo hint, *answer;
int err;
memset(&hint, 0, sizeof hint);
#ifdef AI_NUMERICHOST
hint.ai_flags = AI_NUMERICHOST;
#endif
hint.ai_socktype = SOCK_STREAM;
if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
rprintf(FLOG, "malformed address %s: %s\n",
addr, gai_strerror(err));
return name_buf;
}
switch (answer->ai_family) {
case AF_INET:
ss_len = sizeof (struct sockaddr_in);
memcpy(&ss, answer->ai_addr, ss_len);
break;
#ifdef INET6
case AF_INET6:
ss_len = sizeof (struct sockaddr_in6);
memcpy(&ss, answer->ai_addr, ss_len);
break;
#endif
default:
exit_cleanup(RERR_SOCKETIO);
int dots = 0;
char *p;
for (p = addr; *p && (dots <= 3); p++) {
if (*p == '.')
dots++;
}
freeaddrinfo(answer);
if (dots > 3) {
/* more than 4 parts to IP address, must be ipv6 */
ssp = (struct sockaddr_storage *) &sin6;
ss_len = sizeof sin6;
memset(ssp, 0, ss_len);
inet_pton(AF_INET6, addr, &sin6.sin6_addr);
sin6.sin6_family = AF_INET6;
} else
#endif
{
ssp = (struct sockaddr_storage *) &sin;
ss_len = sizeof sin;
memset(ssp, 0, ss_len);
inet_pton(AF_INET, addr, &sin.sin_addr);
sin.sin_family = AF_INET;
}
} else {
ss_len = sizeof ss;
ssp = &ss;
client_sockaddr(fd, &ss, &ss_len);
}
if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
port_buf, sizeof port_buf) == 0)
check_name(fd, &ss, name_buf, sizeof name_buf);
if (!lookup_name(fd, ssp, ss_len, name_buf, sizeof name_buf,
port_buf, sizeof port_buf))
check_name(fd, ssp, name_buf);
return name_buf;
}
@@ -161,16 +169,17 @@ void client_sockaddr(int fd,
struct sockaddr_storage *ss,
socklen_t *ss_len)
{
memset(ss, 0, sizeof *ss);
memset(ss, 0, sizeof(*ss));
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
/* FIXME: Can we really not continue? */
rsyserr(FLOG, errno, "getpeername on fd%d failed", fd);
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
fd, strerror(errno));
exit_cleanup(RERR_SOCKETIO);
}
#ifdef INET6
if (get_sockaddr_family(ss) == AF_INET6 &&
if (get_sockaddr_family(ss) == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
/* OK, so ss is in the IPv6 family, but it is really
* an IPv4 address: something like
@@ -181,12 +190,12 @@ void client_sockaddr(int fd,
struct sockaddr_in6 sin6;
struct sockaddr_in *sin;
memcpy(&sin6, ss, sizeof sin6);
memcpy(&sin6, ss, sizeof(sin6));
sin = (struct sockaddr_in *)ss;
memset(sin, 0, sizeof *sin);
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
*ss_len = sizeof (struct sockaddr_in);
#ifdef HAVE_SOCKADDR_IN_LEN
*ss_len = sizeof(struct sockaddr_in);
#ifdef HAVE_SOCKADDR_LEN
sin->sin_len = *ss_len;
#endif
sin->sin_port = sin6.sin6_port;
@@ -195,8 +204,8 @@ void client_sockaddr(int fd,
* (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
* to be present in the Linux headers. */
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
sizeof sin->sin_addr);
}
sizeof(sin->sin_addr));
}
#endif
}
@@ -208,20 +217,21 @@ void client_sockaddr(int fd,
**/
int lookup_name(int fd, const struct sockaddr_storage *ss,
socklen_t ss_len,
char *name_buf, size_t name_buf_size,
char *port_buf, size_t port_buf_size)
char *name_buf, size_t name_buf_len,
char *port_buf, size_t port_buf_len)
{
int name_err;
/* reverse lookup */
name_err = getnameinfo((struct sockaddr *) ss, ss_len,
name_buf, name_buf_size,
port_buf, port_buf_size,
name_buf, name_buf_len,
port_buf, port_buf_len,
NI_NAMEREQD | NI_NUMERICSERV);
if (name_err != 0) {
strlcpy(name_buf, default_name, name_buf_size);
rprintf(FLOG, "name lookup failed for %s: %s\n",
client_addr(fd), gai_strerror(name_err));
strcpy(name_buf, default_name);
rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
client_addr(fd),
gai_strerror(name_err));
return name_err;
}
@@ -240,9 +250,10 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
{
int ss_family = get_sockaddr_family(ss);
const char fn[] = "compare_addrinfo_sockaddr";
if (ai->ai_family != ss_family) {
rprintf(FLOG, "%s: response family %d != %d\n",
rprintf(FERROR,
"%s: response family %d != %d\n",
fn, ai->ai_family, ss_family);
return 1;
}
@@ -253,20 +264,20 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
sin1 = (const struct sockaddr_in *) ss;
sin2 = (const struct sockaddr_in *) ai->ai_addr;
return memcmp(&sin1->sin_addr, &sin2->sin_addr,
sizeof sin1->sin_addr);
}
#ifdef INET6
if (ss_family == AF_INET6) {
else if (ss_family == AF_INET6) {
const struct sockaddr_in6 *sin1, *sin2;
sin1 = (const struct sockaddr_in6 *) ss;
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
if (ai->ai_addrlen < sizeof(struct sockaddr_in6)) {
rprintf(FERROR,
"%s: too short sockaddr_in6; length=%d\n",
fn, ai->ai_addrlen);
return 1;
}
@@ -282,9 +293,10 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
return 0;
}
#endif /* INET6 */
/* don't know */
return 1;
else {
/* don't know */
return 1;
}
}
@@ -300,24 +312,26 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
**/
int check_name(int fd,
const struct sockaddr_storage *ss,
char *name_buf, size_t name_buf_size)
char *name_buf)
{
struct addrinfo hints, *res, *res0;
int error;
int ss_family = get_sockaddr_family(ss);
memset(&hints, 0, sizeof hints);
memset(&hints, 0, sizeof(hints));
hints.ai_family = ss_family;
hints.ai_flags = AI_CANONNAME;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(name_buf, NULL, &hints, &res0);
if (error) {
rprintf(FLOG, "forward name lookup for %s failed: %s\n",
rprintf(FERROR,
RSYNC_NAME ": forward name lookup for %s failed: %s\n",
name_buf, gai_strerror(error));
strlcpy(name_buf, default_name, name_buf_size);
strcpy(name_buf, default_name);
return error;
}
/* Given all these results, we expect that one of them will be
* the same as ss. The comparison is a bit complicated. */
for (res = res0; res; res = res->ai_next) {
@@ -328,17 +342,23 @@ int check_name(int fd,
if (!res0) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FLOG, "no known address for \"%s\": "
"spoofed address?\n", name_buf);
strlcpy(name_buf, default_name, name_buf_size);
rprintf(FERROR, RSYNC_NAME
": no known address for \"%s\": "
"spoofed address?\n",
name_buf);
strcpy(name_buf, default_name);
} else if (res == NULL) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FLOG, "%s is not a known address for \"%s\": "
"spoofed address?\n", client_addr(fd), name_buf);
strlcpy(name_buf, default_name, name_buf_size);
rprintf(FERROR, RSYNC_NAME
": %s is not a known address for \"%s\": "
"spoofed address?\n",
client_addr(fd),
name_buf);
strcpy(name_buf, default_name);
}
freeaddrinfo(res0);
return 0;
}

View File

File diff suppressed because it is too large Load Diff

119
compat.c
View File

@@ -1,54 +1,63 @@
/*
/*
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.
*/
/**
* @file compat.c
*
* Compatibility routines for older rsync protocol versions.
*
* Copyright (C) Andrew Tridgell 1996
* Copyright (C) Paul Mackerras 1996
* Copyright (C) 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
**/
#include "rsync.h"
int remote_protocol = 0;
extern int verbose;
extern int am_server;
extern int inplace;
extern int fuzzy_basis;
extern int read_batch;
extern int preserve_links;
extern int preserve_perms;
extern int preserve_devices;
extern int preserve_uid;
extern int preserve_gid;
extern int preserve_times;
extern int always_checksum;
extern int checksum_seed;
extern int basis_dir_cnt;
extern int prune_empty_dirs;
extern int protocol_version;
extern char *dest_option;
extern int verbose;
extern int read_batch;
extern int write_batch;
void setup_protocol(int f_out,int f_in)
{
if (remote_protocol == 0) {
if (!read_batch)
if (am_server) {
remote_protocol = read_int(f_in);
write_int(f_out, protocol_version);
remote_protocol = read_int(f_in);
} else {
write_int(f_out, protocol_version);
remote_protocol = read_int(f_in);
}
if (protocol_version > remote_protocol)
protocol_version = remote_protocol;
}
if (read_batch && remote_protocol > protocol_version) {
rprintf(FERROR, "The protocol version in the batch file is too new (%d > %d).\n",
remote_protocol, protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
if (verbose > 3) {
rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n",
@@ -56,7 +65,7 @@ void setup_protocol(int f_out,int f_in)
}
if (remote_protocol < MIN_PROTOCOL_VERSION
|| remote_protocol > MAX_PROTOCOL_VERSION) {
rprintf(FERROR,"protocol version mismatch -- is your shell clean?\n");
rprintf(FERROR,"protocol version mismatch - is your shell clean?\n");
rprintf(FERROR,"(see the rsync man page for an explanation)\n");
exit_cleanup(RERR_PROTOCOL);
}
@@ -75,44 +84,12 @@ void setup_protocol(int f_out,int f_in)
exit_cleanup(RERR_PROTOCOL);
}
if (protocol_version < 29) {
if (fuzzy_basis) {
rprintf(FERROR,
"--fuzzy requires protocol 29 or higher"
" (negotiated %d).\n",
protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
if (basis_dir_cnt && inplace) {
rprintf(FERROR,
"%s with --inplace requires protocol 29 or higher"
" (negotiated %d).\n",
dest_option, protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
if (basis_dir_cnt > 1) {
rprintf(FERROR,
"Using more than one %s option requires protocol"
" 29 or higher (negotiated %d).\n",
dest_option, protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
if (prune_empty_dirs) {
rprintf(FERROR,
"--prune-empty-dirs requires protocol 29 or higher"
" (negotiated %d).\n",
protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
}
if (am_server) {
if (!checksum_seed)
if (read_batch || write_batch)
checksum_seed = 32761;
else
checksum_seed = time(NULL);
write_int(f_out, checksum_seed);
write_int(f_out,checksum_seed);
} else {
checksum_seed = read_int(f_in);
}

745
config.guess vendored
View File

File diff suppressed because it is too large Load Diff

258
config.sub vendored
View File

@@ -1,10 +1,9 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
# Inc.
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
timestamp='2006-07-02'
timestamp='2003-01-22'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
@@ -22,15 +21,14 @@ timestamp='2006-07-02'
#
# 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., 51 Franklin Street - Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# 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.
# Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry.
#
@@ -72,7 +70,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
@@ -85,11 +83,11 @@ Try \`$me --help' for more information."
while test $# -gt 0 ; do
case $1 in
--time-stamp | --time* | -t )
echo "$timestamp" ; exit ;;
echo "$timestamp" ; exit 0 ;;
--version | -v )
echo "$version" ; exit ;;
echo "$version" ; exit 0 ;;
--help | --h* | -h )
echo "$usage"; exit ;;
echo "$usage"; exit 0 ;;
-- ) # Stop option processing
shift; break ;;
- ) # Use stdin as input.
@@ -101,7 +99,7 @@ while test $# -gt 0 ; do
*local*)
# First pass through any local machine types.
echo $1
exit ;;
exit 0;;
* )
break ;;
@@ -120,9 +118,7 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
@@ -148,7 +144,7 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-apple | -axis | -knuth | -cray)
-apple | -axis)
os=
basic_machine=$1
;;
@@ -173,10 +169,6 @@ case $os in
-hiux*)
os=-hiuxwe2
;;
-sco6)
os=-sco5v6
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco5)
os=-sco3.2v5
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@@ -193,10 +185,6 @@ case $os in
# Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco5v6*)
# Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco*)
os=-sco3.2v2
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@@ -240,17 +228,14 @@ case $basic_machine in
| a29k \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
| bfin \
| c4x | clipper \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
| clipper \
| d10v | d30v | dlx | dsp16xx \
| fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
| m32c | m32r | m32rle | m68000 | m68k | m88k \
| maxq | mb | microblaze | mcore \
| ip2k \
| m32r | m68000 | m68k | m88k | mcore \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
@@ -259,32 +244,27 @@ case $basic_machine in
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
| mips64vr5900 | mips64vr5900el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa64 | mipsisa64el \
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
| mt \
| msp430 \
| nios | nios2 \
| ns16k | ns32k \
| or32 \
| openrisc | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \
| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
| spu | strongarm \
| tahoe | thumb | tic4x | tic80 | tron \
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
| strongarm \
| tahoe | thumb | tic80 | tron \
| v850 | v850e \
| we32k \
| x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
| x86 | xscale | xstormy16 | xtensa \
| z8k)
basic_machine=$basic_machine-unknown
;;
@@ -295,9 +275,6 @@ case $basic_machine in
;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
;;
ms1)
basic_machine=mt-unknown
;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
@@ -317,20 +294,20 @@ case $basic_machine in
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
| clipper-* | craynv-* | cydra-* \
| avr-* \
| bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* \
| clipper-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
| m32c-* | m32r-* | m32rle-* \
| ip2k-* \
| m32r-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | maxq-* | mcore-* \
| m88110-* | m88k-* | mcore-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
@@ -339,36 +316,28 @@ case $basic_machine in
| mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
| mips64vr5900-* | mips64vr5900el-* \
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa64-* | mipsisa64el-* \
| mipsisa64r2-* | mipsisa64r2el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
| mt-* \
| msp430-* \
| nios-* | nios2-* \
| none-* | np1-* | ns16k-* | ns32k-* \
| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \
| romp-* | rs6000-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
| tahoe-* | thumb-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tron-* \
| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
| tahoe-* | thumb-* | tic30-* | tic4x-* | tic54x-* | tic80-* | tron-* \
| v850-* | v850e-* | vax-* \
| we32k-* \
| x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
| xstormy16-* | xtensa-* \
| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
| xtensa-* \
| ymp-* \
| z8k-*)
;;
@@ -388,9 +357,6 @@ case $basic_machine in
basic_machine=a29k-amd
os=-udi
;;
abacus)
basic_machine=abacus-unknown
;;
adobe68k)
basic_machine=m68010-adobe
os=-scout
@@ -405,12 +371,6 @@ case $basic_machine in
basic_machine=a29k-none
os=-bsd
;;
amd64)
basic_machine=x86_64-pc
;;
amd64-*)
basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
amdahl)
basic_machine=580-amdahl
os=-sysv
@@ -470,27 +430,12 @@ case $basic_machine in
basic_machine=j90-cray
os=-unicos
;;
craynv)
basic_machine=craynv-cray
os=-unicosmp
;;
cr16c)
basic_machine=cr16c-unknown
os=-elf
;;
crds | unos)
basic_machine=m68k-crds
;;
crisv32 | crisv32-* | etraxfs*)
basic_machine=crisv32-axis
;;
cris | cris-* | etrax*)
basic_machine=cris-axis
;;
crx)
basic_machine=crx-unknown
os=-elf
;;
da30 | da30-*)
basic_machine=m68k-da30
;;
@@ -513,10 +458,6 @@ case $basic_machine in
basic_machine=m88k-motorola
os=-sysv3
;;
djgpp)
basic_machine=i586-pc
os=-msdosdjgpp
;;
dpx20 | dpx20-*)
basic_machine=rs6000-bull
os=-bosx
@@ -695,6 +636,10 @@ case $basic_machine in
mips3*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
;;
mmix*)
basic_machine=mmix-knuth
os=-mmixware
;;
monitor)
basic_machine=m68k-rom68k
os=-coff
@@ -707,9 +652,6 @@ case $basic_machine in
basic_machine=i386-pc
os=-msdos
;;
ms1-*)
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;;
mvs)
basic_machine=i370-ibm
os=-mvs
@@ -778,6 +720,10 @@ case $basic_machine in
np1)
basic_machine=np1-gould
;;
nv1)
basic_machine=nv1-cray
os=-unicosmp
;;
nsr-tandem)
basic_machine=nsr-tandem
;;
@@ -785,12 +731,9 @@ case $basic_machine in
basic_machine=hppa1.1-oki
os=-proelf
;;
openrisc | openrisc-*)
or32 | or32-*)
basic_machine=or32-unknown
;;
os400)
basic_machine=powerpc-ibm
os=-os400
os=-coff
;;
OSE68000 | ose68000)
basic_machine=m68000-ericsson
@@ -817,36 +760,24 @@ case $basic_machine in
pc532 | pc532-*)
basic_machine=ns32k-pc532
;;
pc98)
basic_machine=i386-pc
;;
pc98-*)
basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentium | p5 | k5 | k6 | nexgen | viac3)
basic_machine=i586-pc
;;
pentiumpro | p6 | 6x86 | athlon | athlon_*)
basic_machine=i686-pc
;;
pentiumii | pentium2 | pentiumiii | pentium3)
pentiumii | pentium2)
basic_machine=i686-pc
;;
pentium4)
basic_machine=i786-pc
;;
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentiumpro-* | p6-* | 6x86-* | athlon-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
pentiumii-* | pentium2-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentium4-*)
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pn)
basic_machine=pn-gould
;;
@@ -879,10 +810,6 @@ case $basic_machine in
basic_machine=i586-unknown
os=-pw32
;;
rdos)
basic_machine=i386-pc
os=-rdos
;;
rom68k)
basic_machine=m68k-rom68k
os=-coff
@@ -909,10 +836,6 @@ case $basic_machine in
sb1el)
basic_machine=mipsisa64sb1el-unknown
;;
sei)
basic_machine=mips-sei
os=-seiux
;;
sequent)
basic_machine=i386-sequent
;;
@@ -920,9 +843,6 @@ case $basic_machine in
basic_machine=sh-hitachi
os=-hms
;;
sh64)
basic_machine=sh64-unknown
;;
sparclite-wrs | simso-wrs)
basic_machine=sparclite-wrs
os=-vxworks
@@ -997,18 +917,14 @@ case $basic_machine in
basic_machine=t90-cray
os=-unicos
;;
tic4x | c4x*)
basic_machine=tic4x-unknown
os=-coff
;;
tic54x | c54x*)
basic_machine=tic54x-unknown
os=-coff
;;
tic55x | c55x*)
basic_machine=tic55x-unknown
os=-coff
;;
tic6x | c6x*)
basic_machine=tic6x-unknown
os=-coff
;;
tx39)
basic_machine=mipstx39-unknown
;;
@@ -1022,10 +938,6 @@ case $basic_machine in
tower | tower-32)
basic_machine=m68k-ncr
;;
tpf)
basic_machine=s390x-ibm
os=-tpf
;;
udi29k)
basic_machine=a29k-amd
os=-udi
@@ -1069,10 +981,6 @@ case $basic_machine in
basic_machine=hppa1.1-winbond
os=-proelf
;;
xbox)
basic_machine=i686-pc
os=-mingw32
;;
xps | xps100)
basic_machine=xps100-honeywell
;;
@@ -1103,9 +1011,6 @@ case $basic_machine in
romp)
basic_machine=romp-ibm
;;
mmix)
basic_machine=mmix-knuth
;;
rs6000)
basic_machine=rs6000-ibm
;;
@@ -1122,10 +1027,13 @@ case $basic_machine in
we32k)
basic_machine=we32k-att
;;
sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele)
basic_machine=sh-unknown
;;
sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
sh64)
basic_machine=sh64-unknown
;;
sparc | sparcv9 | sparcv9b)
basic_machine=sparc-sun
;;
cydra)
@@ -1198,23 +1106,19 @@ case $os in
| -aos* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
| -openbsd* | -solidbsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* \
| -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers*)
| -powermax* | -dnix* | -microbsd*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1232,15 +1136,12 @@ case $os in
os=`echo $os | sed -e 's|nto|nto-qnx|'`
;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
| -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
;;
-mac*)
os=`echo $os | sed -e 's|mac|macos|'`
;;
-linux-dietlibc)
os=-linux-dietlibc
;;
-linux*)
os=`echo $os | sed -e 's|linux|linux-gnu|'`
;;
@@ -1253,9 +1154,6 @@ case $os in
-opened*)
os=-openedition
;;
-os400*)
os=-os400
;;
-wince*)
os=-wince
;;
@@ -1277,9 +1175,6 @@ case $os in
-atheos*)
os=-atheos
;;
-syllable*)
os=-syllable
;;
-386bsd)
os=-bsd
;;
@@ -1302,9 +1197,6 @@ case $os in
-sinix*)
os=-sysv4
;;
-tpf*)
os=-tpf
;;
-triton*)
os=-sysv3
;;
@@ -1338,12 +1230,6 @@ case $os in
-aros*)
os=-aros
;;
-kaos*)
os=-kaos
;;
-zvmoe)
os=-zvmoe
;;
-none)
;;
*)
@@ -1366,9 +1252,6 @@ else
# system, and we'll never get to this point.
case $basic_machine in
spu-*)
os=-elf
;;
*-acorn)
os=-riscix1.2
;;
@@ -1378,9 +1261,6 @@ case $basic_machine in
arm*-semi)
os=-aout
;;
c4x-* | tic4x-*)
os=-coff
;;
# This must come before the *-dec entry.
pdp10-*)
os=-tops20
@@ -1424,15 +1304,9 @@ case $basic_machine in
*-be)
os=-beos
;;
*-haiku)
os=-haiku
;;
*-ibm)
os=-aix
;;
*-knuth)
os=-mmixware
;;
*-wec)
os=-proelf
;;
@@ -1565,15 +1439,9 @@ case $basic_machine in
-mvs* | -opened*)
vendor=ibm
;;
-os400*)
vendor=ibm
;;
-ptx*)
vendor=sequent
;;
-tpf*)
vendor=ibm
;;
-vxsim* | -vxworks* | -windiss*)
vendor=wrs
;;
@@ -1598,7 +1466,7 @@ case $basic_machine in
esac
echo $basic_machine$os
exit
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)

View File

@@ -3,9 +3,9 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT()
AC_CONFIG_SRCDIR([byteorder.h])
AC_CONFIG_HEADER(config.h)
AC_PREREQ(2.59)
AC_PREREQ(2.52)
RSYNC_VERSION=2.6.9
RSYNC_VERSION=2.5.7
AC_SUBST(RSYNC_VERSION)
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
@@ -18,7 +18,6 @@ AC_CANONICAL_TARGET([])
dnl Checks for programs.
AC_PROG_CC
AC_PROG_CPP
AC_PROG_EGREP
AC_PROG_INSTALL
AC_PROG_CC_STDC
AC_SUBST(SHELL)
@@ -26,7 +25,8 @@ AC_SUBST(SHELL)
AC_DEFINE([_GNU_SOURCE], 1,
[Define _GNU_SOURCE so that we get all necessary prototypes])
if test x"$ac_cv_prog_cc_stdc" = x"no"; then
if test "x$ac_cv_prog_cc_stdc" = xno
then
AC_MSG_WARN([rsync requires an ANSI C compiler and you don't seem to have one])
fi
@@ -37,10 +37,12 @@ fi
AC_MSG_CHECKING([whether to include debugging symbols])
AC_ARG_ENABLE(debug,
AC_HELP_STRING([--disable-debug],
[turn off debugging symbols and features]))
AC_HELP_STRING([--enable-debug],
[including debugging symbols and features (default yes)]),
[], [])
if test x"$enable_debug" = x"no"; then
if test x"$enable_debug" = x"no"
then
AC_MSG_RESULT(no)
CFLAGS=${CFLAGS-"-O"}
else
@@ -51,19 +53,25 @@ else
fi
AC_ARG_ENABLE(profile,
AC_HELP_STRING([--enable-profile],
[turn on CPU profiling]))
if test x"$enable_profile" = x"yes"; then
AC_HELP_STRING([--enable-profile],
[turn on CPU profiling (default no)],
[], []))
if test x"$enable_profile" = xyes
then
CFLAGS="$CFLAGS -pg"
fi
# Specifically, this turns on panic_action handling.
AC_ARG_ENABLE(maintainer-mode,
AC_HELP_STRING([--enable-maintainer-mode],
[turn on extra debug features]))
if test x"$enable_maintainer_mode" = x"yes"; then
AC_HELP_STRING([--enable-maintainer-mode],
[turn on extra debug features],
[], []))
if test x"$enable_maintainer_mode" = xyes
then
CFLAGS="$CFLAGS -DMAINTAINER_MODE"
fi
@@ -73,77 +81,40 @@ fi
CFLAGS="$CFLAGS -DHAVE_CONFIG_H"
# If GCC, turn on warnings.
if test x"$GCC" = x"yes"; then
if test "x$GCC" = "xyes"
then
CFLAGS="$CFLAGS -Wall -W"
fi
AC_ARG_WITH(included-popt,
AC_HELP_STRING([--with-included-popt], [use bundled popt library, not from system]))
[ --with-included-popt use bundled popt library, not from system])
AC_ARG_WITH(rsync-path,
AC_HELP_STRING([--with-rsync-path=PATH], [set default --rsync-path to PATH (default: rsync)]),
[ --with-rsync-path=PATH set default --rsync-path to PATH (default: \"rsync\")],
[ RSYNC_PATH="$with_rsync_path" ],
[ RSYNC_PATH="rsync" ])
AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [location of rsync on remote machine])
AC_ARG_WITH(rsyncd-conf,
AC_HELP_STRING([--with-rsyncd-conf=PATH], [set configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]),
[ if test ! -z "$with_rsyncd_conf" ; then
case $with_rsyncd_conf in
yes|no)
RSYNCD_SYSCONF="/etc/rsyncd.conf"
;;
/*)
RSYNCD_SYSCONF="$with_rsyncd_conf"
;;
*)
AC_MSG_ERROR(You must specify an absolute path to --with-rsyncd-conf=PATH)
;;
esac
else
RSYNCD_SYSCONF="/etc/rsyncd.conf"
fi ],
[ RSYNCD_SYSCONF="/etc/rsyncd.conf" ])
AC_DEFINE_UNQUOTED(RSYNCD_SYSCONF, "$RSYNCD_SYSCONF", [location of configuration file for rsync server])
AC_ARG_WITH(rsh,
AC_HELP_STRING([--with-rsh=CMD], [set remote shell command to CMD (default: ssh)]))
AC_HELP_STRING([--with-rsh=CMD], [set rsh command to CMD (default: \"remsh\" or \"rsh\")]))
AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0)
if test x$HAVE_REMSH = x1; then
AC_DEFINE(HAVE_REMSH, 1, [Define to 1 if remote shell is remsh, not rsh])
AC_DEFINE_UNQUOTED(HAVE_REMSH, $HAVE_REMSH, [remote shell is remsh not rsh])
if test x"$with_rsh" != x
then
RSYNC_RSH="$with_rsh"
elif test x"$HAVE_REMSH" = x1
then
RSYNC_RSH="remsh"
else
RSYNC_RSH="rsh"
fi
if test x"$with_rsh" != x; then
RSYNC_RSH="$with_rsh"
else
RSYNC_RSH="ssh"
fi
AC_DEFINE_UNQUOTED(RSYNC_RSH, "$RSYNC_RSH", [default -e command])
AC_ARG_WITH(nobody-group,
AC_HELP_STRING([--with-nobody-group=GROUP],
[set the default unprivileged group (default nobody or nogroup)]),
[ NOBODY_GROUP="$with_nobody_group" ])
if test x"$with_nobody_group" = x; then
AC_MSG_CHECKING([the group for user "nobody"])
if grep '^nobody:' /etc/group >/dev/null 2>&1; then
NOBODY_GROUP=nobody
elif grep '^nogroup:' /etc/group >/dev/null 2>&1; then
NOBODY_GROUP=nogroup
else
NOBODY_GROUP=nobody # test for others?
fi
AC_MSG_RESULT($NOBODY_GROUP)
fi
AC_DEFINE_UNQUOTED(NOBODY_USER, "nobody", [unprivileged user--e.g. nobody])
AC_DEFINE_UNQUOTED(NOBODY_GROUP, "$NOBODY_GROUP", [unprivileged group for unprivileged user])
# arrgh. libc in some old debian version screwed up the largefile
# arrgh. libc in the current debian stable screws up the largefile
# stuff, getting byte range locking wrong
AC_CACHE_CHECK([for broken largefile support],rsync_cv_HAVE_BROKEN_LARGEFILE,[
AC_TRY_RUN([
@@ -153,29 +124,24 @@ AC_TRY_RUN([
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
int main(void)
{
struct flock lock;
int status;
char tpl[32] = "/tmp/locktest.XXXXXX";
int fd = mkstemp(tpl);
if (fd < 0) {
strcpy(tpl, "conftest.dat");
fd = open(tpl, O_CREAT|O_RDWR, 0600);
}
int status;
int fd = open("conftest.dat", O_CREAT|O_RDWR, 0600);
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 1;
lock.l_pid = 0;
fcntl(fd,F_SETLK,&lock);
if (fork() == 0) {
lock.l_start = 1;
_exit(fcntl(fd,F_SETLK,&lock) == 0);
}
wait(&status);
unlink(tpl);
lock.l_start = 1;
exit(fcntl(fd,F_SETLK,&lock) == 0);
}
wait(&status);
unlink("conftest.dat");
exit(WEXITSTATUS(status));
}
],
@@ -188,10 +154,11 @@ ipv6type=unknown
ipv6lib=none
ipv6trylibc=yes
AC_ARG_ENABLE(ipv6,
AC_HELP_STRING([--disable-ipv6],
[don't even try to use IPv6]))
if test x"$enable_ipv6" != x"no"; then
AC_ARG_ENABLE(ipv6,
AC_HELP_STRING([--disable-ipv6], [don't even try to use IPv6]))
if test "x$enable_ipv6" != xno
then
AC_MSG_CHECKING([ipv6 stack type])
for i in inria kame linux-glibc linux-inet6 toshiba v6d zeta; do
case $i in
@@ -213,7 +180,7 @@ yes
#ifdef __KAME__
yes
#endif],
[ipv6type=$i;
[ipv6type=$i;
AC_DEFINE(INET6, 1, [true if you have IPv6])])
;;
linux-glibc)
@@ -280,21 +247,11 @@ yes
AC_SEARCH_LIBS(getaddrinfo, inet6)
fi
dnl Do you want to disable use of locale functions
AC_ARG_ENABLE([locale],
AC_HELP_STRING([--disable-locale],
[turn off locale features]))
AH_TEMPLATE([CONFIG_LOCALE],
[Undefine if you don't want locale features. By default this is defined.])
if test x"$enable_locale" != x"no"; then
AC_DEFINE(CONFIG_LOCALE)
fi
AC_MSG_CHECKING([whether to call shutdown on all sockets])
case $host_os in
*cygwin* ) AC_MSG_RESULT(yes)
AC_DEFINE(SHUTDOWN_ALL_SOCKETS, 1,
[Define to 1 if sockets need to be shutdown])
AC_DEFINE(SHUTDOWN_ALL_SOCKETS, 1,
[Define if sockets need to be shutdown])
;;
* ) AC_MSG_RESULT(no);;
esac
@@ -303,47 +260,19 @@ AC_C_BIGENDIAN
AC_HEADER_DIRENT
AC_HEADER_TIME
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
unistd.h utime.h grp.h compat.h sys/param.h ctype.h sys/wait.h \
sys/ioctl.h sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h \
sys/un.h glob.h mcheck.h arpa/inet.h arpa/nameser.h locale.h \
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h)
AC_HEADER_MAJOR
AC_CACHE_CHECK([if makedev takes 3 args],rsync_cv_MAKEDEV_TAKES_3_ARGS,[
AC_TRY_RUN([
#include <sys/types.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
# if !defined makedev && (defined mkdev || defined _WIN32 || defined __WIN32__)
# define makedev mkdev
# endif
#elif defined MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#endif
int main(void)
{
dev_t dev = makedev(0, 5, 7);
if (major(dev) != 5 || minor(dev) != 7)
exit(1);
return 0;
}
],
rsync_cv_MAKEDEV_TAKES_3_ARGS=yes,rsync_cv_MAKEDEV_TAKES_3_ARGS=no,rsync_cv_MAKEDEV_TAKES_3_ARGS=no)])
if test x"$rsync_cv_MAKEDEV_TAKES_3_ARGS" = x"yes"; then
AC_DEFINE(MAKEDEV_TAKES_3_ARGS, 1, [Define to 1 if makedev() takes 3 args])
fi
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h unistd.h utime.h grp.h)
AC_CHECK_HEADERS(compat.h sys/param.h ctype.h sys/wait.h sys/ioctl.h)
AC_CHECK_HEADERS(sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h sys/un.h)
AC_CHECK_HEADERS(glob.h mcheck.h sys/sysctl.h arpa/inet.h arpa/nameser.h)
AC_CHECK_HEADERS(netdb.h)
AC_CHECK_HEADERS(malloc.h)
AC_CHECK_HEADERS(float.h)
AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(long)
AC_CHECK_SIZEOF(long long)
AC_CHECK_SIZEOF(short)
AC_CHECK_SIZEOF(off_t)
AC_CHECK_SIZEOF(off64_t)
AC_C_INLINE
AC_C_LONG_DOUBLE
AC_TYPE_SIGNAL
AC_TYPE_UID_T
@@ -354,13 +283,14 @@ AC_TYPE_PID_T
AC_TYPE_GETGROUPS
AC_CHECK_MEMBERS([struct stat.st_rdev])
AC_CHECK_TYPE([ino_t], [unsigned])
TYPE_SOCKLEN_T
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, 1, [Define to 1 if errno is declared in errno.h])
AC_DEFINE(HAVE_ERRNO_DECL, 1, [ ])
fi
# The following test taken from the cvs sources
@@ -391,24 +321,20 @@ if test x"$ac_cv_func_connect" = x"no"; then
esac
dnl We can't just call AC_CHECK_FUNCS(connect) here, because the value
dnl has been cached.
if test x"$ac_cv_lib_socket_connect" = x"yes" ||
if test x"$ac_cv_lib_socket_connect" = x"yes" ||
test x"$ac_cv_lib_inet_connect" = x"yes"; then
# ac_cv_func_connect=yes
# don't! it would cause AC_CHECK_FUNC to succeed next time configure is run
AC_DEFINE(HAVE_CONNECT, 1, [Define to 1 if you have the "connect" function])
AC_DEFINE(HAVE_CONNECT, 1, [ ])
fi
fi
AC_SEARCH_LIBS(inet_ntop, resolv)
# Solaris and HP-UX weirdness:
# Search for libiconv_open (not iconv_open) to discover if -liconv is needed!
AC_SEARCH_LIBS(libiconv_open, iconv)
AC_CHECK_LIB(resolv, inet_ntop)
dnl AC_MSG_NOTICE([Looking in libraries: $LIBS])
AC_CHECK_FUNCS(inet_ntop, , [AC_LIBOBJ(lib/inet_ntop)])
AC_CHECK_FUNCS(inet_pton, , [AC_LIBOBJ(lib/inet_pton)])
AC_CHECK_FUNCS(inet_ntop, , AC_LIBOBJ(lib/inet_ntop))
AC_CHECK_FUNCS(inet_pton, , AC_LIBOBJ(lib/inet_pton))
# Irix 6.5 has getaddrinfo but not the corresponding defines, so use
# builtin getaddrinfo if one of the defines don't exist
@@ -420,7 +346,7 @@ AC_CACHE_CHECK([whether defines needed by getaddrinfo exist],
#include <netdb.h>
#ifdef AI_PASSIVE
yes
#endif],
#endif],
rsync_cv_HAVE_GETADDR_DEFINES=yes,
rsync_cv_HAVE_GETADDR_DEFINES=no)])
if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes"; then
@@ -434,39 +360,22 @@ if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes"; then
#include <netdb.h>],[getaddrinfo(NULL, NULL, NULL, NULL);],
[AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_GETADDRINFO, 1,
[Define to 1 if you have the "getaddrinfo" function.])],
[Define if you have the `getaddrinfo' function.])],
[AC_MSG_RESULT([no])
AC_LIBOBJ(lib/getaddrinfo)])])
AC_CHECK_FUNCS(getnameinfo, , [AC_LIBOBJ(lib/getnameinfo)])
AC_CHECK_FUNCS(getnameinfo, , AC_LIBOBJ(lib/getnameinfo))
else
AC_LIBOBJ(lib/getaddrinfo)
AC_LIBOBJ(lib/getnameinfo)
fi
AC_CHECK_MEMBER([struct sockaddr.sa_len],
[ AC_DEFINE(HAVE_SOCKADDR_LEN, 1, [Do we have sockaddr.sa_len?]) ],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
])
AC_CHECK_MEMBER([struct sockaddr_in.sin_len],
[ AC_DEFINE(HAVE_SOCKADDR_IN_LEN, 1, [Do we have sockaddr_in.sin_len?]) ],
AC_CHECK_MEMBER([struct sockaddr.sa_len],
[ AC_DEFINE(HAVE_SOCKADDR_LEN) ],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
])
AC_CHECK_MEMBER([struct sockaddr_un.sun_len],
[ AC_DEFINE(HAVE_SOCKADDR_UN_LEN, 1, [Do we have sockaddr_un.sun_len?]) ],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
])
AC_MSG_CHECKING(struct sockaddr_storage)
@@ -474,12 +383,12 @@ AC_TRY_COMPILE([#include <sys/types.h>
#include <sys/socket.h>],
[struct sockaddr_storage x;],
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1,
[Define to 1 if you have struct sockaddr_storage.] ),
AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1,
[Define if you have strct sockaddr_storage.] ),
AC_MSG_RESULT(no))
AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id],
[ AC_DEFINE(HAVE_SOCKADDR_IN6_SCOPE_ID, 1, [Do we have sockaddr_in6.sin6_scope_id?]) ],
[ AC_DEFINE(HAVE_SOCKADDR_IN6_SCOPE_ID) ],
[],
[
#include <sys/types.h>
@@ -487,27 +396,6 @@ AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id],
#include <netinet/in.h>
])
AC_MSG_CHECKING(struct stat64)
AC_TRY_COMPILE([#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#if STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# if HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
],[struct stat64 st;],
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_STRUCT_STAT64,1,[Define to 1 if you have struct stat64.]),
AC_MSG_RESULT(no))
# if we can't find strcasecmp, look in -lresolv (for Unixware at least)
#
AC_CHECK_FUNCS(strcasecmp)
@@ -517,80 +405,15 @@ fi
dnl At the moment we don't test for a broken memcmp(), because all we
dnl need to do is test for equality, not comparison, and it seems that
dnl every platform has a memcmp that can do at least that.
dnl every platform has a memcmp that can do at least that.
dnl AC_FUNC_MEMCMP
AC_FUNC_UTIME_NULL
AC_FUNC_ALLOCA
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \
memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
strerror putenv iconv_open locale_charset nl_langinfo \
sigaction sigprocmask)
AC_CHECK_FUNCS(getpgrp tcgetpgrp)
if test $ac_cv_func_getpgrp = yes; then
AC_FUNC_GETPGRP
fi
AC_CACHE_CHECK([whether chown() modifies symlinks],rsync_cv_chown_modifies_symlink,[
AC_TRY_RUN([
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdlib.h>
#include <errno.h>
main() {
char const *dangling_symlink = "conftest.dangle";
unlink(dangling_symlink);
if (symlink("conftest.no-such", dangling_symlink) < 0) abort();
if (chown(dangling_symlink, getuid(), getgid()) < 0 && errno == ENOENT) exit(1);
exit(0);
}],
rsync_cv_chown_modifies_symlink=yes,rsync_cv_chown_modifies_symlink=no,rsync_cv_chown_modifies_symlink=no)])
if test $rsync_cv_chown_modifies_symlink = yes; then
AC_DEFINE(CHOWN_MODIFIES_SYMLINK, 1, [Define to 1 if chown modifies symlinks.])
fi
AC_CACHE_CHECK([whether link() can hard-link symlinks],rsync_cv_can_hardlink_symlink,[
AC_TRY_RUN([
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdlib.h>
#include <errno.h>
#define FILENAME "conftest.dangle"
main() {
unlink(FILENAME);
if (symlink("conftest.no-such", FILENAME) < 0) abort();
if (link(FILENAME, FILENAME "2") < 0) exit(1);
exit(0);
}],
rsync_cv_can_hardlink_symlink=yes,rsync_cv_can_hardlink_symlink=no,rsync_cv_can_hardlink_symlink=no)])
if test $rsync_cv_can_hardlink_symlink = yes; then
AC_DEFINE(CAN_HARDLINK_SYMLINK, 1, [Define to 1 if link() can hard-link symlinks.])
fi
AC_CACHE_CHECK([whether link() can hard-link special files],rsync_cv_can_hardlink_special,[
AC_TRY_RUN([
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdlib.h>
#include <errno.h>
#define FILENAME "conftest.fifi"
main() {
unlink(FILENAME);
if (mkfifo(FILENAME, 0777) < 0) abort();
if (link(FILENAME, FILENAME "2") < 0) exit(1);
exit(0);
}],
rsync_cv_can_hardlink_special=yes,rsync_cv_can_hardlink_special=no,rsync_cv_can_hardlink_special=no)])
if test $rsync_cv_can_hardlink_special = yes; then
AC_DEFINE(CAN_HARDLINK_SPECIAL, 1, [Define to 1 if link() can hard-link special files.])
fi
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo)
AC_CHECK_FUNCS(fchmod fstat strchr readlink link utime utimes strftime)
AC_CHECK_FUNCS(memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk)
AC_CHECK_FUNCS(strlcat strlcpy strtol mtrace mallinfo setgroups)
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
AC_TRY_RUN([
@@ -603,15 +426,26 @@ main() {
}],
rsync_cv_HAVE_SOCKETPAIR=yes,rsync_cv_HAVE_SOCKETPAIR=no,rsync_cv_HAVE_SOCKETPAIR=cross)])
if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then
AC_DEFINE(HAVE_SOCKETPAIR, 1, [Define to 1 if you have the "socketpair" function])
AC_DEFINE(HAVE_SOCKETPAIR, 1, [ ])
fi
if test x"$with_included_popt" != x"yes"; then
AC_CACHE_CHECK([for working fnmatch],rsync_cv_HAVE_FNMATCH,[
AC_TRY_RUN([#include <fnmatch.h>
main() { exit((fnmatch("*.o", "x.o", FNM_PATHNAME) == 0 &&
fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME) != 0) ? 0: 1); }],
rsync_cv_HAVE_FNMATCH=yes,rsync_cv_HAVE_FNMATCH=no,rsync_cv_HAVE_FNMATCH=cross)])
if test x"$rsync_cv_HAVE_FNMATCH" = x"yes"; then
AC_DEFINE(HAVE_FNMATCH, 1, [ ])
fi
if test x"$with_included_popt" != x"yes"
then
AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
fi
AC_MSG_CHECKING([whether to use included libpopt])
if test x"$with_included_popt" = x"yes"; then
if test x"$with_included_popt" = x"yes"
then
AC_MSG_RESULT($srcdir/popt)
BUILD_POPT='$(popt_OBJS)'
CFLAGS="$CFLAGS -I$srcdir/popt"
@@ -625,11 +459,39 @@ else
AC_MSG_RESULT(no)
fi
AC_CACHE_CHECK([for unsigned char],rsync_cv_SIGNED_CHAR_OK,[
AC_TRY_COMPILE([],[signed char *s = ""],
rsync_cv_SIGNED_CHAR_OK=yes,rsync_cv_SIGNED_CHAR_OK=no)])
if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then
AC_DEFINE(SIGNED_CHAR_OK, 1, [Define to 1 if "signed char" is a valid type])
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); }],
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, 1, [ ])
fi
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)) 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, 1, [ ])
fi
AC_CACHE_CHECK([for short ino_t],rsync_cv_HAVE_SHORT_INO_T,[
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; }],
rsync_cv_HAVE_SHORT_INO_T=yes,rsync_cv_HAVE_SHORT_INO_T=no,rsync_cv_HAVE_SHORT_INO_T=cross)])
if test x"$rsync_cv_HAVE_SHORT_INO_T" = x"yes"; then
AC_DEFINE(HAVE_SHORT_INO_T, 1, [ ])
fi
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); }],
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, 1, [ ])
fi
AC_CACHE_CHECK([for broken readdir],rsync_cv_HAVE_BROKEN_READDIR,[
@@ -640,32 +502,33 @@ if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 &&
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, 1, [Define to 1 if readdir() is broken])
AC_DEFINE(HAVE_BROKEN_READDIR, 1, [ ])
fi
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; exit(utime("foo.c",&tbuf));],
rsync_cv_HAVE_UTIMBUF=yes,rsync_cv_HAVE_UTIMBUF=no)])
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, 1, [Define to 1 if you have the "struct utimbuf" type])
AC_DEFINE(HAVE_UTIMBUF, 1, [ ])
fi
AC_CACHE_CHECK([if gettimeofday takes tz argument],rsync_cv_HAVE_GETTIMEOFDAY_TZ,[
AC_TRY_COMPILE([#include <sys/time.h>
#include <unistd.h>],
[struct timeval tv; exit(gettimeofday(&tv, NULL));],
rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no)])
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [Define to 1 if gettimeofday() takes a time-zone arg])
AC_TRY_RUN([
#include <sys/time.h>
#include <unistd.h>
main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}],
rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no,rsync_cv_HAVE_GETTIMEOFDAY_TZ=cross)])
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [ ])
fi
AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[
AC_TRY_RUN([
#include <sys/types.h>
#include <stdarg.h>
void foo(const char *format, ...) {
void foo(const char *format, ...) {
va_list ap;
int len;
char buf[5];
@@ -683,7 +546,7 @@ main() { foo("hello"); }
],
rsync_cv_HAVE_C99_VSNPRINTF=yes,rsync_cv_HAVE_C99_VSNPRINTF=no,rsync_cv_HAVE_C99_VSNPRINTF=cross)])
if test x"$rsync_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [Define to 1 if vsprintf has a C99-compatible return value])
AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [ ])
fi
@@ -692,10 +555,10 @@ AC_TRY_RUN([#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
main() {
main() {
struct stat st;
char tpl[20]="/tmp/test.XXXXXX";
int fd = mkstemp(tpl);
char tpl[20]="/tmp/test.XXXXXX";
int fd = mkstemp(tpl);
if (fd == -1) exit(1);
unlink(tpl);
if (fstat(fd, &st) != 0) exit(1);
@@ -706,46 +569,37 @@ rsync_cv_HAVE_SECURE_MKSTEMP=yes,
rsync_cv_HAVE_SECURE_MKSTEMP=no,
rsync_cv_HAVE_SECURE_MKSTEMP=cross)])
if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
case $target_os in
hpux*)
dnl HP-UX has a broken mkstemp() implementation they refuse to fix,
dnl so we noisily skip using it. See HP change request JAGaf34426
dnl for details. (sbonds)
AC_MSG_WARN(Skipping broken HP-UX mkstemp() -- using mktemp() instead)
;;
*)
AC_DEFINE(HAVE_SECURE_MKSTEMP, 1, [Define to 1 if mkstemp() is available and works right])
;;
esac
AC_DEFINE(HAVE_SECURE_MKSTEMP, 1, [ ])
fi
AC_CACHE_CHECK([if mknod creates FIFOs],rsync_cv_MKNOD_CREATES_FIFOS,[
AC_CACHE_CHECK([for broken inet_ntoa],rsync_cv_REPLACE_INET_NTOA,[
AC_TRY_RUN([
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
main() { int rc, ec; char *fn = "fifo-test";
unlink(fn); rc = mknod(fn,S_IFIFO,0600); ec = errno; unlink(fn);
if (rc) {printf("(%d %d) ",rc,ec); return ec;}
return 0;}],
rsync_cv_MKNOD_CREATES_FIFOS=yes,rsync_cv_MKNOD_CREATES_FIFOS=no,rsync_cv_MKNOD_CREATES_FIFOS=cross)])
if test x"$rsync_cv_MKNOD_CREATES_FIFOS" = x"yes"; then
AC_DEFINE(MKNOD_CREATES_FIFOS, 1, [Define to 1 if mknod() can create FIFOs.])
#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(1); }
exit(0);}],
rsync_cv_REPLACE_INET_NTOA=no,rsync_cv_REPLACE_INET_NTOA=yes,rsync_cv_REPLACE_INET_NTOA=cross)])
if test x"$rsync_cv_REPLACE_INET_NTOA" = x"yes"; then
AC_DEFINE(REPLACE_INET_NTOA, 1, [ ])
fi
AC_CACHE_CHECK([if mknod creates sockets],rsync_cv_MKNOD_CREATES_SOCKETS,[
AC_CACHE_CHECK([for broken inet_aton],rsync_cv_REPLACE_INET_ATON,[
AC_TRY_RUN([
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
main() { int rc, ec; char *fn = "sock-test";
unlink(fn); rc = mknod(fn,S_IFSOCK,0600); ec = errno; unlink(fn);
if (rc) {printf("(%d %d) ",rc,ec); return ec;}
return 0;}],
rsync_cv_MKNOD_CREATES_SOCKETS=yes,rsync_cv_MKNOD_CREATES_SOCKETS=no,rsync_cv_MKNOD_CREATES_SOCKETS=cross)])
if test x"$rsync_cv_MKNOD_CREATES_SOCKETS" = x"yes"; then
AC_DEFINE(MKNOD_CREATES_SOCKETS, 1, [Define to 1 if mknod() can create sockets.])
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
main() { struct in_addr ip;
if (inet_aton("example", &ip) == 0) exit(0); exit(1);}],
rsync_cv_REPLACE_INET_ATON=no,rsync_cv_REPLACE_INET_ATON=yes,rsync_cv_REPLACE_INET_ATON=cross)])
if test x"$rsync_cv_REPLACE_INET_ATON" = x"yes"; then
AC_DEFINE(REPLACE_INET_ATON, 1, [ ])
fi
#

View File

@@ -1,25 +1,25 @@
/*
* Support the max connections option.
*
* Copyright (C) 1998 Andrew Tridgell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
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.
*/
/* support the max connections option */
#include "rsync.h"
/****************************************************************************
simple routine to do connection counting
****************************************************************************/
@@ -39,7 +39,7 @@ int claim_connection(char *fname,int max_connections)
/* find a free spot */
for (i=0;i<max_connections;i++) {
if (lock_range(fd, i*4, 4)) return 1;
}
}
/* only interested in open failures */
errno = 0;

View File

@@ -1,32 +1,32 @@
/*
* Error codes returned by rsync.
*
* Copyright (C) 1998-2000 Andrew Tridgell
* Copyright (C) 2003, 2005 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* -*- c-file-style: "linux"; -*-
Copyright (C) 1998-2000 by Andrew Tridgell
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* If you change these, please also update the string mappings in log.c and
* the EXIT VALUES in rsync.yo. */
/*
* error codes returned by rsync. If you change these, please also update the
* string mappings in log.c and the EXIT VALUES in rsync.yo
*/
#define RERR_OK 0
#define RERR_SYNTAX 1 /* syntax or usage error */
#define RERR_PROTOCOL 2 /* protocol incompatibility */
#define RERR_FILESELECT 3 /* errors selecting input/output files, dirs */
#define RERR_UNSUPPORTED 4 /* requested action not supported */
#define RERR_UNSUPPORTED 4 /* requested action not supported */
#define RERR_STARTCLIENT 5 /* error starting client-server protocol */
#define RERR_SOCKETIO 10 /* error in socket IO */
@@ -34,16 +34,11 @@
#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_CRASHED 15 /* sibling crashed */
#define RERR_TERMINATED 16 /* sibling terminated abnormally */
#define RERR_SIGNAL1 19 /* status returned when sent SIGUSR1 */
#define RERR_SIGNAL 20 /* status returned when sent SIGINT, SIGTERM, SIGHUP */
#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_PARTIAL 23 /* partial transfer */
#define RERR_VANISHED 24 /* file(s) vanished on sender side */
#define RERR_DEL_LIMIT 25 /* skipped some deletes due to --max-delete */
#define RERR_TIMEOUT 30 /* timeout in data send/receive */

1484
exclude.c
View File

File diff suppressed because it is too large Load Diff

251
fileio.c
View File

@@ -1,35 +1,30 @@
/*
Copyright (C) Andrew Tridgell 1998
Copyright (C) 2002 by Martin Pool
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* File IO utilities used in rsync.
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
File IO utilities used in rsync
*/
#include "rsync.h"
#ifndef ENODATA
#define ENODATA EAGAIN
#endif
extern int sparse_files;
static char last_byte;
static int last_sparse;
extern int sparse_files;
int sparse_end(int f)
{
@@ -47,8 +42,8 @@ static int write_sparse(int f,char *buf,size_t len)
size_t l1=0, l2=0;
int ret;
for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
for (l1=0;l1<len && buf[l1]==0;l1++) ;
for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
last_byte = buf[len-1];
@@ -56,83 +51,39 @@ static int write_sparse(int f,char *buf,size_t len)
last_sparse=1;
if (l1 > 0) {
do_lseek(f,l1,SEEK_CUR);
do_lseek(f,l1,SEEK_CUR);
}
if (l1 == len)
if (l1 == len)
return len;
ret = write(f, buf + l1, len - (l1+l2));
if (ret == -1 || ret == 0)
return ret;
else if (ret != (int) (len - (l1+l2)))
else if (ret != (int) (len - (l1+l2)))
return (l1+ret);
if (l2 > 0)
do_lseek(f,l2,SEEK_CUR);
return len;
}
static char *wf_writeBuf;
static size_t wf_writeBufSize;
static size_t wf_writeBufCnt;
int flush_write_file(int f)
{
int ret = 0;
char *bp = wf_writeBuf;
while (wf_writeBufCnt > 0) {
if ((ret = write(f, bp, wf_writeBufCnt)) < 0) {
if (errno == EINTR)
continue;
return ret;
}
wf_writeBufCnt -= ret;
bp += ret;
}
return ret;
}
/*
* write_file does not allow incomplete writes. It loops internally
* until len bytes are written or errno is set.
*/
int write_file(int f,char *buf,size_t len)
{
int ret = 0;
while (len > 0) {
int r1;
if (sparse_files) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
r1 = write_sparse(f, buf, len1);
} else {
if (!wf_writeBuf) {
wf_writeBufSize = WRITE_SIZE * 8;
wf_writeBufCnt = 0;
wf_writeBuf = new_array(char, wf_writeBufSize);
if (!wf_writeBuf)
out_of_memory("write_file");
}
r1 = MIN(len, wf_writeBufSize - wf_writeBufCnt);
if (r1) {
memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1);
wf_writeBufCnt += r1;
}
if (wf_writeBufCnt == wf_writeBufSize) {
if (flush_write_file(f) < 0)
return -1;
if (!r1 && len)
continue;
}
}
if (!sparse_files) {
return write(f,buf,len);
}
while (len>0) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
int r1 = write_sparse(f, buf, len1);
if (r1 <= 0) {
if (ret > 0)
return ret;
if (ret > 0) return ret;
return r1;
}
len -= r1;
@@ -143,67 +94,75 @@ int write_file(int f,char *buf,size_t len)
}
/* This provides functionality somewhat similar to mmap() but using read().
* It gives sliding window access to a file. mmap() is not used because of
* the possibility of another program (such as a mailer) truncating the
* file thus giving us a SIGBUS. */
struct map_struct *map_file(int fd, OFF_T len, int32 read_size,
int32 blk_size)
/* this provides functionality somewhat similar to mmap() but using
read(). It gives sliding window access to a file. mmap() is not
used because of the possibility of another program (such as a
mailer) truncating the file thus giving us a SIGBUS */
struct map_struct *map_file(int fd,OFF_T len)
{
struct map_struct *map;
map = new(struct map_struct);
if (!map) out_of_memory("map_file");
if (!(map = new(struct map_struct)))
out_of_memory("map_file");
if (blk_size && (read_size % blk_size))
read_size += blk_size - (read_size % blk_size);
memset(map, 0, sizeof map[0]);
map->fd = fd;
map->file_size = len;
map->def_window_size = read_size;
map->p = NULL;
map->p_size = 0;
map->p_offset = 0;
map->p_fd_offset = 0;
map->p_len = 0;
return map;
}
/* slide the read window in the file */
char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
char *map_ptr(struct map_struct *map,OFF_T offset,int len)
{
int32 nread;
int nread;
OFF_T window_start, read_start;
int32 window_size, read_size, read_offset;
int window_size, read_size, read_offset;
if (len == 0)
if (len == 0) {
return NULL;
if (len < 0) {
rprintf(FERROR, "invalid len passed to map_ptr: %ld\n",
(long)len);
exit_cleanup(RERR_FILEIO);
}
/* can't go beyond the end of file */
if (len > (map->file_size - offset)) {
len = map->file_size - offset;
}
/* in most cases the region will already be available */
if (offset >= map->p_offset && offset+len <= map->p_offset+map->p_len)
return map->p + (offset - map->p_offset);
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
return (map->p + (offset - map->p_offset));
}
/* nope, we are going to have to do a read. Work out our desired window */
window_start = offset;
window_size = map->def_window_size;
if (window_start + window_size > map->file_size)
if (offset > 2*CHUNK_SIZE) {
window_start = offset - 2*CHUNK_SIZE;
window_start &= ~((OFF_T)(CHUNK_SIZE-1)); /* assumes power of 2 */
} else {
window_start = 0;
}
window_size = MAX_MAP_SIZE;
if (window_start + window_size > map->file_size) {
window_size = map->file_size - window_start;
if (len > window_size)
window_size = len;
}
if (offset + len > window_start + window_size) {
window_size = (offset+len) - window_start;
}
/* make sure we have allocated enough memory for the window */
if (window_size > map->p_size) {
map->p = realloc_array(map->p, char, window_size);
if (!map->p)
out_of_memory("map_ptr");
if (!map->p) out_of_memory("map_ptr");
map->p_size = window_size;
}
/* Now try to avoid re-reading any bytes by reusing any bytes
* from the previous buffer. */
/* now try to avoid re-reading any bytes by reusing any bytes from the previous
buffer. */
if (window_start >= map->p_offset &&
window_start < map->p_offset + map->p_len &&
window_start + window_size >= map->p_offset + map->p_len) {
@@ -218,53 +177,39 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
}
if (read_size <= 0) {
rprintf(FERROR, "invalid read_size of %ld in map_ptr\n",
(long)read_size);
exit_cleanup(RERR_FILEIO);
}
if (map->p_fd_offset != read_start) {
OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET);
if (ret != read_start) {
rsyserr(FERROR, errno, "lseek returned %.0f, not %.0f",
(double)ret, (double)read_start);
exit_cleanup(RERR_FILEIO);
rprintf(FINFO,"Warning: unexpected read size of %d in map_ptr\n", read_size);
} else {
if (map->p_fd_offset != read_start) {
if (do_lseek(map->fd,read_start,SEEK_SET) != read_start) {
rprintf(FERROR,"lseek failed in map_ptr\n");
exit_cleanup(RERR_FILEIO);
}
map->p_fd_offset = read_start;
}
map->p_fd_offset = read_start;
}
map->p_offset = window_start;
map->p_len = window_size;
while (read_size > 0) {
nread = read(map->fd, map->p + read_offset, read_size);
if (nread <= 0) {
if (!map->status)
map->status = nread ? errno : ENODATA;
/* The best we can do is zero the buffer -- the file
* has changed mid transfer! */
memset(map->p + read_offset, 0, read_size);
break;
if ((nread=read(map->fd,map->p + read_offset,read_size)) != read_size) {
if (nread < 0) nread = 0;
/* the best we can do is zero the buffer - the file
has changed mid transfer! */
memset(map->p+read_offset+nread, 0, read_size - nread);
}
map->p_fd_offset += nread;
read_offset += nread;
read_size -= nread;
}
return map->p;
map->p_offset = window_start;
map->p_len = window_size;
return map->p + (offset - map->p_offset);
}
int unmap_file(struct map_struct *map)
void unmap_file(struct map_struct *map)
{
int ret;
if (map->p) {
free(map->p);
map->p = NULL;
}
ret = map->status;
memset(map, 0, sizeof map[0]);
memset(map, 0, sizeof(*map));
free(map);
return ret;
}

2298
flist.c
View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,64 +1,50 @@
/*
* Print out the gids of all groups for the current user. This is like
* `id -G` on Linux, but it's too hard to find a portable equivalent.
*
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2003, 2004 Wayne Davison
*
* Copyright (C) 2002 by Martin Pool
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*
* 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 getgroups.c
*
* Print out the gids of all groups for the current user. This is
* like `id -G` on Linux, but it's too hard to find a portable
* equivalent.
**/
#include "rsync.h"
#ifndef NGROUPS
/* It ought to be defined, but just in case. */
# define NGROUPS 32
#endif
int
main(UNUSED(int argc), UNUSED(char *argv[]))
{
int n, i;
gid_t *list;
gid_t gid = MY_GID();
int gid_in_list = 0;
gid_t list[NGROUPS];
#ifdef HAVE_GETGROUPS
if ((n = getgroups(0, NULL)) < 0) {
if ((n = getgroups(NGROUPS, list)) == -1) {
perror("getgroups");
return 1;
}
#else
n = 0;
#endif
list = (gid_t*)malloc(sizeof (gid_t) * (n + 1));
if (!list) {
fprintf(stderr, "out of memory!\n");
exit(1);
}
#ifdef HAVE_GETGROUPS
if (n > 0)
n = getgroups(n, list);
#endif
for (i = 0; i < n; i++) {
printf("%lu ", (unsigned long)list[i]);
if (list[i] == gid)
gid_in_list = 1;
}
/* The default gid might not be in the list on some systems. */
if (!gid_in_list)
printf("%lu", (unsigned long)gid);
for (i = 0; i < n; i++)
printf("%u ", list[i]);
printf("\n");
return 0;
}

409
hlink.c
View File

@@ -1,315 +1,184 @@
/*
* Routines to support hard-linking.
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
Copyright (C) 2002 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rsync.h"
extern int dry_run;
extern int verbose;
extern int do_xfers;
extern int link_dest;
extern int make_backups;
extern int remove_source_files;
extern int stdout_format_has_i;
extern char *basis_dir[];
extern struct file_list *the_file_list;
#ifdef SUPPORT_HARD_LINKS
#define SKIPPED_LINK (-1)
#define FINISHED_LINK (-2)
#define FPTR(i) (the_file_list->files[i])
#define LINKED(p1,p2) (FPTR(p1)->F_DEV == FPTR(p2)->F_DEV \
&& FPTR(p1)->F_INODE == FPTR(p2)->F_INODE)
static int hlink_compare(int *int1, int *int2)
#if SUPPORT_HARD_LINKS
static int hlink_compare(struct file_struct *f1, struct file_struct *f2)
{
struct file_struct *f1 = FPTR(*int1);
struct file_struct *f2 = FPTR(*int2);
if (!S_ISREG(f1->mode) && !S_ISREG(f2->mode))
return 0;
if (!S_ISREG(f1->mode))
return -1;
if (!S_ISREG(f2->mode))
return 1;
if (f1->F_DEV != f2->F_DEV)
return (int) (f1->F_DEV > f2->F_DEV ? 1 : -1);
if (f1->dev != f2->dev)
return (int) (f1->dev > f2->dev ? 1 : -1);
if (f1->F_INODE != f2->F_INODE)
return (int) (f1->F_INODE > f2->F_INODE ? 1 : -1);
if (f1->inode != f2->inode)
return (int) (f1->inode > f2->inode ? 1 : -1);
return f_name_cmp(f1, f2);
return file_compare(&f1, &f2);
}
static int32 *hlink_list;
static int32 hlink_count;
/* Analyze the data in the hlink_list[], remove items that aren't multiply
* linked, and replace the dev+inode data with the hlindex+next linked list. */
static void link_idev_data(void)
{
int32 cur, from, to, start;
alloc_pool_t hlink_pool;
alloc_pool_t idev_pool = the_file_list->hlink_pool;
hlink_pool = pool_create(128 * 1024, sizeof (struct hlink),
out_of_memory, POOL_INTERN);
for (from = to = 0; from < hlink_count; from++) {
start = from;
while (1) {
cur = hlink_list[from];
if (from == hlink_count-1
|| !LINKED(cur, hlink_list[from+1]))
break;
pool_free(idev_pool, 0, FPTR(cur)->link_u.idev);
FPTR(cur)->link_u.links = pool_talloc(hlink_pool,
struct hlink, 1, "hlink_list");
FPTR(cur)->F_HLINDEX = to;
FPTR(cur)->F_NEXT = hlink_list[++from];
FPTR(cur)->link_u.links->link_dest_used = 0;
}
pool_free(idev_pool, 0, FPTR(cur)->link_u.idev);
if (from > start) {
int head = hlink_list[start];
FPTR(cur)->link_u.links = pool_talloc(hlink_pool,
struct hlink, 1, "hlink_list");
FPTR(head)->flags |= FLAG_HLINK_TOL;
FPTR(cur)->F_HLINDEX = to;
FPTR(cur)->F_NEXT = head;
FPTR(cur)->flags |= FLAG_HLINK_EOL;
FPTR(cur)->link_u.links->link_dest_used = 0;
hlink_list[to++] = head;
} else
FPTR(cur)->link_u.links = NULL;
}
if (!to) {
free(hlink_list);
hlink_list = NULL;
pool_destroy(hlink_pool);
hlink_pool = NULL;
} else {
hlink_count = to;
hlink_list = realloc_array(hlink_list, int32, hlink_count);
if (!hlink_list)
out_of_memory("init_hard_links");
}
the_file_list->hlink_pool = hlink_pool;
pool_destroy(idev_pool);
}
static struct file_struct *hlink_list;
static int hlink_count;
#endif
void init_hard_links(void)
void init_hard_links(struct file_list *flist)
{
#ifdef SUPPORT_HARD_LINKS
#if SUPPORT_HARD_LINKS
int i;
if (flist->count < 2)
return;
if (hlink_list)
free(hlink_list);
if (!(hlink_list = new_array(int32, the_file_list->count)))
if (!(hlink_list = new_array(struct file_struct, flist->count)))
out_of_memory("init_hard_links");
hlink_count = 0;
for (i = 0; i < the_file_list->count; i++) {
if (FPTR(i)->link_u.idev)
hlink_list[hlink_count++] = i;
}
for (i = 0; i < flist->count; i++)
memcpy(&hlink_list[i], flist->files[i],
sizeof(hlink_list[0]));
qsort(hlink_list, hlink_count,
sizeof hlink_list[0], (int (*)()) hlink_compare);
qsort(hlink_list, flist->count,
sizeof(hlink_list[0]), (int (*)()) hlink_compare);
if (!hlink_count) {
free(hlink_list);
hlink_list = NULL;
} else
link_idev_data();
hlink_count = flist->count;
#endif
}
#ifdef SUPPORT_HARD_LINKS
static int maybe_hard_link(struct file_struct *file, int ndx,
char *fname, int statret, STRUCT_STAT *st,
char *toname, STRUCT_STAT *to_st,
int itemizing, enum logcode code)
/* check if a file should be skipped because it is the same as an
earlier hard link */
int check_hard_link(struct file_struct *file)
{
if (statret == 0) {
if (st->st_dev == to_st->st_dev
&& st->st_ino == to_st->st_ino) {
if (itemizing) {
itemize(file, ndx, statret, st,
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
0, "");
}
return 0;
}
if (make_backups) {
if (!make_backup(fname))
return -1;
} else if (robust_unlink(fname)) {
rsyserr(FERROR, errno, "unlink %s failed",
full_fname(fname));
return -1;
}
}
return hard_link_one(file, ndx, fname, statret, st, toname,
0, itemizing, code);
}
#endif
#if SUPPORT_HARD_LINKS
int low = 0, high = hlink_count - 1;
int ret = 0;
int hard_link_check(struct file_struct *file, int ndx, char *fname,
int statret, STRUCT_STAT *st, int itemizing,
enum logcode code, int skip)
{
#ifdef SUPPORT_HARD_LINKS
int head;
if (skip && !(file->flags & FLAG_HLINK_EOL))
head = hlink_list[file->F_HLINDEX] = file->F_NEXT;
else
head = hlink_list[file->F_HLINDEX];
if (ndx != head) {
struct file_struct *head_file = FPTR(head);
if (!stdout_format_has_i && verbose > 1) {
rprintf(FINFO, "\"%s\" is a hard link\n",
f_name(file, NULL));
if (!hlink_list || !S_ISREG(file->mode))
return 0;
while (low != high) {
int mid = (low + high) / 2;
ret = hlink_compare(&hlink_list[mid], file);
if (ret == 0) {
low = mid;
break;
}
if (ret > 0)
high = mid;
else
low = mid + 1;
}
/* XXX: To me this looks kind of dodgy -- why do we use [low]
* here and [low-1] below? -- mbp */
if (hlink_compare(&hlink_list[low], file) != 0)
return 0;
if (low > 0 &&
S_ISREG(hlink_list[low - 1].mode) &&
file->dev == hlink_list[low - 1].dev &&
file->inode == hlink_list[low - 1].inode) {
if (verbose >= 2) {
rprintf(FINFO, "check_hard_link: \"%s\" is a hard link to file %d, \"%s\"\n",
f_name(file), low-1, f_name(&hlink_list[low-1]));
}
if (head_file->F_HLINDEX == FINISHED_LINK) {
STRUCT_STAT st2, st3;
char toname[MAXPATHLEN];
int ldu = head_file->link_u.links->link_dest_used;
if (ldu) {
pathjoin(toname, MAXPATHLEN, basis_dir[ldu-1],
f_name(head_file, NULL));
} else
f_name(head_file, toname);
if (link_stat(toname, &st2, 0) < 0) {
rsyserr(FERROR, errno, "stat %s failed",
full_fname(toname));
return -1;
}
if (statret < 0 && basis_dir[0] != NULL) {
char cmpbuf[MAXPATHLEN];
int j = 0;
do {
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, &st3, 0) < 0)
continue;
if (link_dest) {
if (st2.st_dev != st3.st_dev
|| st2.st_ino != st3.st_ino)
continue;
statret = 1;
st = &st3;
if (verbose < 2 || !stdout_format_has_i) {
itemizing = 0;
code = FNONE;
}
break;
}
if (!unchanged_file(cmpbuf, file, &st3))
continue;
statret = 1;
st = &st3;
if (unchanged_attrs(file, &st3))
break;
} while (basis_dir[++j] != NULL);
}
maybe_hard_link(file, ndx, fname, statret, st,
toname, &st2, itemizing, code);
if (remove_source_files == 1 && do_xfers) {
char numbuf[4];
SIVAL(numbuf, 0, ndx);
send_msg(MSG_SUCCESS, numbuf, 4);
}
file->F_HLINDEX = FINISHED_LINK;
} else
file->F_HLINDEX = SKIPPED_LINK;
return 1;
}
#endif
return 0;
}
#ifdef SUPPORT_HARD_LINKS
int hard_link_one(struct file_struct *file, int ndx, char *fname,
int statret, STRUCT_STAT *st, char *toname, int terse,
int itemizing, enum logcode code)
#if SUPPORT_HARD_LINKS
static void hard_link_one(int i)
{
if (do_link(toname, fname)) {
if (terse) {
if (!verbose)
return -1;
code = FINFO;
} else
code = FERROR;
rsyserr(code, errno, "link %s => %s failed",
full_fname(fname), toname);
return -1;
}
if (itemizing) {
itemize(file, ndx, statret, st,
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
terse ? "" : toname);
}
if (code != FNONE && verbose && !terse)
rprintf(code, "%s => %s\n", fname, toname);
return 0;
}
#endif
void hard_link_cluster(struct file_struct *file, int master, int itemizing,
enum logcode code)
{
#ifdef SUPPORT_HARD_LINKS
char hlink1[MAXPATHLEN];
char *hlink2;
STRUCT_STAT st1, st2;
int statret, ndx = master;
file->F_HLINDEX = FINISHED_LINK;
if (link_stat(f_name(file, hlink1), &st1, 0) < 0)
if (link_stat(f_name(&hlink_list[i - 1]), &st1) != 0)
return;
if (!(file->flags & FLAG_HLINK_TOL)) {
while (!(file->flags & FLAG_HLINK_EOL)) {
ndx = file->F_NEXT;
file = FPTR(ndx);
if (link_stat(f_name(&hlink_list[i]), &st2) != 0) {
if (do_link
(f_name(&hlink_list[i - 1]),
f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
rprintf(FINFO, "link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i - 1]),
strerror(errno));
return;
}
} else {
if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino)
return;
if (robust_unlink(f_name(&hlink_list[i])) != 0 ||
do_link(f_name(&hlink_list[i - 1]),
f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
rprintf(FINFO, "link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i - 1]),
strerror(errno));
return;
}
}
do {
ndx = file->F_NEXT;
file = FPTR(ndx);
if (file->F_HLINDEX != SKIPPED_LINK)
continue;
hlink2 = f_name(file, NULL);
statret = link_stat(hlink2, &st2, 0);
maybe_hard_link(file, ndx, hlink2, statret, &st2,
hlink1, &st1, itemizing, code);
if (remove_source_files == 1 && do_xfers) {
char numbuf[4];
SIVAL(numbuf, 0, ndx);
send_msg(MSG_SUCCESS, numbuf, 4);
if (verbose > 0)
rprintf(FINFO, "%s => %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i - 1]));
}
#endif
/**
* Create any hard links in the global hlink_list. They were put
* there by running init_hard_links on the filelist.
**/
void do_hard_links(void)
{
#if SUPPORT_HARD_LINKS
int i;
if (!hlink_list)
return;
for (i = 1; i < hlink_count; i++) {
if (S_ISREG(hlink_list[i].mode) &&
S_ISREG(hlink_list[i - 1].mode) &&
hlink_list[i].basename && hlink_list[i - 1].basename &&
hlink_list[i].dev == hlink_list[i - 1].dev &&
hlink_list[i].inode == hlink_list[i - 1].inode) {
hard_link_one(i);
}
file->F_HLINDEX = FINISHED_LINK;
} while (!(file->flags & FLAG_HLINK_EOL));
}
#endif
}

1424
io.c
View File

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,35 +1,42 @@
/*
* Reimplementations of standard functions for platforms that don't have them.
/*
Copyright (C) Andrew Tridgell 1998
Copyright (C) 2002 by Martin Pool
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* @file compat.c
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
* Reimplementations of standard functions for platforms that don't
* have them.
**/
#include "rsync.h"
#ifndef HAVE_STRDUP
char *strdup(char *s)
{
int len = strlen(s) + 1;
char *ret = (char *)malloc(len);
if (ret)
memcpy(ret, s, len);
return ret;
int l = strlen(s) + 1;
char *ret = (char *)malloc(l);
if (ret)
strcpy(ret,s);
return ret;
}
#endif
@@ -79,7 +86,7 @@
/**
* Find the first ocurrence in @p s of any character in @p accept.
*
* Derived from glibc
* Derived from glibc
**/
char *strpbrk(const char *s, const char *accept)
{
@@ -98,7 +105,7 @@
#ifndef HAVE_STRLCPY
/**
* Like strncpy but does not 0 fill the buffer and always null
* Like strncpy but does not 0 fill the buffer and always null
* terminates.
*
* @param bufsize is the size of the destination buffer.
@@ -109,19 +116,17 @@
{
size_t len = strlen(s);
size_t ret = len;
if (bufsize > 0) {
if (len >= bufsize)
len = bufsize-1;
memcpy(d, s, len);
d[len] = 0;
}
if (bufsize <= 0) return 0;
if (len >= bufsize) len = bufsize-1;
memcpy(d, s, len);
d[len] = 0;
return ret;
}
#endif
#ifndef HAVE_STRLCAT
/**
* Like strncat() but does not 0 fill the buffer and always null
* Like strncat() but does not 0 fill the buffer and always null
* terminates.
*
* @param bufsize length of the buffer, which should be one more than
@@ -133,9 +138,10 @@
size_t len2 = strlen(s);
size_t ret = len1 + len2;
if (len1 < bufsize - 1) {
if (len2 >= bufsize - len1)
len2 = bufsize - len1 - 1;
if (len1+len2 >= bufsize) {
len2 = bufsize - (len1+1);
}
if (len2 > 0) {
memcpy(d+len1, s, len2);
d[len1+len2] = 0;
}
@@ -143,10 +149,53 @@
}
#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
snprintf(buf, 18, "%d.%d.%d.%d",
(int)p[0], (int)p[1], (int)p[2], (int)p[3]);
#else
snprintf(buf, 18, "%d.%d.%d.%d",
(int)p[3], (int)p[2], (int)p[1], (int)p[0]);
#endif
return buf;
}
#endif
#ifdef REPLACE_INET_ATON
int inet_aton(const char *cp, struct in_addr *inp)
{
unsigned int a1, a2, a3, a4;
unsigned long ret;
if (strcmp(cp, "255.255.255.255") == 0) {
inp->s_addr = (unsigned) -1;
return 0;
}
if (sscanf(cp, "%u.%u.%u.%u", &a1, &a2, &a3, &a4) != 4 ||
a1 > 255 || a2 > 255 || a3 > 255 || a4 > 255) {
return 0;
}
ret = (a1 << 24) | (a2 << 16) | (a3 << 8) | a4;
inp->s_addr = htonl(ret);
if (inp->s_addr == (unsigned) -1) {
return 0;
}
return 1;
}
#endif
/* some systems don't take the 2nd argument */
int sys_gettimeofday(struct timeval *tv)
{
#ifdef HAVE_GETTIMEOFDAY_TZ
#if HAVE_GETTIMEOFDAY_TZ
return gettimeofday(tv, NULL);
#else
return gettimeofday(tv);

View File

@@ -75,14 +75,13 @@ inet_ntop4(const unsigned char *src, char *dst, size_t size)
{
static const char *fmt = "%u.%u.%u.%u";
char tmp[sizeof "255.255.255.255"];
size_t len;
len = snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]);
if (len >= size) {
if ((size_t)sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) >= size)
{
errno = ENOSPC;
return (NULL);
}
memcpy(dst, tmp, len + 1);
strcpy(dst, tmp);
return (dst);
}
@@ -107,7 +106,7 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size)
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
struct { int base, len; } best, cur;
unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
int i, inc;
int i;
/*
* Preprocess:
@@ -158,14 +157,13 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size)
/* Is this address an encapsulated IPv4? */
if (i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
if (!inet_ntop4(src+12, tp,
sizeof tmp - (tp - tmp)))
return (NULL);
tp += strlen(tp);
break;
}
inc = snprintf(tp, 5, "%x", words[i]);
assert(inc < 5);
tp += inc;
tp += sprintf(tp, "%x", words[i]);
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) ==
@@ -180,7 +178,7 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size)
errno = ENOSPC;
return (NULL);
}
memcpy(dst, tmp, tp - tmp);
strcpy(dst, tmp);
return (dst);
}
#endif /* AF_INET6 */

View File

@@ -1,31 +1,30 @@
/*
* Unix SMB/Netbios implementation.
* Version 1.9.
* An implementation of MD4 designed for use in the SMB authentication protocol.
*
* Copyright (C) 1997-1998 Andrew Tridgell
* Copyright (C) 2005 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
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. */
It assumes that a int is at least 32 bits long
*/
static struct mdfour *m;
@@ -207,11 +206,9 @@ void mdfour(unsigned char *out, unsigned char *in, int n)
}
#ifdef TEST_MDFOUR
int protocol_version = 28;
static void file_checksum1(char *fname)
{
int fd, i, was_multiple_of_64 = 1;
int fd, i;
struct mdfour md;
unsigned char buf[64*1024], sum[16];
@@ -225,13 +222,9 @@ static void file_checksum1(char *fname)
while (1) {
int n = read(fd, buf, sizeof(buf));
if (n <= 0)
break;
was_multiple_of_64 = !(n % 64);
if (n <= 0) break;
mdfour_update(&md, buf, n);
}
if (was_multiple_of_64 && protocol_version >= 27)
mdfour_update(&md, buf, 0);
close(fd);

View File

@@ -1,24 +1,23 @@
/*
* Unix SMB/Netbios implementation.
* Version 1.9.
* An implementation of MD4 designed for use in the SMB authentication protocol.
*
* Copyright (C) 1997-1998 Andrew Tridgell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
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;
@@ -30,3 +29,7 @@ void mdfour_begin(struct mdfour *md);
void mdfour_update(struct mdfour *md, unsigned char *in, uint32 n);
void mdfour_result(struct mdfour *md, unsigned char *out);
void mdfour(unsigned char *out, unsigned char *in, int n);

View File

@@ -1,40 +1,41 @@
/*
* A single utility routine.
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001 Martin Pool <mbp@samba.org>
* Copyright (C) 2003, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
Copyright (C) 2001 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rsync.h"
/* Produce a string representation of Unix mode bits like that used by ls(1).
* The "buf" buffer must be at least 11 characters. */
void permstring(char *perms, mode_t mode)
/**
* Produce a string representation of Unix mode bits like that used by
* ls(1).
*
* @param buf buffer of at least 11 characters
**/
void permstring(char *perms,
int mode)
{
static const char *perm_map = "rwxrwxrwx";
int i;
strlcpy(perms, "----------", 11);
for (i = 0; i < 9; i++) {
if (mode & (1 << i))
perms[9-i] = perm_map[8-i];
strcpy(perms, "----------");
for (i=0;i<9;i++) {
if (mode & (1<<i)) perms[9-i] = perm_map[8-i];
}
/* Handle setuid/sticky bits. You might think the indices are
@@ -45,22 +46,18 @@ void permstring(char *perms, mode_t mode)
if (mode & S_ISGID)
perms[6] = (mode & S_IXGRP) ? 's' : 'S';
#ifdef S_ISVTX
if (mode & S_ISVTX)
perms[9] = (mode & S_IXOTH) ? 't' : 'T';
#endif
if (S_ISDIR(mode))
perms[0] = 'd';
else if (S_ISLNK(mode))
perms[0] = 'l';
else if (S_ISBLK(mode))
perms[0] = 'b';
else if (S_ISCHR(mode))
perms[0] = 'c';
else if (S_ISSOCK(mode))
perms[0] = 's';
else if (S_ISFIFO(mode))
perms[0] = 'p';
if (S_ISLNK(mode)) perms[0] = 'l';
if (S_ISDIR(mode)) perms[0] = 'd';
if (S_ISBLK(mode)) perms[0] = 'b';
if (S_ISCHR(mode)) perms[0] = 'c';
if (S_ISSOCK(mode)) perms[0] = 's';
if (S_ISFIFO(mode)) perms[0] = 'p';
}

View File

@@ -1,3 +1,3 @@
#define PERMSTRING_SIZE 11
void permstring(char *perms, mode_t mode);
void permstring(char *perms, int mode);

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,3 @@
/*
* NOTE: If you change this file, please merge it into rsync, samba, etc.
*/
/*
* Copyright Patrick Powell 1995
* This code is based on code written by Patrick Powell (papowell@astart.com)
@@ -57,57 +53,14 @@
* got rid of fcvt code (twas buggy and made testing harder)
* added C99 semantics
*
* date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0
* actually print args for %g and %e
*
* date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0
* Since includes.h isn't included here, VA_COPY has to be defined here. I don't
* see any include file that is guaranteed to be here, so I'm defining it
* locally. Fixes AIX and Solaris builds.
*
* date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13
* put the ifdef for HAVE_VA_COPY in one place rather than in lots of
* functions
*
* date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4
* Fix usage of va_list passed as an arg. Use __va_copy before using it
* when it exists.
*
* date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14
* Fix incorrect zpadlen handling in fmtfp.
* Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
* few mods to make it easier to compile the tests.
* addedd the "Ollie" test to the floating point ones.
*
* Martin Pool (mbp@samba.org) April 2003
* Remove NO_CONFIG_H so that the test case can be built within a source
* tree with less trouble.
* Remove unnecessary SAFE_FREE() definition.
*
* Martin Pool (mbp@samba.org) May 2003
* Put in a prototype for dummy_snprintf() to quiet compiler warnings.
*
* Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
* if the C library has some snprintf functions already.
* Paul Green (paulg@samba.org) April 9, 2003
* fixed handling of %f when converting fractions with leading zeros.
* (e.g., 0.025).
**************************************************************/
#ifndef NO_CONFIG_H
#ifndef NO_CONFIG_H /* for some tests */
#include "config.h"
#else
#define NULL 0
#endif
#ifdef TEST_SNPRINTF /* need math library headers for testing */
/* In test mode, we pretend that this system doesn't have any snprintf
* functions, regardless of what config.h says. */
# undef HAVE_SNPRINTF
# undef HAVE_VSNPRINTF
# undef HAVE_C99_VSNPRINTF
# undef HAVE_ASPRINTF
# undef HAVE_VASPRINTF
# include <math.h>
#endif /* TEST_SNPRINTF */
#endif
#ifdef HAVE_STRING_H
#include <string.h>
@@ -129,9 +82,8 @@
/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
#include <stdio.h>
/* make the compiler happy with an empty file */
void dummy_snprintf(void);
void dummy_snprintf(void) {}
#endif /* HAVE_SNPRINTF, etc */
#else
#ifdef HAVE_LONG_DOUBLE
#define LDOUBLE long double
@@ -139,22 +91,21 @@
#define LDOUBLE double
#endif
#if SIZEOF_LONG_LONG
#ifdef HAVE_LONG_LONG
#define LLONG long long
#else
#define LLONG long
#endif
#ifndef VA_COPY
#if defined HAVE_VA_COPY || defined va_copy
#define VA_COPY(dest, src) va_copy(dest, src)
#else
#ifdef HAVE___VA_COPY
#define VA_COPY(dest, src) __va_copy(dest, src)
#else
#define VA_COPY(dest, src) (dest) = (src)
#endif
#endif
static size_t 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
@@ -190,20 +141,7 @@
#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
#endif
/* yes this really must be a ||. Don't muck with this (tridge) */
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
static size_t dopr(char *buffer, size_t maxlen, const char *format,
va_list args_in);
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);
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
{
char ch;
LLONG value;
@@ -215,9 +153,6 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
int flags;
int cflags;
size_t currlen;
va_list args;
VA_COPY(args, args_in);
state = DP_S_DEFAULT;
currlen = flags = cflags = min = 0;
@@ -387,7 +322,6 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
break;
case 'G':
flags |= DP_F_UP;
@@ -396,14 +330,12 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
break;
case 'c':
dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
break;
case 's':
strvalue = va_arg (args, char *);
if (!strvalue) strvalue = "(NULL)";
if (max == -1) {
max = strlen(strvalue);
}
@@ -632,26 +564,28 @@ static double my_modf(double x0, double *iptr)
for (i=0;i<100;i++) {
l = (long)x;
if (l <= (x+1) && l >= (x-1)) {
if (i != 0) {
double i2;
double ret;
ret = my_modf(x0-l*f, &i2);
(*iptr) = l*f + i2;
return ret;
}
(*iptr) = l;
return x - (*iptr);
}
if (l <= (x+1) && l >= (x-1)) break;
x *= 0.1;
f *= 10.0;
}
/* yikes! the number is beyond what we can handle. What do we do? */
(*iptr) = 0;
return 0;
if (i == 100) {
/* yikes! the number is beyond what we can handle. What do we do? */
(*iptr) = 0;
return 0;
}
if (i != 0) {
double i2;
double ret;
ret = my_modf(x0-l*f, &i2);
(*iptr) = l*f + i2;
return ret;
}
(*iptr) = l;
return x - (*iptr);
}
@@ -667,7 +601,7 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
int padlen = 0; /* amount to pad */
int zpadlen = 0;
int caps = 0;
int idx;
int index;
double intpart;
double fracpart;
double temp;
@@ -724,13 +658,14 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
/* Convert integer part */
do {
temp = intpart*0.1;
my_modf(temp, &intpart);
idx = (int) ((temp -intpart +0.05)* 10.0);
/* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
/* printf ("%llf, %f, %x\n", temp, intpart, idx); */
temp = intpart;
my_modf(intpart*0.1, &intpart);
temp = temp*0.1;
index = (int) ((temp -intpart +0.05)* 10.0);
/* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
/* printf ("%llf, %f, %x\n", temp, intpart, index); */
iconvert[iplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
} while (intpart && (iplace < 311));
if (iplace == 311) iplace--;
iconvert[iplace] = 0;
@@ -739,13 +674,14 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
if (fracpart)
{
do {
temp = fracpart*0.1;
my_modf(temp, &fracpart);
idx = (int) ((temp -fracpart +0.05)* 10.0);
/* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
/* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
temp = fracpart;
my_modf(fracpart*0.1, &fracpart);
temp = temp*0.1;
index = (int) ((temp -fracpart +0.05)* 10.0);
/* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
/* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
fconvert[fplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
} while(fracpart && (fplace < 311));
if (fplace == 311) fplace--;
}
@@ -793,14 +729,14 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
dopr_outch (buffer, currlen, maxlen, '.');
while (zpadlen > 0) {
dopr_outch (buffer, currlen, maxlen, '0');
--zpadlen;
dopr_outch (buffer, currlen, maxlen, '0');
--zpadlen;
}
while (fplace > 0)
dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
}
while (padlen < 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
++padlen;
@@ -815,21 +751,17 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
(*currlen)++;
}
int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
#define vsnprintf rsync_vsnprintf
int vsnprintf(char *str, size_t count, const char *fmt, va_list args)
{
return dopr(str, count, fmt, args);
}
#define vsnprintf rsync_vsnprintf
#endif
/* yes this really must be a ||. Don't muck with this (tridge)
*
* The logic for these two is that we need our own definition if the
* OS *either* has no definition of *sprintf, or if it does have one
* that doesn't work properly according to the autoconf test.
*/
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
int rsync_snprintf(char *str,size_t count,const char *fmt,...)
#define snprintf rsync_snprintf
int snprintf(char *str,size_t count,const char *fmt,...)
{
size_t ret;
va_list ap;
@@ -839,7 +771,6 @@ int rsync_snprintf(char *str,size_t count,const char *fmt,...)
va_end(ap);
return ret;
}
#define snprintf rsync_snprintf
#endif
#endif
@@ -848,19 +779,13 @@ int rsync_snprintf(char *str,size_t count,const char *fmt,...)
int vasprintf(char **ptr, const char *format, va_list ap)
{
int ret;
va_list ap2;
VA_COPY(ap2, ap);
ret = vsnprintf(NULL, 0, format, ap2);
ret = vsnprintf(NULL, 0, format, ap);
if (ret <= 0) return ret;
(*ptr) = (char *)malloc(ret+1);
if (!*ptr) return -1;
VA_COPY(ap2, ap);
ret = vsnprintf(*ptr, ret+1, format, ap2);
ret = vsnprintf(*ptr, ret+1, format, ap);
return ret;
}
@@ -873,7 +798,6 @@ int rsync_snprintf(char *str,size_t count,const char *fmt,...)
va_list ap;
int ret;
*ptr = NULL;
va_start(ap, format);
ret = vasprintf(ptr, format, ap);
va_end(ap);
@@ -908,9 +832,8 @@ int rsync_snprintf(char *str,size_t count,const char *fmt,...)
"-16.16f",
NULL
};
double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
0.9996, 1.996, 4.136, 5.030201, 0.00205,
/* END LIST */ 0};
double fp_nums[] = { 6442452944.1234, -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",
@@ -1005,10 +928,8 @@ int rsync_snprintf(char *str,size_t count,const char *fmt,...)
{
double v0 = 0.12345678901234567890123456789012345678901;
for (x=0; x<100; x++) {
double p = pow(10, x);
double r = v0*p;
snprintf(buf1, sizeof(buf1), "%1.1f", r);
sprintf(buf2, "%1.1f", r);
snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x));
sprintf(buf2, "%1.1f", v0*pow(10, x));
if (strcmp(buf1, buf2)) {
printf("we seem to support %d digits\n", x-1);
break;
@@ -1018,4 +939,4 @@ int rsync_snprintf(char *str,size_t count,const char *fmt,...)
return 0;
}
#endif /* TEST_SNPRINTF */
#endif /* SNPRINTF_TEST */

View File

@@ -57,312 +57,173 @@
int wildmatch_iteration_count;
#endif
static int force_lower_case = 0;
/* Match pattern "p" against the a virtually-joined string consisting
* of "text" and any strings in array "a". */
static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
static int domatch(const unsigned char *p, const unsigned char *text)
{
uchar p_ch;
int matched, special;
unsigned char ch, prev;
#ifdef WILD_TEST_ITERATIONS
wildmatch_iteration_count++;
#endif
for ( ; (p_ch = *p) != '\0'; text++, p++) {
int matched, special;
uchar t_ch, prev_ch;
while ((t_ch = *text) == '\0') {
if (*a == NULL) {
if (p_ch != '*')
return ABORT_ALL;
break;
}
text = *a++;
}
if (force_lower_case && ISUPPER(t_ch))
t_ch = tolower(t_ch);
switch (p_ch) {
for ( ; (ch = *p) != '\0'; text++, p++) {
if (*text == '\0' && ch != '*')
return FALSE;
switch (ch) {
case '\\':
/* Literal match with following character. Note that the test
* in "default" handles the p[1] == '\0' failure case. */
p_ch = *++p;
ch = *++p;
/* FALLTHROUGH */
default:
if (t_ch != p_ch)
if (*text != ch)
return FALSE;
continue;
case '?':
/* Match anything but '/'. */
if (t_ch == '/')
if (*text == '/')
return FALSE;
continue;
case '*':
if (*++p == '*') {
while (*++p == '*') {}
special = TRUE;
} else
}
else
special = FALSE;
if (*p == '\0') {
/* Trailing "**" matches everything. Trailing "*" matches
* only if there are no more slash characters. */
if (!special) {
do {
if (strchr((char*)text, '/') != NULL)
return FALSE;
} while ((text = *a++) != NULL);
}
return TRUE;
return special? TRUE : strchr((char*)text, '/') == NULL;
}
while (1) {
if (t_ch == '\0') {
if ((text = *a++) == NULL)
break;
t_ch = *text;
continue;
}
if ((matched = dowild(p, text, a)) != FALSE) {
for ( ; *text; text++) {
if ((matched = domatch(p, text)) != FALSE) {
if (!special || matched != ABORT_TO_STARSTAR)
return matched;
} else if (!special && t_ch == '/')
}
else if (!special && *text == '/')
return ABORT_TO_STARSTAR;
t_ch = *++text;
}
return ABORT_ALL;
case '[':
p_ch = *++p;
ch = *++p;
#ifdef NEGATE_CLASS2
if (p_ch == NEGATE_CLASS2)
p_ch = NEGATE_CLASS;
if (ch == NEGATE_CLASS2)
ch = NEGATE_CLASS;
#endif
/* Assign literal TRUE/FALSE because of "matched" comparison. */
special = p_ch == NEGATE_CLASS? TRUE : FALSE;
special = ch == NEGATE_CLASS? TRUE : FALSE;
if (special) {
/* Inverted character class. */
p_ch = *++p;
ch = *++p;
}
prev_ch = 0;
prev = 0;
matched = FALSE;
do {
if (!p_ch)
if (!ch)
return ABORT_ALL;
if (p_ch == '\\') {
p_ch = *++p;
if (!p_ch)
if (ch == '\\') {
ch = *++p;
if (!ch)
return ABORT_ALL;
if (t_ch == p_ch)
if (*text == ch)
matched = TRUE;
} else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {
p_ch = *++p;
if (p_ch == '\\') {
p_ch = *++p;
if (!p_ch)
}
else if (ch == '-' && prev && p[1] && p[1] != ']') {
ch = *++p;
if (ch == '\\') {
ch = *++p;
if (!ch)
return ABORT_ALL;
}
if (t_ch <= p_ch && t_ch >= prev_ch)
if (*text <= ch && *text >= prev)
matched = TRUE;
p_ch = 0; /* This makes "prev_ch" get set to 0. */
} else if (p_ch == '[' && p[1] == ':') {
const uchar *s;
ch = 0; /* This makes "prev" get set to 0. */
}
else if (ch == '[' && p[1] == ':') {
const unsigned char *s = p += 2;
int i;
for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {}
if (!p_ch)
while ((ch = *p) && ch != ']') p++;
if (!ch)
return ABORT_ALL;
i = p - s - 1;
if (i < 0 || p[-1] != ':') {
/* Didn't find ":]", so treat like a normal set. */
p = s - 2;
p_ch = '[';
if (t_ch == p_ch)
ch = '[';
if (*text == ch)
matched = TRUE;
continue;
}
if (CC_EQ(s,i, "alnum")) {
if (ISALNUM(t_ch))
if (ISALNUM(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "alpha")) {
if (ISALPHA(t_ch))
}
else if (CC_EQ(s,i, "alpha")) {
if (ISALPHA(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "blank")) {
if (ISBLANK(t_ch))
}
else if (CC_EQ(s,i, "blank")) {
if (ISBLANK(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "cntrl")) {
if (ISCNTRL(t_ch))
}
else if (CC_EQ(s,i, "cntrl")) {
if (ISCNTRL(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "digit")) {
if (ISDIGIT(t_ch))
}
else if (CC_EQ(s,i, "digit")) {
if (ISDIGIT(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "graph")) {
if (ISGRAPH(t_ch))
}
else if (CC_EQ(s,i, "graph")) {
if (ISGRAPH(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "lower")) {
if (ISLOWER(t_ch))
}
else if (CC_EQ(s,i, "lower")) {
if (ISLOWER(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "print")) {
if (ISPRINT(t_ch))
}
else if (CC_EQ(s,i, "print")) {
if (ISPRINT(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "punct")) {
if (ISPUNCT(t_ch))
}
else if (CC_EQ(s,i, "punct")) {
if (ISPUNCT(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "space")) {
if (ISSPACE(t_ch))
}
else if (CC_EQ(s,i, "space")) {
if (ISSPACE(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "upper")) {
if (ISUPPER(t_ch))
}
else if (CC_EQ(s,i, "upper")) {
if (ISUPPER(*text))
matched = TRUE;
} else if (CC_EQ(s,i, "xdigit")) {
if (ISXDIGIT(t_ch))
}
else if (CC_EQ(s,i, "xdigit")) {
if (ISXDIGIT(*text))
matched = TRUE;
} else /* malformed [:class:] string */
}
else /* malformed [:class:] string */
return ABORT_ALL;
p_ch = 0; /* This makes "prev_ch" get set to 0. */
} else if (t_ch == p_ch)
ch = 0; /* This makes "prev" get set to 0. */
}
else if (*text == ch)
matched = TRUE;
} while (prev_ch = p_ch, (p_ch = *++p) != ']');
if (matched == special || t_ch == '/')
} while (prev = ch, (ch = *++p) != ']');
if (matched == special || *text == '/')
return FALSE;
continue;
}
}
do {
if (*text)
return FALSE;
} while ((text = *a++) != NULL);
return TRUE;
return *text == '\0';
}
/* Match literal string "s" against the a virtually-joined string consisting
* of "text" and any strings in array "a". */
static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
/* Find the pattern (p) in the text string (t). */
int wildmatch(const char *p, const char *t)
{
for ( ; *s != '\0'; text++, s++) {
while (*text == '\0') {
if ((text = *a++) == NULL)
return FALSE;
}
if (*text != *s)
return FALSE;
}
do {
if (*text)
return FALSE;
} while ((text = *a++) != NULL);
return TRUE;
}
/* Return the last "count" path elements from the concatenated string.
* We return a string pointer to the start of the string, and update the
* array pointer-pointer to point to any remaining string elements. */
static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count)
{
const uchar*const *a = *a_ptr;
const uchar*const *first_a = a;
while (*a)
a++;
while (a != first_a) {
const uchar *s = *--a;
s += strlen((char*)s);
while (--s >= *a) {
if (*s == '/' && !--count) {
*a_ptr = a+1;
return s+1;
}
}
}
if (count == 1) {
*a_ptr = a+1;
return *a;
}
return NULL;
}
/* Match the "pattern" against the "text" string. */
int wildmatch(const char *pattern, const char *text)
{
static const uchar *nomore[1]; /* A NULL pointer. */
#ifdef WILD_TEST_ITERATIONS
wildmatch_iteration_count = 0;
#endif
return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
}
/* Match the "pattern" against the forced-to-lower-case "text" string. */
int iwildmatch(const char *pattern, const char *text)
{
static const uchar *nomore[1]; /* A NULL pointer. */
int ret;
#ifdef WILD_TEST_ITERATIONS
wildmatch_iteration_count = 0;
#endif
force_lower_case = 1;
ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
force_lower_case = 0;
return ret;
}
/* Match pattern "p" against the a virtually-joined string consisting
* of all the pointers in array "texts" (which has a NULL pointer at the
* end). The int "where" can be 0 (normal matching), > 0 (match only
* the trailing N slash-separated filename components of "texts"), or < 0
* (match the "pattern" at the start or after any slash in "texts"). */
int wildmatch_array(const char *pattern, const char*const *texts, int where)
{
const uchar *p = (const uchar*)pattern;
const uchar*const *a = (const uchar*const*)texts;
const uchar *text;
int matched;
#ifdef WILD_TEST_ITERATIONS
wildmatch_iteration_count = 0;
#endif
if (where > 0)
text = trailing_N_elements(&a, where);
else
text = *a++;
if (!text)
return FALSE;
if ((matched = dowild(p, text, a)) != TRUE && where < 0
&& matched != ABORT_ALL) {
while (1) {
if (*text == '\0') {
if ((text = (uchar*)*a++) == NULL)
return FALSE;
continue;
}
if (*text++ == '/' && (matched = dowild(p, text, a)) != FALSE
&& matched != ABORT_TO_STARSTAR)
break;
}
}
return matched == TRUE;
}
/* Match literal string "s" against the a virtually-joined string consisting
* of all the pointers in array "texts" (which has a NULL pointer at the
* end). The int "where" can be 0 (normal matching), or > 0 (match
* only the trailing N slash-separated filename components of "texts"). */
int litmatch_array(const char *string, const char*const *texts, int where)
{
const uchar *s = (const uchar*)string;
const uchar*const *a = (const uchar* const*)texts;
const uchar *text;
if (where > 0)
text = trailing_N_elements(&a, where);
else
text = *a++;
if (!text)
return FALSE;
return doliteral(s, text, a) == TRUE;
return domatch((const unsigned char*)p, (const unsigned char*)t) == TRUE;
}

View File

@@ -1,6 +1,3 @@
/* wildmatch.h */
int wildmatch(const char *pattern, const char *text);
int iwildmatch(const char *pattern, const char *text);
int wildmatch_array(const char *pattern, const char*const *texts, int where);
int litmatch_array(const char *string, const char*const *texts, int where);
int wildmatch(const char *p, const char *text);

View File

@@ -1,27 +1,27 @@
/* This is based on loadparm.c from Samba, written by Andrew Tridgell
and Karl Auer */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* some fixes
*
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
*/
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Load parameters.
*
@@ -36,7 +36,7 @@
* 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
* 4) If it's a global then initialise it in init_globals. If a local
* (ie. service) parameter then initialise it in the sDefault structure
*
*
*
* Notes:
* The configuration file is processed sequentially for speed. It is NOT
@@ -57,15 +57,11 @@
typedef char pstring[1024];
#define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring))
#ifndef LOG_DAEMON
#define LOG_DAEMON 0
#endif
/* the following are used by loadparm for option lists */
typedef enum
{
P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
P_PATH,P_STRING,P_GSTRING,P_ENUM,P_SEP
P_STRING,P_GSTRING,P_ENUM,P_SEP
} parm_type;
typedef enum
@@ -97,114 +93,94 @@ struct parm_struct
#define iSERVICE(i) (*pSERVICE(i))
#define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
/*
/*
* This structure describes global (ie., server-wide) parameters.
*/
typedef struct
{
char *bind_address;
char *motd_file;
char *log_file;
char *pid_file;
int syslog_facility;
char *socket_options;
int rsync_port;
} global;
static global Globals;
/*
* This structure describes a single service. Their order must match the
* initializers below, which you can accomplish by keeping each sub-section
* sorted. (e.g. in vim, just visually select each subsection and use !sort.)
/*
* This structure describes a single service.
*/
typedef struct
{
char *auth_users;
char *name;
char *path;
char *comment;
char *dont_compress;
char *exclude;
char *exclude_from;
char *filter;
char *lock_file;
BOOL read_only;
BOOL list;
BOOL use_chroot;
BOOL transfer_logging;
BOOL ignore_errors;
char *uid;
char *gid;
char *hosts_allow;
char *hosts_deny;
char *auth_users;
char *secrets_file;
BOOL strict_modes;
char *exclude;
char *exclude_from;
char *include;
char *include_from;
char *incoming_chmod;
char *lock_file;
char *log_file;
char *log_format;
char *name;
char *outgoing_chmod;
char *path;
char *postxfer_exec;
char *prexfer_exec;
char *refuse_options;
char *secrets_file;
char *temp_dir;
char *uid;
int max_connections;
int max_verbosity;
int syslog_facility;
char *dont_compress;
int timeout;
BOOL ignore_errors;
int max_connections;
BOOL ignore_nonreadable;
BOOL list;
BOOL read_only;
BOOL strict_modes;
BOOL transfer_logging;
BOOL use_chroot;
BOOL write_only;
} service;
/* This is a default service used to prime a services structure. In order
* to make these easy to keep sorted in the same way as the variables
* above, use the variable name in the leading comment, including a
* trailing ';' (to avoid a sorting problem with trailing digits). */
static service sDefault =
/* This is a default service used to prime a services structure */
static service sDefault =
{
/* auth_users; */ NULL,
/* comment; */ NULL,
/* dont_compress; */ "*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz",
/* exclude; */ NULL,
/* exclude_from; */ NULL,
/* filter; */ NULL,
/* gid; */ NOBODY_GROUP,
/* hosts_allow; */ NULL,
/* hosts_deny; */ NULL,
/* include; */ NULL,
/* include_from; */ NULL,
/* incoming_chmod; */ NULL,
/* lock_file; */ DEFAULT_LOCK_FILE,
/* log_file; */ NULL,
/* log_format; */ "%o %h [%a] %m (%u) %f %l",
/* name; */ NULL,
/* outgoing_chmod; */ NULL,
/* path; */ NULL,
/* postxfer_exec; */ NULL,
/* prexfer_exec; */ NULL,
/* refuse_options; */ NULL,
/* secrets_file; */ NULL,
/* temp_dir; */ NULL,
/* uid; */ NOBODY_USER,
/* max_connections; */ 0,
/* max_verbosity; */ 1,
/* syslog_facility; */ LOG_DAEMON,
/* timeout; */ 0,
/* ignore_errors; */ False,
/* ignore_nonreadable; */ False,
/* list; */ True,
/* read_only; */ True,
/* strict_modes; */ True,
/* transfer_logging; */ False,
/* use_chroot; */ True,
/* write_only; */ False,
NULL, /* name */
NULL, /* path */
NULL, /* comment */
DEFAULT_LOCK_FILE, /* lock file */
True, /* read only */
True, /* list */
True, /* use chroot */
False, /* transfer logging */
False, /* ignore errors */
"nobody",/* uid */
/* TODO: This causes problems on Debian, where it is called
* "nogroup". Debian patch this in their version of the
* package, but it would be nice to be consistent. Possibly
* other systems are different again.
*
* What is the best behaviour? Perhaps always using (gid_t)
* -2? */
"nobody",/* gid */
NULL, /* hosts allow */
NULL, /* hosts deny */
NULL, /* auth users */
NULL, /* secrets file */
True, /* strict modes */
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 *.iso *.bz2 *.tbz", /* dont compress */
0, /* timeout */
0, /* max connections */
False /* ignore nonreadable */
};
@@ -246,7 +222,7 @@ static struct enum_list enum_facilities[] = {
{ LOG_NEWS, "news" },
#endif
#ifdef LOG_AUTH
{ LOG_AUTH, "security" },
{ LOG_AUTH, "security" },
#endif
#ifdef LOG_SYSLOG
{ LOG_SYSLOG, "syslog" },
@@ -287,64 +263,55 @@ static struct enum_list enum_facilities[] = {
/* note that we do not initialise the defaults union - it is not allowed in ANSI C */
static struct parm_struct parm_table[] =
{
{"address", P_STRING, P_GLOBAL,&Globals.bind_address, NULL,0},
{"motd file", P_STRING, P_GLOBAL,&Globals.motd_file, NULL,0},
{"pid file", P_STRING, P_GLOBAL,&Globals.pid_file, NULL,0},
{"port", P_INTEGER,P_GLOBAL,&Globals.rsync_port, NULL,0},
{"socket options", P_STRING, P_GLOBAL,&Globals.socket_options, NULL,0},
{"motd file", P_STRING, P_GLOBAL, &Globals.motd_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},
{"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL,0},
{"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL,0},
{"dont compress", P_STRING, P_LOCAL, &sDefault.dont_compress, NULL,0},
{"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from, NULL,0},
{"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL,0},
{"filter", P_STRING, P_LOCAL, &sDefault.filter, NULL,0},
{"gid", P_STRING, P_LOCAL, &sDefault.gid, NULL,0},
{"hosts allow", P_STRING, P_LOCAL, &sDefault.hosts_allow, NULL,0},
{"hosts deny", P_STRING, P_LOCAL, &sDefault.hosts_deny, NULL,0},
{"ignore errors", P_BOOL, P_LOCAL, &sDefault.ignore_errors, NULL,0},
{"ignore nonreadable",P_BOOL, P_LOCAL, &sDefault.ignore_nonreadable,NULL,0},
{"include from", P_STRING, P_LOCAL, &sDefault.include_from, NULL,0},
{"include", P_STRING, P_LOCAL, &sDefault.include, NULL,0},
{"incoming chmod", P_STRING, P_LOCAL, &sDefault.incoming_chmod, NULL,0},
{"list", P_BOOL, P_LOCAL, &sDefault.list, NULL,0},
{"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL,0},
{"log file", P_STRING, P_LOCAL, &sDefault.log_file, NULL,0},
{"log format", P_STRING, P_LOCAL, &sDefault.log_format, NULL,0},
{"max connections", P_INTEGER,P_LOCAL, &sDefault.max_connections, NULL,0},
{"max verbosity", P_INTEGER,P_LOCAL, &sDefault.max_verbosity, NULL,0},
{"name", P_STRING, P_LOCAL, &sDefault.name, NULL,0},
{"outgoing chmod", P_STRING, P_LOCAL, &sDefault.outgoing_chmod, NULL,0},
{"path", P_PATH, P_LOCAL, &sDefault.path, NULL,0},
#ifdef HAVE_PUTENV
{"post-xfer exec", P_STRING, P_LOCAL, &sDefault.postxfer_exec, NULL,0},
{"pre-xfer exec", P_STRING, P_LOCAL, &sDefault.prexfer_exec, NULL,0},
#endif
{"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL,0},
{"refuse options", P_STRING, P_LOCAL, &sDefault.refuse_options, NULL,0},
{"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file, NULL,0},
{"strict modes", P_BOOL, P_LOCAL, &sDefault.strict_modes, NULL,0},
{"syslog facility", P_ENUM, P_LOCAL, &sDefault.syslog_facility,enum_facilities,0},
{"temp dir", P_PATH, P_LOCAL, &sDefault.temp_dir, NULL,0},
{"timeout", P_INTEGER,P_LOCAL, &sDefault.timeout, NULL,0},
{"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging, NULL,0},
{"uid", P_STRING, P_LOCAL, &sDefault.uid, NULL,0},
{"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL,0},
{"write only", P_BOOL, P_LOCAL, &sDefault.write_only, NULL,0},
{NULL, P_BOOL, P_NONE, NULL, NULL,0}
{"timeout", P_INTEGER, P_LOCAL, &sDefault.timeout, NULL, 0},
{"max connections", P_INTEGER, P_LOCAL, &sDefault.max_connections,NULL, 0},
{"name", P_STRING, P_LOCAL, &sDefault.name, NULL, 0},
{"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, 0},
{"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL, 0},
{"path", P_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},
{"ignore nonreadable",P_BOOL, P_LOCAL, &sDefault.ignore_nonreadable, 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},
{"hosts deny", P_STRING, P_LOCAL, &sDefault.hosts_deny, NULL, 0},
{"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL, 0},
{"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file,NULL, 0},
{"strict modes", P_BOOL, P_LOCAL, &sDefault.strict_modes,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},
{"ignore errors", P_BOOL, P_LOCAL, &sDefault.ignore_errors,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}
};
/***************************************************************************
* Initialise the global parameter structure.
Initialise the global parameter structure.
***************************************************************************/
static void init_globals(void)
{
memset(&Globals, 0, sizeof Globals);
memset(&Globals, 0, sizeof(Globals));
#ifdef LOG_DAEMON
Globals.syslog_facility = LOG_DAEMON;
#endif
}
/***************************************************************************
* Initialise the sDefault parameter structure.
Initialise the sDefault parameter structure.
***************************************************************************/
static void init_locals(void)
{
@@ -352,8 +319,8 @@ static void init_locals(void)
/*
In this section all the functions that are used to access the
parameters from the rest of the program are defined
In this section all the functions that are used to access the
parameters from the rest of the program are defined
*/
#define FN_GLOBAL_STRING(fn_name,ptr) \
@@ -375,64 +342,52 @@ static void init_locals(void)
int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address)
FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_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_syslog_facility, &Globals.syslog_facility)
FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port)
FN_LOCAL_STRING(lp_auth_users, auth_users)
FN_LOCAL_STRING(lp_name, name)
FN_LOCAL_STRING(lp_comment, comment)
FN_LOCAL_STRING(lp_dont_compress, dont_compress)
FN_LOCAL_STRING(lp_exclude, exclude)
FN_LOCAL_STRING(lp_exclude_from, exclude_from)
FN_LOCAL_STRING(lp_filter, filter)
FN_LOCAL_STRING(lp_path, path)
FN_LOCAL_STRING(lp_lock_file, lock_file)
FN_LOCAL_BOOL(lp_read_only, read_only)
FN_LOCAL_BOOL(lp_list, list)
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
FN_LOCAL_STRING(lp_uid, uid)
FN_LOCAL_STRING(lp_gid, gid)
FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
FN_LOCAL_STRING(lp_auth_users, auth_users)
FN_LOCAL_STRING(lp_secrets_file, secrets_file)
FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
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_incoming_chmod, incoming_chmod)
FN_LOCAL_STRING(lp_lock_file, lock_file)
FN_LOCAL_STRING(lp_log_file, log_file)
FN_LOCAL_STRING(lp_log_format, log_format)
FN_LOCAL_STRING(lp_name, name)
FN_LOCAL_STRING(lp_outgoing_chmod, outgoing_chmod)
FN_LOCAL_STRING(lp_path, path)
FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec)
FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
FN_LOCAL_STRING(lp_refuse_options, refuse_options)
FN_LOCAL_STRING(lp_secrets_file, secrets_file)
FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
FN_LOCAL_STRING(lp_temp_dir, temp_dir)
FN_LOCAL_STRING(lp_uid, uid)
FN_LOCAL_INTEGER(lp_max_connections, max_connections)
FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
FN_LOCAL_STRING(lp_dont_compress, dont_compress)
FN_LOCAL_INTEGER(lp_timeout, timeout)
FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
FN_LOCAL_BOOL(lp_list, list)
FN_LOCAL_BOOL(lp_read_only, read_only)
FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
FN_LOCAL_BOOL(lp_write_only, write_only)
FN_LOCAL_INTEGER(lp_max_connections, max_connections)
/* local prototypes */
static int strwicmp(char *psz1, char *psz2);
static int map_parameter(char *parmname);
static BOOL set_boolean(BOOL *pb, char *parmvalue);
static int strwicmp( char *psz1, char *psz2 );
static int map_parameter( char *parmname);
static BOOL set_boolean( BOOL *pb, char *parmvalue );
static int getservicebyname(char *name, service *pserviceDest);
static void copy_service(service *pserviceDest, service *pserviceSource);
static void copy_service( service *pserviceDest,
service *pserviceSource);
static BOOL do_parameter(char *parmname, char *parmvalue);
static BOOL do_section(char *sectionname);
/***************************************************************************
* initialise a service to the defaults
initialise a service to the defaults
***************************************************************************/
static void init_service(service *pservice)
{
@@ -466,8 +421,8 @@ static void string_set(char **s, const char *v)
/***************************************************************************
* add a new service to the services array initialising it with the given
* service
add a new service to the services array initialising it with the given
service
***************************************************************************/
static int add_a_service(service *pservice, char *name)
{
@@ -478,7 +433,7 @@ static int add_a_service(service *pservice, char *name)
tservice = *pservice;
/* it might already exist */
if (name)
if (name)
{
i = getservicebyname(name,NULL);
if (i >= 0)
@@ -500,13 +455,13 @@ static int add_a_service(service *pservice, char *name)
init_service(pSERVICE(i));
copy_service(pSERVICE(i),&tservice);
if (name)
string_set(&iSERVICE(i).name,name);
string_set(&iSERVICE(i).name,name);
return(i);
}
/***************************************************************************
* Do a case-insensitive, whitespace-ignoring string compare.
Do a case-insensitive, whitespace-ignoring string compare.
***************************************************************************/
static int strwicmp(char *psz1, char *psz2)
{
@@ -538,8 +493,8 @@ static int strwicmp(char *psz1, char *psz2)
}
/***************************************************************************
* Map a parameter's string representation to something we can use.
* Returns False if the parameter string is not recognised, else TRUE.
Map a parameter's string representation to something we can use.
Returns False if the parameter string is not recognised, else TRUE.
***************************************************************************/
static int map_parameter(char *parmname)
{
@@ -548,7 +503,7 @@ static int map_parameter(char *parmname)
if (*parmname == '-')
return(-1);
for (iIndex = 0; parm_table[iIndex].label; iIndex++)
for (iIndex = 0; parm_table[iIndex].label; iIndex++)
if (strwicmp(parm_table[iIndex].label, parmname) == 0)
return(iIndex);
@@ -558,9 +513,9 @@ static int map_parameter(char *parmname)
/***************************************************************************
* Set a boolean variable from the text value stored in the passed string.
* Returns True in success, False if the passed string does not correctly
* represent a boolean.
Set a boolean variable from the text value stored in the passed string.
Returns True in success, False if the passed string does not correctly
represent a boolean.
***************************************************************************/
static BOOL set_boolean(BOOL *pb, char *parmvalue)
{
@@ -586,14 +541,14 @@ static BOOL set_boolean(BOOL *pb, char *parmvalue)
}
/***************************************************************************
* Find a service by name. Otherwise works like get_service.
Find a service by name. Otherwise works like get_service.
***************************************************************************/
static int getservicebyname(char *name, service *pserviceDest)
{
int iService;
for (iService = iNumServices - 1; iService >= 0; iService--)
if (strwicmp(iSERVICE(iService).name, name) == 0)
if (strwicmp(iSERVICE(iService).name, name) == 0)
{
if (pserviceDest != NULL)
copy_service(pserviceDest, pSERVICE(iService));
@@ -606,9 +561,10 @@ static int getservicebyname(char *name, service *pserviceDest)
/***************************************************************************
* Copy a service structure to another
Copy a service structure to another
***************************************************************************/
static void copy_service(service *pserviceDest,
static void copy_service(service *pserviceDest,
service *pserviceSource)
{
int i;
@@ -616,9 +572,9 @@ static void copy_service(service *pserviceDest,
for (i=0;parm_table[i].label;i++)
if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
void *def_ptr = parm_table[i].ptr;
void *src_ptr =
void *src_ptr =
((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
void *dest_ptr =
void *dest_ptr =
((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
switch (parm_table[i].type)
@@ -638,7 +594,6 @@ static void copy_service(service *pserviceDest,
*(char *)dest_ptr = *(char *)src_ptr;
break;
case P_PATH:
case P_STRING:
string_set(dest_ptr,*(char **)src_ptr);
break;
@@ -651,15 +606,14 @@ static void copy_service(service *pserviceDest,
/***************************************************************************
* Process a parameter for a particular service number. If snum < 0
* then assume we are in the globals
Process a parameter for a particular service number. If snum < 0
then assume we are in the globals
***************************************************************************/
static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
{
int parmnum, i;
void *parm_ptr=NULL; /* where we are going to store the result */
void *def_ptr=NULL;
char *cp;
parmnum = map_parameter(parmname);
@@ -706,15 +660,6 @@ static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
sscanf(parmvalue,"%o",(int *)parm_ptr);
break;
case P_PATH:
string_set(parm_ptr,parmvalue);
if ((cp = *(char**)parm_ptr) != NULL) {
int len = strlen(cp);
while (len > 1 && cp[len-1] == '/') len--;
cp[len] = '\0';
}
break;
case P_STRING:
string_set(parm_ptr,parmvalue);
break;
@@ -743,7 +688,7 @@ static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
}
/***************************************************************************
* Process a parameter.
Process a parameter.
***************************************************************************/
static BOOL do_parameter(char *parmname, char *parmvalue)
{
@@ -751,9 +696,9 @@ static BOOL do_parameter(char *parmname, char *parmvalue)
}
/***************************************************************************
* Process a new section (service). At this stage all sections are services.
* Later we'll have special sections that permit server parameters to be set.
* Returns True on success, False on failure.
Process a new section (service). At this stage all sections are services.
Later we'll have special sections that permit server parameters to be set.
Returns True on success, False on failure.
***************************************************************************/
static BOOL do_section(char *sectionname)
{
@@ -766,7 +711,7 @@ static BOOL do_section(char *sectionname)
init_locals();
/* if we've just struck a global section, note the fact. */
bInGlobalSection = isglobal;
bInGlobalSection = isglobal;
/* check for multiple global sections */
if (bInGlobalSection)
@@ -798,25 +743,26 @@ static BOOL do_section(char *sectionname)
/***************************************************************************
* Load the services array from the services file. Return True on success,
* False on failure.
Load the services array from the services file. Return True on success,
False on failure.
***************************************************************************/
BOOL lp_load(char *pszFname, int globals_only)
{
extern int am_server;
extern int am_daemon;
extern int am_root;
pstring n2;
BOOL bRetval;
bRetval = False;
bInGlobalSection = True;
init_globals();
if (pszFname)
pstrcpy(n2,pszFname);
else if (am_server && !am_root)
else if (am_server && am_daemon && !am_root)
pstrcpy(n2,RSYNCD_USERCONF);
else
pstrcpy(n2,RSYNCD_SYSCONF);
@@ -824,13 +770,13 @@ BOOL lp_load(char *pszFname, int globals_only)
/* We get sections first, so have to start 'behind' to make up */
iServiceIndex = -1;
bRetval = pm_process(n2, globals_only?NULL:do_section, do_parameter);
return (bRetval);
}
/***************************************************************************
* return the max number of services
return the max number of services
***************************************************************************/
int lp_numservices(void)
{
@@ -838,17 +784,17 @@ int lp_numservices(void)
}
/***************************************************************************
* Return the number of the service with the given name, or -1 if it doesn't
* exist. Note that this is a DIFFERENT ANIMAL from the internal function
* getservicebyname()! This works ONLY if all services have been loaded, and
* does not copy the found service.
Return the number of the service with the given name, or -1 if it doesn't
exist. Note that this is a DIFFERENT ANIMAL from the internal function
getservicebyname()! This works ONLY if all services have been loaded, and
does not copy the found service.
***************************************************************************/
int lp_number(char *name)
{
int iService;
for (iService = iNumServices - 1; iService >= 0; iService--)
if (strcmp(lp_name(iService), name) == 0)
if (strequal(lp_name(iService), name))
break;
return (iService);

949
log.c
View File

File diff suppressed because it is too large Load Diff

1334
main.c
View File

File diff suppressed because it is too large Load Diff

414
match.c
View File

@@ -1,69 +1,89 @@
/*
* Block matching used by the file-transfer code.
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
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 do_progress;
extern int checksum_seed;
extern int append_mode;
extern int csum_length;
int updating_basis_file;
extern int verbose;
extern int am_server;
extern int remote_version;
typedef unsigned short tag;
#define TABLESIZE (1<<16)
#define NULL_TAG (-1)
static int false_alarms;
static int hash_hits;
static int tag_hits;
static int matches;
static int64 data_transfer;
static int total_false_alarms;
static int total_hash_hits;
static int total_tag_hits;
static int total_matches;
extern struct stats stats;
#define TABLESIZE (1<<16)
struct target {
tag t;
int i;
};
static int32 *hash_table;
static struct target *targets;
static int *tag_table;
#define gettag2(s1,s2) (((s1) + (s2)) & 0xFFFF)
#define gettag(sum) gettag2((sum)&0xFFFF,(sum)>>16)
static int compare_targets(struct target *t1,struct target *t2)
{
return((int)t1->t - (int)t2->t);
}
#define SUM2HASH2(s1,s2) (((s1) + (s2)) & 0xFFFF)
#define SUM2HASH(sum) SUM2HASH2((sum)&0xFFFF,(sum)>>16)
static void build_hash_table(struct sum_struct *s)
{
int32 i;
int i;
if (!hash_table) {
hash_table = new_array(int32, TABLESIZE);
if (!hash_table)
out_of_memory("build_hash_table");
}
if (!tag_table)
tag_table = new_array(int, TABLESIZE);
memset(hash_table, 0xFF, TABLESIZE * sizeof hash_table[0]);
targets = new_array(struct target, s->count);
if (!tag_table || !targets)
out_of_memory("build_hash_table");
for (i = 0; i < s->count; i++) {
uint32 t = SUM2HASH(s->sums[i].sum1);
s->sums[i].chain = hash_table[t];
hash_table[t] = i;
}
for (i=0;i<(int) s->count;i++) {
targets[i].i = i;
targets[i].t = gettag(s->sums[i].sum1);
}
qsort(targets,s->count,sizeof(targets[0]),(int (*)())compare_targets);
for (i=0;i<TABLESIZE;i++)
tag_table[i] = NULL_TAG;
for (i=s->count-1;i>=0;i--) {
tag_table[targets[i].t] = i;
}
}
@@ -82,196 +102,158 @@ static OFF_T last_match;
* @param i If >0, the number of a matched token. If 0, indicates we
* have only literal data.
**/
static void matched(int f, struct sum_struct *s, struct map_struct *buf,
OFF_T offset, int32 i)
static void matched(int f,struct sum_struct *s,struct map_struct *buf,
OFF_T offset,int i)
{
int32 n = offset - last_match; /* max value: block_size (int32) */
int32 j;
OFF_T n = offset - last_match;
OFF_T j;
if (verbose > 2 && i >= 0) {
rprintf(FINFO,
"match at %.0f last_match=%.0f j=%d len=%ld n=%ld\n",
(double)offset, (double)last_match, i,
(long)s->sums[i].len, (long)n);
}
if (verbose > 2 && i >= 0)
rprintf(FINFO,"match at %.0f last_match=%.0f j=%d len=%d n=%.0f\n",
(double)offset,(double)last_match,i,s->sums[i].len,(double)n);
send_token(f, i, buf, last_match, n, i < 0 ? 0 : s->sums[i].len);
send_token(f,i,buf,last_match,n,i<0?0:s->sums[i].len);
data_transfer += n;
if (i >= 0) {
stats.matched_data += s->sums[i].len;
n += s->sums[i].len;
}
for (j = 0; j < n; j += CHUNK_SIZE) {
int32 n1 = MIN(CHUNK_SIZE, n - j);
sum_update(map_ptr(buf, last_match + j, n1), n1);
for (j=0;j<n;j+=CHUNK_SIZE) {
int n1 = MIN(CHUNK_SIZE,n-j);
sum_update(map_ptr(buf,last_match+j,n1),n1);
}
if (i >= 0)
last_match = offset + s->sums[i].len;
else
last_match = offset;
if (buf && do_progress)
if (buf) {
show_progress(last_match, buf->file_size);
if (i == -1) end_progress(buf->file_size);
}
}
static void hash_search(int f,struct sum_struct *s,
struct map_struct *buf, OFF_T len)
struct map_struct *buf,OFF_T len)
{
OFF_T offset, end, backup;
int32 k, want_i;
OFF_T offset, end;
int j,k, last_i;
char sum2[SUM_LENGTH];
uint32 s1, s2, sum;
int more;
uint32 s1, s2, sum;
schar *map;
/* want_i is used to encourage adjacent matches, allowing the RLL
* coding of the output to work more efficiently. */
want_i = 0;
/* last_i is used to encourage adjacent matches, allowing the RLL coding of the
output to work more efficiently */
last_i = -1;
if (verbose > 2) {
rprintf(FINFO, "hash search b=%ld len=%.0f\n",
(long)s->blength, (double)len);
}
k = (int32)MIN(len, (OFF_T)s->blength);
map = (schar *)map_ptr(buf, 0, k);
if (verbose > 2)
rprintf(FINFO,"hash search b=%ld len=%.0f\n",
(long) s->n, (double)len);
/* cast is to make s->n signed; it should always be reasonably
* small */
k = MIN(len, (OFF_T) s->n);
map = (schar *)map_ptr(buf,0,k);
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
if (verbose > 3)
rprintf(FINFO, "sum=%.8x k=%ld\n", sum, (long)k);
rprintf(FINFO, "sum=%.8x k=%d\n", sum, k);
offset = 0;
end = len + 1 - s->sums[s->count-1].len;
if (verbose > 3) {
rprintf(FINFO, "hash search s->blength=%ld len=%.0f count=%.0f\n",
(long)s->blength, (double)len, (double)s->count);
}
if (verbose > 3)
rprintf(FINFO, "hash search s->n=%ld len=%.0f count=%ld\n",
(long) s->n, (double) len, (long) s->count);
do {
tag t = gettag2(s1,s2);
int done_csum2 = 0;
int32 i;
if (verbose > 4) {
rprintf(FINFO, "offset=%.0f sum=%04x%04x\n",
(double)offset, s2 & 0xFFFF, s1 & 0xFFFF);
j = tag_table[t];
if (verbose > 4)
rprintf(FINFO,"offset=%.0f sum=%08x\n",(double)offset,sum);
if (j == NULL_TAG) {
goto null_tag;
}
i = hash_table[SUM2HASH2(s1,s2)];
if (i < 0)
goto null_hash;
sum = (s1 & 0xffff) | (s2 << 16);
hash_hits++;
do {
int32 l;
if (sum != s->sums[i].sum1)
continue;
tag_hits++;
for (; j < (int) s->count && targets[j].t == t; j++) {
int l, i = targets[j].i;
if (sum != s->sums[i].sum1) continue;
/* also make sure the two blocks are the same length */
l = (int32)MIN((OFF_T)s->blength, len-offset);
if (l != s->sums[i].len)
continue;
/* in-place: ensure chunk's offset is either >= our
* offset or that the data didn't move. */
if (updating_basis_file && s->sums[i].offset < offset
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET))
continue;
if (verbose > 3) {
rprintf(FINFO,
"potential match at %.0f i=%ld sum=%08x\n",
(double)offset, (long)i, sum);
}
l = MIN(s->n,len-offset);
if (l != s->sums[i].len) continue;
if (verbose > 3)
rprintf(FINFO,"potential match at %.0f target=%d %d sum=%08x\n",
(double)offset,j,i,sum);
if (!done_csum2) {
map = (schar *)map_ptr(buf,offset,l);
get_checksum2((char *)map,l,sum2);
done_csum2 = 1;
}
if (memcmp(sum2,s->sums[i].sum2,s->s2length) != 0) {
if (memcmp(sum2,s->sums[i].sum2,csum_length) != 0) {
false_alarms++;
continue;
}
/* When updating in-place, the best possible match is
* one with an identical offset, so we prefer that over
* the following want_i optimization. */
if (updating_basis_file) {
int32 i2;
for (i2 = i; i2 >= 0; i2 = s->sums[i2].chain) {
if (s->sums[i2].offset != offset)
continue;
if (i2 != i) {
if (sum != s->sums[i2].sum1)
break;
if (memcmp(sum2, s->sums[i2].sum2,
s->s2length) != 0)
break;
i = i2;
}
/* This chunk was at the same offset on
* both the sender and the receiver. */
s->sums[i].flags |= SUMFLG_SAME_OFFSET;
goto set_want_i;
/* we've found a match, but now check to see
if last_i can hint at a better match */
for (j++; j < (int) s->count && targets[j].t == t; j++) {
int i2 = targets[j].i;
if (i2 == last_i + 1) {
if (sum != s->sums[i2].sum1) break;
if (memcmp(sum2,s->sums[i2].sum2,csum_length) != 0) break;
/* we've found an adjacent match - the RLL coder
will be happy */
i = i2;
break;
}
}
/* we've found a match, but now check to see
* if want_i can hint at a better match. */
if (i != want_i && want_i < s->count
&& (!updating_basis_file || s->sums[want_i].offset >= offset
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
&& sum == s->sums[want_i].sum1
&& memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
/* we've found an adjacent match - the RLL coder
* will be happy */
i = want_i;
}
set_want_i:
want_i = i + 1;
last_i = i;
matched(f,s,buf,offset,i);
offset += s->sums[i].len - 1;
k = (int32)MIN((OFF_T)s->blength, len-offset);
map = (schar *)map_ptr(buf, offset, k);
k = MIN((len-offset), s->n);
map = (schar *)map_ptr(buf,offset,k);
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
matches++;
break;
} while ((i = s->sums[i].chain) >= 0);
null_hash:
backup = offset - last_match;
/* We sometimes read 1 byte prior to last_match... */
if (backup < 0)
backup = 0;
}
null_tag:
/* Trim off the first byte from the checksum */
more = offset + k < len;
map = (schar *)map_ptr(buf, offset - backup, k + more + backup)
+ backup;
map = (schar *)map_ptr(buf,offset,k+1);
s1 -= map[0] + CHAR_OFFSET;
s2 -= k * (map[0]+CHAR_OFFSET);
/* Add on the next byte (if there is one) to the checksum */
if (more) {
s1 += map[k] + CHAR_OFFSET;
if (k < (len-offset)) {
s1 += (map[k]+CHAR_OFFSET);
s2 += s1;
} else
} else {
--k;
}
/* By matching early we avoid re-reading the
data 3 times in the case where a token
@@ -279,12 +261,15 @@ static void hash_search(int f,struct sum_struct *s,
match. The 3 reads are caused by the
running match, the checksum update and the
literal send. */
if (backup >= s->blength+CHUNK_SIZE && end-offset > CHUNK_SIZE)
matched(f, s, buf, offset - s->blength, -2);
if (offset > last_match &&
offset-last_match >= CHUNK_SIZE+s->n &&
(end-offset > CHUNK_SIZE)) {
matched(f,s,buf,offset - s->n, -2);
}
} while (++offset < end);
matched(f, s, buf, len, -1);
map_ptr(buf, len-1, 1);
matched(f,s,buf,len,-1);
map_ptr(buf,len-1,1);
}
@@ -305,66 +290,56 @@ static void hash_search(int f,struct sum_struct *s,
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
{
char file_sum[MD4_SUM_LENGTH];
extern int write_batch; /* dw */
last_match = 0;
false_alarms = 0;
hash_hits = 0;
matches = 0;
data_transfer = 0;
tag_hits = 0;
matches=0;
data_transfer=0;
sum_init(checksum_seed);
sum_init();
if (append_mode) {
OFF_T j = 0;
for (j = CHUNK_SIZE; j < s->flength; j += CHUNK_SIZE) {
if (buf && do_progress)
show_progress(last_match, buf->file_size);
sum_update(map_ptr(buf, last_match, CHUNK_SIZE),
CHUNK_SIZE);
last_match = j;
}
if (last_match < s->flength) {
int32 len = s->flength - last_match;
if (buf && do_progress)
show_progress(last_match, buf->file_size);
sum_update(map_ptr(buf, last_match, len), len);
last_match = s->flength;
}
s->count = 0;
}
if (len > 0 && s->count > 0) {
if (len > 0 && s->count>0) {
build_hash_table(s);
if (verbose > 2)
if (verbose > 2)
rprintf(FINFO,"built hash table\n");
hash_search(f,s,buf,len);
if (verbose > 2)
if (verbose > 2)
rprintf(FINFO,"done hash search\n");
} else {
OFF_T j;
/* by doing this in pieces we avoid too many seeks */
for (j = last_match + CHUNK_SIZE; j < len; j += CHUNK_SIZE)
matched(f, s, buf, j, -2);
matched(f, s, buf, len, -1);
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);
}
sum_end(file_sum);
/* If we had a read error, send a bad checksum. */
if (buf && buf->status != 0)
file_sum[0]++;
if (remote_version >= 14) {
if (verbose > 2)
rprintf(FINFO,"sending file_sum\n");
write_buf(f,file_sum,MD4_SUM_LENGTH);
if (write_batch) /* dw */
write_batch_delta_file(file_sum, MD4_SUM_LENGTH);
}
if (targets) {
free(targets);
targets=NULL;
}
if (verbose > 2)
rprintf(FINFO,"sending file_sum\n");
write_buf(f,file_sum,MD4_SUM_LENGTH);
if (verbose > 2)
rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
false_alarms, hash_hits, matches);
total_hash_hits += hash_hits;
rprintf(FINFO, "false_alarms=%d tag_hits=%d matches=%d\n",
false_alarms, tag_hits, matches);
total_tag_hits += tag_hits;
total_false_alarms += false_alarms;
total_matches += matches;
stats.literal_data += data_transfer;
@@ -376,7 +351,8 @@ void match_report(void)
return;
rprintf(FINFO,
"total: matches=%d hash_hits=%d false_alarms=%d data=%.0f\n",
total_matches, total_hash_hits, total_false_alarms,
"total: matches=%d tag_hits=%d false_alarms=%d data=%.0f\n",
total_matches,total_tag_hits,
total_false_alarms,
(double)stats.literal_data);
}

View File

@@ -54,14 +54,15 @@ BEGIN {
printf "int %s(void);\n", a[2]
}
/^static|^extern/ || /[;]/ {
/^static|^extern/ || !/^[a-zA-Z]/ || /[;]/ {
next;
}
!/^[A-Za-z][A-Za-z0-9_]* / {
!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time/ {
next;
}
/[(].*[)][ \t]*$/ {
printf "%s;\n",$0;
next;
@@ -72,3 +73,4 @@ BEGIN {
printf "%s\n",$0;
next;
}

1826
options.c
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,60 +1,31 @@
Summary: A program for synchronizing files over a network.
Summary: Program for efficient remote updates of files.
Name: rsync
Version: 2.6.9
Version: 2.5.7
Release: 1
Group: Applications/Internet
Source: ftp://rsync.samba.org/pub/rsync/rsync-%{version}.tar.gz
URL: http://rsync.samba.org/
Prefix: %{_prefix}
BuildRoot: /var/tmp/%{name}-root
License: GPL
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.5.7.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
%description
Rsync uses a reliable algorithm to bring remote and host files into
sync very quickly. Rsync is fast because it just sends the differences
in the files over the network instead of sending the complete
files. Rsync is often used as a very powerful mirroring process or
just as a more capable replacement for the rcp command. A technical
report which describes the rsync algorithm is included in this
package.
rsync is a replacement for rcp that has many more features.
%prep
%setup -q
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
differences in the files across the link, without requiring that both
sets of files are present at one of the ends of the link beforehand.
%build
%configure
make
%install
rm -rf $RPM_BUILD_ROOT
%makeinstall
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc COPYING README tech_report.tex
%{_prefix}/bin/rsync
%{_mandir}/man1/rsync.1*
%{_mandir}/man5/rsyncd.conf.5*
A technical report describing the rsync algorithm is included with
this package.
%changelog
* Thu Jan 30 2003 Horst von Brand <vonbrand@inf.utfsm.cl>
Fixed "Sept" date in %changelog here
Use %{_mandir} to point to manpages
Support for compressed manpages (* at end catches them in %files)
Add doc/README-SGML and doc/rsync.sgml to %doc
* Mon Sep 11 2000 John H Terpstra <jht@turbolinux.com>
* Mon Sept 11 2000 John H Terpstra <jht@turbolinux.com>
Changed target paths to be Linux Standards Base compliant
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
@@ -86,3 +57,28 @@ to '%build', removed '%prefix'.
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
previous package(s).)
%prep
%setup
%build
./configure --prefix=/usr --mandir=/usr/share/man
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/{bin,share/man/{man1,man5}}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1 $RPM_BUILD_ROOT/usr/share/man/man1
install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/usr/share/man/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) /usr/share/man/man1/rsync.1
%attr(-,root,root) /usr/share/man/man5/rsyncd.conf.5
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING

View File

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

View File

@@ -1,122 +0,0 @@
#!/usr/bin/perl
use strict;
# This script expects the directory ~/samba-rsync-ftp to exist and to be a
# copy of the /home/ftp/pub/rsync dir on samba.org. It also requires a
# pristine CVS checkout of rsync (don't use your normal rsync build dir
# unless you're 100% sure that there are not unchecked-in changes).
#
# If this is run with -ctu, it will make an updated "nightly" tar file in
# the nightly dir. It will also remove any old tar files, regenerate the
# HTML man pages in the nightly dir, and then rsync the changes to the
# samba.org server.
use Getopt::Long;
use Date::Format;
# Choose any dir where a pristine rsync has been checked out of CVS.
our $unpacked = $ENV{HOME} . '/release/nightly';
# Where the local copy of /home/ftp/pub/rsync/nightly should be updated.
our $nightly = $ENV{HOME} . '/samba-rsync-ftp/nightly';
our $nightly_symlink = "$nightly/rsync-HEAD.tar.gz";
our($cvs_update, $make_tar, $upload, $help_opt);
&Getopt::Long::Configure('bundling');
&usage if !&GetOptions(
'cvs-update|c' => \$cvs_update,
'make-tar|t' => \$make_tar,
'upload|u' => \$upload,
'help|h' => \$help_opt,
) || $help_opt;
our $name = time2str('rsync-HEAD-%Y%m%d-%H%M%Z', time, 'GMT');
our $ztoday = time2str('%d %b %Y', time);
our $today = $ztoday;
chdir($unpacked) or die $!;
if ($cvs_update) {
print "Updating from cvs...\n";
system 'cvs -q up' and die $!;
}
if ($make_tar) {
print "Generating list of active CVS files...\n";
my($dir, @files);
open(CVS, '-|', 'cvs status 2>&1') or die $!;
while (<CVS>) {
if (/^cvs status: Examining (.*)/) {
if ($1 eq '.') {
$dir = '';
} else {
push(@files, $1);
$dir = $1 . '/';
}
} elsif (/^File: (.*?)\s+Status: (.*)/ && $1 ne '.cvsignore') {
push(@files, $dir . $1);
if ($2 ne 'Up-to-date') {
print "*** Not up-to-date: $dir$1\n";
}
}
}
close CVS;
print "Creating $unpacked/$name.tar.gz\n";
chdir('..') or die $!;
rename($unpacked, $name) or die $!;
open(TAR, '|-', "fakeroot tar --files-from=- --no-recursion --mode=g-w -czf $nightly/$name.tar.gz $name") or die $!;
foreach (@files) {
print TAR "$name/$_\n";
}
close TAR;
rename($name, $unpacked) or die $!;
unlink($nightly_symlink);
symlink("$name.tar.gz", $nightly_symlink);
}
chdir($nightly) or die $!;
foreach my $fn (qw( rsync.yo rsyncd.conf.yo )) {
my $html_fn = $fn;
$html_fn =~ s/\.yo/.html/;
open(IN, '<', "$unpacked/$fn") or die $!;
undef $/; $_ = <IN>; $/ = "\n";
close IN;
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m;
#s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m;
open(OUT, '>', $fn) or die $!;
print OUT $_;
close OUT;
system "yodl2html -o $html_fn $fn";
unlink($fn);
}
system "find . -name 'rsync-HEAD-*' -daystart -mtime +14 | xargs rm -f";
system 'ls -ltr';
if ($upload) {
my $opt = '';
if (defined $ENV{RSYNC_PARTIAL_DIR}) {
$opt = " -f 'R $ENV{RSYNC_PARTIAL_DIR}'";
}
system "rsync$opt -aviHP --delete-after . samba.org:/home/ftp/pub/rsync/nightly";
}
exit;
sub usage
{
die <<EOT;
Usage: nightly-rsync [OPTIONS]
-c, --cvs-update update $unpacked via CVS.
-t, --make-tar create a new tar file in $nightly
-u, --upload upload the revised nightly dir to samba.org
-h, --help display this help
EOT
}

View File

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

View File

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

View File

@@ -1,319 +0,0 @@
#!/usr/bin/perl
use strict;
# This script expects the directory ~/samba-rsync-ftp to exist and to
# be a copy of the /home/ftp/pub/rsync dir on samba.org. If it is run
# in test mode, it instead expects a dir named ~/tmp/samba-rsync-ftp
# (e.g. copy ~/samba-rsync-ftp into ~/tmp and you can do a trial-run of
# a release without affecting the files in the ~/samba-rsync-ftp dir).
#
# Run this as "release-rsync live" to affect ~/samba-rsync-ftp instead
# of ~/tmp/samba-rsync-ftp.
use Date::Format;
my $dest = $ENV{HOME} . '/samba-rsync-ftp';
my $releasedir = $ENV{HOME} . '/release';
my $cvsroot = $ENV{CVSROOT} = 'samba.org:/data/cvs';
my $ztoday = time2str('%d %b %Y', time);
my $today = $ztoday;
$today =~ s/^0//;
my $break = <<EOT;
==========================================================================
EOT
my $note = <<EOT;
== Note: type "-a u,n" if you want to auto-accept the U,N suggestions. ==
EOT
my $live = shift;
my $skipping = '';
print $break;
if ($live) {
print <<EOT;
== This will release a new version of rsync onto an unsuspecting world. ==
EOT
} else {
print <<EOT;
== **** TESTMODE **** (Add "live" arg to avoid this.) ==
EOT
$dest =~ s#([^/]+$)#tmp/$1#;
$skipping = ' ** SKIPPING **';
}
die "$dest does not exist\n" unless -d $dest;
print $break, "\nChecking out the latest rsync into $releasedir ...\n";
mkdir($releasedir, 0755) or die $! unless -d $releasedir;
chdir($releasedir) or die $!;
system 'rm -rf rsync';
my(%dirs, @files);
open(CVS, '-|', 'cvs checkout -P rsync') or die $!;
while (<CVS>) {
print $_;
next if /\.(cvs)?ignore$/;
if (m#^[UP] rsync/(.*)#) {
my $fn = $1;
my($dir) = $fn =~ m#^(.+)/#;
push(@files, $dir) if defined($dir) && !$dirs{$1}++;
push(@files, $fn);
}
}
chdir('rsync') or die $!;
my($version, $lastversion);
open(IN, 'configure.in') or die $!;
while (<IN>) {
if (/^RSYNC_VERSION=(.*)/) {
$version = $lastversion = $1;
last;
}
}
close IN;
$lastversion =~ s/(\d+)cvs$/ $1 - 1 /e;
$version =~ s/cvs/pre1/ || $version =~ s/pre(\d+)/ 'pre' . ($1 + 1) /e;
print $break, "\nPlease enter the version number of this release: [$version] ";
chomp($_ = <STDIN>);
if ($_ eq '.') {
$version =~ s/pre\d+//;
} elsif ($_ ne '') {
$version = $_;
}
$version =~ s/[-.]*pre[-.]*/pre/;
$lastversion =~ s/(\d+)pre\d+$/ $1 - 1 /e unless $version =~ /pre/;
my $cvstag = "release-$version";
$cvstag =~ s/[.]/-/g;
$cvstag =~ s/pre/-pre/;
print "Enter the previous version to produce a patch against: [$lastversion] ";
chomp($_ = <STDIN>);
$lastversion = $_ if $_ ne '';
$lastversion =~ s/[-.]*pre[-.]*/pre/;
my $release = 1;
print "Please enter the RPM release number of this release: [$release] ";
chomp($_ = <STDIN>);
$release = $_ if $_ ne '';
my $diffdir;
my $skipping2;
if ($lastversion =~ /pre/) {
if ($version !~ /pre/) {
die "You should not diff a release version against a pre-release version.\n";
}
$diffdir = "$dest/old-previews";
$skipping2 = ' ** SKIPPING **';
} elsif ($version =~ /pre/) {
$diffdir = $dest;
$skipping2 = ' ** SKIPPING **';
} else {
$diffdir = "$dest/old-versions";
$skipping2 = '';
}
print "\n", $break, <<EOT;
\$version is "$version"
\$lastversion is "$lastversion"
\$cvstag is "$cvstag"
\$dest is "$dest"
\$releasedir is "$releasedir"
\$diffdir is "$diffdir"
\$release is "$release"
About to:
- make sure that configure, config.h.in, and proto.h are updated
- tweak the version in configure.in, configure, and the spec files
- tweak NEWS and OLDNEWS to update the release date$skipping2
- tweak the date in the *.yo files and re-generate the man pages
- make sure that the patches dir has been updated
- page through the "cvs diff" output
EOT
print "<Press Enter to continue> ";
$_ = <STDIN>;
my $f_opt = /f/ ? ' -f' : '';
print $break;
system "./prepare-source && touch proto.h";
my @tweak_files = ( glob('packaging/*.spec'), glob('packaging/*/*.spec'),
glob('*.yo'), qw( configure.in configure ) );
if ($version !~ /pre/) {
push(@tweak_files, qw( NEWS OLDNEWS ));
}
foreach my $fn (@tweak_files) {
open(IN, '<', $fn) or die $!;
undef $/; $_ = <IN>; $/ = "\n";
close IN;
if ($fn =~ /configure/) {
s/^RSYNC_VERSION=.*/RSYNC_VERSION=$version/m;
} elsif ($fn =~ /\.spec/) {
s/^(Version:) .*/$1 $version/m;
s/^(Release:) .*/$1 $release/m;
} elsif ($fn =~ /\.yo/) {
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m;
s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m;
} elsif ($fn eq 'NEWS') {
s/^(NEWS for rsync \Q$version\E) \(UNRELEASED\)\s*\n/$1 ($today)\n/mi
or die "Couldn't update NEWS file with release date!\n";
} elsif ($fn eq 'OLDNEWS') {
s/^\t\S\S\s\S\S\S\s\d\d\d\d(\t\Q$version\E)/\t$ztoday$1/m
or die "Couldn't update OLDNEWS file with release date!\n";
} else {
die "Unrecognized file in \@tweak_files: $fn\n";
}
open(OUT, '>', $fn) or die $!;
print OUT $_;
close OUT;
}
system "yodl2man -o rsync.1 rsync.yo; ./tweak_manpage_dashes rsync.1";
system "yodl2man -o rsyncd.conf.5 rsyncd.conf.yo; ./tweak_manpage_dashes rsyncd.conf.5";
mkdir('patches/tmp') or die $!;
system "rsync -a --exclude=patches/ --exclude-from=.cvsignore . patches/tmp/cvsdir/";
print "\n", $break, $note, $break;
system "patches/verify-patches -n -an$f_opt";
print $break;
system "cvs -q diff | egrep -v '^(===============|RCS file: |retrieving revision |Index: )' | less -p '^diff .*'";
print $break, <<EOT;
About to:
- "cvs commit" all changes$skipping
- "cvs tag" this release as $cvstag$skipping
- change the diffs in the patches dir to include generated files
EOT
print "<Press Enter to continue> ";
$_ = <STDIN>;
if ($live) {
system "cvs commit -m 'Preparing for release of $version'";
system "cvs tag -F $cvstag .";
}
if (!/skip/i) {
print "\n", $break, $note, $break;
system "patches/verify-patches -pun -an";
}
my $tar_name = "rsync-$version.tar.gz";
my $diff_name = "rsync-$lastversion-$version.diffs.gz";
my $tar_file = "$dest/$tar_name";
my $diff_file = "$dest/$diff_name";
print $break, <<EOT;
About to do the following in the samba-rsync-ftp dir:
- move the old tar/diff files into the appropriate old-* dirs
- hard-link the moved tar/diff files on samba.org$skipping
- create release tar, "$tar_name"
- create release diffs, "$diff_name"
- update README, *NEWS, TODO, and cvs.log
- update rsync*.html man pages
- gpg-sign the release files$skipping
EOT
print "<Press Enter to continue> ";
$_ = <STDIN>;
chdir($releasedir) or die $!;
print $break;
system "rm -rf rsync-$version";
rename('rsync', "rsync-$version") or die $!;
# When creating a pre-release after a normal release, there's nothing to move.
if ($diffdir ne $dest) {
chdir($dest) or die $!;
print "Shuffling old files ...\n";
# We need to run this regardless of $lastversion's "pre"ness.
my @moved_files;
foreach my $fn (glob('rsync*pre*.tar.gz*'), glob('rsync*pre*-NEWS')) {
link($fn, "old-previews/$fn") or die $!;
push(@moved_files, $fn);
}
if ($version !~ /pre/) {
foreach my $fn (glob('rsync*.tar.gz*'), glob('rsync*-NEWS')) {
next if $fn =~ /^rsync.*pre/;
link($fn, "old-versions/$fn") or die $!;
push(@moved_files, $fn);
}
foreach my $fn (glob('rsync*pre*.diffs.gz*')) {
unlink($fn);
}
foreach my $fn (glob('rsync*.diffs.gz*')) {
link($fn, "old-patches/$fn") or die $!;
push(@moved_files, $fn);
}
}
# Optimize our future upload (in the absence of --detect-renamed) by
# using rsync to hard-link the above files on samba.org.
if ($live) {
system "rsync -avHOC --include='rsync*.gz*' --include='old-*/' --exclude='*' . samba.org:/home/ftp/pub/rsync";
}
foreach (@moved_files) {
unlink($_);
}
chdir($releasedir) or die $!;
}
print "Creating $tar_file ...\n";
system "fakeroot tar czf $tar_file rsync-$version";
open(TAR, '|-', "fakeroot tar --files-from=- --no-recursion --mode=g+w -czf $tar_file rsync-$version") or die $!;
foreach (@files) {
print TAR "rsync-$version/$_\n";
}
close TAR;
print "Creating $diff_file ...\n";
system "rm -rf rsync-$version rsync-$lastversion";
system "tar xzf $tar_file; tar xzf $diffdir/rsync-$lastversion.tar.gz";
## TWEAK THE VERSIONS AS DESIRED HERE ##
#mkdir("rsync-$lastversion/support", 0755) or die $!;
#rename("rsync-$lastversion/rsyncstats", "rsync-$lastversion/support/rsyncstats");
#unlink("rsync-$lastversion/.ignore");
## END ##
system "diff -urN --exclude=patches rsync-$lastversion rsync-$version| gzip -9 >$diff_file";
print "Updating the other files in $dest ...\n";
system "rsync -a rsync-$version/{README,NEWS,OLDNEWS,TODO} $dest";
unlink("$dest/rsync-$version-NEWS");
link("$dest/NEWS", "$dest/rsync-$version-NEWS");
system "rsync -a $cvsroot/CVSROOT/rsync.updates $dest/cvs.log";
system "yodl2html -o $dest/rsync.html rsync-$version/rsync.yo";
system "yodl2html -o $dest/rsyncd.conf.html rsync-$version/rsyncd.conf.yo";
system "rm -rf rsync-*";
if ($live) {
chdir($dest) or die $!;
system "gpg -ba $tar_name; gpg -ba $diff_name";
print $break, <<EOT;
All done. Remember to announce the release on *BOTH*
rsync-announce\@lists.samba.org and rsync\@lists.samba.org!
EOT
} else {
print $break, "All done.\n";
}

View File

@@ -1,7 +1,7 @@
/* This modules is based on the params.c module from Samba, written by Karl Auer
and much modifed by Christopher Hertel. */
/*
This modules is based on the params.c module from Samba, written by Karl Auer
and much modifed by Christopher Hertel.
* 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
@@ -12,12 +12,11 @@
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* -------------------------------------------------------------------------- **
* 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.
*
* -------------------------------------------------------------------------- **
*
* Module name: params
*
@@ -492,8 +491,8 @@ static FILE *OpenConfFile( char *FileName )
OpenedFile = fopen( FileName, "r" );
if( NULL == OpenedFile )
{
rsyserr(FERROR, errno, "unable to open configuration file \"%s\"",
FileName);
rprintf(FERROR,"rsync: unable to open configuration file \"%s\": %s\n",
FileName, strerror(errno));
}
return( OpenedFile );

110
pipe.c
View File

@@ -1,41 +1,31 @@
/*
* Routines used to setup various kinds of inter-process pipes.
*
* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2004, 2005, 2006 Wayne Davison
*
/* -*- c-file-style: "linux" -*-
*
* Copyright (C) 1996-2000 by Andrew Tridgell
* Copyright (C) Paul Mackerras 1996
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*
* 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 am_sender;
extern int am_server;
extern int blocking_io;
extern int filesfrom_fd;
extern mode_t orig_umask;
extern char *logfile_name;
extern struct chmod_mode_struct *chmod_modes;
/**
* Create a child connected to us via its stdin/stdout.
*
* This is derived from CVS code
* Create a child connected to use on stdin/stdout.
*
* This is derived from CVS code
*
* Note that in the child STDIN is set to blocking and STDOUT
* is set to non-blocking. This is necessary as rsh relies on stdin being blocking
* and ssh relies on stdout being non-blocking
@@ -49,28 +39,32 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
pid_t pid;
int to_child_pipe[2];
int from_child_pipe[2];
extern int blocking_io;
if (verbose >= 2) {
print_child_argv(command);
}
if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
rsyserr(FERROR, errno, "pipe");
rprintf(FERROR, "pipe: %s\n", strerror(errno));
exit_cleanup(RERR_IPC);
}
pid = do_fork();
if (pid == -1) {
rsyserr(FERROR, errno, "fork");
rprintf(FERROR, "fork: %s\n", strerror(errno));
exit_cleanup(RERR_IPC);
}
if (pid == 0) {
extern int orig_umask;
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
close(to_child_pipe[1]) < 0 ||
close(from_child_pipe[0]) < 0 ||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
rsyserr(FERROR, errno, "Failed to dup/close");
rprintf(FERROR, "Failed to dup/close : %s\n",
strerror(errno));
exit_cleanup(RERR_IPC);
}
if (to_child_pipe[0] != STDIN_FILENO)
@@ -79,15 +73,17 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
close(from_child_pipe[1]);
umask(orig_umask);
set_blocking(STDIN_FILENO);
if (blocking_io > 0)
if (blocking_io) {
set_blocking(STDOUT_FILENO);
}
execvp(command[0], command);
rsyserr(FERROR, errno, "Failed to exec %s", command[0]);
rprintf(FERROR, "Failed to exec %s : %s\n",
command[0], strerror(errno));
exit_cleanup(RERR_IPC);
}
if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
rsyserr(FERROR, errno, "Failed to close");
rprintf(FERROR, "Failed to close : %s\n", strerror(errno));
exit_cleanup(RERR_IPC);
}
@@ -97,72 +93,60 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
return pid;
}
/* This function forks a child which calls child_main(). First,
* however, it has to establish communication paths to and from the
* newborn child. It creates two socket pairs -- one for writing to
* the child (from the parent) and one for reading from the child
* (writing to the parent). Since that's four socket ends, each
* process has to close the two ends it doesn't need. The remaining
* two socket ends are retained for reading and writing. In the
* child, the STDIN and STDOUT file descriptors refer to these
* sockets. In the parent, the function arguments f_in and f_out are
* set to refer to these sockets. */
pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
int (*child_main)(int, char*[]))
{
pid_t pid;
int to_child_pipe[2];
int from_child_pipe[2];
/* The parent process is always the sender for a local rsync. */
assert(am_sender);
extern int read_batch;
extern int am_sender;
extern int am_server;
extern int filesfrom_fd;
if (fd_pair(to_child_pipe) < 0 ||
fd_pair(from_child_pipe) < 0) {
rsyserr(FERROR, errno, "pipe");
rprintf(FERROR,"pipe: %s\n",strerror(errno));
exit_cleanup(RERR_IPC);
}
pid = do_fork();
if (pid == -1) {
rsyserr(FERROR, errno, "fork");
rprintf(FERROR,"fork: %s\n",strerror(errno));
exit_cleanup(RERR_IPC);
}
if (pid == 0) {
am_sender = 0;
am_server = 1;
filesfrom_fd = -1;
chmod_modes = NULL; /* Let the sending side handle this. */
am_sender = read_batch ? 0 : !am_sender;
am_server = 1;
if (!am_sender)
filesfrom_fd = -1;
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
close(to_child_pipe[1]) < 0 ||
close(from_child_pipe[0]) < 0 ||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
rsyserr(FERROR, errno, "Failed to dup/close");
rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
exit_cleanup(RERR_IPC);
}
if (to_child_pipe[0] != STDIN_FILENO)
close(to_child_pipe[0]);
if (from_child_pipe[1] != STDOUT_FILENO)
close(from_child_pipe[1]);
if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
child_main(argc, argv);
}
/* Let the client side handle this. */
if (logfile_name) {
logfile_name = NULL;
logfile_close();
}
if (!am_sender)
filesfrom_fd = -1;
if (close(from_child_pipe[1]) < 0 ||
close(to_child_pipe[0]) < 0) {
rsyserr(FERROR, errno, "Failed to close");
rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
exit_cleanup(RERR_IPC);
}
*f_in = from_child_pipe[0];
*f_out = to_child_pipe[1];
return pid;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,12 +0,0 @@
#!/bin/sh
# Use autoconf, autoheader, yodl, etc. to ready the generated files in the
# release. This is typically used after applying a diff from the "patches"
# directory in a CVS-checked-out version.
#
# NOTE: if you use a diff from the "patches" directory of a *release tar*
# (as opposed to from CVS), this is not needed (but doesn't hurt anything).
dir=`dirname $0`
if test x"$dir" != x -a x"$dir" != x.; then
cd "$dir"
fi
make -f prepare-source.mak

View File

@@ -1,25 +0,0 @@
gen: configure config.h.in proto.h man
configure: configure.in aclocal.m4
autoconf
config.h.in: configure.in aclocal.m4
autoheader && touch config.h.in
proto.h: *.c lib/compat.c
cat *.c lib/compat.c | awk -f mkproto.awk >proto.h.new
if diff proto.h proto.h.new >/dev/null; then \
rm proto.h.new; \
else \
mv proto.h.new proto.h; \
fi
man: rsync.1 rsyncd.conf.5
rsync.1: rsync.yo
yodl2man -o rsync.1 rsync.yo
-./tweak_manpage_dashes rsync.1
rsyncd.conf.5: rsyncd.conf.yo
yodl2man -o rsyncd.conf.5 rsyncd.conf.yo
-./tweak_manpage_dashes rsyncd.conf.5

View File

@@ -1,52 +1,35 @@
/*
* Routines to output progress information during a file transfer.
*
* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
*
/* -*- c-file-style: "linux" -*-
*
* Copyright (C) 1996-2000 by Andrew Tridgell
* Copyright (C) Paul Mackerras 1996
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*
* 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 struct stats stats;
extern int am_server;
#define PROGRESS_HISTORY_SECS 5
#ifdef GETPGRP_VOID
#define GETPGRP_ARG
#else
#define GETPGRP_ARG 0
#endif
struct progress_history {
struct timeval time;
OFF_T ofs;
};
static struct progress_history ph_start;
static struct progress_history ph_list[PROGRESS_HISTORY_SECS];
static int newest_hpos, oldest_hpos;
static OFF_T last_ofs;
static struct timeval print_time;
static struct timeval start_time;
static OFF_T start_ofs;
static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
{
return (t2->tv_sec - t1->tv_sec) * 1000L
+ (t2->tv_usec - t1->tv_usec) / 1000;
return (t2->tv_sec - t1->tv_sec) * 1000
+ (t2->tv_usec - t1->tv_usec) / 1000;
}
@@ -60,118 +43,79 @@ static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
int is_last)
{
char eol[256];
const char *units;
int pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
unsigned long diff;
double rate, remain;
int remain_h, remain_m, remain_s;
int pct = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
unsigned long diff = msdiff(&start_time, now);
double rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
const char *units;
/* If we've finished transferring this file, show the time taken;
* otherwise show expected time to complete. That's kind of
* inconsistent, but people can probably cope. Hopefully we'll
* get more consistent and complete progress reporting soon. --
* mbp */
double remain = is_last
? (double) diff / 1000.0
: rate ? (double) (size-ofs) / rate / 1000.0 : 0.0;
int remain_h, remain_m, remain_s;
if (is_last) {
/* Compute stats based on the starting info. */
if (!ph_start.time.tv_sec
|| !(diff = msdiff(&ph_start.time, now)))
diff = 1;
rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0;
/* Switch to total time taken for our last update. */
remain = (double) diff / 1000.0;
} else {
/* Compute stats based on recent progress. */
if (!(diff = msdiff(&ph_list[oldest_hpos].time, now)))
diff = 1;
rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0
/ diff / 1024.0;
remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
}
if (rate > 1024*1024) {
rate /= 1024.0 * 1024.0;
units = "GB/s";
} else if (rate > 1024) {
rate /= 1024.0;
units = "MB/s";
} else {
units = "kB/s";
}
if (rate > 1024*1024) {
rate /= 1024.0 * 1024.0;
units = "GB/s";
} else if (rate > 1024) {
rate /= 1024.0;
units = "MB/s";
} else {
units = "kB/s";
}
remain_s = (int) remain % 60;
remain_m = (int) (remain / 60.0) % 60;
remain_h = (int) (remain / 3600.0);
if (is_last) {
snprintf(eol, sizeof eol, " (xfer#%d, to-check=%d/%d)\n",
stats.num_transferred_files,
stats.num_files - stats.current_file_index - 1,
stats.num_files);
} else
strlcpy(eol, "\r", sizeof eol);
rprintf(FCLIENT, "%12s %3d%% %7.2f%s %4d:%02d:%02d%s",
human_num(ofs), pct, rate, units,
remain_h, remain_m, remain_s, eol);
remain_s = (int) remain % 60;
remain_m = (int) (remain / 60.0) % 60;
remain_h = (int) (remain / 3600.0);
rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
(double) ofs, pct, rate, units,
remain_h, remain_m, remain_s,
is_last ? "\n" : "\r");
}
void end_progress(OFF_T size)
{
extern int am_server;
if (!am_server) {
struct timeval now;
gettimeofday(&now, NULL);
rprint_progress(size, size, &now, True);
}
memset(&ph_start, 0, sizeof ph_start);
last_ofs = 0;
start_ofs = 0;
print_time.tv_sec = print_time.tv_usec = 0;
start_time.tv_sec = start_time.tv_usec = 0;
}
void show_progress(OFF_T ofs, OFF_T size)
{
extern int am_server;
struct timeval now;
#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
static pid_t pgrp = -1;
pid_t tc_pgrp;
#endif
if (am_server)
return;
#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
if (pgrp == -1)
pgrp = getpgrp(GETPGRP_ARG);
#endif
gettimeofday(&now, NULL);
if (!ph_start.time.tv_sec) {
int i;
/* Try to guess the real starting time when the sender started
* to send us data by using the time we last received some data
* in the last file (if it was recent enough). */
if (msdiff(&ph_list[newest_hpos].time, &now) <= 1500) {
ph_start.time = ph_list[newest_hpos].time;
ph_start.ofs = 0;
} else {
ph_start.time.tv_sec = now.tv_sec;
ph_start.time.tv_usec = now.tv_usec;
ph_start.ofs = ofs;
}
for (i = 0; i < PROGRESS_HISTORY_SECS; i++)
ph_list[i] = ph_start;
if (!start_time.tv_sec) {
gettimeofday(&now, NULL);
start_time.tv_sec = now.tv_sec;
start_time.tv_usec = now.tv_usec;
start_ofs = ofs;
if (am_server)
return;
}
else {
if (msdiff(&ph_list[newest_hpos].time, &now) < 1000)
if (am_server)
return;
newest_hpos = oldest_hpos;
oldest_hpos = (oldest_hpos + 1) % PROGRESS_HISTORY_SECS;
ph_list[newest_hpos].time.tv_sec = now.tv_sec;
ph_list[newest_hpos].time.tv_usec = now.tv_usec;
ph_list[newest_hpos].ofs = ofs;
gettimeofday(&now, NULL);
}
#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
tc_pgrp = tcgetpgrp(STDOUT_FILENO);
if (tc_pgrp != pgrp && tc_pgrp != -1)
return;
#endif
rprint_progress(ofs, size, &now, False);
if (ofs > last_ofs + 1000
&& msdiff(&print_time, &now) > 250) {
rprint_progress(ofs, size, &now, False);
last_ofs = ofs;
print_time.tv_sec = now.tv_sec;
print_time.tv_usec = now.tv_usec;
}
}

View File

File diff suppressed because it is too large Load Diff

422
rsync.c
View File

@@ -1,93 +1,36 @@
/*
* Routines common to more than one of the rsync processes.
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
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.
*/
/* this file contains code used by more than one part of the rsync
process */
#include "rsync.h"
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
#include <iconv.h>
#endif
#if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
#include <libcharset.h>
#elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
#include <langinfo.h>
#endif
extern int verbose;
extern int dry_run;
extern int preserve_perms;
extern int preserve_executability;
extern int preserve_times;
extern int omit_dir_times;
extern int am_root;
extern int am_server;
extern int am_sender;
extern int am_generator;
extern int am_starting_up;
extern int allow_8bit_chars;
extern int preserve_uid;
extern int preserve_gid;
extern int inplace;
extern int keep_dirlinks;
extern int preserve_perms;
extern int make_backups;
extern mode_t orig_umask;
extern struct stats stats;
extern struct chmod_mode_struct *daemon_chmod_modes;
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
iconv_t ic_chck = (iconv_t)-1;
static const char *default_charset(void)
{
#if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
return locale_charset();
#elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
return nl_langinfo(CODESET);
#else
return ""; /* Works with (at the very least) gnu iconv... */
#endif
}
void setup_iconv()
{
if (!am_server && !allow_8bit_chars) {
const char *defset = default_charset();
/* It's OK if this fails... */
ic_chck = iconv_open(defset, defset);
if (verbose > 3) {
if (ic_chck == (iconv_t)-1) {
rprintf(FINFO,
"note: iconv_open(\"%s\", \"%s\") failed (%d)"
" -- using isprint() instead of iconv().\n",
defset, defset, errno);
} else {
rprintf(FINFO,
"note: iconv_open(\"%s\", \"%s\") succeeded.\n",
defset, defset);
}
}
}
}
#endif
/*
free a sums struct
@@ -98,212 +41,219 @@ void free_sums(struct sum_struct *s)
free(s);
}
/* This is only called when we aren't preserving permissions. Figure out what
* the permissions should be and return them merged back into the mode. */
mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int exists)
/*
* delete a file or directory. If force_delete is set then delete
* recursively
*/
int delete_file(char *fname)
{
int new_mode;
/* If the file already exists, we'll return the local permissions,
* possibly tweaked by the --executability option. */
if (exists) {
new_mode = (flist_mode & ~CHMOD_BITS) | (stat_mode & CHMOD_BITS);
if (preserve_executability && S_ISREG(flist_mode)) {
/* If the source file is executable, grant execute
* rights to everyone who can read, but ONLY if the
* file isn't already executable. */
if (!(flist_mode & 0111))
new_mode &= ~0111;
else if (!(stat_mode & 0111))
new_mode |= (new_mode & 0444) >> 2;
}
} else {
/* Apply the umask and turn off special permissions. */
new_mode = flist_mode & (~CHMOD_BITS | (ACCESSPERMS & ~orig_umask));
DIR *d;
struct dirent *di;
char buf[MAXPATHLEN];
extern int force_delete;
STRUCT_STAT st;
int ret;
extern int recurse;
#if SUPPORT_LINKS
ret = do_lstat(fname, &st);
#else
ret = do_stat(fname, &st);
#endif
if (ret) {
return -1;
}
return new_mode;
if (!S_ISDIR(st.st_mode)) {
if (robust_unlink(fname) == 0 || errno == ENOENT) return 0;
rprintf(FERROR,"delete_file: unlink(%s) : %s\n", fname, strerror(errno));
return -1;
}
if (do_rmdir(fname) == 0 || errno == ENOENT) return 0;
if (!force_delete || !recurse ||
(errno != ENOTEMPTY && errno != EEXIST)) {
rprintf(FERROR,"delete_file: rmdir(%s) : %s\n", fname, strerror(errno));
return -1;
}
/* now we do a recsursive delete on the directory ... */
d = opendir(fname);
if (!d) {
rprintf(FERROR,"delete_file: opendir(%s): %s\n",
fname,strerror(errno));
return -1;
}
for (di=readdir(d); di; di=readdir(d)) {
char *dname = d_name(di);
if (strcmp(dname,".")==0 ||
strcmp(dname,"..")==0)
continue;
snprintf(buf, sizeof(buf), "%s/%s", fname, dname);
if (verbose > 0)
rprintf(FINFO,"deleting %s\n", buf);
if (delete_file(buf) != 0) {
closedir(d);
return -1;
}
}
closedir(d);
if (do_rmdir(fname) != 0) {
rprintf(FERROR,"delete_file: rmdir(%s) : %s\n", fname, strerror(errno));
return -1;
}
return 0;
}
int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
int flags)
static int is_in_group(gid_t gid)
{
#ifdef GETGROUPS_T
static gid_t last_in = (gid_t) -2, last_out;
static int ngroups = -2;
static GETGROUPS_T *gidset;
int n;
if (gid == last_in)
return last_out;
if (ngroups < -1) {
/* treat failure (-1) as if not member of any group */
ngroups = getgroups(0, 0);
if (ngroups > 0) {
gidset = new_array(GETGROUPS_T, ngroups);
ngroups = getgroups(ngroups, gidset);
}
}
last_in = gid;
last_out = 0;
for (n = 0; n < ngroups; n++) {
if (gidset[n] == gid) {
last_out = 1;
break;
}
}
return last_out;
#else
return 0;
#endif
}
int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
int report)
{
int updated = 0;
STRUCT_STAT st2;
int change_uid, change_gid;
mode_t new_mode = file->mode;
if (dry_run) return 0;
if (!st) {
if (dry_run)
return 1;
if (link_stat(fname, &st2, 0) < 0) {
rsyserr(FERROR, errno, "stat %s failed",
full_fname(fname));
if (link_stat(fname,&st2) != 0) {
rprintf(FERROR,"stat %s : %s\n",fname,strerror(errno));
return 0;
}
st = &st2;
if (!preserve_perms && S_ISDIR(new_mode)
&& st->st_mode & S_ISGID) {
/* We just created this directory and its setgid
* bit is on, so make sure it stays on. */
new_mode |= S_ISGID;
}
}
if (!preserve_times || (S_ISDIR(st->st_mode) && omit_dir_times))
flags |= ATTRS_SKIP_MTIME;
if (!(flags & ATTRS_SKIP_MTIME)
&& cmp_time(st->st_mtime, file->modtime) != 0) {
int ret = set_modtime(fname, file->modtime, st->st_mode);
if (ret < 0) {
rsyserr(FERROR, errno, "failed to set times on %s",
full_fname(fname));
if (preserve_times && !S_ISLNK(st->st_mode) &&
cmp_modtime(st->st_mtime, file->modtime) != 0) {
/* don't complain about not setting times on directories
because some filesystems can't do it */
if (set_modtime(fname,file->modtime) != 0 &&
!S_ISDIR(st->st_mode)) {
rprintf(FERROR,"failed to set times on %s : %s\n",
fname,strerror(errno));
return 0;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
} else {
updated = 1;
}
}
change_uid = am_root && preserve_uid && st->st_uid != file->uid;
change_gid = preserve_gid && file->gid != GID_NONE
&& st->st_gid != file->gid;
#if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK
if (S_ISLNK(st->st_mode))
;
else
#endif
change_gid = preserve_gid && file->gid != (gid_t) -1 && \
st->st_gid != file->gid;
if (change_gid && !am_root) {
/* enforce bsd-style group semantics: non-root can only
change to groups that the user is a member of */
change_gid = is_in_group(file->gid);
}
if (change_uid || change_gid) {
if (verbose > 2) {
if (change_uid) {
rprintf(FINFO,
"set uid of %s from %ld to %ld\n",
fname,
(long)st->st_uid, (long)file->uid);
}
if (change_gid) {
rprintf(FINFO,
"set gid of %s from %ld to %ld\n",
fname,
(long)st->st_gid, (long)file->gid);
}
}
if (do_lchown(fname,
change_uid ? file->uid : st->st_uid,
change_gid ? file->gid : st->st_gid) != 0) {
change_uid?file->uid:st->st_uid,
change_gid?file->gid:st->st_gid) != 0) {
/* shouldn't have attempted to change uid or gid
* unless have the privilege */
rsyserr(FERROR, errno, "%s %s failed",
change_uid ? "chown" : "chgrp",
full_fname(fname));
unless have the privilege */
rprintf(FERROR,"chown %s : %s\n", fname,strerror(errno));
return 0;
}
/* a lchown had been done - we have to re-stat if the
* destination had the setuid or setgid bits set due
* to the side effect of the chown call */
destination had the setuid or setgid bits set due
to the side effect of the chown call */
if (st->st_mode & (S_ISUID | S_ISGID)) {
link_stat(fname, st,
keep_dirlinks && S_ISDIR(st->st_mode));
link_stat(fname, st);
}
updated = 1;
}
if (daemon_chmod_modes && !S_ISLNK(new_mode))
new_mode = tweak_mode(new_mode, daemon_chmod_modes);
#ifdef HAVE_CHMOD
if ((st->st_mode & CHMOD_BITS) != (new_mode & CHMOD_BITS)) {
int ret = do_chmod(fname, new_mode);
if (ret < 0) {
rsyserr(FERROR, errno,
"failed to set permissions on %s",
full_fname(fname));
return 0;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
if (!S_ISLNK(st->st_mode)) {
if (st->st_mode != file->mode) {
updated = 1;
if (do_chmod(fname,file->mode) != 0) {
rprintf(FERROR,"failed to set permissions on %s : %s\n",
fname,strerror(errno));
return 0;
}
}
}
#endif
if (verbose > 1 && flags & ATTRS_REPORT) {
if (verbose > 1 && report) {
if (updated)
rprintf(FCLIENT, "%s\n", fname);
rprintf(FINFO,"%s\n",fname);
else
rprintf(FCLIENT, "%s is uptodate\n", fname);
rprintf(FINFO,"%s is uptodate\n",fname);
}
return updated;
}
RETSIGTYPE sig_int(UNUSED(int val))
void sig_int(void)
{
/* KLUGE: if the user hits Ctrl-C while ssh is prompting
* for a password, then our cleanup's sending of a SIGUSR1
* signal to all our children may kill ssh before it has a
* chance to restore the tty settings (i.e. turn echo back
* on). By sleeping for a short time, ssh gets a bigger
* chance to do the right thing. If child processes are
* not ssh waiting for a password, then this tiny delay
* shouldn't hurt anything. */
msleep(400);
exit_cleanup(RERR_SIGNAL);
}
/* Finish off a file transfer: renaming the file and setting the file's
* attributes (e.g. permissions, ownership, etc.). If partialptr is not
* NULL and the robust_rename() call is forced to copy the temp file, we
* stage the file into the partial-dir and then rename it into place. */
void finish_transfer(char *fname, char *fnametmp, char *partialptr,
struct file_struct *file, int ok_to_set_time,
int overwriting_basis)
/* finish off a file transfer, renaming the file and setting the permissions
and ownership */
void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
{
int ret;
if (inplace) {
if (verbose > 2)
rprintf(FINFO, "finishing %s\n", fname);
fnametmp = fname;
goto do_set_file_attrs;
}
if (make_backups && overwriting_basis && !make_backup(fname))
if (make_backups && !make_backup(fname))
return;
/* Change permissions before putting the file into place. */
set_file_attrs(fnametmp, file, NULL,
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
/* move tmp file over real file */
if (verbose > 2)
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
ret = robust_rename(fnametmp, fname, partialptr,
file->mode & INITACCESSPERMS);
if (ret < 0) {
rsyserr(FERROR, errno, "%s %s -> \"%s\"",
ret == -2 ? "copy" : "rename",
full_fname(fnametmp), fname);
if (robust_rename(fnametmp,fname) != 0) {
if (errno == EXDEV) {
/* rename failed on cross-filesystem link.
Copy the file instead. */
if (copy_file(fnametmp,fname, file->mode & INITACCESSPERMS)) {
rprintf(FERROR,"copy %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
} else {
set_perms(fname,file,NULL,0);
}
} else {
rprintf(FERROR,"rename %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
}
do_unlink(fnametmp);
return;
}
if (ret == 0) {
/* The file was moved into place (not copied), so it's done. */
return;
}
/* The file was copied, so tweak the perms of the copied file. If it
* was copied to partialptr, move it into its final destination. */
fnametmp = partialptr ? partialptr : fname;
do_set_file_attrs:
set_file_attrs(fnametmp, file, NULL,
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
if (partialptr) {
if (do_rename(fnametmp, fname) < 0) {
rsyserr(FERROR, errno, "rename %s -> \"%s\"",
full_fname(fnametmp), fname);
} else
handle_partial_dir(partialptr, PDIR_DELETE);
} else {
set_perms(fname,file,NULL,0);
}
}
const char *who_am_i(void)
{
if (am_starting_up)
return am_server ? "server" : "client";
return am_sender ? "sender" : am_generator ? "generator" : "receiver";
}

645
rsync.h
View File

@@ -1,33 +1,32 @@
/*
* Copyright (C) 1996, 2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Copyright (C) by Andrew Tridgell 1996, 2000
Copyright (C) Paul Mackerras 1996
Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define False 0
#define True 1
#define BLOCK_SIZE 700
#define RSYNC_RSH_ENV "RSYNC_RSH"
#define RSYNC_RSH_IO_ENV "RSYNC_RSH_IO"
#define RSYNC_NAME "rsync"
/* RSYNCD_SYSCONF is now set in config.h */
#define RSYNCD_SYSCONF "/etc/rsyncd.conf"
#define RSYNCD_USERCONF "rsyncd.conf"
#define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock"
@@ -39,56 +38,32 @@
incompatible with older versions :-( */
#define CHAR_OFFSET 0
/* These flags are only used during the flist transfer. */
#define XMIT_TOP_DIR (1<<0)
#define XMIT_SAME_MODE (1<<1)
#define XMIT_EXTENDED_FLAGS (1<<2)
#define XMIT_SAME_RDEV_pre28 XMIT_EXTENDED_FLAGS /* Only in protocols < 28 */
#define XMIT_SAME_UID (1<<3)
#define XMIT_SAME_GID (1<<4)
#define XMIT_SAME_NAME (1<<5)
#define XMIT_LONG_NAME (1<<6)
#define XMIT_SAME_TIME (1<<7)
#define XMIT_SAME_RDEV_MAJOR (1<<8)
#define XMIT_HAS_IDEV_DATA (1<<9)
#define XMIT_SAME_DEV (1<<10)
#define XMIT_RDEV_MINOR_IS_SMALL (1<<11)
/* These flags are used in the live flist data. */
#define FLAG_TOP_DIR (1<<0)
#define FLAG_SENT (1<<1) /* sender */
#define FLAG_HLINK_EOL (1<<1) /* receiver/generator */
#define FLAG_MOUNT_POINT (1<<2) /* sender/generator */
#define FLAG_DEL_HERE (1<<3) /* receiver/generator */
#define FLAG_HLINK_TOL (1<<4) /* receiver/generator */
#define FLAG_NO_FUZZY (1<<5) /* generator */
#define FLAG_MISSING (1<<6) /* generator */
#define FLAG_DELETE (1<<0)
#define SAME_MODE (1<<1)
#define SAME_RDEV (1<<2)
#define SAME_UID (1<<3)
#define SAME_GID (1<<4)
#define SAME_DIR (1<<5)
#define SAME_NAME SAME_DIR
#define LONG_NAME (1<<6)
#define SAME_TIME (1<<7)
/* update this if you make incompatible changes */
#define PROTOCOL_VERSION 29
#define PROTOCOL_VERSION 26
/* We refuse to interoperate with versions that are not in this range.
* Note that we assume we'll work with later versions: the onus is on
* people writing them to make sure that they don't send us anything
* we won't understand.
*
* Interoperation with old but supported protocol versions
* should cause a warning to be printed. At a future date
* the old protocol will become the minimum and
* compatibility code removed.
*
* There are two possible explanations for the limit at
* MAX_PROTOCOL_VERSION: either to allow new major-rev versions that
* do not interoperate with us, and (more likely) so that we can
* detect an attempt to connect rsync to a non-rsync server, which is
* unlikely to begin by sending a byte between MIN_PROTOCL_VERSION and
* MAX_PROTOCOL_VERSION. */
#define MIN_PROTOCOL_VERSION 20
#define OLD_PROTOCOL_VERSION 25
#define MAX_PROTOCOL_VERSION 40
* There are two possible explanations for the limit at thirty: either
* to allow new major-rev versions that do not interoperate with us,
* and (more likely) so that we can detect an attempt to connect rsync
* to a non-rsync server, which is unlikely to begin by sending a byte
* between 15 and 30. */
#define MIN_PROTOCOL_VERSION 15
#define MAX_PROTOCOL_VERSION 30
#define RSYNC_PORT 873
@@ -97,130 +72,52 @@
#define CHUNK_SIZE (32*1024)
#define MAX_MAP_SIZE (256*1024)
#define IO_BUFFER_SIZE (4092)
#define MAX_BLOCK_SIZE ((int32)1 << 29)
#define IOERR_GENERAL (1<<0) /* For backward compatibility, this must == 1 */
#define IOERR_VANISHED (1<<1)
#define IOERR_DEL_LIMIT (1<<2)
#define MAX_ARGS 1000
#define MAX_BASIS_DIRS 20
#define MAX_SERVER_ARGS (MAX_BASIS_DIRS*2 + 100)
#define MPLEX_BASE 7
#define NO_FILTERS 0
#define SERVER_FILTERS 1
#define ALL_FILTERS 2
#define XFLG_FATAL_ERRORS (1<<0)
#define XFLG_OLD_PREFIXES (1<<1)
#define XFLG_ANCHORED2ABS (1<<2)
#define XFLG_ABS_IF_SLASH (1<<3)
#define ATTRS_REPORT (1<<0)
#define ATTRS_SKIP_MTIME (1<<1)
#define FULL_FLUSH 1
#define NORMAL_FLUSH 0
#define PDIR_CREATE 1
#define PDIR_DELETE 0
/* Note: 0x00 - 0x7F are used for basis_dir[] indexes! */
#define FNAMECMP_BASIS_DIR_LOW 0x00 /* Must remain 0! */
#define FNAMECMP_BASIS_DIR_HIGH 0x7F
#define FNAMECMP_FNAME 0x80
#define FNAMECMP_PARTIAL_DIR 0x81
#define FNAMECMP_BACKUP 0x82
#define FNAMECMP_FUZZY 0x83
/* For use by the itemize_changes code */
#define ITEM_REPORT_ATIME (1<<0)
#define ITEM_REPORT_CHECKSUM (1<<1)
#define ITEM_REPORT_SIZE (1<<2)
#define ITEM_REPORT_TIME (1<<3)
#define ITEM_REPORT_PERMS (1<<4)
#define ITEM_REPORT_OWNER (1<<5)
#define ITEM_REPORT_GROUP (1<<6)
#define ITEM_REPORT_ACL (1<<7)
#define ITEM_REPORT_XATTR (1<<8)
#define ITEM_BASIS_TYPE_FOLLOWS (1<<11)
#define ITEM_XNAME_FOLLOWS (1<<12)
#define ITEM_IS_NEW (1<<13)
#define ITEM_LOCAL_CHANGE (1<<14)
#define ITEM_TRANSFER (1<<15)
/* These are outside the range of the transmitted flags. */
#define ITEM_MISSING_DATA (1<<16) /* used by log_formatted() */
#define ITEM_DELETED (1<<17) /* used by log_formatted() */
#define SIGNIFICANT_ITEM_FLAGS (~(\
ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE))
/* Log-message categories. Only FERROR and FINFO get sent over the socket,
* but FLOG and FSOCKERR can be sent over the receiver -> generator pipe.
* FLOG only goes to the log file, not the client; FCLIENT is the opposite. */
enum logcode { FNONE=0, FERROR=1, FINFO=2, FLOG=3, FCLIENT=4, FSOCKERR=5 };
/* Messages types that are sent over the message channel. The logcode
* values must all be present here with identical numbers. */
enum msgcode {
MSG_DATA=0, /* raw data on the multiplexed stream */
MSG_ERROR=FERROR, MSG_INFO=FINFO, /* remote logging */
MSG_LOG=FLOG, MSG_SOCKERR=FSOCKERR, /* sibling logging */
MSG_REDO=9, /* reprocess indicated flist index */
MSG_SUCCESS=100,/* successfully updated indicated flist index */
MSG_DELETED=101,/* successfully deleted a file on receiving side */
MSG_DONE=86 /* current phase is done */
};
/* Log values. I *think* what these mean is: FLOG goes to the server
* logfile; FERROR and FINFO try to end up on the client, with
* different levels of filtering. */
enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
#include "errcode.h"
#include "config.h"
/* The default RSYNC_RSH is always set in config.h. */
/* The default RSYNC_RSH is always set in config.h, either to "remsh",
* "rsh", or otherwise something specified by the user. HAVE_REMSH
* controls parameter munging for HP/UX, etc. */
#include <sys/types.h>
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
#ifdef HAVE_STRING_H
# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
# include <memory.h>
# endif
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#include <unistd.h>
#endif
#include <stdio.h>
#include <stddef.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#if defined HAVE_MALLOC_H && (defined HAVE_MALLINFO || !defined HAVE_STDLIB_H)
#include <malloc.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#ifdef TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
@@ -240,6 +137,8 @@ enum msgcode {
#endif
#endif
#include <sys/stat.h>
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
@@ -275,10 +174,20 @@ enum msgcode {
#endif
#endif
#ifdef HAVE_FNMATCH
#include <fnmatch.h>
#else
#include "lib/fnmatch.h"
#endif
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
/* these are needed for the uid/gid mapping code */
#include <pwd.h>
#include <grp.h>
@@ -290,47 +199,27 @@ enum msgcode {
#include <syslog.h>
#include <sys/file.h>
#ifdef HAVE_DIRENT_H
#if HAVE_DIRENT_H
# include <dirent.h>
#else
# define dirent direct
# ifdef HAVE_SYS_NDIR_H
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# ifdef HAVE_SYS_DIR_H
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# ifdef HAVE_NDIR_H
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
# if !defined makedev && (defined mkdev || defined _WIN32 || defined __WIN32__)
# define makedev mkdev
# endif
#elif defined MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#endif
#ifdef MAKEDEV_TAKES_3_ARGS
#define MAKEDEV(devmajor,devminor) makedev(0,devmajor,devminor)
#else
#define MAKEDEV(devmajor,devminor) makedev(devmajor,devminor)
#endif
#ifdef HAVE_COMPAT_H
#include <compat.h>
#endif
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#include <assert.h>
#include "lib/pool_alloc.h"
#define BOOL int
@@ -338,85 +227,50 @@ enum msgcode {
#define uchar unsigned char
#endif
#ifdef SIGNED_CHAR_OK
#if HAVE_UNSIGNED_CHAR
#define schar signed char
#else
#define schar char
#endif
/* Find a variable that is either exactly 32-bits or longer.
* If some code depends on 32-bit truncation, it will need to
* take special action in a "#if SIZEOF_INT32 > 4" section. */
#ifndef int32
#if SIZEOF_INT == 4
# define int32 int
# define SIZEOF_INT32 4
#elif SIZEOF_LONG == 4
# define int32 long
# define SIZEOF_INT32 4
#elif SIZEOF_SHORT == 4
# define int32 short
# define SIZEOF_INT32 4
#elif SIZEOF_INT > 4
# define int32 int
# define SIZEOF_INT32 SIZEOF_INT
#elif SIZEOF_LONG > 4
# define int32 long
# define SIZEOF_INT32 SIZEOF_LONG
#if (SIZEOF_INT == 4)
#define int32 int
#elif (SIZEOF_LONG == 4)
#define int32 long
#elif (SIZEOF_SHORT == 4)
#define int32 short
#else
# error Could not find a 32-bit integer variable
/* I hope this works */
#define int32 int
#define LARGE_INT32
#endif
#else
# define SIZEOF_INT32 4
#endif
#ifndef uint32
#define uint32 unsigned int32
#endif
#if SIZEOF_OFF_T == 8 || !SIZEOF_OFF64_T || !defined HAVE_STRUCT_STAT64
#define OFF_T off_t
#define STRUCT_STAT struct stat
#else
#if HAVE_OFF64_T
#define OFF_T off64_t
#define STRUCT_STAT struct stat64
#define USE_STAT64_FUNCS 1
#else
#define OFF_T off_t
#define STRUCT_STAT struct stat
#endif
/* CAVEAT: on some systems, int64 will really be a 32-bit integer IFF
* that's the maximum size the file system can handle and there is no
* 64-bit type available. The rsync source must therefore take steps
* to ensure that any code that really requires a 64-bit integer has
* it (e.g. the checksum code uses two 32-bit integers for its 64-bit
* counter). */
#if SIZEOF_LONG == 8
# define int64 long
# define SIZEOF_INT64 8
#elif SIZEOF_INT == 8
# define int64 int
# define SIZEOF_INT64 8
#elif SIZEOF_LONG_LONG == 8
# define int64 long long
# define SIZEOF_INT64 8
#elif SIZEOF_OFF64_T == 8
# define int64 off64_t
# define SIZEOF_INT64 8
#elif SIZEOF_OFF_T == 8
# define int64 off_t
# define SIZEOF_INT64 8
#elif SIZEOF_INT > 8
# define int64 int
# define SIZEOF_INT64 SIZEOF_INT
#elif SIZEOF_LONG > 8
# define int64 long
# define SIZEOF_INT64 SIZEOF_LONG
#elif SIZEOF_LONG_LONG > 8
# define int64 long long
# define SIZEOF_INT64 SIZEOF_LONG_LONG
#if HAVE_OFF64_T
#define int64 off64_t
#elif (SIZEOF_LONG == 8)
#define int64 long
#elif (SIZEOF_INT == 8)
#define int64 int
#elif HAVE_LONGLONG
#define int64 long long
#else
/* As long as it gets... */
# define int64 off_t
# define SIZEOF_INT64 SIZEOF_OFF_T
#define int64 off_t
#define NO_INT64
#endif
/* Starting from protocol version 26, we always use 64-bit
@@ -441,14 +295,17 @@ enum msgcode {
* device numbers will be truncated. But it's a kind of silly thing
* to do anyhow.
*
* FIXME: I don't think the code in flist.c has ever worked on a system
* where dev_t is a struct.
*/
struct idev {
int64 inode;
int64 dev;
};
* FIXME: In future, we should probable split the device number into
* major/minor, and transfer the two parts as 32-bit ints. That gives
* you somewhat more of a chance that they'll come from a big machine
* to a little one in a useful way.
*
* FIXME: Really we need an unsigned type, and we perhaps ought to
* cope with platforms on which this is an unsigned int or even a
* struct. Later.
*/
#define INO64_T int64
#define DEV64_T int64
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
@@ -465,25 +322,11 @@ struct idev {
/* the length of the md4 checksum */
#define MD4_SUM_LENGTH 16
#define SUM_LENGTH 16
#define SHORT_SUM_LENGTH 2
#define BLOCKSUM_BIAS 10
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
/* We want a roomy line buffer that can hold more than MAXPATHLEN,
* and significantly more than an overly short MAXPATHLEN. */
#if MAXPATHLEN < 4096
#define BIGPATHBUFLEN (4096+1024)
#else
#define BIGPATHBUFLEN (MAXPATHLEN+1024)
#endif
#ifndef NAME_MAX
#define NAME_MAX 255
#endif
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
@@ -492,148 +335,73 @@ struct idev {
#define IN_LOOPBACKNET 127
#endif
#define GID_NONE ((gid_t)-1)
#define HL_CHECK_MASTER 0
#define HL_SKIP 1
struct hlink {
int32 next;
int32 hlindex;
unsigned short link_dest_used;
};
#define F_DEV link_u.idev->dev
#define F_INODE link_u.idev->inode
#define F_HLINDEX link_u.links->hlindex
#define F_NEXT link_u.links->next
struct file_struct {
union {
dev_t rdev; /* The device number, if this is a device */
char *sum; /* Only a normal file can have a checksum */
char *link; /* Points to symlink string, if a symlink */
} u;
OFF_T length;
char *basename; /* The current item's name (AKA filename) */
char *dirname; /* The directory info inside the transfer */
union {
char *root; /* Sender-side dir info outside transfer */
int depth; /* Receiver-side directory depth info */
} dir;
union {
struct idev *idev;
struct hlink *links;
} link_u;
unsigned flags;
time_t modtime;
OFF_T length;
mode_t mode;
INO64_T inode;
/** Device this file lives upon */
DEV64_T dev;
/** If this is a device node, the device number. */
DEV64_T rdev;
uid_t uid;
gid_t gid;
mode_t mode;
uchar flags; /* this item MUST remain last */
char *basename;
char *dirname;
char *basedir;
char *link;
char *sum;
};
/*
* Start the flist array at FLIST_START entries and grow it
* by doubling until FLIST_LINEAR then grow by FLIST_LINEAR
*/
#define FLIST_START (32 * 1024)
#define FLIST_LINEAR (FLIST_START * 512)
/*
* Extent size for allocation pools A minimum size of 128KB
* is needed to mmap them so that freeing will release the
* space to the OS.
*
* Larger sizes reduce leftover fragments and speed free calls
* (when they happen) Smaller sizes increase the chance of
* freed allocations freeing whole extents.
*/
#define FILE_EXTENT (256 * 1024)
#define HLINK_EXTENT (128 * 1024)
#define ARENA_SIZE (32 * 1024)
#define WITH_HLINK 1
#define WITHOUT_HLINK 0
struct string_area {
char *base;
char *end;
char *current;
struct string_area *next;
};
struct file_list {
struct file_struct **files;
alloc_pool_t file_pool;
alloc_pool_t hlink_pool;
int count;
int malloced;
int low, high;
struct file_struct **files;
struct string_area *string_area;
};
#define SUMFLG_SAME_OFFSET (1<<0)
struct sum_buf {
OFF_T offset; /**< offset in file of this chunk */
int32 len; /**< length of chunk of file */
int len; /**< length of chunk of file */
int i; /**< index of this chunk */
uint32 sum1; /**< simple checksum */
int32 chain; /**< next hash-table collision */
short flags; /**< flag bits */
char sum2[SUM_LENGTH]; /**< checksum */
};
struct sum_struct {
OFF_T flength; /**< total file length */
size_t count; /**< how many chunks */
size_t remainder; /**< flength % block_length */
size_t n; /**< block_length */
struct sum_buf *sums; /**< points to info for each chunk */
int32 count; /**< how many chunks */
int32 blength; /**< block_length */
int32 remainder; /**< flength % block_length */
int s2length; /**< sum2_length */
};
struct map_struct {
OFF_T file_size; /* File size (from stat) */
OFF_T p_offset; /* Window start */
OFF_T p_fd_offset; /* offset of cursor in fd ala lseek */
char *p; /* Window pointer */
int32 p_size; /* Largest window size we allocated */
int32 p_len; /* Latest (rounded) window size */
int32 def_window_size; /* Default window size */
int fd; /* File Descriptor */
int status; /* first errno from read errors */
char *p;
int fd,p_size,p_len;
OFF_T file_size, p_offset, p_fd_offset;
};
#define MATCHFLG_WILD (1<<0) /* pattern has '*', '[', and/or '?' */
#define MATCHFLG_WILD2 (1<<1) /* pattern has '**' */
#define MATCHFLG_WILD2_PREFIX (1<<2) /* pattern starts with "**" */
#define MATCHFLG_WILD3_SUFFIX (1<<3) /* pattern ends with "***" */
#define MATCHFLG_ABS_PATH (1<<4) /* path-match on absolute path */
#define MATCHFLG_INCLUDE (1<<5) /* this is an include, not an exclude */
#define MATCHFLG_DIRECTORY (1<<6) /* this matches only directories */
#define MATCHFLG_WORD_SPLIT (1<<7) /* split rules on whitespace */
#define MATCHFLG_NO_INHERIT (1<<8) /* don't inherit these rules */
#define MATCHFLG_NO_PREFIXES (1<<9) /* parse no prefixes from patterns */
#define MATCHFLG_MERGE_FILE (1<<10)/* specifies a file to merge */
#define MATCHFLG_PERDIR_MERGE (1<<11)/* merge-file is searched per-dir */
#define MATCHFLG_EXCLUDE_SELF (1<<12)/* merge-file name should be excluded */
#define MATCHFLG_FINISH_SETUP (1<<13)/* per-dir merge file needs setup */
#define MATCHFLG_NEGATE (1<<14)/* rule matches when pattern does not */
#define MATCHFLG_CVS_IGNORE (1<<15)/* rule was -C or :C */
#define MATCHFLG_SENDER_SIDE (1<<16)/* rule applies to the sending side */
#define MATCHFLG_RECEIVER_SIDE (1<<17)/* rule applies to the receiving side */
#define MATCHFLG_CLEAR_LIST (1<<18)/* this item is the "!" token */
#define MATCHFLGS_FROM_CONTAINER (MATCHFLG_ABS_PATH | MATCHFLG_INCLUDE \
| MATCHFLG_DIRECTORY | MATCHFLG_SENDER_SIDE \
| MATCHFLG_NEGATE | MATCHFLG_RECEIVER_SIDE)
struct filter_struct {
struct filter_struct *next;
struct exclude_struct {
char *pattern;
uint32 match_flags;
union {
int slash_cnt;
struct filter_list_struct *mergelist;
} u;
};
struct filter_list_struct {
struct filter_struct *head;
struct filter_struct *tail;
char *debug_type;
int regular_exp;
int fnmatch_flags;
int include;
int directory;
int local;
};
struct stats {
@@ -643,32 +411,26 @@ struct stats {
int64 total_read;
int64 literal_data;
int64 matched_data;
int64 flist_buildtime;
int64 flist_xfertime;
int flist_size;
int num_files;
int num_transferred_files;
int current_file_index;
};
struct chmod_mode_struct;
/* 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 */
static inline int flist_up(struct file_list *flist, int i)
{
while (!flist->files[i]->basename) i++;
return i;
}
#include "byteorder.h"
#include "lib/mdfour.h"
#include "lib/wildmatch.h"
#include "lib/permstring.h"
#include "lib/addrinfo.h"
#if !defined __GNUC__ || defined __APPLE__
/* Apparently the OS X port of gcc gags on __attribute__.
*
* <http://www.opensource.apple.com/bugs/X/gcc/2512150.html> */
#define __attribute__(x)
#endif
#define UNUSED(x) x __attribute__((__unused__))
#define NORETURN __attribute__((__noreturn__))
#include "proto.h"
/* We have replacement versions of these if they're missing. */
@@ -680,18 +442,16 @@ int asprintf(char **ptr, const char *format, ...);
int vasprintf(char **ptr, const char *format, va_list ap);
#endif
#if !defined HAVE_VSNPRINTF || !defined HAVE_C99_VSNPRINTF
#define vsnprintf rsync_vsnprintf
int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
#if !defined(HAVE_VSNPRINTF) && !defined(HAVE_C99_VSNPRINTF)
int vsnprintf (char *str, size_t count, const char *fmt, va_list args);
#endif
#if !defined HAVE_SNPRINTF || !defined HAVE_C99_VSNPRINTF
#define snprintf rsync_snprintf
#if !defined(HAVE_SNPRINTF) && !defined(HAVE_C99_VSNPRINTF)
int snprintf(char *str,size_t count,const char *fmt,...);
#endif
#ifndef HAVE_STRERROR
#if !HAVE_STRERROR
extern char *sys_errlist[];
#define strerror(i) sys_errlist[i]
#endif
@@ -705,19 +465,17 @@ extern char *sys_errlist[];
extern int errno;
#endif
#ifdef HAVE_READLINK
#define SUPPORT_LINKS 1
#endif
#ifdef HAVE_LINK
#define SUPPORT_HARD_LINKS 1
#define SUPPORT_LINKS HAVE_READLINK
#define SUPPORT_HARD_LINKS HAVE_LINK
/* This could be bad on systems which have no lchown and where chown
* follows symbollic links. On such systems it might be better not to
* try to chown symlinks at all. */
#ifndef HAVE_LCHOWN
#define lchown chown
#endif
#ifdef HAVE_SIGACTION
#define SIGACTION(n,h) sigact.sa_handler=(h), sigaction((n),&sigact,NULL)
#define signal(n,h) we_need_to_call_SIGACTION_not_signal(n,h)
#else
#define SIGACTION(n,h) signal(n,h)
#endif
#define SIGNAL_CAST (RETSIGTYPE (*)())
#ifndef EWOULDBLOCK
#define EWOULDBLOCK EAGAIN
@@ -735,24 +493,10 @@ extern int errno;
#define STDERR_FILENO 2
#endif
#ifndef S_IRUSR
#define S_IRUSR 0400
#endif
#ifndef S_IWUSR
#define S_IWUSR 0200
#endif
#ifndef ACCESSPERMS
#define ACCESSPERMS 0777
#endif
#ifndef S_ISVTX
#define S_ISVTX 0
#endif
#define CHMOD_BITS (S_ISUID | S_ISGID | S_ISVTX | ACCESSPERMS)
#ifndef _S_IFMT
#define _S_IFMT 0170000
#endif
@@ -800,9 +544,9 @@ extern int errno;
/* work out what fcntl flag to use for non-blocking */
#ifdef O_NONBLOCK
# define NONBLOCK_FLAG O_NONBLOCK
#elif defined SYSV
#elif defined(SYSV)
# define NONBLOCK_FLAG O_NDELAY
#else
#else
# define NONBLOCK_FLAG FNDELAY
#endif
@@ -814,9 +558,11 @@ extern int errno;
#define INADDR_NONE 0xffffffff
#endif
#define IS_SPECIAL(mode) (S_ISSOCK(mode) || S_ISFIFO(mode))
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode))
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) || S_ISFIFO(mode))
#ifndef ACCESSPERMS
#define ACCESSPERMS 0777
#endif
/* Initial mask on permissions given to temporary files. Mask off setuid
bits and group access because of potential race-condition security
holes, and mask other access because mode 707 is bizarre */
@@ -825,6 +571,14 @@ extern int errno;
/* handler for null strings in printf format */
#define NS(s) ((s)?(s):"<NULL>")
#if !defined(__GNUC__) || defined(APPLE)
/* Apparently the OS X port of gcc gags on __attribute__.
*
* <http://www.opensource.apple.com/bugs/X/gcc/2512150.html> */
#define __attribute__(x)
#endif
/* Convenient wrappers for malloc and realloc. Use them. */
#define new(type) ((type *)malloc(sizeof(type)))
#define new_array(type, num) ((type *)_new_array(sizeof(type), (num)))
@@ -841,11 +595,11 @@ void rsyserr(enum logcode, int, const char *, ...)
__attribute__((format (printf, 3, 4)))
;
/* Make sure that the O_BINARY flag is defined. */
#ifndef O_BINARY
#define O_BINARY 0
#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
@@ -857,29 +611,16 @@ size_t strlcat(char *d, const char *s, size_t bufsize);
#ifndef WEXITSTATUS
#define WEXITSTATUS(stat) ((int)(((stat)>>8)&0xFF))
#endif
#ifndef WIFEXITED
#define WIFEXITED(stat) ((int)((stat)&0xFF) == 0)
#endif
#define exit_cleanup(code) _exit_cleanup(code, __FILE__, __LINE__)
#ifdef HAVE_GETEUID
#define MY_UID() geteuid()
#else
#define MY_UID() getuid()
#endif
#ifdef HAVE_GETEGID
#define MY_GID() getegid()
#else
#define MY_GID() getgid()
#endif
extern int verbose;
#ifndef HAVE_INET_NTOP
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
const char *
inet_ntop(int af, const void *src, char *dst, size_t size);
#endif /* !HAVE_INET_NTOP */
#ifndef HAVE_INET_PTON
int inet_pton(int af, const char *src, void *dst);
@@ -888,3 +629,7 @@ int inet_pton(int af, const char *src, void *dst);
#ifdef MAINTAINER_MODE
const char *get_panic_action(void);
#endif
#define UNUSED(x) x __attribute__((__unused__))
extern const char *io_write_phase, *io_read_phase;

2759
rsync.yo
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
mailto(rsync-bugs@samba.org)
manpage(rsyncd.conf)(5)(6 Nov 2006)()()
manpagename(rsyncd.conf)(configuration file for rsync in daemon mode)
manpage(rsyncd.conf)(5)(26 Jan 2003)()()
manpagename(rsyncd.conf)(configuration file for rsync server)
manpagesynopsis()
rsyncd.conf
@@ -8,27 +8,27 @@ rsyncd.conf
manpagedescription()
The rsyncd.conf file is the runtime configuration file for rsync when
run as an rsync daemon.
run as an rsync server.
The rsyncd.conf file controls authentication, access, logging and
available modules.
manpagesection(FILE FORMAT)
The file consists of modules and parameters. A module begins with the
The file consists of modules and parameters. A module begins with the
name of the module in square brackets and continues until the next
module begins. Modules contain parameters of the form 'name = value'.
The file is line-based -- that is, each newline-terminated line represents
The file is line-based - that is, each newline-terminated line represents
either a comment, a module name or a parameter.
Only the first equals sign in a parameter is significant. Whitespace before
Only the first equals sign in a parameter is significant. Whitespace before
or after the first equals sign is discarded. Leading, trailing and internal
whitespace in module and parameter names is irrelevant. Leading and
trailing whitespace in a parameter value is discarded. Internal whitespace
within a parameter value is retained verbatim.
Any line beginning with a hash (#) is ignored, as are lines containing
Any line beginning with a hash (#) is ignored, as are lines containing
only whitespace.
Any line ending in a \ is "continued" on the next line in the
@@ -37,12 +37,12 @@ customary UNIX fashion.
The values following the equals sign in parameters are all either a string
(no quotes needed) or a boolean, which may be given as yes/no, 0/1 or
true/false. Case is not significant in boolean values, but is preserved
in string values.
in string values.
manpagesection(LAUNCHING THE RSYNC DAEMON)
The rsync daemon is launched by specifying the bf(--daemon) option to
rsync.
The rsync daemon is launched by specifying the --daemon option to
rsync.
The daemon must run with root privileges if you wish to use chroot, to
bind to a port numbered under 1024 (as is the default 873), or to set
@@ -51,28 +51,31 @@ write the appropriate data, log, and lock files.
You can launch it either via inetd, as a stand-alone daemon, or from
an rsync client via a remote shell. If run as a stand-alone daemon then
just run the command "bf(rsync --daemon)" from a suitable startup script.
just run the command "rsync --daemon" from a suitable startup script.
If run from an rsync client via a remote shell (by specifying both the
"-e/--rsh" option and server mode with "::" or "rsync://"), the --daemon
option is automatically passed to the remote side.
When run via inetd you should add a line like this to /etc/services:
verb( rsync 873/tcp)
quote(rsync 873/tcp)
and a single line something like this to /etc/inetd.conf:
verb( rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon)
quote(rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon)
Replace "/usr/bin/rsync" with the path to where you have rsync installed on
your system. You will then need to send inetd a HUP signal to tell it to
reread its config file.
Note that you should bf(not) send the rsync daemon a HUP signal to force
Note that you should not send the rsync server a HUP signal to force
it to reread the tt(rsyncd.conf) file. The file is re-read on each client
connection.
connection.
manpagesection(GLOBAL OPTIONS)
The first parameters in the file (before a [module] header) are the
global parameters.
global parameters.
You may also include any module parameters in the global part of the
config file in which case the supplied value will override the
@@ -84,24 +87,28 @@ dit(bf(motd file)) The "motd file" option allows you to specify a
usually contains site information and any legal notices. The default
is no motd file.
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.
its process id to that file.
dit(bf(port)) You can override the default port the daemon will listen on
by specifying this value (defaults to 873). This is ignored if the daemon
is being run by inetd, and is superseded by the bf(--port) command-line option.
dit(bf(address)) You can override the default IP address the daemon
will listen on by specifying this value. This is ignored if the daemon is
being run by inetd, and is superseded by the bf(--address) command-line option.
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
defined on your system. Common names are auth, authpriv, cron, daemon,
ftp, kern, lpr, mail, news, security, syslog, user, uucp, local0,
local1, local2, local3, local4, local5, local6 and local7. The default
is daemon.
dit(bf(socket options)) This option can provide endless fun for people
who like to tune their systems to the utmost degree. You can set all
sorts of socket options which may make transfers faster (or
slower!). Read the man page for the code(setsockopt()) system call for
slower!). Read the man page for the setsockopt() system call for
details on some of the options you may be able to set. By default no
special socket options are set. These settings are superseded by the
bf(--sockopts) command-line option.
special socket options are set.
enddit()
@@ -119,44 +126,20 @@ dit(bf(comment)) The "comment" option specifies a description string
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 daemon's
dit(bf(path)) The "path" option specifies the directory in the servers
filesystem to make available in this module. You must specify this option
for each module in tt(rsyncd.conf).
dit(bf(use chroot)) If "use chroot" is true, the rsync daemon will chroot
dit(bf(use chroot)) If "use chroot" is true, the rsync server will chroot
to the "path" before starting the file transfer with the client. This has
the advantage of extra protection against possible implementation security
holes, but it has the disadvantages of requiring super-user privileges,
of not being able to follow symbolic links that are either absolute or outside
of the new root path, and of complicating the preservation of usernames and groups
(see below). When "use chroot" is false, for security reasons,
holes, but it has the disadvantages of requiring super-user privileges,
of not being able to follow symbolic links outside of the new root path
when reading, and of implying the --numeric-ids option because /etc/passwd
becomes inaccessible. When "use chroot" is false, for security reasons
symlinks may only be relative paths pointing to other files within the root
path, and leading slashes are removed from most absolute paths (options
such as bf(--backup-dir), bf(--compare-dest), etc. interpret an absolute path as
rooted in the module's "path" dir, just as if chroot was specified).
The default for "use chroot" is true.
In order to preserve usernames and groupnames, rsync needs to be able to
use the standard library functions for looking up names and IDs (i.e.
code(getpwuid()), code(getgrgid()), code(getpwname()), and code(getgrnam())). This means a
process in the chroot namespace will need to have access to the resources
used by these library functions (traditionally /etc/passwd and
/etc/group). If these resources are not available, rsync will only be
able to copy the IDs, just as if the bf(--numeric-ids) option had been
specified.
Note that you are free to setup user/group information in the chroot area
differently from your normal system. For example, you could abbreviate
the list of users and groups. Also, you can protect this information from
being downloaded/uploaded by adding an exclude rule to the rsyncd.conf file
(e.g. "exclude = /etc/**"). Note that having the exclusion affect uploads
is a relatively new feature in rsync, so make sure your daemon is
at least 2.6.3 to effect this. Also note that it is safest to exclude a
directory and all its contents combining the rule "/some/dir/" with the
rule "/some/dir/**" just to be sure that rsync will not allow deeper
access to some of the excluded files inside the directory (rsync tries to
do this automatically, but you might as well specify both to be extra
sure).
path, and leading slashes are removed from absolute paths. The default for
"use chroot" is true.
dit(bf(max connections)) The "max connections" option allows you to
specify the maximum number of simultaneous connections you will allow.
@@ -164,146 +147,89 @@ Any clients connecting when the maximum has been reached will receive a
message telling them to try later. The default is 0 which means no limit.
See also the "lock file" option.
dit(bf(log file)) When the "log file" option is set to a non-empty
string, the rsync daemon will log messages to the indicated file rather
than using syslog. This is particularly useful on systems (such as AIX)
where code(syslog()) doesn't work for chrooted programs. The file is
opened before code(chroot()) is called, allowing it to be placed outside
the transfer. If this value is set on a per-module basis instead of
globally, the global log will still contain any authorization failures
or config-file error messages.
If the daemon fails to open to specified file, it will fall back to
using syslog and output an error about the failure. (Note that the
failure to open the specified log file used to be a fatal error.)
dit(bf(syslog facility)) The "syslog facility" option allows you to
specify the syslog facility name to use when logging messages from the
rsync daemon. You may use any standard syslog facility name which is
defined on your system. Common names are auth, authpriv, cron, daemon,
ftp, kern, lpr, mail, news, security, syslog, user, uucp, local0,
local1, local2, local3, local4, local5, local6 and local7. The default
is daemon. This setting has no effect if the "log file" setting is a
non-empty string (either set in the per-modules settings, or inherited
from the global settings).
dit(bf(max verbosity)) The "max verbosity" option allows you to control
the maximum amount of verbose information that you'll allow the daemon to
generate (since the information goes into the log file). The default is 1,
which allows the client to request one level of verbosity.
dit(bf(lock file)) The "lock file" option specifies the file to use to
support the "max connections" option. The rsync daemon uses record
support the "max connections" option. The rsync server uses record
locking on this file to ensure that the max connections limit is not
exceeded for the modules sharing the lock file.
exceeded for the modules sharing the lock file.
The default is tt(/var/run/rsyncd.lock).
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
attempted uploads will fail. If "read only" is false then uploads will
be possible if file permissions on the daemon side allow them. The default
be possible if file permissions on the server allow them. The default
is for all modules to be read only.
dit(bf(write only)) The "write only" option determines whether clients
will be able to download files or not. If "write only" is true then any
attempted downloads will fail. If "write only" is false then downloads
will be possible if file permissions on the daemon side allow them. The
default is for this option to be disabled.
dit(bf(list)) The "list" option determines if this module should be
listed when the client asks for a listing of available modules. By
setting this to false you can create hidden modules. The default is
for modules to be listable.
dit(bf(uid)) The "uid" option specifies the user name or user ID that
dit(bf(uid)) The "uid" option specifies the user name or user id that
file transfers to and from that module should take place as when the daemon
was run as root. In combination with the "gid" option this determines what
file permissions are available. The default is uid -2, which is normally
the user "nobody".
dit(bf(gid)) The "gid" option specifies the group name or group ID that
dit(bf(gid)) The "gid" option specifies the group name or group id that
file transfers to and from that module should take place as when the daemon
was run as root. This complements the "uid" option. The default is gid -2,
which is normally the group "nobody".
dit(bf(filter)) The "filter" option allows you to specify a space-separated
list of filter rules that the daemon will not allow to be read or written.
This is only superficially equivalent to the client specifying these
patterns with the bf(--filter) option. Only one "filter" option may be
specified, but it may contain as many rules as you like, including
merge-file rules. Note that per-directory merge-file rules do not provide
as much protection as global rules, but they can be used to make bf(--delete)
work better when a client downloads the daemon's files (if the per-dir
merge files are included in the transfer).
dit(bf(exclude)) The "exclude" option allows you to specify a
space-separated list of patterns that the daemon will not allow to be read
or written. This is only superficially equivalent to the client
specifying these patterns with the bf(--exclude) option. Only one "exclude"
option may be specified, but you can use "-" and "+" before patterns to
specify exclude/include.
dit(bf(exclude)) The "exclude" option allows you to specify a space
separated list of patterns to add to the exclude list.
This is only superficially equivalent
to the client specifying these patterns with the --exclude option.
Only one "exclude" option may be specified, but
you can use "-" and "+" before patterns to specify exclude/include.
Because this exclude list is not passed to the client it only applies on
the daemon: that is, it excludes files received by a client when receiving
from a daemon and files deleted on a daemon when sending to a daemon, but
it doesn't exclude files from being deleted on a client when receiving
from a daemon.
the server: that is, it excludes files received by a client when receiving
from a server and files deleted on a server when sending to a server, but
it doesn't exclude files sent from a client when sending to a server or
files deleted on a client when receiving from a server.
Note that this option is not designed with strong security in
mind, it is quite possible that a client may find a way to bypass this
exclude list. If you want to absolutely ensure that certain files
cannot be accessed then use the uid/gid options in combination with
file permissions.
dit(bf(exclude from)) The "exclude from" option specifies a filename
on the daemon that contains exclude patterns, one per line.
on the server that contains exclude patterns, one per line.
This is only superficially equivalent
to the client specifying the bf(--exclude-from) option with an equivalent file.
to the client specifying the --exclude-from option with an equivalent file.
See the "exclude" option above.
dit(bf(include)) The "include" option allows you to specify a
space-separated list of patterns which rsync should not exclude. This is
only superficially equivalent to the client specifying these patterns with
the bf(--include) option because it applies only on the daemon. This is
useful as it allows you to build up quite complex exclude/include rules.
Only one "include" option may be specified, but you can use "+" and "-"
before patterns to switch include/exclude. See the "exclude" option
above.
dit(bf(include)) The "include" option allows you to specify a space
separated list of patterns which rsync should not exclude. This is
only superficially equivalent to the client specifying these patterns
with the --include option because it applies only on the server.
This is useful as it
allows you to build up quite complex exclude/include rules. Only one
"include" option may be specified, but you can use "+" and "-" before
patterns to switch include/exclude. See the "exclude" option above.
dit(bf(include from)) The "include from" option specifies a filename
on the daemon that contains include patterns, one per line. This is
on the server that contains include patterns, one per line. This is
only superficially equivalent to the client specifying the
bf(--include-from) option with a equivalent file.
--include-from option with a equivalent file.
See the "exclude" option above.
dit(bf(incoming chmod)) This option allows you to specify a set of
comma-separated chmod strings that will affect the permissions of all
incoming files (files that are being received by the daemon). These
changes happen after all other permission calculations, and this will
even override destination-default and/or existing permissions when the
client does not specify bf(--perms).
See the description of the bf(--chmod) rsync option and the bf(chmod)(1)
manpage for information on the format of this string.
dit(bf(outgoing chmod)) This option allows you to specify a set of
comma-separated chmod strings that will affect the permissions of all
outgoing files (files that are being sent out from the daemon). These
changes happen first, making the sent permissions appear to be different
than those stored in the filesystem itself. For instance, you could
disable group write permissions on the server while having it appear to
be on to the clients.
See the description of the bf(--chmod) rsync option and the bf(chmod)(1)
manpage for information on the format of this string.
dit(bf(auth users)) The "auth users" option specifies a comma and
space-separated list of usernames that will be allowed to connect to
space separated list of usernames that will be allowed to connect to
this module. The usernames do not need to exist on the local
system. The usernames may also contain shell wildcard characters. If
"auth users" is set then the client will be challenged to supply a
username and password to connect to the module. A challenge response
authentication protocol is used for this exchange. The plain text
usernames and passwords are stored in the file specified by the
usernames are passwords are stored in the file specified by the
"secrets file" option. The default is for all users to be able to
connect without a password (this is called "anonymous rsync").
See also the "CONNECTING TO AN RSYNC DAEMON OVER A REMOTE SHELL
PROGRAM" section in bf(rsync)(1) for information on how handle an
See also the bf(CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL
PROGRAM) section in rsync(1) for information on how handle an
rsyncd.conf-level username that differs from the remote-shell-level
username when using a remote shell to connect to an rsync daemon.
username when using a remote shell to connect to a rsync server.
dit(bf(secrets file)) The "secrets file" option specifies the name of
a file that contains the username:password pairs used for
@@ -313,15 +239,15 @@ username:password pairs separated by a single colon. Any line starting
with a hash (#) is considered a comment and is skipped. The passwords
can contain any characters but be warned that many operating systems
limit the length of passwords that can be typed at the client end, so
you may find that passwords longer than 8 characters don't work.
you may find that passwords longer than 8 characters don't work.
There is no default for the "secrets file" option, you must choose a name
(such as tt(/etc/rsyncd.secrets)). The file must normally not be readable
by "other"; see "strict modes".
dit(bf(strict modes)) The "strict modes" option determines whether or not
dit(bf(strict modes)) The "strict modes" option determines whether or not
the permissions on the secrets file will be checked. If "strict modes" is
true, then the secrets file must not be readable by any user ID other
true, then the secrets file must not be readable by any user id other
than the one that the rsync daemon is running under. If "strict modes" is
false, the check is not performed. The default is true. This option
was added to accommodate rsync running on the Windows operating system.
@@ -333,38 +259,40 @@ connection is rejected.
Each pattern can be in one of five forms:
quote(itemization(
itemize(
it() a dotted decimal IPv4 address of the form a.b.c.d, or an IPv6 address
of the form a:b:c::d:e:f. In this case the incoming machine's IP address
must match exactly.
it() an address/mask in the form ipaddr/n where ipaddr is the IP address
and n is the number of one bits in the netmask. All IP addresses which
match the masked IP address will be allowed in.
it() an address/mask in the form ipaddr/maskaddr where ipaddr is the
IP address and maskaddr is the netmask in dotted decimal notation for IPv4,
or similar for IPv6, e.g. ffff:ffff:ffff:ffff:: instead of /64. All IP
addresses which match the masked IP address will be allowed in.
it() a hostname. The hostname as determined by a reverse lookup will
be matched (case insensitive) against the pattern. Only an exact
match is allowed in.
it() a hostname pattern using wildcards. These are matched using the
same rules as normal unix filename matching. If the pattern matches
then the client is allowed in.
))
)
Note IPv6 link-local addresses can have a scope in the address specification:
quote(
tt( fe80::1%link1)nl()
tt( fe80::%link1/64)nl()
tt( fe80::%link1/ffff:ffff:ffff:ffff::)nl()
)
quote(fe80::1%link1)
quote(fe80::%link1/64)
quote(fe80::%link1/ffff:ffff:ffff:ffff::)
You can also combine "hosts allow" with a separate "hosts deny"
option. If both options are specified then the "hosts allow" option s
checked first and a match results in the client being able to
connect. The "hosts deny" option is then checked and a match means
that the host is rejected. If the host does not match either the
that the host is rejected. If the host does not match either the
"hosts allow" or the "hosts deny" patterns then it is allowed to
connect.
@@ -378,157 +306,92 @@ rejected. See the "hosts allow" option for more information.
The default is no "hosts deny" option, which means all hosts can connect.
dit(bf(ignore errors)) The "ignore errors" option tells rsyncd to
ignore I/O errors on the daemon when deciding whether to run the delete
phase of the transfer. Normally rsync skips the bf(--delete) step if any
I/O errors have occurred in order to prevent disastrous deletion due
to a temporary resource shortage or other I/O error. In some cases this
ignore IO errors on the server when deciding whether to run the delete
phase of the transfer. Normally rsync skips the --delete step if any
IO errors have occurred in order to prevent disasterous deletion due
to a temporary resource shortage or other IO error. In some cases this
test is counter productive so you can use this option to turn off this
behavior.
behaviour.
dit(bf(ignore nonreadable)) This tells the rsync daemon to completely
dit(bf(ignore nonreadable)) This tells the rsync server to completely
ignore files that are not readable by the user. This is useful for
public archives that may have some non-readable files among the
directories, and the sysadmin doesn't want those files to be seen at all.
dit(bf(transfer logging)) The "transfer logging" option enables per-file
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. The daemon always logs the transfer at the end, so
if a transfer is aborted, no mention will be made in the log file.
If you want to customize the log lines, see the "log format" option.
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. An optional numeric
field width may also be specified between the percent and the escape
letter (e.g. "%-50n %8l %07p").
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 date 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", and a "%t [%p] "
is always prefixed when using the "log file" option.
(A perl script that will summarize this default log format is included
in the rsync source code distribution in the "support" subdirectory:
rsyncstats.)
is always added to the beginning when using the "log file" option.
The single-character escapes that are understood are as follows:
quote(itemization(
it() %a the remote IP address
it() %b the number of bytes actually transferred
it() %B the permission bits of the file (e.g. rwxrwxrwt)
it() %c the checksum bytes received for this file (only when sending)
it() %f the filename (long form on sender; no trailing "/")
it() %G the gid of the file (decimal) or "DEFAULT"
it() %h the remote host name
it() %i an itemized list of what is being updated
it() %l the length of the file in bytes
it() %L the string " -> SYMLINK", " => HARDLINK", or "" (where bf(SYMLINK) or bf(HARDLINK) is a filename)
it() %m the module name
it() %M the last-modified time of the file
it() %n the filename (short form; trailing "/" on dir)
it() %o the operation, which is "send", "recv", or "del." (the latter includes the trailing period)
it() %p the process ID of this rsync session
it() %P the module path
it() %t the current date time
it() %u the authenticated username or an empty string
it() %U the uid of the file (decimal)
))
For a list of what the characters mean that are output by "%i", see the
bf(--itemize-changes) option in the rsync manpage.
Note that some of the logged output changes when talking with older
rsync versions. For instance, deleted files were only output as verbose
messages prior to rsync 2.6.4.
A perl script called rsyncstats to summarize this format is included
in the rsync source code distribution.
dit(bf(timeout)) The "timeout" option allows you to override the
clients choice for I/O timeout for this module. Using this option you
clients choice for IO timeout for this module. Using this option you
can ensure that rsync won't wait on a dead client forever. The timeout
is specified in seconds. A value of zero means no timeout and is the
default. A good choice for anonymous rsync daemons may be 600 (giving
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 daemon.
You may specify the full option name, its one-letter abbreviation, or a
wild-card string that matches multiple options.
For example, this would refuse bf(--checksum) (bf(-c)) and all the various
delete options:
quote(tt( refuse options = c delete))
The reason the above refuses all delete options is that the options imply
bf(--delete), and implied options are refused just like explicit options.
As an additional safety feature, the refusal of "delete" also refuses
bf(remove-sent-files) when the daemon is the sender; if you want the latter
without the former, instead refuse "delete-*" -- that refuses all the
delete modes without affecting bf(--remove-sent-files).
When an option is refused, the daemon prints an error message and exits.
To prevent all compression when serving files,
you can use "dont compress = *" (see below)
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
when pulling files from the daemon (no analogous option exists to
govern the pushing of files to a daemon).
Compression is expensive in terms of CPU usage, so it
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.
such as already compressed files.
The "dont compress" option takes a space-separated list of
The "dont compress" option takes a space separated list of
case-insensitive wildcard patterns. Any source filename matching one
of the patterns will not be compressed during transfer.
The default setting is tt(*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz)
dit(bf(pre-xfer exec), bf(post-xfer exec)) You may specify a command to be run
before and/or after the transfer. If the bf(pre-xfer exec) command fails, the
transfer is aborted before it begins.
The following environment variables will be set, though some are
specific to the pre-xfer or the post-xfer environment:
quote(itemization(
it() bf(RSYNC_MODULE_NAME): The name of the module being accessed.
it() bf(RSYNC_MODULE_PATH): The path configured for the module.
it() bf(RSYNC_HOST_ADDR): The accessing host's IP address.
it() bf(RSYNC_HOST_NAME): The accessing host's name.
it() bf(RSYNC_USER_NAME): The accessing user's name (empty if no user).
it() bf(RSYNC_PID): A unique number for this transfer.
it() bf(RSYNC_REQUEST): (pre-xfer only) The module/path info specified
by the user (note that the user can specify multiple source files,
so the request can be something like "mod/path1 mod/path2", etc.).
it() bf(RSYNC_ARG#): (pre-xfer only) The pre-request arguments are set
in these numbered values. RSYNC_ARG0 is always "rsyncd", and the last
value contains a single period.
it() bf(RSYNC_EXIT_STATUS): (post-xfer only) the server side's exit value.
This will be 0 for a successful run, a positive value for an error that the
server generated, or a -1 if rsync failed to exit properly. Note that an
error that occurs on the client side does not currently get sent to the
server side, so this is not the final exit status for the whole transfer.
it() bf(RSYNC_RAW_STATUS): (post-xfer only) the raw exit value from code(waitpid()).
))
Even though the commands can be associated with a particular module, they
are run using the permissions of the user that started the daemon (not the
module's uid/gid setting) without any chroot restrictions.
The default setting is verb(*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz)
enddit()
manpagesection(AUTHENTICATION STRENGTH)
The authentication protocol used in rsync is a 128 bit MD4 based
challenge response system. This is fairly weak protection, though (with
at least one brute-force hash-finding algorithm publicly available), so
if you want really top-quality security, then I recommend that you run
rsync over ssh. (Yes, a future version of rsync will switch over to a
stronger hashing method.)
challenge response system. Although I believe that no one has ever
demonstrated a brute-force break of this sort of system you should
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.
Also note that the rsync daemon protocol does not currently provide any
Also note that the rsync server protocol does not currently provide any
encryption of the data that is transferred over the connection. Only
authentication is provided. Use ssh as the transport if you want
encryption.
@@ -547,17 +410,17 @@ verb(
comment = ftp export area
)
A more sophisticated example would be:
verb(
uid = nobody
gid = nobody
use chroot = no
max connections = 4
syslog facility = local5
uid = nobody nl()
gid = nobody nl()
use chroot = no nl()
max connections = 4 nl()
syslog facility = local5 nl()
pid file = /var/run/rsyncd.pid
[ftp]
verb([ftp]
path = /var/ftp/pub
comment = whole ftp area (approx 6.1 GB)
@@ -568,7 +431,7 @@ pid file = /var/run/rsyncd.pid
[rsyncftp]
path = /var/ftp/pub/rsync
comment = rsync ftp area (approx 6 MB)
[sambawww]
path = /public_html/samba
comment = Samba WWW pages (approx 240 MB)
@@ -582,10 +445,8 @@ pid file = /var/run/rsyncd.pid
The /etc/rsyncd.secrets file would look something like this:
quote(
tt(tridge:mypass)nl()
tt(susan:herpass)nl()
)
tridge:mypass nl()
susan:herpass
manpagefiles()
@@ -593,18 +454,21 @@ manpagefiles()
manpageseealso()
bf(rsync)(1)
rsync(1)
manpagediagnostics()
manpagebugs()
The rsync server does not send all types of error messages to the
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://rsync.samba.org/)(http://rsync.samba.org/)
manpagesection(VERSION)
This man page is current for version 2.6.9 of rsync.
This man page is current for version 2.0 of rsync
manpagesection(CREDITS)
@@ -625,13 +489,12 @@ Gailly and Mark Adler.
manpagesection(THANKS)
Thanks to Warren Stanley for his original idea and patch for the rsync
daemon. Thanks to Karsten Thygesen for his many suggestions and
documentation!
server. Thanks to Karsten Thygesen for his many suggestions and
documentation!
manpageauthor()
rsync was written by Andrew Tridgell and Paul Mackerras.
Many people have later contributed to it.
rsync was written by Andrew Tridgell and Paul Mackerras. They may be
contacted via email at tridge@samba.org and
Paul.Mackerras@cs.anu.edu.au
Mailing lists for support and development are available at
url(http://lists.samba.org)(lists.samba.org)

View File

@@ -1,7 +1,6 @@
#! /bin/sh
# Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
# Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version
@@ -14,7 +13,8 @@
#
# You should have received a copy of the GNU Lesser 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
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# rsync top-level test script -- this invokes all the other more
# detailed tests in order. This script can either be called by `make
@@ -85,7 +85,7 @@
# they're explicitly given on the command line.
# Also, we can't count on 'cp -a' or 'mkdir -p', although they're
# pretty handy (see function makepath for the latter).
# pretty handy.
# I think some of the GNU documentation suggests that we shouldn't
# rely on shell functions. However, the Bash manual seems to say that
@@ -100,8 +100,6 @@
# You cannot do "export VAR=VALUE" all on one line; the export must be
# separate from the assignment. (SCO SysV)
# Don't rely on grep -q, as that doesn't work everywhere -- just redirect
# stdout to /dev/null to keep it quiet.
# STILL TO DO:
@@ -126,82 +124,54 @@ set -e
. "./shconfig"
RUNSHFLAGS='-e'
export RUNSHFLAGS
# for Solaris
[ -d /usr/xpg4/bin ] && PATH="/usr/xpg4/bin/:$PATH"
PATH="/usr/xpg4/bin/:$PATH"
if [ "x$loglevel" != x ] && [ "$loglevel" -gt 8 ]; then
if set -x; then
if [ -n "$loglevel" ] && [ "$loglevel" -gt 8 ]
then
if set -x
then
# If it doesn't work the first time, don't keep trying.
RUNSHFLAGS="$RUNSHFLAGS -x"
fi
fi
POSIXLY_CORRECT=1
if test x"$TOOLDIR" = x; then
TOOLDIR=`pwd`
fi
srcdir=`dirname $0`
if test x"$srcdir" = x -o x"$srcdir" = x.; then
srcdir="$TOOLDIR"
fi
if test x"$rsync_bin" = x; then
rsync_bin="$TOOLDIR/rsync"
fi
# This allows the user to specify extra rsync options -- use carefully!
RSYNC="$rsync_bin $*"
#RSYNC="valgrind $rsync_bin $*"
export POSIXLY_CORRECT TOOLDIR srcdir RSYNC
echo "============================================================"
echo "$0 running in $TOOLDIR"
echo " rsync_bin=$RSYNC"
echo "$0 running in `pwd`"
echo " rsync_bin=$rsync_bin"
echo " srcdir=$srcdir"
if [ -f /usr/bin/whoami ]; then
testuser=`/usr/bin/whoami`
elif [ -f /usr/ucb/whoami ]; then
testuser=`/usr/ucb/whoami`
elif [ -f /bin/whoami ]; then
testuser=`/bin/whoami`
else
testuser=`id -un 2>/dev/null || echo ${LOGNAME:-${USERNAME:-${USER:-'UNKNOWN'}}}`
fi
testuser=`whoami || echo UNKNOWN`
echo " testuser=$testuser"
echo " os=`uname -a`"
# It must be "yes", not just nonnull
if [ "x$preserve_scratch" = xyes ]; then
if test "x$preserve_scratch" = xyes
then
echo " preserve_scratch=yes"
else
echo " preserve_scratch=no"
fi
# Check if setfacl is around and if it supports the -k or -s option.
if setfacl --help 2>&1 | grep ' -k,\|\[-[a-z]*k' >/dev/null; then
setfacl_nodef='setfacl -k'
elif setfacl -s u::7,g::5,o:5 testsuite 2>/dev/null; then
setfacl_nodef='setfacl -s u::7,g::5,o:5'
else
setfacl_nodef=true
fi
export setfacl_nodef
if [ ! -f "$rsync_bin" ]; then
if test ! -f $rsync_bin
then
echo "rsync_bin $rsync_bin is not a file" >&2
exit 2
fi
if [ ! -d "$srcdir" ]; then
if test ! -d $srcdir
then
echo "srcdir $srcdir is not a directory" >&2
exit 2
fi
RSYNC="$rsync_bin"
export rsync_bin RSYNC
skipped=0
missing=0
passed=0
@@ -210,7 +180,7 @@ failed=0
# Prefix for scratch directory. We create separate directories for
# each test case, so that they can be left behind in case of failure
# to aid investigation.
scratchbase="$TOOLDIR"/testtmp
scratchbase="`pwd`"/testtmp
echo " scratchbase=$scratchbase"
suitedir="$srcdir/testsuite"
@@ -220,9 +190,6 @@ export scratchdir suitedir
prep_scratch() {
[ -d "$scratchdir" ] && rm -rf "$scratchdir"
mkdir "$scratchdir"
# Get rid of default ACLs and dir-setgid to avoid confusing some tests.
$setfacl_nodef "$scratchdir" || true
chmod g-s "$scratchdir"
return 0
}
@@ -231,13 +198,14 @@ maybe_discard_scratch() {
return 0
}
if [ "x$whichtests" = x ]; then
if [ "x$whichtests" = x ]
then
whichtests="*.test"
fi
for testscript in $suitedir/$whichtests
do
testbase=`echo $testscript | sed -e 's!.*/!!' -e 's/.test\$//'`
testbase=`echo $testscript | sed 's!.*/!!' | sed -e 's/.test\$//'`
scratchdir="$scratchbase.$testbase"
prep_scratch
@@ -252,11 +220,6 @@ do
echo "----- $testbase log follows"
cat "$scratchdir/test.log"
echo "----- $testbase log ends"
if [ -f "$scratchdir/rsyncd.log" ]; then
echo "----- $testbase rsyncd.log follows"
cat "$scratchdir/rsyncd.log"
echo "----- $testbase rsyncd.log ends"
fi
fi
case $result in
@@ -282,7 +245,8 @@ do
*)
echo "FAIL $testbase"
failed=`expr $failed + 1`
if [ "x$nopersist" = xyes ]; then
if [ "x$nopersist" = "xyes" ]
then
exit 1
fi
esac

500
sender.c
View File

@@ -1,49 +1,31 @@
/*
* Routines only used by the sending process.
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
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 do_xfers;
extern int am_server;
extern int am_daemon;
extern int log_before_transfer;
extern int stdout_format_has_i;
extern int logfile_format_has_i;
extern int remote_version;
extern int csum_length;
extern int append_mode;
extern int io_error;
extern int allowed_lull;
extern int protocol_version;
extern int remove_source_files;
extern int updating_basis_file;
extern int make_backups;
extern int do_progress;
extern int inplace;
extern int batch_fd;
extern int write_batch;
extern struct stats stats;
extern struct file_list *the_file_list;
extern char *stdout_format;
extern int io_error;
extern int dry_run;
extern int am_server;
/**
@@ -54,63 +36,51 @@ extern char *stdout_format;
* machine holding the source files.
**/
/**
* Receive the checksums for a buffer
**/
static struct sum_struct *receive_sums(int f)
{
struct sum_struct *s;
int32 i;
int lull_mod = allowed_lull * 5;
int i;
OFF_T offset = 0;
if (!(s = new(struct sum_struct)))
out_of_memory("receive_sums");
read_sum_head(f, s);
s = new(struct sum_struct);
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=%.0f n=%ld rem=%ld\n",
(double)s->count, (long)s->blength, (long)s->remainder);
}
if (verbose > 3)
rprintf(FINFO,"count=%ld n=%ld rem=%ld\n",
(long) s->count, (long) s->n, (long) s->remainder);
if (append_mode) {
s->flength = (OFF_T)s->count * s->blength;
if (s->remainder)
s->flength -= s->blength - s->remainder;
return s;
}
if (s->count == 0)
if (s->count == 0)
return(s);
if (!(s->sums = new_array(struct sum_buf, s->count)))
out_of_memory("receive_sums");
s->sums = new_array(struct sum_buf, s->count);
if (!s->sums) out_of_memory("receive_sums");
for (i = 0; i < s->count; i++) {
for (i=0; i < (int) s->count;i++) {
s->sums[i].sum1 = read_int(f);
read_buf(f, s->sums[i].sum2, s->s2length);
read_buf(f,s->sums[i].sum2,csum_length);
s->sums[i].offset = offset;
s->sums[i].flags = 0;
s->sums[i].i = i;
if (i == s->count-1 && s->remainder != 0)
if (i == (int) s->count-1 && s->remainder != 0) {
s->sums[i].len = s->remainder;
else
s->sums[i].len = s->blength;
} else {
s->sums[i].len = s->n;
}
offset += s->sums[i].len;
if (allowed_lull && !(i % lull_mod))
maybe_send_keepalive();
if (verbose > 3) {
rprintf(FINFO,
"chunk[%d] len=%d offset=%.0f sum1=%08x\n",
i, s->sums[i].len, (double)s->sums[i].offset,
s->sums[i].sum1);
}
if (verbose > 3)
rprintf(FINFO,"chunk[%d] len=%d offset=%.0f sum1=%08x\n",
i,s->sums[i].len,(double)s->sums[i].offset,s->sums[i].sum1);
}
s->flength = offset;
@@ -118,269 +88,215 @@ static struct sum_struct *receive_sums(int f)
return s;
}
void successful_send(int ndx)
{
char fname[MAXPATHLEN];
struct file_struct *file;
unsigned int offset;
if (ndx < 0 || ndx >= the_file_list->count)
return;
file = the_file_list->files[ndx];
if (file->dir.root) {
offset = stringjoin(fname, sizeof fname,
file->dir.root, "/", NULL);
} else
offset = 0;
f_name(file, fname + offset);
if (remove_source_files) {
if (do_unlink(fname) == 0) {
if (verbose > 1)
rprintf(FINFO, "sender removed %s\n", fname + offset);
} else
rsyserr(FERROR, errno, "sender failed to remove %s", fname + offset);
}
}
static void write_ndx_and_attrs(int f_out, int ndx, int iflags,
uchar fnamecmp_type, char *buf, int len)
{
write_int(f_out, ndx);
if (protocol_version < 29)
return;
write_shortint(f_out, iflags);
if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
write_byte(f_out, fnamecmp_type);
if (iflags & ITEM_XNAME_FOLLOWS)
write_vstring(f_out, buf, len);
}
/* This is also used by receive.c with f_out = -1. */
int read_item_attrs(int f_in, int f_out, int ndx, uchar *type_ptr,
char *buf, int *len_ptr)
{
int len;
uchar fnamecmp_type = FNAMECMP_FNAME;
int iflags = protocol_version >= 29 ? read_shortint(f_in)
: ITEM_TRANSFER | ITEM_MISSING_DATA;
/* Handle the new keep-alive (no-op) packet. */
if (ndx == the_file_list->count && iflags == ITEM_IS_NEW)
;
else if (ndx < 0 || ndx >= the_file_list->count) {
rprintf(FERROR, "Invalid file index: %d (count=%d) [%s]\n",
ndx, the_file_list->count, who_am_i());
exit_cleanup(RERR_PROTOCOL);
} else if (iflags == ITEM_IS_NEW) {
rprintf(FERROR, "Invalid itemized flag word: %x [%s]\n",
iflags, who_am_i());
exit_cleanup(RERR_PROTOCOL);
}
if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
fnamecmp_type = read_byte(f_in);
*type_ptr = fnamecmp_type;
if (iflags & ITEM_XNAME_FOLLOWS) {
if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0)
exit_cleanup(RERR_PROTOCOL);
} else {
*buf = '\0';
len = -1;
}
*len_ptr = len;
if (iflags & ITEM_TRANSFER) {
if (!S_ISREG(the_file_list->files[ndx]->mode)) {
rprintf(FERROR,
"received request to transfer non-regular file: %d [%s]\n",
ndx, who_am_i());
exit_cleanup(RERR_PROTOCOL);
}
} else if (f_out >= 0) {
write_ndx_and_attrs(f_out, ndx, iflags,
fnamecmp_type, buf, len);
}
return iflags;
}
void send_files(struct file_list *flist, int f_out, int f_in)
{
void send_files(struct file_list *flist,int f_out,int f_in)
{
int fd = -1;
struct sum_struct *s;
struct map_struct *mbuf = NULL;
struct map_struct *buf = NULL;
STRUCT_STAT st;
char *fname2, fname[MAXPATHLEN];
char xname[MAXPATHLEN];
uchar fnamecmp_type;
int iflags, xlen;
char fname[MAXPATHLEN];
int i;
struct file_struct *file;
int phase = 0, max_phase = protocol_version >= 29 ? 2 : 1;
int phase = 0;
extern struct stats stats;
struct stats initial_stats;
int save_make_backups = make_backups;
int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
enum logcode log_code = log_before_transfer ? FLOG : FINFO;
int f_xfer = write_batch < 0 ? batch_fd : f_out;
int i, j;
extern int write_batch; /* dw */
extern int read_batch; /* dw */
int checksums_match; /* dw */
int buff_len; /* dw */
char buff[CHUNK_SIZE]; /* dw */
int j; /* dw */
int done; /* dw */
if (verbose > 2)
rprintf(FINFO, "send_files starting\n");
rprintf(FINFO,"send_files starting\n");
while (1) {
unsigned int offset;
int offset=0;
i = read_int(f_in);
if (i == -1) {
if (++phase > max_phase)
break;
csum_length = SUM_LENGTH;
if (verbose > 2)
rprintf(FINFO, "send_files phase=%d\n", phase);
write_int(f_out, -1);
/* For inplace: redo phase turns off the backup
* flag so that we do a regular inplace send. */
make_backups = 0;
append_mode = 0;
continue;
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;
}
iflags = read_item_attrs(f_in, f_out, i, &fnamecmp_type,
xname, &xlen);
if (iflags == ITEM_IS_NEW) /* no-op packet */
continue;
file = flist->files[i];
if (file->dir.root) {
/* N.B. We're sure that this fits, so offset is OK. */
offset = strlcpy(fname, file->dir.root, sizeof fname);
if (!offset || fname[offset-1] != '/')
fname[offset++] = '/';
} else
offset = 0;
fname2 = f_name(file, fname + offset);
if (verbose > 2)
rprintf(FINFO, "send_files(%d, %s)\n", i, fname);
if (!(iflags & ITEM_TRANSFER)) {
maybe_log_item(file, iflags, itemizing, xname);
continue;
}
if (phase == 2) {
rprintf(FERROR,
"got transfer request in phase 2 [%s]\n",
who_am_i());
if (i < 0 || i >= flist->count) {
rprintf(FERROR,"Invalid file index %d (count=%d)\n",
i, flist->count);
exit_cleanup(RERR_PROTOCOL);
}
updating_basis_file = inplace && (protocol_version >= 29
? fnamecmp_type == FNAMECMP_FNAME : !make_backups);
file = flist->files[i];
stats.current_file_index = i;
stats.num_transferred_files++;
stats.total_transferred_size += file->length;
if (!do_xfers) { /* log the transfer */
log_item(FCLIENT, file, &stats, iflags, NULL);
write_ndx_and_attrs(f_out, i, iflags, fnamecmp_type,
xname, xlen);
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;
if (!(s = receive_sums(f_in))) {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "receive_sums failed\n");
s = receive_sums(f_in);
if (!s) {
io_error = 1;
rprintf(FERROR,"receive_sums failed\n");
return;
}
fd = do_open(fname, O_RDONLY, 0);
if (fd == -1) {
if (errno == ENOENT) {
enum logcode c = am_daemon
&& protocol_version < 28 ? FERROR
: FINFO;
io_error |= IOERR_VANISHED;
rprintf(c, "file has vanished: %s\n",
full_fname(fname));
} else {
io_error |= IOERR_GENERAL;
rsyserr(FERROR, errno,
"send_files failed to open %s",
full_fname(fname));
if (write_batch)
write_batch_csum_info(&i,flist->count,s);
if (!read_batch) {
fd = do_open(fname, O_RDONLY, 0);
if (fd == -1) {
io_error = 1;
rprintf(FERROR,"send_files failed to open %s: %s\n",
fname,strerror(errno));
free_sums(s);
continue;
}
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 %.0f\n",
fname,(double)st.st_size);
write_int(f_out,i);
if (write_batch)
write_batch_delta_file((char *)&i,sizeof(i));
write_int(f_out,s->count);
write_int(f_out,s->n);
write_int(f_out,s->remainder);
}
/* map the local file */
if (do_fstat(fd, &st) != 0) {
io_error |= IOERR_GENERAL;
rsyserr(FERROR, errno, "fstat failed");
free_sums(s);
close(fd);
return;
}
if (st.st_size) {
int32 read_size = MAX(s->blength * 3, MAX_MAP_SIZE);
mbuf = map_file(fd, st.st_size, read_size, s->blength);
} else
mbuf = NULL;
if (verbose > 2) {
rprintf(FINFO, "send_files mapped %s of size %.0f\n",
fname, (double)st.st_size);
}
write_ndx_and_attrs(f_out, i, iflags, fnamecmp_type,
xname, xlen);
write_sum_head(f_xfer, s);
if (verbose > 2)
rprintf(FINFO, "calling match_sums %s\n", fname);
if (log_before_transfer)
log_item(FCLIENT, file, &initial_stats, iflags, NULL);
else if (!am_server && verbose && do_progress)
rprintf(FCLIENT, "%s\n", fname2);
if (!read_batch)
rprintf(FINFO,"calling match_sums %s\n",fname);
if (!am_server) {
log_transfer(file, fname+offset);
}
set_compression(fname);
match_sums(f_xfer, s, mbuf, st.st_size);
if (do_progress)
end_progress(st.st_size);
if (read_batch) { /* dw */
/* read checksums originally computed on sender side */
read_batch_csum_info(i, s, &checksums_match);
if (checksums_match) {
read_batch_delta_file( (char *) &j, sizeof(int) );
if (j != i) { /* if flist index entries don't match*/
rprintf(FINFO,"index mismatch in send_files\n");
rprintf(FINFO,"read index = %d flist ndx = %d\n",j,i);
close_batch_delta_file();
close_batch_csums_file();
exit_cleanup(1);
}
else {
write_int(f_out,j);
write_int(f_out,s->count);
write_int(f_out,s->n);
write_int(f_out,s->remainder);
done=0;
while (!done) {
read_batch_delta_file( (char *) &buff_len, sizeof(int) );
write_int(f_out,buff_len);
if (buff_len == 0) {
done = 1;
}
else {
if (buff_len > 0) {
read_batch_delta_file(buff, buff_len);
write_buf(f_out,buff,buff_len);
}
}
} /* end while */
read_batch_delta_file( buff, MD4_SUM_LENGTH);
write_buf(f_out, buff, MD4_SUM_LENGTH);
log_item(log_code, file, &initial_stats, iflags, NULL);
} /* j=i */
} else { /* not checksum match */
rprintf (FINFO,"readbatch & checksums don't match\n");
rprintf (FINFO,"filename=%s is being skipped\n",
fname);
continue;
}
} else {
match_sums(f_out,s,buf,st.st_size);
log_send(file, &initial_stats);
}
if (mbuf) {
j = unmap_file(mbuf);
if (j) {
io_error |= IOERR_GENERAL;
rsyserr(FERROR, j,
"read errors mapping %s",
full_fname(fname));
}
if (!read_batch) { /* dw */
if (buf) unmap_file(buf);
close(fd);
}
close(fd);
free_sums(s);
if (verbose > 2)
rprintf(FINFO, "sender finished %s\n", fname);
/* Flag that we actually sent this entry. */
file->flags |= FLAG_SENT;
rprintf(FINFO,"sender finished %s\n",fname);
}
make_backups = save_make_backups;
if (verbose > 2)
rprintf(FINFO, "send files finished\n");
rprintf(FINFO,"send files finished\n");
match_report();
write_int(f_out, -1);
write_int(f_out,-1);
if (write_batch || read_batch) { /* dw */
close_batch_csums_file();
close_batch_delta_file();
}
}

594
socket.c
View File

@@ -1,84 +1,59 @@
/*
/* -*- c-file-style: "linux" -*-
rsync -- fast file replication program
Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* @file socket.c
*
* Socket functions used in rsync.
*
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* This file is now converted to use the new-style getaddrinfo()
* This file is now converted to use the new-style getaddrinfo()
* interface, which supports IPv6 but is also supported on recent
* IPv4-only machines. On systems that don't have that interface, we
* emulate it using the KAME implementation. */
* emulate it using the KAME implementation.
**/
#include "rsync.h"
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
extern char *bind_address;
extern int default_af_hint;
#ifdef HAVE_SIGACTION
static struct sigaction sigact;
#endif
/**
* Establish a proxy connection on an open socket to a web proxy by
* using the CONNECT method. If proxy_user and proxy_pass are not NULL,
* they are used to authenticate to the proxy using the "Basic"
* proxy-authorization protocol
* using the HTTP CONNECT method.
**/
static int establish_proxy_connection(int fd, char *host, int port,
char *proxy_user, char *proxy_pass)
static int establish_proxy_connection(int fd, char *host, int port)
{
char *cp, buffer[1024];
char *authhdr, authbuf[1024];
int len;
char buffer[1024];
char *cp;
if (proxy_user && proxy_pass) {
stringjoin(buffer, sizeof buffer,
proxy_user, ":", proxy_pass, NULL);
len = strlen(buffer);
if ((len*8 + 5) / 6 >= (int)sizeof authbuf - 3) {
rprintf(FERROR,
"authentication information is too long\n");
return -1;
}
base64_encode(buffer, len, authbuf, 1);
authhdr = "\r\nProxy-Authorization: Basic ";
} else {
*authbuf = '\0';
authhdr = "";
}
snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n",
host, port, authhdr, authbuf);
len = strlen(buffer);
if (write(fd, buffer, len) != len) {
rsyserr(FERROR, errno, "failed to write to proxy");
snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
if (write(fd, buffer, strlen(buffer)) != (int) strlen(buffer)) {
rprintf(FERROR, "failed to write to proxy: %s\n",
strerror(errno));
return -1;
}
for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; cp++) {
if (read(fd, cp, 1) != 1) {
rsyserr(FERROR, errno, "failed to read from proxy");
rprintf(FERROR, "failed to read from proxy: %s\n",
strerror(errno));
return -1;
}
if (*cp == '\n')
@@ -91,32 +66,34 @@ static int establish_proxy_connection(int fd, char *host, int port,
if (*cp == '\r')
*cp = '\0';
if (strncmp(buffer, "HTTP/", 5) != 0) {
rprintf(FERROR, "bad response from proxy -- %s\n",
rprintf(FERROR, "bad response from proxy - %s\n",
buffer);
return -1;
}
for (cp = &buffer[5]; isdigit(*(uchar*)cp) || *cp == '.'; cp++) {}
for (cp = &buffer[5]; isdigit(* (unsigned char *) cp) || (*cp == '.'); cp++)
;
while (*cp == ' ')
cp++;
if (*cp != '2') {
rprintf(FERROR, "bad response from proxy -- %s\n",
rprintf(FERROR, "bad response from proxy - %s\n",
buffer);
return -1;
}
/* throw away the rest of the HTTP header */
while (1) {
for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
for (cp = buffer; cp < &buffer[sizeof(buffer) - 1];
cp++) {
if (read(fd, cp, 1) != 1) {
rsyserr(FERROR, errno,
"failed to read from proxy");
rprintf(FERROR, "failed to read from proxy: %s\n",
strerror(errno));
return -1;
}
if (*cp == '\n')
break;
}
if (cp > buffer && *cp == '\n')
if ((cp > buffer) && (*cp == '\n'))
cp--;
if (cp == buffer && (*cp == '\n' || *cp == '\r'))
if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r')))
break;
}
return 0;
@@ -127,19 +104,20 @@ static int establish_proxy_connection(int fd, char *host, int port,
* Try to set the local address for a newly-created socket. Return -1
* if this fails.
**/
int try_bind_local(int s, int ai_family, int ai_socktype,
const char *bind_addr)
int try_bind_local(int s,
int ai_family, int ai_socktype,
const char *bind_address)
{
int error;
struct addrinfo bhints, *bres_all, *r;
memset(&bhints, 0, sizeof bhints);
memset(&bhints, 0, sizeof(bhints));
bhints.ai_family = ai_family;
bhints.ai_socktype = ai_socktype;
bhints.ai_flags = AI_PASSIVE;
if ((error = getaddrinfo(bind_addr, NULL, &bhints, &bres_all))) {
if ((error = getaddrinfo(bind_address, NULL, &bhints, &bres_all))) {
rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n",
bind_addr, gai_strerror(error));
bind_address, gai_strerror(error));
return -1;
}
@@ -173,68 +151,51 @@ int try_bind_local(int s, int ai_family, int ai_socktype,
* reachable, perhaps because we can't e.g. route ipv6 to that network
* but we can get ip4 packets through.
*
* @param bind_addr Local address to use. Normally NULL to bind
* @param bind_address Local address to use. Normally NULL to bind
* the wildcard address.
*
* @param af_hint Address family, e.g. AF_INET or AF_INET6.
**/
int open_socket_out(char *host, int port, const char *bind_addr,
int open_socket_out(char *host, int port, const char *bind_address,
int af_hint)
{
int type = SOCK_STREAM;
int error, s;
int error;
int s;
struct addrinfo hints, *res0, *res;
char portbuf[10];
char *h, *cp;
char *h;
int proxied = 0;
char buffer[1024];
char *proxy_user = NULL, *proxy_pass = NULL;
char *cp;
/* if we have a RSYNC_PROXY env variable then redirect our
* connetcion via a web proxy at the given address. */
* connetcion via a web proxy at the given address. The format
* is hostname:port */
h = getenv("RSYNC_PROXY");
proxied = h != NULL && *h != '\0';
proxied = (h != NULL) && (*h != '\0');
if (proxied) {
strlcpy(buffer, h, sizeof buffer);
/* Is the USER:PASS@ prefix present? */
if ((cp = strrchr(buffer, '@')) != NULL) {
*cp++ = '\0';
/* The remainder is the HOST:PORT part. */
h = cp;
if ((cp = strchr(buffer, ':')) == NULL) {
rprintf(FERROR,
"invalid proxy specification: should be USER:PASS@HOST:PORT\n");
return -1;
}
*cp++ = '\0';
proxy_user = buffer;
proxy_pass = cp;
} else {
/* The whole buffer is the HOST:PORT part. */
h = buffer;
}
if ((cp = strchr(h, ':')) == NULL) {
strlcpy(buffer, h, sizeof(buffer));
cp = strchr(buffer, ':');
if (cp == NULL) {
rprintf(FERROR,
"invalid proxy specification: should be HOST:PORT\n");
return -1;
}
*cp++ = '\0';
strlcpy(portbuf, cp, sizeof portbuf);
strcpy(portbuf, cp);
h = buffer;
if (verbose >= 2) {
rprintf(FINFO, "connection via http proxy %s port %s\n",
h, portbuf);
}
} else {
snprintf(portbuf, sizeof portbuf, "%d", port);
snprintf(portbuf, sizeof(portbuf), "%d", port);
h = host;
}
memset(&hints, 0, sizeof hints);
memset(&hints, 0, sizeof(hints));
hints.ai_family = af_hint;
hints.ai_socktype = type;
error = getaddrinfo(h, portbuf, &hints, &res0);
@@ -254,30 +215,31 @@ int open_socket_out(char *host, int port, const char *bind_addr,
if (s < 0)
continue;
if (bind_addr
&& try_bind_local(s, res->ai_family, type,
bind_addr) == -1) {
close(s);
s = -1;
continue;
}
if (bind_address)
if (try_bind_local(s, res->ai_family, type,
bind_address) == -1) {
close(s);
s = -1;
continue;
}
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
close(s);
s = -1;
continue;
}
if (proxied
&& establish_proxy_connection(s, host, port,
proxy_user, proxy_pass) != 0) {
if (proxied &&
establish_proxy_connection(s, host, port) != 0) {
close(s);
s = -1;
continue;
}
break;
} else
break;
}
freeaddrinfo(res0);
if (s < 0) {
rsyserr(FERROR, errno, "failed to connect to %s", h);
rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
h, strerror(errno));
return -1;
}
return s;
@@ -294,135 +256,95 @@ int open_socket_out(char *host, int port, const char *bind_addr,
*
* This is based on the Samba LIBSMB_PROG feature.
*
* @param bind_addr Local address to use. Normally NULL to get the stack default.
* @param bind_address Local address to use. Normally NULL to get the stack default.
**/
int open_socket_out_wrapped(char *host, int port, const char *bind_addr,
int af_hint)
int open_socket_out_wrapped (char *host,
int port,
const char *bind_address,
int af_hint)
{
char *prog = getenv("RSYNC_CONNECT_PROG");
char *prog;
if (verbose >= 2) {
rprintf(FINFO, "%sopening tcp connection to %s port %d\n",
prog ? "Using RSYNC_CONNECT_PROG instead of " : "",
host, port);
}
if (prog)
return sock_exec(prog);
return open_socket_out(host, port, bind_addr, af_hint);
if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
return sock_exec (prog);
else
return open_socket_out (host, port, bind_address,
af_hint);
}
/**
* Open one or more sockets for incoming data using the specified type,
* port, and address.
* Open a socket of the specified type, port and address for incoming data
*
* The getaddrinfo() call may return several address results, e.g. for
* the machine's IPv4 and IPv6 name.
*
* We return an array of file-descriptors to the sockets, with a trailing
* -1 value to indicate the end of the list.
*
* @param bind_addr Local address to bind, or NULL to allow it to
* Try to be better about handling the results of getaddrinfo(): when
* opening an inbound socket, we might get several address results,
* e.g. for the machine's ipv4 and ipv6 name.
*
* If binding a wildcard, then any one of them should do. If an address
* was specified but it's insufficiently specific then that's not our
* fault.
*
* However, some of the advertized addresses may not work because e.g. we
* don't have IPv6 support in the kernel. In that case go on and try all
* addresses until one succeeds.
*
* @param bind_address Local address to bind, or NULL to allow it to
* default.
**/
static int *open_socket_in(int type, int port, const char *bind_addr,
int af_hint)
static int open_socket_in(int type, int port, const char *bind_address,
int af_hint)
{
int one = 1;
int s, *socks, maxs, i, ecnt;
int one=1;
int s;
struct addrinfo hints, *all_ai, *resp;
char portbuf[10], **errmsgs;
char portbuf[10];
int error;
memset(&hints, 0, sizeof hints);
memset(&hints, 0, sizeof(hints));
hints.ai_family = af_hint;
hints.ai_socktype = type;
hints.ai_flags = AI_PASSIVE;
snprintf(portbuf, sizeof portbuf, "%d", port);
error = getaddrinfo(bind_addr, portbuf, &hints, &all_ai);
snprintf(portbuf, sizeof(portbuf), "%d", port);
error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
if (error) {
rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
bind_addr, gai_strerror(error));
return NULL;
bind_address, gai_strerror(error));
return -1;
}
/* Count max number of sockets we might open. */
for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {}
socks = new_array(int, maxs + 1);
errmsgs = new_array(char *, maxs);
if (!socks || !errmsgs)
out_of_memory("open_socket_in");
/* We may not be able to create the socket, if for example the
* machine knows about IPv6 in the C library, but not in the
* kernel. */
for (resp = all_ai, i = ecnt = 0; resp; resp = resp->ai_next) {
for (resp = all_ai; resp; resp = resp->ai_next) {
s = socket(resp->ai_family, resp->ai_socktype,
resp->ai_protocol);
if (s == -1) {
int r = asprintf(&errmsgs[ecnt++],
"socket(%d,%d,%d) failed: %s\n",
(int)resp->ai_family, (int)resp->ai_socktype,
(int)resp->ai_protocol, strerror(errno));
if (r < 0)
out_of_memory("open_socket_in");
if (s == -1)
/* See if there's another address that will work... */
continue;
}
setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof one);
#ifdef IPV6_V6ONLY
if (resp->ai_family == AF_INET6) {
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&one, sizeof one) < 0
&& default_af_hint != AF_INET6) {
close(s);
continue;
}
}
#endif
/* Now we've got a socket - we need to bind it. */
if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) {
/* now we've got a socket - we need to bind it */
if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) {
/* Nope, try another */
int r = asprintf(&errmsgs[ecnt++],
"bind() failed: %s (address-family %d)\n",
strerror(errno), (int)resp->ai_family);
if (r < 0)
out_of_memory("open_socket_in");
close(s);
continue;
}
socks[i++] = s;
}
socks[i] = -1;
if (all_ai)
freeaddrinfo(all_ai);
/* Only output the socket()/bind() messages if we were totally
* unsuccessful, or if the daemon is being run with -vv. */
for (s = 0; s < ecnt; s++) {
if (!i || verbose > 1)
rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]));
free(errmsgs[s]);
return s;
}
free(errmsgs);
if (!i) {
rprintf(FERROR,
"unable to bind any inbound sockets on port %d\n",
port);
free(socks);
return NULL;
}
return socks;
rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
"%s\n",
port,
strerror(errno));
freeaddrinfo(all_ai);
return -1;
}
@@ -432,70 +354,55 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
int is_a_socket(int fd)
{
int v;
socklen_t l = sizeof (int);
socklen_t l;
l = sizeof(int);
/* Parameters to getsockopt, setsockopt etc are very
* unstandardized across platforms, so don't be surprised if
* there are compiler warnings on e.g. SCO OpenSwerver or AIX.
* It seems they all eventually get the right idea.
*
* Debian says: ``The fifth argument of getsockopt and
* setsockopt is in reality an int [*] (and this is what BSD
* 4.* and libc4 and libc5 have). Some POSIX confusion
* resulted in the present socklen_t. The draft standard has
* not been adopted yet, but glibc2 already follows it and
* also has socklen_t [*]. See also accept(2).''
*
* We now return to your regularly scheduled programming. */
return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0;
/* Parameters to getsockopt, setsockopt etc are very
* unstandardized across platforms, so don't be surprised if
* there are compiler warnings on e.g. SCO OpenSwerver or AIX.
* It seems they all eventually get the right idea.
*
* Debian says: ``The fifth argument of getsockopt and
* setsockopt is in reality an int [*] (and this is what BSD
* 4.* and libc4 and libc5 have). Some POSIX confusion
* resulted in the present socklen_t. The draft standard has
* not been adopted yet, but glibc2 already follows it and
* also has socklen_t [*]. See also accept(2).''
*
* We now return to your regularly scheduled programming. */
return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
}
static RETSIGTYPE sigchld_handler(UNUSED(int val))
{
signal(SIGCHLD, sigchld_handler);
#ifdef WNOHANG
while (waitpid(-1, NULL, WNOHANG) > 0) {}
#endif
#ifndef HAVE_SIGACTION
signal(SIGCHLD, sigchld_handler);
#endif
}
void start_accept_loop(int port, int (*fn)(int, int))
{
fd_set deffds;
int *sp, maxfd, i;
#ifdef HAVE_SIGACTION
sigact.sa_flags = SA_NOCLDSTOP;
#endif
int s;
extern char *bind_address;
extern int default_af_hint;
/* open an incoming socket */
sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
if (sp == NULL)
s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
if (s == -1)
exit_cleanup(RERR_SOCKETIO);
/* ready to listen */
FD_ZERO(&deffds);
for (i = 0, maxfd = -1; sp[i] >= 0; i++) {
if (listen(sp[i], 5) < 0) {
rsyserr(FERROR, errno, "listen() on socket failed");
#ifdef INET6
if (errno == EADDRINUSE && i > 0) {
rprintf(FINFO,
"Try using --ipv4 or --ipv6 to avoid this listen() error.\n");
}
#endif
exit_cleanup(RERR_SOCKETIO);
}
FD_SET(sp[i], &deffds);
if (maxfd < sp[i])
maxfd = sp[i];
if (listen(s, 5) == -1) {
close(s);
exit_cleanup(RERR_SOCKETIO);
}
/* now accept incoming connections - forking a new process
* for each incoming connection */
for each incoming connection */
while (1) {
fd_set fds;
pid_t pid;
@@ -504,45 +411,39 @@ void start_accept_loop(int port, int (*fn)(int, int))
socklen_t addrlen = sizeof addr;
/* close log file before the potentially very long select so
* file can be trimmed by another process instead of growing
* forever */
logfile_close();
file can be trimmed by another process instead of growing
forever */
log_close();
#ifdef FD_COPY
FD_COPY(&deffds, &fds);
#else
fds = deffds;
#endif
FD_ZERO(&fds);
FD_SET(s, &fds);
if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
continue;
for (i = 0, fd = -1; sp[i] >= 0; i++) {
if (FD_ISSET(sp[i], &fds)) {
fd = accept(sp[i], (struct sockaddr *)&addr,
&addrlen);
break;
}
}
if (fd < 0)
continue;
if(!FD_ISSET(s, &fds)) continue;
SIGACTION(SIGCHLD, sigchld_handler);
fd = accept(s,(struct sockaddr *)&addr,&addrlen);
if (fd == -1) continue;
signal(SIGCHLD, sigchld_handler);
if ((pid = fork()) == 0) {
int ret;
for (i = 0; sp[i] >= 0; i++)
close(sp[i]);
/* Re-open log file in child before possibly giving
* up privileges (see logfile_close() above). */
logfile_reopen();
close(s);
/* open log file in child before possibly giving
up privileges */
log_open();
ret = fn(fd, fd);
close_all();
_exit(ret);
} else if (pid < 0) {
rsyserr(FERROR, errno,
"could not create child server process");
rprintf(FERROR,
RSYNC_NAME
": could not create child server process: %s\n",
strerror(errno));
close(fd);
/* This might have happened because we're
* overloaded. Sleep briefly before trying to
@@ -598,7 +499,7 @@ struct
#endif
{NULL,0,0,0,0}};
/**
* Set user socket options
@@ -606,16 +507,13 @@ struct
void set_socket_options(int fd, char *options)
{
char *tok;
if (!options || !*options)
return;
if (!options || !*options) return;
options = strdup(options);
if (!options) out_of_memory("set_socket_options");
if (!options)
out_of_memory("set_socket_options");
for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) {
for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
int ret=0,i;
int value = 1;
char *p;
@@ -627,10 +525,9 @@ void set_socket_options(int fd, char *options)
got_value = 1;
}
for (i = 0; socket_options[i].name; i++) {
for (i=0;socket_options[i].name;i++)
if (strcmp(socket_options[i].name,tok)==0)
break;
}
if (!socket_options[i].name) {
rprintf(FERROR,"Unknown socket option %s\n",tok);
@@ -641,27 +538,24 @@ void set_socket_options(int fd, char *options)
case OPT_BOOL:
case OPT_INT:
ret = setsockopt(fd,socket_options[i].level,
socket_options[i].option,
(char *)&value, sizeof (int));
socket_options[i].option,(char *)&value,sizeof(int));
break;
case OPT_ON:
if (got_value)
rprintf(FERROR,"syntax error -- %s does not take a value\n",tok);
rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
{
int on = socket_options[i].value;
ret = setsockopt(fd,socket_options[i].level,
socket_options[i].option,
(char *)&on, sizeof (int));
socket_options[i].option,(char *)&on,sizeof(int));
}
break;
}
if (ret != 0) {
rsyserr(FERROR, errno,
"failed to set socket option %s", tok);
break;
}
if (ret != 0)
rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
strerror(errno));
}
free(options);
@@ -681,17 +575,19 @@ void become_daemon(void)
/* detach from the terminal */
#ifdef HAVE_SETSID
setsid();
#elif defined TIOCNOTTY
#else
#ifdef TIOCNOTTY
i = open("/dev/tty", O_RDWR);
if (i >= 0) {
ioctl(i, (int)TIOCNOTTY, (char *)0);
ioctl(i, (int) TIOCNOTTY, (char *)0);
close(i);
}
#endif /* TIOCNOTTY */
#endif
/* make sure that stdin, stdout an stderr don't stuff things
* up (library functions, for example) */
for (i = 0; i < 3; i++) {
close(i);
up (library functions, for example) */
for (i=0;i<3;i++) {
close(i);
open("/dev/null", O_RDWR);
}
}
@@ -700,7 +596,7 @@ void become_daemon(void)
/**
* This is like socketpair but uses tcp. It is used by the Samba
* regression test code.
*
*
* The function guarantees that nobody else can attach to the socket,
* or if they do that this function fails and the socket gets closed
* returns 0 on success, -1 on failure the resulting file descriptors
@@ -711,67 +607,56 @@ static int socketpair_tcp(int fd[2])
int listener;
struct sockaddr_in sock;
struct sockaddr_in sock2;
socklen_t socklen = sizeof sock;
socklen_t socklen = sizeof(sock);
int connect_done = 0;
fd[0] = fd[1] = listener = -1;
memset(&sock, 0, sizeof sock);
memset(&sock, 0, sizeof(sock));
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1)
goto failed;
memset(&sock2, 0, sizeof sock2);
#ifdef HAVE_SOCKADDR_IN_LEN
sock2.sin_len = sizeof sock2;
memset(&sock2, 0, sizeof(sock2));
#ifdef HAVE_SOCKADDR_LEN
sock2.sin_len = sizeof(sock2);
#endif
sock2.sin_family = PF_INET;
sock2.sin_family = PF_INET;
bind(listener, (struct sockaddr *)&sock2, sizeof sock2);
bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
if (listen(listener, 1) != 0)
goto failed;
if (listen(listener, 1) != 0) goto failed;
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0)
goto failed;
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1)
goto failed;
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
set_nonblocking(fd[1]);
sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) == -1) {
if (errno != EINPROGRESS)
goto failed;
} else
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
if (errno != EINPROGRESS) goto failed;
} else {
connect_done = 1;
}
if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1)
goto failed;
if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
close(listener);
listener = -1;
set_blocking(fd[1]);
if (connect_done == 0) {
if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0
&& errno != EISCONN)
goto failed;
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
&& errno != EISCONN) goto failed;
}
set_blocking (fd[1]);
/* all OK! */
return 0;
failed:
if (fd[0] != -1)
close(fd[0]);
if (fd[1] != -1)
close(fd[1]);
if (listener != -1)
close(listener);
if (fd[0] != -1) close(fd[0]);
if (fd[1] != -1) close(fd[1]);
if (listener != -1) close(listener);
return -1;
}
@@ -789,21 +674,30 @@ static int socketpair_tcp(int fd[2])
int sock_exec(const char *prog)
{
int fd[2];
if (socketpair_tcp(fd) != 0) {
rsyserr(FERROR, errno, "socketpair_tcp failed");
rprintf (FERROR, RSYNC_NAME
": socketpair_tcp failed (%s)\n",
strerror(errno));
return -1;
}
if (verbose >= 2)
rprintf(FINFO, "Running socket program: \"%s\"\n", prog);
if (fork() == 0) {
close(fd[0]);
close(0);
close(1);
dup(fd[1]);
dup(fd[1]);
exit(system(prog));
if (verbose > 3) {
/* Can't use rprintf because we've forked. */
fprintf (stderr,
RSYNC_NAME ": execute socket program \"%s\"\n",
prog);
}
exit (system (prog));
}
close(fd[1]);
close (fd[1]);
return fd[0];
}

View File

@@ -1,6 +0,0 @@
all: savetransfer
savetransfer: savetransfer.o
clean:
rm -f *.o savetransfer

View File

@@ -1,90 +0,0 @@
#!/usr/bin/perl
#
# This script lets you update a hierarchy of files in an atomic way by
# first creating a new hierarchy using rsync's --link-dest option, and
# then swapping the hierarchy into place. **See the usage message for
# more details and some important caveats!**
use strict;
use Cwd 'abs_path';
my $RSYNC_PROG = '/usr/bin/rsync';
my $RM_PROG = '/bin/rm';
my $dest_dir = $ARGV[-1];
usage(1) if $dest_dir eq '' || $dest_dir =~ /^--/;
if (!-d $dest_dir) {
print STDERR "$dest_dir is not a directory.\n\n";
usage(1);
}
if (@_ = grep(/^--(link|compare)-dest/, @ARGV)) {
$_ = join(' or ', @_);
print STDERR "You may not use $_ as an rsync option.\n\n";
usage(1);
}
$dest_dir = abs_path($dest_dir);
if ($dest_dir eq '/') {
print STDERR 'You must not use "/" as the destination directory.', "\n\n";
usage(1);
}
my $old_dir = "$dest_dir~old~";
my $new_dir = $ARGV[-1] = "$dest_dir~new~";
system($RM_PROG, '-rf', $old_dir) if -d $old_dir;
if (system($RSYNC_PROG, "--link-dest=$dest_dir", @ARGV)) {
if ($? == -1) {
print "failed to execute $RSYNC_PROG: $!\n";
} elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
} else {
printf "child exited with value %d\n", $? >> 8;
}
exit $?;
}
rename($dest_dir, $old_dir) or die "Unable to rename $new_dir to $old_dir: $!";
rename($new_dir, $dest_dir) or die "Unable to rename $new_dir to $dest_dir: $!";
exit;
sub usage
{
my($ret) = @_;
my $fh = $ret ? *STDERR : *STDOUT;
print $fh <<EOT;
Usage: atomic-rsync [RSYNC-OPTIONS] HOST:/SOURCE/DIR/ /DEST/DIR/
atomic-rsync [RSYNC-OPTIONS] HOST::MOD/DIR/ /DEST/DIR/
This script lets you update a hierarchy of files in an atomic way by first
creating a new hierarchy (using hard-links to leverage the existing files),
and then swapping the new hierarchy into place. You must be pulling files
to a local directory, and that directory must already exist. For example:
atomic-rsync -av host:/remote/files/ /local/files/
This would make the transfer to the directory /local/files~new~ and then
swap out /local/files at the end of the transfer by renaming it to
/local/files~old~ and putting the new directory into its place. The
/local/files~old~ directory will be preserved until the next update, at
which point it will be deleted.
Do NOT specify this command:
atomic-rsync -av host:/remote/files /local/
... UNLESS you want the entire /local dir to be swapped out!
See the "rsync" command for its list of options. You may not use the
--link-dest or --compare-dest options (since this script uses --link-dest
to make the transfer efficient). Also, the destination directory cannot
be "/".
EOT
exit $ret;
}

View File

@@ -1,64 +0,0 @@
#!/usr/bin/perl
# This script outputs some perl code that parses all possible options
# that the code in options.c might send to the server. This perl code
# is included in the rrsync script.
use strict;
our(%short_no_arg, %short_with_num, %long_opt);
our $last_long_opt;
open(IN, '../options.c') or die "Unable to open ../options.c: $!\n";
while (<IN>) {
if (/\Qargstr[x++]\E = '(.)'/) {
$short_no_arg{$1} = 1;
undef $last_long_opt;
} elsif (/\Qasprintf(\E[^,]+, "-([a-zA-Z0-9])\%l?[ud]"/) {
$short_with_num{$1} = 1;
undef $last_long_opt;
} elsif (/\Qargs[ac++]\E = "--([^"=]+)"/) {
$last_long_opt = $1;
$long_opt{$1} = 0;
} elsif (defined($last_long_opt)
&& /\Qargs[ac++]\E = ([^["\s]+);/ && $1 ne 'dest_option') {
$long_opt{$last_long_opt} = 2;
undef $last_long_opt;
} elsif (/dest_option = "--([^"]+)"/) {
$long_opt{$1} = 2;
undef $last_long_opt;
} elsif (/\Qasprintf(\E[^,]+, "--([^"=]+)=/ || /\Qargs[ac++]\E = "--([^"=]+)=/) {
$long_opt{$1} = 1;
undef $last_long_opt;
}
}
close IN;
my $short_no_arg = join('', sort keys %short_no_arg);
my $short_with_num = join('', sort keys %short_with_num);
print <<EOT;
# These options are the only options that rsync might send to the server,
# and only in the option format that the stock rsync produces.
# To disable a short-named option, add its letter to this string:
our \$short_disabled = '';
our \$short_no_arg = '$short_no_arg'; # DO NOT REMOVE ANY
our \$short_with_num = '$short_with_num'; # DO NOT REMOVE ANY
# To disable a long-named option, change its value to a -1. The values mean:
# 0 = the option has no arg; 1 = the arg doesn't need any checking; 2 = only
# check the arg when receiving; and 3 = always check the arg.
our \%long_opt = (
EOT
foreach my $opt (sort keys %long_opt) {
my $val = $long_opt{$opt};
$val = 1 if $opt =~ /^(max-|min-)/;
$val = 3 if $opt eq 'files-from';
$val = '$ro ? -1 : ' . $val if $opt =~ /^remove-/;
print " '$opt' => $val,\n";
}
print ");\n\n";

View File

@@ -1,42 +0,0 @@
#!/usr/bin/perl
#
# This script finds all CVS/Entries files in the current directory and below
# and creates a local .cvsinclude file with non-inherited rules including each
# checked-in file. Then, use this option whenever using --cvs-exclude (-C):
#
# -f ': .cvsinclude'
#
# That ensures that all checked-in files/dirs are included in the transfer.
# (You could alternately put ": .cvsinclude" into an .rsync-filter file and
# use the -F option, which is easier to type.)
#
# The downside is that you need to remember to re-run cvs2includes whenever
# You add a new file to the project.
use strict;
open(FIND, 'find . -name CVS -type d |') or die $!;
while (<FIND>) {
chomp;
s#^\./##;
my $entries = "$_/Entries";
s/CVS$/.cvsinclude/;
my $filter = $_;
open(ENTRIES, $entries) or die "Unable to open $entries: $!\n";
my @includes;
while (<ENTRIES>) {
push(@includes, $1) if m#/(.+?)/#;
}
close ENTRIES;
if (@includes) {
open(FILTER, ">$filter") or die "Unable to write $filter: $!\n";
print FILTER '+ /', join("\n+ /", @includes), "\n";
close FILTER;
print "Updated $filter\n";
} elsif (-f $filter) {
unlink($filter);
print "Removed $filter\n";
}
}
close FIND;

View File

@@ -1,173 +0,0 @@
#!/usr/bin/perl
# This script will parse the output of "find ARG [ARG...] -ls" and
# apply (at your discretion) the permissions, owner, and group info
# it reads onto any existing files and dirs (it doesn't try to affect
# symlinks). Run this with --help (-h) for a usage summary.
use strict;
use Getopt::Long;
our($p_opt, $o_opt, $g_opt, $map_file, $dry_run, $verbosity, $help_opt);
&Getopt::Long::Configure('bundling');
&usage if !&GetOptions(
'all|a' => sub { $p_opt = $o_opt = $g_opt = 1 },
'perms|p' => \$p_opt,
'owner|o' => \$o_opt,
'groups|g' => \$g_opt,
'map|m=s' => \$map_file,
'dry-run|n' => \$dry_run,
'help|h' => \$help_opt,
'verbose|v+' => \$verbosity,
) || $help_opt;
our(%uid_hash, %gid_hash);
$" = ', '; # How to join arrays referenced in double-quotes.
&parse_map_file($map_file) if defined $map_file;
my $detail_line = qr{
^ \s* \d+ \s+ # ignore inode
\d+ \s+ # ignore size
([-bcdlps]) # 1. File type
( [-r][-w][-xsS] # 2. user-permissions
[-r][-w][-xsS] # 3. group-permissions
[-r][-w][-xtT] ) \s+ # 4. other-permissions
\d+ \s+ # ignore number of links
(\S+) \s+ # 5. owner
(\S+) \s+ # 6. group
(?: \d+ \s+ )? # ignore size (when present)
\w+ \s+ \d+ \s+ # ignore month and date
\d+ (?: : \d+ )? \s+ # ignore time or year
([^\r\n]+) $ # 7. name
}x;
while (<>) {
my($type, $perms, $owner, $group, $name) = /$detail_line/;
die "Invalid input line $.:\n$_" unless defined $name;
die "A filename is not properly escaped:\n$_" unless $name =~ /^[^"\\]*(\\(\d\d\d|\D)[^"\\]*)*$/;
my $fn = $name;
$fn =~ s/\\(\d+|.)/ eval "\"\\$1\"" /eg;
if ($type eq '-') {
undef $type unless -f $fn;
} elsif ($type eq 'd') {
undef $type unless -d $fn;
} elsif ($type eq 'b') {
undef $type unless -b $fn;
} elsif ($type eq 'c') {
undef $type unless -c $fn;
} elsif ($type eq 'p') {
undef $type unless -p $fn;
} elsif ($type eq 's') {
undef $type unless -S $fn;
} else {
if ($verbosity) {
if ($type eq 'l') {
$name =~ s/ -> .*//;
$type = 'symlink';
} else {
$type = "type '$type'";
}
print "Skipping $name ($type ignored)\n";
}
next;
}
if (!defined $type) {
my $reason = -e _ ? "types don't match" : 'missing';
print "Skipping $name ($reason)\n";
next;
}
my($cur_mode, $cur_uid, $cur_gid) = (stat(_))[2,4,5];
$cur_mode &= 07777;
my $highs = join('', $perms =~ /..(.)..(.)..(.)/);
$highs =~ tr/-rwxSTst/00001111/;
$perms =~ tr/-STrwxst/00011111/;
my $mode = $p_opt ? oct('0b' . $highs . $perms) : $cur_mode;
my $uid = $o_opt ? $uid_hash{$owner} : $cur_uid;
if (!defined $uid) {
if ($owner =~ /^\d+$/) {
$uid = $owner;
} else {
$uid = getpwnam($owner);
}
$uid_hash{$owner} = $uid;
}
my $gid = $g_opt ? $gid_hash{$group} : $cur_gid;
if (!defined $gid) {
if ($group =~ /^\d+$/) {
$gid = $group;
} else {
$gid = getgrnam($group);
}
$gid_hash{$group} = $gid;
}
my @changes;
if ($mode != $cur_mode) {
push(@changes, 'permissions');
if (!$dry_run && !chmod($mode, $fn)) {
warn "chmod($mode, \"$name\") failed: $!\n";
}
}
if ($uid != $cur_uid || $gid != $cur_gid) {
push(@changes, 'owner') if $uid != $cur_uid;
push(@changes, 'group') if $gid != $cur_gid;
if (!$dry_run) {
if (!chown($uid, $gid, $fn)) {
warn "chown($uid, $gid, \"$name\") failed: $!\n";
}
if (($mode & 06000) && !chmod($mode, $fn)) {
warn "post-chown chmod($mode, \"$name\") failed: $!\n";
}
}
}
if (@changes) {
print "$name: changed @changes\n";
} elsif ($verbosity) {
print "$name: OK\n";
}
}
exit;
sub parse_map_file
{
my($fn) = @_;
open(IN, $fn) or die "Unable to open $fn: $!\n";
while (<IN>) {
if (/^user\s+(\S+)\s+(\S+)/) {
$uid_hash{$1} = $2;
} elsif (/^group\s+(\S+)\s+(\S+)/) {
$gid_hash{$1} = $2;
} else {
die "Invalid line #$. in mapfile `$fn':\n$_";
}
}
close IN;
}
sub usage
{
die <<EOT;
Usage: file-attr-restore [OPTIONS] FILE [FILE...]
-a, --all Restore all the attributes (-pog)
-p, --perms Restore the permissions
-o, --owner Restore the ownership
-g, --groups Restore the group
-m, --map=FILE Read user/group mappings from FILE
-n, --dry-run Don't actually make the changes
-v, --verbose Increase verbosity
-h, --help Show this help text
The FILE arg(s) should have been created by running the "find"
program with "-ls" as the output specifier.
The input file for the --map option must be in this format:
user FROM TO
group FROM TO
The "FROM" should be an user/group mentioned in the input, and the TO
should be either a uid/gid number, or a local user/group name.
EOT
}

View File

@@ -1,27 +0,0 @@
#!/usr/bin/perl
# This script takes an input of filenames and outputs a set of
# include/exclude directives that can be used by rsync to copy
# just the indicated files using an --exclude-from=FILE option.
use strict;
my %hash;
while (<>) {
chomp;
s#^/+##;
my $path = '/';
while (m#([^/]+/)/*#g) {
$path .= $1;
print "+ $path\n" unless $hash{$path}++;
}
if (m#([^/]+)$#) {
print "+ $path$1\n";
} else {
delete $hash{$path};
}
}
foreach (sort keys %hash) {
print "- $_*\n";
}
print "- /*\n";

View File

@@ -1,34 +0,0 @@
#!/usr/bin/perl
# Filter the rsync daemon log messages by module name. The log file can be
# in either syslog format or rsync's own log-file format. Note that the
# MODULE_NAME parameter is used in a regular-expression match in order to
# allow regex wildcards to be used. You can also limit the output by
# directory hierarchy in a module. Examples:
#
# logfilter foo /var/log/rsyncd.log # output lines for module foo
# logfilter foo/dir /var/log/syslog # limit lines to those in dir of foo
use strict;
my $match = shift;
die "Usage: logfilter MODULE_NAME [LOGFILE ...]\n" unless defined $match;
my $syslog_prefix = '\w\w\w +\d+ \d\d:\d\d:\d\d \S+ rsyncd';
my $rsyncd_prefix = '\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d ';
my %pids;
while (<>) {
my($pid,$msg) = /^(?:$syslog_prefix|$rsyncd_prefix)\[(\d+)\]:? (.*)/o;
next unless defined $pid;
my($mod_spec) = $msg =~ /^rsync (?:on|to) (\S+) from /;
if (defined $mod_spec) {
if ($mod_spec =~ /^$match(\/\S*)?$/o) {
$pids{$pid} = 1;
} else {
delete $pids{$pid};
}
}
next unless $pids{$pid};
print $_;
}

View File

@@ -1,44 +0,0 @@
#!/usr/bin/perl -w
# This script takes a command-line arg of a source directory
# that will be passed to rsync, and generates a set of excludes
# that will exclude all mount points from the list. This is
# useful if you have "bind" mounts since the --one-file-system
# option won't notice the transition to a different spot on
# the same disk. For example:
#
# mnt-excl /dir | rsync --exclude-from=- ... /dir /dest/
# mnt-excl /dir/ | rsync --exclude-from=- ... /dir/ /dest/
# ssh host mnt-excl /dir | rsync --exclude-from=- ... host:/dir /dest/
#
# Imagine that /dir/foo is a mount point: the first invocation of
# mnt-excl would have output /dir/foo, while the second would have
# output /foo (which are the properly anchored excludes).
#
# NOTE: This script expects /proc/mounts to exist, but could be
# easily adapted to read /etc/mtab or similar.
#
# ADDENDUM: The addition of the --filter option (which has support for
# absolute-anchored excludes) has made this script less useful than it
# was. Beginning with 2.6.4, you can achieve the effect of this script
# through this command:
#
# awk '{print $2}' /proc/mounts | rsync -f 'merge,/- -' host:/dir /dest/
use strict;
use Cwd 'abs_path';
my $file = '/proc/mounts';
my $dir = shift || '/';
$dir = abs_path($dir);
$dir =~ s#([^/]*)$##;
my $trailing = $1;
$trailing = '' if $trailing eq '.' || !-d "$dir$trailing";
$trailing .= '/' if $trailing ne '';
open(IN, $file) or die "Unable to open $file: $!\n";
while (<IN>) {
$_ = (split)[1];
next unless s#^\Q$dir$trailing\E##o && $_ ne '';
print "- /$trailing$_\n";
}
close IN;

View File

@@ -1,205 +0,0 @@
#!/usr/bin/perl
# Name: /usr/local/bin/rrsync (should also have a symlink in /usr/bin)
# Purpose: Restricts rsync to subdirectory declared in .ssh/authorized_keys
# Author: Joe Smith <js-cgi@inwap.com> 30-Sep-2004
# Modified by: Wayne Davison <wayned@samba.org>
use strict;
use Socket;
use Cwd 'abs_path';
use File::Glob ':glob';
# You may configure these values to your liking. See also the section
# of options if you want to disable any options that rsync accepts.
use constant RSYNC => '/usr/bin/rsync';
use constant LOGFILE => 'rrsync.log';
my $Usage = <<EOM;
Use 'command="$0 [-ro] SUBDIR"'
in front of lines in $ENV{HOME}/.ssh/authorized_keys
EOM
our $ro = (@ARGV && $ARGV[0] eq '-ro') ? shift : ''; # -ro = Read-Only
our $subdir = shift;
die "$0: No subdirectory specified\n$Usage" unless defined $subdir;
$subdir = abs_path($subdir);
die "$0: Restricted directory does not exist!\n" if $subdir ne '/' && !-d $subdir;
# The client uses "rsync -av -e ssh src/ server:dir/", and sshd on the server
# executes this program when .ssh/authorized_keys has 'command="..."'.
# For example:
# command="rrsync logs/client" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAzGhEeNlPr...
# command="rrsync -ro results" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAmkHG1WCjC...
#
# Format of the envrionment variables set by sshd:
# SSH_ORIGINAL_COMMAND=rsync --server -vlogDtpr --partial . ARG # push
# SSH_ORIGINAL_COMMAND=rsync --server --sender -vlogDtpr --partial . ARGS # pull
# SSH_CONNECTION=client_addr client_port server_port
my $command = $ENV{SSH_ORIGINAL_COMMAND};
die "$0: Not invoked via sshd\n$Usage" unless defined $command;
die "$0: SSH_ORIGINAL_COMMAND='$command' is not rsync\n" unless $command =~ s/^rsync\s+//;
our $am_sender = $command =~ /^--server\s+--sender\s/; # Restrictive on purpose!
die "$0 -ro: sending to read-only server not allowed\n" if $ro && !$am_sender;
### START of options data produced by the cull_options script. ###
# These options are the only options that rsync might send to the server,
# and only in the option format that the stock rsync produces.
# To disable a short-named option, add its letter to this string:
our $short_disabled = '';
our $short_no_arg = 'CDEHIKLORSWbcdgklmnoprtuvxz'; # DO NOT REMOVE ANY
our $short_with_num = 'B'; # DO NOT REMOVE ANY
# To disable a long-named option, change its value to a -1. The values mean:
# 0 = the option has no arg; 1 = the arg doesn't need any checking; 2 = only
# check the arg when receiving; and 3 = always check the arg.
our %long_opt = (
'append' => 0,
'backup-dir' => 2,
'bwlimit' => 1,
'checksum-seed' => 1,
'compare-dest' => 2,
'compress-level' => 1,
'copy-dest' => 2,
'copy-unsafe-links' => 0,
'daemon' => 0,
'delay-updates' => 0,
'delete' => 0,
'delete-after' => 0,
'delete-before' => 0,
'delete-during' => 0,
'delete-excluded' => 0,
'existing' => 0,
'files-from' => 3,
'force' => 0,
'from0' => 0,
'fuzzy' => 0,
'ignore-errors' => 0,
'ignore-existing' => 0,
'inplace' => 0,
'link-dest' => 2,
'list-only' => 0,
'log-format' => 1,
'max-delete' => 1,
'max-size' => 1,
'min-size' => 1,
'modify-window' => 1,
'no-implied-dirs' => 0,
'no-r' => 0,
'no-relative' => 0,
'no-specials' => 0,
'numeric-ids' => 0,
'only-write-batch' => 1,
'partial' => 0,
'partial-dir' => 2,
'remove-sent-files' => $ro ? -1 : 0,
'remove-source-files' => $ro ? -1 : 0,
'safe-links' => 0,
'sender' => 0,
'server' => 0,
'size-only' => 0,
'specials' => 0,
'suffix' => 1,
'super' => 0,
'temp-dir' => 2,
'timeout' => 1,
);
### END of options data produced by the cull_options script. ###
if ($short_disabled ne '') {
$short_no_arg =~ s/[$short_disabled]//go;
$short_with_num =~ s/[$short_disabled]//go;
}
$short_no_arg = "[$short_no_arg]" if length($short_no_arg) > 1;
$short_with_num = "[$short_with_num]" if length($short_with_num) > 1;
my $write_log = -f LOGFILE && open(LOG, '>>', LOGFILE);
chdir($subdir) or die "$0: Unable to chdir to restricted dir: $!\n";
my(@opts, @args);
my $in_options = 1;
my $last_opt = '';
my $check_type;
while ($command =~ /((?:[^\s\\]+|\\.[^\s\\]*)+)/g) {
$_ = $1;
if ($check_type) {
push(@opts, check_arg($last_opt, $_, $check_type));
$check_type = 0;
} elsif ($in_options) {
push(@opts, $_);
if ($_ eq '.') {
$in_options = 0;
} else {
next if /^-$short_no_arg+$/o || /^-$short_with_num\d+$/o;
my($opt,$arg) = /^--([^=]+)(?:=(.*))?$/;
my $disabled;
if (defined $opt) {
my $ct = $long_opt{$opt};
last unless defined $ct;
next if $ct == 0;
if ($ct > 0) {
if (!defined $arg) {
$check_type = $ct;
$last_opt = $opt;
next;
}
$arg = check_arg($opt, $arg, $ct);
$opts[-1] =~ s/=.*/=$arg/;
next;
}
$disabled = 1;
$opt = "--$opt";
} elsif ($short_disabled ne '') {
$disabled = /^-$short_no_arg*([$short_disabled])/o;
$opt = "-$1";
}
last unless $disabled; # Generate generic failure
die "$0: option $opt has been disabled on this server.\n";
}
} else {
if ($subdir ne '/') {
# Validate args to ensure they don't try to leave our restricted dir.
s#//+#/#g;
s#^/##;
s#^$#.#;
die "Do not use .. in any path!\n" if m#(^|/)\\?\.\\?\.(\\?/|$)#;
}
push(@args, bsd_glob($_, GLOB_LIMIT|GLOB_NOCHECK|GLOB_BRACE|GLOB_QUOTE));
}
}
die "$0: invalid rsync-command syntax or options\n" if $in_options;
@args = ( '.' ) if !@args;
if ($write_log) {
my ($mm,$hh) = (localtime)[1,2];
my $host = $ENV{SSH_CONNECTION} || 'unknown';
$host =~ s/ .*//; # Keep only the client's IP addr
$host =~ s/^::ffff://;
$host = gethostbyaddr(inet_aton($host),AF_INET) || $host;
printf LOG "%02d:%02d %-13s [%s]\n", $hh, $mm, $host, "@opts @args";
close LOG;
}
# Note: This assumes that the rsync protocol will not be maliciously hijacked.
exec(RSYNC, @opts, @args) or die "exec(rsync @opts @args) failed: $? $!";
sub check_arg
{
my($opt, $arg, $type) = @_;
$arg =~ s/\\(.)/$1/g;
if ($subdir ne '/' && ($type == 3 || ($type == 2 && !$am_sender))) {
$arg =~ s#//#/#g;
die "Do not use .. in --$opt; anchor the path at the root of your restricted dir.\n"
if $arg =~ m#(^|/)\.\.(/|$)#;
$arg =~ s#^/#$subdir/#;
}
$arg;
}

View File

@@ -1,80 +1,72 @@
#!/usr/bin/perl
#! /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 also parses a slightly tweaked
# version of the default format where %o has been replaced with %i.
#
# This script is derived from the xferstats script that comes with wuftpd. See
# the usage message at the bottom for the options it takes.
# 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
#
# ---------------------------------------------------------------------------
use Getopt::Long;
# You may wish to edit the next line to customize for your default log file.
$usage_file = "/var/log/rsyncd.log";
# 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.
$hourly_report = 0;
$domain_report = 0;
$total_report = 0;
$depth_limit = 9999;
$only_section = '';
$opt_h = 1;
$opt_d = 0;
$opt_t = 1;
$opt_l = 2;
&Getopt::Long::Configure('bundling');
&usage if !&GetOptions(
'hourly-report|h' => \$hourly_report,
'domain-report|d' => \$domain_report,
'domain|D:s' => \$only_domain,
'total-report|t' => \$total_report,
'depth-limit|l:i' => \$depth_limit,
'real|r' => \$real,
'anon|a' => \$anon,
'section|s:s' => \$only_section,
'file|f:s' => \$usage_file,
);
require 'getopts.pl';
&Getopts('f:rahdD:l:s:');
$anon = 1 if !$real && !$anon;
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";
open (LOG,$usage_file) || die "Error opening usage log file: $usage_file\n";
if ($only_domain) {
print "Transfer Totals include the '$only_domain' domain only.\n";
print "All other domains are filtered out for this report.\n\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 ($only_section) {
print "Transfer Totals include the '$only_section' section only.\n";
print "All other sections 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>) {
my $syslog_prefix = '\w\w\w +\d+ \d\d:\d\d:\d\d \S+ rsyncd';
my $rsyncd_prefix = '\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d ';
@line = split;
next unless ($day,$time,$op,$host,$module,$file,$bytes)
= m{^
( \w\w\w\s+\d+ | \d+/\d\d/\d\d ) \s+ # day
(\d\d:\d\d:\d\d) \s+ # time
[^[]* \[\d+\]:? \s+ # pid (ignored)
(send|recv|[<>]f\S+) \s+ # op (%o or %i)
(\S+) \s+ # host
\[\d+\.\d+\.\d+\.\d+\] \s+ # IP (ignored)
(\S+) \s+ # module
\(\S*\) \s+ # user (ignored)
(.*) \s+ # file name
(\d+) # file length in bytes
$ }x;
$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];
# TODO actually divide the data by into send/recv categories
if ($op =~ /^>/) {
$op = 'send';
} elsif ($op =~ /^</) {
$op = 'recv';
}
next if ($#line != 9);
next if ($op != "send" && $op != "recv");
$daytime = $day;
$hour = substr($time,0,2);
@@ -86,13 +78,11 @@ my $rsyncd_prefix = '\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d ';
@path = split(/\//, $file);
$pathkey = "";
for ($i=0; $i <= $#path && $i <= $depth_limit; $i++) {
for ($i=0; $i <= $#path && $i <= $opt_l;$i++) {
$pathkey = $pathkey . "/" . $path[$i];
}
if ($only_section ne '') {
next unless (substr($pathkey,0,length($only_section)) eq $only_section);
}
next if (substr($pathkey,0,length("$opt_s")) ne "$opt_s");
$host =~ tr/A-Z/a-z/;
@@ -102,12 +92,12 @@ my $rsyncd_prefix = '\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d ';
if ( int($address[0]) > 0 || $#address < 2 )
{ $domain = "unresolved"; }
if ($only_domain ne '') {
next unless (substr($domain,0,length($only_domain)) eq $only_domain);
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",
# printf ("c=%d day=%s bytes=%d file=%s path=%s\n",
# $#line, $daytime, $bytes, $file, $pathkey);
$xferfiles++; # total files sent
@@ -127,20 +117,20 @@ my $rsyncd_prefix = '\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d ';
}
close LOG;
#@syslist = keys %systemfiles;
@dates = sort datecompare keys %xferbytes;
@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 ("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",
printf ("Average Files Transmitted Daily %12.0f\n",
$xferfiles / ($#dates + 1));
printf("Average Bytes Transmitted Daily %12.0f\n",
printf ("Average Bytes Transmitted Daily %12.0f\n",
$xferbytes / ($#dates + 1));
format top1 =
@@ -160,7 +150,7 @@ $date, $nfiles, $nbytes/(1024*1024), $pctfiles, $pctbytes
$^ = top1;
$~ = line1;
foreach $date (sort datecompare keys %xferbytes) {
foreach $date ( sort datecompare keys(xferbytes) ) {
$nfiles = $xferfiles{$date};
$nbytes = $xferbytes{$date};
@@ -169,7 +159,7 @@ foreach $date (sort datecompare keys %xferbytes) {
write;
}
if ($total_report) {
if ($opt_t) {
format top2 =
Total Transfers from each Archive Section (By bytes)
@@ -189,7 +179,7 @@ $- = 0;
$^ = top2;
$~ = line2;
foreach $section (sort bytecompare keys %groupfiles) {
foreach $section ( sort bytecompare keys(groupfiles) ) {
$files = $groupfiles{$section};
$bytes = $groupbytes{$section};
@@ -203,7 +193,7 @@ if ( $xferfiles < 1 ) { $xferfiles = 1; }
if ( $xferbytes < 1 ) { $xferbytes = 1; }
}
if ($domain_report) {
if ($opt_d) {
format top3 =
Total Transfer Amount By Domain
@@ -222,7 +212,7 @@ $- = 0;
$^ = top3;
$~ = line3;
foreach $domain (sort domnamcompare keys %domainfiles) {
foreach $domain ( sort domnamcompare keys(domainfiles) ) {
if ( $domainsecs{$domain} < 1 ) { $domainsecs{$domain} = 1; }
@@ -236,7 +226,7 @@ foreach $domain (sort domnamcompare keys %domainfiles) {
}
if ($hourly_report) {
if ($opt_h) {
format top8 =
@@ -258,7 +248,7 @@ $- = 0;
$^ = top8;
$~ = line8;
foreach $hour (sort keys %xfertbytes) {
foreach $hour ( sort keys(xfertbytes) ) {
$nfiles = $xfertfiles{$hour};
$nbytes = $xfertbytes{$hour};
@@ -294,19 +284,3 @@ sub faccompare {
}
sub usage
{
die <<EOT;
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 Set DEPTH of path detail for sections.
-s SECTION Set SECTION to report on. For example, "-s /pub"
will report only on paths under "/pub".
EOT
}

View File

@@ -1,171 +0,0 @@
/* This program can record the stream of data flowing to or from a program.
* This allows it to be used to check that rsync's data that is flowing
* through a remote shell is not being corrupted (for example).
*
* Usage: savetransfer [-i|-o] OUTPUT_FILE PROGRAM [ARGS...]
* -i Save the input going to PROGRAM to the OUTPUT_FILE
* -o Save the output coming from PROGRAM to the OUTPUT_FILE
*
* If you want to capture the flow of data for an rsync command, use one of
* the following commands (the resulting files should be identical):
*
* rsync -av --rsh="savetransfer -i /tmp/to.server ssh"
* --rsync-path="savetransfer -i /tmp/from.client rsync" SOURCE DEST
*
* rsync -av --rsh="savetransfer -o /tmp/from.server ssh"
* --rsync-path="savetransfer -o /tmp/to.client rsync" SOURCE DEST
*
* Note that this program aborts after 30 seconds of inactivity, so you'll need
* to change it if that is not enough dead time for your transfer. Also, some
* of the above commands will not notice that the transfer is done (if we're
* saving the input to a PROGRAM and the PROGRAM goes away: we won't notice
* that it's gone unless more data comes in) -- when this happens it will delay
* at the end of the transfer until the timeout period expires.
*/
#include "../rsync.h"
#define TIMEOUT_SECONDS 30
void run_program(char **command);
char buf[4096];
int save_data_from_program = 0;
int
main(int argc, char *argv[])
{
int fd_file, len;
struct timeval tv;
fd_set fds;
argv++;
if (--argc && argv[0][0] == '-') {
if (argv[0][1] == 'o')
save_data_from_program = 1;
else if (argv[0][1] == 'i')
save_data_from_program = 0;
else {
fprintf(stderr, "Unknown option: %s\n", argv[0]);
exit(1);
}
argv++;
argc--;
}
if (argc < 2) {
fprintf(stderr, "Usage: savetransfer [-i|-o] OUTPUT_FILE PROGRAM [ARGS...]\n");
fprintf(stderr, "-i Save the input going to PROGRAM to the OUTPUT_FILE\n");
fprintf(stderr, "-o Save the output coming from PROGRAM to the OUTPUT_FILE\n");
exit(1);
}
if ((fd_file = open(*argv, O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, 0644)) < 0) {
fprintf(stderr, "Unable to write to `%s': %s\n", *argv, strerror(errno));
exit(1);
}
set_blocking(fd_file);
signal(SIGPIPE, SIG_IGN);
run_program(argv + 1);
#if defined HAVE_SETMODE && O_BINARY
setmode(STDIN_FILENO, O_BINARY);
setmode(STDOUT_FILENO, O_BINARY);
#endif
set_nonblocking(STDIN_FILENO);
set_blocking(STDOUT_FILENO);
while (1) {
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
tv.tv_sec = TIMEOUT_SECONDS;
tv.tv_usec = 0;
if (!select(STDIN_FILENO+1, &fds, NULL, NULL, &tv))
break;
if (!FD_ISSET(STDIN_FILENO, &fds))
break;
if ((len = read(STDIN_FILENO, buf, sizeof buf)) <= 0)
break;
if (write(STDOUT_FILENO, buf, len) != len) {
fprintf(stderr, "Failed to write data to stdout: %s\n", strerror(errno));
exit(1);
}
if (write(fd_file, buf, len) != len) {
fprintf(stderr, "Failed to write data to fd_file: %s\n", strerror(errno));
exit(1);
}
}
return 0;
}
void
run_program(char **command)
{
int pipe_fds[2], ret;
pid_t pid;
if (pipe(pipe_fds) < 0) {
fprintf(stderr, "pipe failed: %s\n", strerror(errno));
exit(1);
}
if ((pid = fork()) < 0) {
fprintf(stderr, "fork failed: %s\n", strerror(errno));
exit(1);
}
if (pid == 0) {
if (save_data_from_program)
ret = dup2(pipe_fds[1], STDOUT_FILENO);
else
ret = dup2(pipe_fds[0], STDIN_FILENO);
if (ret < 0) {
fprintf(stderr, "Failed to dup (in child): %s\n", strerror(errno));
exit(1);
}
close(pipe_fds[0]);
close(pipe_fds[1]);
set_blocking(STDIN_FILENO);
set_blocking(STDOUT_FILENO);
execvp(command[0], command);
fprintf(stderr, "Failed to exec %s: %s\n", command[0], strerror(errno));
exit(1);
}
if (save_data_from_program)
ret = dup2(pipe_fds[0], STDIN_FILENO);
else
ret = dup2(pipe_fds[1], STDOUT_FILENO);
if (ret < 0) {
fprintf(stderr, "Failed to dup (in parent): %s\n", strerror(errno));
exit(1);
}
close(pipe_fds[0]);
close(pipe_fds[1]);
}
void
set_nonblocking(int fd)
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) == -1)
return;
if (!(val & NONBLOCK_FLAG)) {
val |= NONBLOCK_FLAG;
fcntl(fd, F_SETFL, val);
}
}
void
set_blocking(int fd)
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) < 0)
return;
if (val & NONBLOCK_FLAG) {
val &= ~NONBLOCK_FLAG;
fcntl(fd, F_SETFL, val);
}
}

210
syscall.c
View File

@@ -1,66 +1,57 @@
/*
/*
Copyright (C) Andrew Tridgell 1998
Copyright (C) 2002 by Martin Pool
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* @file syscall.c
*
* Syscall wrappers to ensure that nothing gets done in dry_run mode
* and to handle system peculiarities.
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
**/
#include "rsync.h"
#if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
#include <sys/un.h>
#endif
extern int dry_run;
extern int read_only;
extern int list_only;
extern int preserve_perms;
#define RETURN_ERROR_IF(x,e) \
do { \
if (x) { \
errno = (e); \
return -1; \
} \
} while (0)
#define CHECK_RO if (read_only || list_only) {errno = EROFS; return -1;}
#define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS)
int do_unlink(const char *fname)
int do_unlink(char *fname)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return unlink(fname);
}
int do_symlink(const char *fname1, const char *fname2)
int do_symlink(char *fname1, char *fname2)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return symlink(fname1, fname2);
}
#ifdef HAVE_LINK
int do_link(const char *fname1, const char *fname2)
#if HAVE_LINK
int do_link(char *fname1, char *fname2)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return link(fname1, fname2);
}
#endif
@@ -68,107 +59,69 @@ int do_link(const char *fname1, const char *fname2)
int do_lchown(const char *path, uid_t owner, gid_t group)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
#ifndef HAVE_LCHOWN
#define lchown chown
#endif
CHECK_RO
return lchown(path, owner, group);
}
#if HAVE_MKNOD
int do_mknod(char *pathname, mode_t mode, dev_t dev)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
#if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
if (S_ISFIFO(mode))
return mkfifo(pathname, mode);
#endif
#if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
if (S_ISSOCK(mode)) {
int sock;
struct sockaddr_un saddr;
unsigned int len;
saddr.sun_family = AF_UNIX;
len = strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path);
#ifdef HAVE_SOCKADDR_UN_LEN
saddr.sun_len = len >= sizeof saddr.sun_path
? sizeof saddr.sun_path : len + 1;
#endif
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0
|| (unlink(pathname) < 0 && errno != ENOENT)
|| (bind(sock, (struct sockaddr*)&saddr, sizeof saddr)) < 0)
return -1;
close(sock);
#ifdef HAVE_CHMOD
return do_chmod(pathname, mode);
#else
return 0;
#endif
}
#endif
#ifdef HAVE_MKNOD
CHECK_RO
return mknod(pathname, mode, dev);
#else
return -1;
#endif
}
#endif
int do_rmdir(const char *pathname)
int do_rmdir(char *pathname)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return rmdir(pathname);
}
int do_open(const char *pathname, int flags, mode_t mode)
int do_open(char *pathname, int flags, mode_t mode)
{
if (flags != O_RDONLY) {
RETURN_ERROR_IF(dry_run, 0);
RETURN_ERROR_IF_RO_OR_LO;
if (dry_run) return -1;
CHECK_RO
}
/* some systems can't handle a double / */
if (pathname[0] == '/' && pathname[1] == '/') pathname++;
return open(pathname, flags | O_BINARY, mode);
}
#ifdef HAVE_CHMOD
#if HAVE_CHMOD
int do_chmod(const char *path, mode_t mode)
{
int code;
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
if (S_ISLNK(mode)) {
#ifdef HAVE_LCHMOD
code = lchmod(path, mode & CHMOD_BITS);
#else
code = 1;
#endif
} else
code = chmod(path, mode & CHMOD_BITS);
if (code != 0 && preserve_perms)
CHECK_RO
code = chmod(path, mode);
if ((code != 0) && preserve_perms)
return code;
return 0;
}
#endif
int do_rename(const char *fname1, const char *fname2)
int do_rename(char *fname1, char *fname2)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
CHECK_RO
return rename(fname1, fname2);
}
void trim_trailing_slashes(char *name)
{
int l;
/* Some BSD systems cannot make a directory if the name
* contains a trailing slash.
* <http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2734739.html> */
/* Don't change empty string; and also we can't improve on
* "/" */
l = strlen(name);
while (l > 1) {
if (name[--l] != '/')
@@ -177,69 +130,63 @@ void trim_trailing_slashes(char *name)
}
}
int do_mkdir(char *fname, mode_t mode)
{
if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO;
trim_trailing_slashes(fname);
if (dry_run)
return 0;
CHECK_RO;
trim_trailing_slashes(fname);
return mkdir(fname, mode);
}
/* like mkstemp but forces permissions */
int do_mkstemp(char *template, mode_t perms)
{
RETURN_ERROR_IF(dry_run, 0);
RETURN_ERROR_IF(read_only, EROFS);
if (dry_run) return -1;
if (read_only) {errno = EROFS; return -1;}
#if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64)
#if defined(HAVE_SECURE_MKSTEMP) && defined(HAVE_FCHMOD)
{
int fd = mkstemp(template);
if (fd == -1)
return -1;
if (fchmod(fd, perms) != 0 && preserve_perms) {
int errno_save = errno;
if (fd == -1) return -1;
if ((fchmod(fd, perms) != 0) && preserve_perms) {
close(fd);
unlink(template);
errno = errno_save;
return -1;
}
#if defined HAVE_SETMODE && O_BINARY
setmode(fd, O_BINARY);
#endif
return fd;
}
#else
if (!mktemp(template))
return -1;
if (!mktemp(template)) return -1;
return do_open(template, O_RDWR|O_EXCL|O_CREAT, perms);
#endif
}
int do_stat(const char *fname, STRUCT_STAT *st)
{
#ifdef USE_STAT64_FUNCS
#if HAVE_OFF64_T
return stat64(fname, st);
#else
return stat(fname, st);
#endif
}
#if SUPPORT_LINKS
int do_lstat(const char *fname, STRUCT_STAT *st)
{
#ifdef SUPPORT_LINKS
# ifdef USE_STAT64_FUNCS
#if HAVE_OFF64_T
return lstat64(fname, st);
# else
return lstat(fname, st);
# endif
#else
return do_stat(fname, st);
return lstat(fname, st);
#endif
}
#endif
int do_fstat(int fd, STRUCT_STAT *st)
{
#ifdef USE_STAT64_FUNCS
#if HAVE_OFF64_T
return fstat64(fd, st);
#else
return fstat(fd, st);
@@ -248,21 +195,28 @@ int do_fstat(int fd, STRUCT_STAT *st)
OFF_T do_lseek(int fd, OFF_T offset, int whence)
{
#ifdef HAVE_LSEEK64
#if !SIZEOF_OFF64_T
OFF_T lseek64();
#else
#if HAVE_OFF64_T
off64_t lseek64();
#endif
return lseek64(fd, offset, whence);
#else
return lseek(fd, offset, 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)
{
#ifdef HAVE_BROKEN_READDIR
#if HAVE_BROKEN_READDIR
return (di->d_name - 2);
#else
return di->d_name;

View File

@@ -1,35 +1,34 @@
/*
* This file contains really simple implementations for rsync global
* functions, so that module test harnesses can run standalone.
*
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
/* -*- c-file-style: "linux" -*-
*
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
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"
/**
* @file t_stub.c
*
* This file contains really simple implementations for rsync global
* functions, so that module test harnesses can run standalone.
**/
int modify_window = 0;
int module_id = -1;
int relative_paths = 0;
int human_readable = 0;
int module_dirlen = 0;
mode_t orig_umask = 002;
char *partial_dir;
struct filter_list_struct server_filter_list;
struct exclude_struct **server_exclude_list;
void rprintf(UNUSED(enum logcode code), const char *format, ...)
{
@@ -39,16 +38,6 @@ struct filter_list_struct server_filter_list;
va_end(ap);
}
void rsyserr(UNUSED(enum logcode code), int errcode, const char *format, ...)
{
va_list ap;
fputs(RSYNC_NAME ": ", stderr);
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
fprintf(stderr, ": %s (%d)\n", strerror(errcode), errcode);
}
void _exit_cleanup(int code, const char *file, int line)
{
fprintf(stderr, "exit(%d): %s(%d)\n",
@@ -56,7 +45,7 @@ struct filter_list_struct server_filter_list;
exit(code);
}
int check_filter(UNUSED(struct filter_list_struct *listp), UNUSED(char *name),
int check_exclude(UNUSED(struct exclude_struct **list), UNUSED(char *name),
UNUSED(int name_is_dir))
{
/* This function doesn't really get called in this test context, so
@@ -66,20 +55,16 @@ struct filter_list_struct server_filter_list;
char *lp_name(UNUSED(int mod))
{
return NULL;
return NULL;
}
BOOL lp_use_chroot(UNUSED(int mod))
{
return 0;
return 0;
}
char *lp_path(UNUSED(int mod))
{
return NULL;
return NULL;
}
const char *who_am_i(void)
{
return "tester";
}

View File

@@ -1,32 +1,36 @@
/*
* Test harness for unsafe_symlink(). Not linked into rsync itself.
*
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2003 Wayne Davison
*
* Copyright (C) 2002 by Martin Pool
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*
* 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.
*/
/* Prints either "safe" or "unsafe" depending on the two arguments.
* Always returns 0 unless something extraordinary happens. */
/**
* @file
*
* Test harness for unsafe_symlink(). Not linked into @c rsync itself.
*
* Prints either "safe" or "unsafe" depending on the two arguments.
* Always returns 0 unless something extraordinary happens.
**/
#include "rsync.h"
int dry_run, read_only, list_only, verbose;
int preserve_perms = 0;
int
main(int argc, char **argv)
{
@@ -37,6 +41,6 @@ main(int argc, char **argv)
printf("%s\n",
unsafe_symlink(argv[1], argv[2]) ? "unsafe" : "safe");
return 0;
}

173
test.sh Executable file
View File

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

View File

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

View File

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

View File

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

View File

@@ -9,10 +9,17 @@
# the test is a member of them. Hopefully they're in at least one
# test.
. "$suitedir/rsync.fns"
. $srcdir/testsuite/rsync.fns
set -x
# Build some hardlinks
fromdir="$scratchdir/from"
todir="$scratchdir/to"
# TODO: I guess some systems will not have 'id', and therefore we have
# to ship or emulate it.
mygrps="`rsync_getgroups`" || fail "Can't get groups"
mkdir "$fromdir"
@@ -24,7 +31,8 @@ do
done
sleep 2
checkit "$RSYNC -rtgpvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
checkit "$RSYNC -rtgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0
# last [] may have failed but if we get here then we've won

View File

@@ -1,72 +0,0 @@
#! /bin/sh
# Copyright (C) 2002 by Martin Pool <mbp@samba.org>
# This program is distributable under the terms of the GNU GPL (see
# COPYING).
# Test that the --chmod option functions correctly.
. $srcdir/testsuite/rsync.fns
# Build some files
fromdir="$scratchdir/from"
todir="$scratchdir/to"
checkdir="$scratchdir/check"
mkdir "$fromdir"
name1="$fromdir/name1"
name2="$fromdir/name2"
dir1="$fromdir/dir1"
dir2="$fromdir/dir2"
echo "This is the file" > "$name1"
echo "This is the other file" > "$name2"
mkdir "$dir1" "$dir2"
chmod 4700 "$name1" || test_skipped "Can't chmod"
chmod 700 "$dir1"
chmod 770 "$dir2"
# Copy the files we've created over to another directory
checkit "$RSYNC -avv \"$fromdir/\" \"$checkdir/\"" "$fromdir" "$checkdir"
# And then manually make the changes which should occur
umask 002
chmod ug-s,a+rX "$checkdir"/*
chmod +w "$checkdir" "$checkdir"/dir*
checkit "$RSYNC -avv --chmod ug-s,a+rX,D+w \"$fromdir/\" \"$todir/\"" "$checkdir" "$todir"
rm -r "$fromdir" "$checkdir" "$todir"
makepath "$todir"
makepath "$fromdir/foo"
touch "$fromdir/bar"
checkit "$RSYNC -avv \"$fromdir/\" \"$checkdir/\"" "$fromdir" "$checkdir"
chmod o+x "$fromdir"/bar
checkit "$RSYNC -avv --chmod=Fo-x \"$fromdir/\" \"$todir/\"" "$checkdir" "$todir"
# Tickle a bug in rsync 2.6.8: if you push a new directory with --perms off to
# a daemon with an incoming chmod, the daemon pretends the directory is a file
# for the purposes of the second application of the incoming chmod.
build_rsyncd_conf
cat >>"$scratchdir/test-rsyncd.conf" <<EOF
[test-incoming-chmod]
path = $todir
read only = no
incoming chmod = Fo-x
EOF
RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
export RSYNC_CONNECT_PROG
rm -r "$todir"
makepath "$todir"
checkit "$RSYNC -rtvv \"$fromdir/\" localhost::test-incoming-chmod/" "$checkdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

Some files were not shown because too many files have changed in this diff Show More