Compare commits

...

14 Commits

Author SHA1 Message Date
Martin Pool
461c6de1a8 Bump version to 2.3.3. 2002-01-25 23:31:06 +00:00
Martin Pool
9c380e07ef Bump version to 2.3.3pre1. 2002-01-25 07:06:33 +00:00
Martin Pool
61ea0c9d9b Merge signedness security patch from Sebastian Krahmer
<krahmer@suse.de> -- in some cases we were not sufficiently careful
about reading integers from the network.

Possibly some other changes are required.
2002-01-25 03:13:35 +00:00
Martin Pool
2e1d43deb2 Ignore autoconf fluff. 2002-01-25 02:53:48 +00:00
Martin Pool
6780f72000 Add code to compare sin6_addrs. 2002-01-25 02:45:09 +00:00
Martin Pool
39e01d2d4b Back out last change -- to see whether an address is spoofed, we don't
want to look at the whole sockaddr, but rather just at the sin_addr
that it contains.

Also fix silly bug where ai_flags was set incorrectly for getaddrinfo.
2002-01-25 02:43:35 +00:00
Martin Pool
f75502950b compare_addrinfo_sockaddr: Add code to compare AF_INET6 addresses. 2002-01-25 02:37:20 +00:00
Martin Pool
974f27e7e9 Split out code to compare addrinfo and sockaddr into it's own
function.  The comparison cannot be done just byte-by-byte, because
different parts of the sockaddr will be meaningful depending on the
protocol.  It looks like on some systems the library sets the unused
parts to 0, but this is not reliable.  IPv6 not implemented yet.
2002-01-25 02:29:53 +00:00
Martin Pool
af32f69eb0 Doc. 2002-01-25 02:15:58 +00:00
Martin Pool
0cd2f40764 The name resolution stuff is getting complicated -- split it out into
its own file.
2002-01-25 02:13:04 +00:00
Martin Pool
0d95824995 Verbose messages for spoof check... doesn't work on old linux libc? 2002-01-24 09:42:52 +00:00
Martin Pool
bbc09ffba9 When doing a name->addr translation to check for spoofing, give the
resolver the address family of the original address as a hint, so that
we're more likely to find the correct A or AAAA record.,
2002-01-24 08:52:28 +00:00
Martin Pool
a4677968cf Message on successful configuration. 2002-01-24 08:50:35 +00:00
Martin Pool
03b1cddc31 Fix comment.
Bump version to 2.5.2pre3
2002-01-24 08:42:21 +00:00
14 changed files with 878 additions and 1610 deletions

View File

@@ -13,3 +13,6 @@ testtmp
testtmp.*
tls
zlib/dummy
confdefs.h
conftest.c
conftest.log

View File

@@ -29,7 +29,8 @@ 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
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o fileio.o batch.o \
clientname.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

29
NEWS
View File

@@ -1,34 +1,7 @@
rsync 2.5.2 (???)
rsync 2.3.3 (26 Jan 2002)
SECURITY FIXES:
* Signedness security patch from Sebastian Krahmer
<krahmer@suse.de> -- in some cases we were not sufficiently
careful about reading integers from the network.
BUG FIXES:
* Fix possible string mangling in log files.
* Fix for setting local address of outgoing sockets.
* Better handling of hardlinks and devices on platforms with
64-bit dev_t or ino_t.
* Name resolution on machines supporting IPv6 is improved.
ENHANCEMENTS:
* With -v, rsync now shows the command used to initiate an ssh/rsh
connection.
* --statistics now shows memory heap usage on platforms that
support mallinfo().
* "The Ted T'so school of program optimization": make progress
visible and people will think it's faster. (With --progress,
rsync will show you how many files it has seen as it builds the
file_list, giving some indication that it has not hung.)
* Improvements to batch mode support. This is still experimental
but testing would be welcome. (Jos Backus)

283
clientname.c Normal file
View File

@@ -0,0 +1,283 @@
/* -*- 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.
*
* 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";
/**
* Return the IP addr of the client as a string
**/
char *client_addr(int fd)
{
struct sockaddr_storage ss;
socklen_t length = sizeof ss;
static char addr_buf[100];
static int initialised;
if (initialised) return addr_buf;
initialised = 1;
client_sockaddr(fd, &ss, &length);
getnameinfo((struct sockaddr *)&ss, length,
addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
return addr_buf;
}
static int get_sockaddr_family(const struct sockaddr_storage *ss)
{
return ((struct sockaddr *) ss)->sa_family;
}
/**
* Return the DNS name of the client.
*
* The name is statically cached so that repeated lookups are quick,
* so there is a limit of one lookup per customer.
*
* If anything goes wrong, including the name->addr->name check, then
* we just use "UNKNOWN", so you can use that value in hosts allow
* lines.
**/
char *client_name(int fd)
{
struct sockaddr_storage ss;
socklen_t ss_len = sizeof ss;
static char name_buf[100];
static char port_buf[100];
static int initialised;
if (initialised) return name_buf;
strcpy(name_buf, default_name);
initialised = 1;
client_sockaddr(fd, &ss, &ss_len);
if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf, port_buf, sizeof port_buf))
check_name(fd, &ss, ss_len, name_buf, port_buf);
return name_buf;
}
/**
* Get the sockaddr for the client.
*
* If it comes in as an ipv4 address mapped into IPv6 format then we
* convert it back to a regular IPv4.
**/
void client_sockaddr(int fd,
struct sockaddr_storage *ss,
socklen_t *ss_len)
{
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
/* FIXME: Can we really not continue? */
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
fd, strerror(errno));
exit_cleanup(RERR_SOCKETIO);
}
#ifdef 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
* "::ffff:10.130.1.2". If we use it as-is, then the
* reverse lookup might fail or perhaps something else
* bad might happen. So instead we convert it to an
* equivalent address in the IPv4 address family. */
struct sockaddr_in6 sin6;
struct sockaddr_in *sin;
memcpy(&sin6, ss, sizeof(sin6));
sin = (struct sockaddr_in *)ss;
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
*ss_len = sizeof(struct sockaddr_in);
#ifdef HAVE_SOCKADDR_LEN
sin->sin_len = *ss_len;
#endif
sin->sin_port = sin6.sin6_port;
/* There is a macro to extract the mapped part
* (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));
}
#endif
}
/**
* Look up a name from @p ss into @p name_buf.
**/
int lookup_name(int fd, const struct sockaddr_storage *ss,
socklen_t ss_len,
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_len,
port_buf, port_buf_len,
NI_NAMEREQD | NI_NUMERICSERV);
if (name_err != 0) {
strcpy(name_buf, default_name);
rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
client_addr(fd),
gai_strerror(name_err));
return name_err;
}
return 0;
}
/**
* Compare an addrinfo from the resolver to a sockinfo.
*
* Like strcmp, returns 0 for identical.
**/
int compare_addrinfo_sockaddr(const struct addrinfo *ai,
const struct sockaddr_storage *ss)
{
int ss_family = get_sockaddr_family(ss);
const char fn[] = "compare_addrinfo_sockaddr";
if (ai->ai_family != ss_family) {
rprintf(FERROR,
"%s: response family %d != %d\n",
fn, ai->ai_family, ss_family);
return 1;
}
/* The comparison method depends on the particular AF. */
if (ss_family == AF_INET) {
const struct sockaddr_in *sin1, *sin2;
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
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;
return memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
sizeof sin1->sin6_addr);
}
#endif /* INET6 */
else {
/* don't know */
return 1;
}
}
/**
* Do a forward lookup on @p name_buf and make sure it corresponds to
* @p ss -- otherwise we may be being spoofed. If we suspect we are,
* then we don't abort the connection but just emit a warning, and
* change @p name_buf to be "UNKNOWN".
**/
int check_name(int fd,
const struct sockaddr_storage *ss,
socklen_t ss_len,
char *name_buf,
const char *port_buf)
{
struct addrinfo hints, *res, *res0;
int error;
int ss_family = get_sockaddr_family(ss);
memset(&hints, 0, sizeof(hints));
hints.ai_family = ss_family;
hints.ai_flags = AI_CANONNAME;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(name_buf, port_buf, &hints, &res0);
if (error) {
rprintf(FERROR,
RSYNC_NAME ": forward name lookup for %s failed: %s\n",
name_buf, gai_strerror(error));
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) {
if (!compare_addrinfo_sockaddr(res, ss))
break; /* OK, identical */
}
if (!res0) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": no known address for \"%s\": "
"spoofed address?\n",
name_buf);
strcpy(name_buf, default_name);
} else if (res == NULL) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": %s is not a known address for \"%s\": "
"spoofed address?\n",
client_addr(fd),
name_buf);
strcpy(name_buf, default_name);
}
freeaddrinfo(res0);
return 0;
}

View File

@@ -5,7 +5,7 @@ AC_CONFIG_SRCDIR([byteorder.h])
AC_CONFIG_HEADER(config.h)
AC_PREREQ(2.52)
RSYNC_VERSION=2.5.2pre2
RSYNC_VERSION=2.5.2pre3
AC_SUBST(RSYNC_VERSION)
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
@@ -30,8 +30,7 @@ then
AC_MSG_WARN([rsync requires an ANSI C compiler and you don't seem to have one])
fi
# compile with optimisation and without debugging by default, unless
# --debug is given. We must decide this before testing the compiler.
# We must decide this before testing the compiler.
# Please allow this to default to yes, so that your users have more
# chance of getting a useful stack trace if problems occur.
@@ -553,3 +552,7 @@ AC_SUBST(BUILD_POPT)
AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
AC_OUTPUT
AC_MSG_RESULT()
AC_MSG_RESULT([ rsync ${RSYNC_VERSION} configuration successful])
AC_MSG_RESULT()

151
exclude.c
View File

@@ -1,7 +1,6 @@
/* -*- c-file-style: "linux" -*-
Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 1996 by Paul Mackerras
/*
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
@@ -21,8 +20,6 @@
/* a lot of this stuff was originally derived from GNU tar, although
it has now changed so much that it is hard to tell :) */
/* include/exclude cluestick added by Martin Pool <mbp@samba.org> */
#include "rsync.h"
extern int verbose;
@@ -30,8 +27,52 @@ extern int delete_mode;
static struct exclude_struct **exclude_list;
/*
* Optimization for special case when all included files are explicitly
* listed without wildcards in the "exclude" list followed by a "- *"
* to exclude the rest.
* Contributed by Dave Dykstra <dwd@bell-labs.com>
*/
static int only_included_files = 1;
static struct exclude_struct *exclude_the_rest;
int send_included_file_names(int f,struct file_list *flist)
{
struct exclude_struct *ex, **ex_list;
int n;
char *p;
if (!only_included_files || (exclude_the_rest == NULL) || delete_mode)
return 0;
if (verbose > 1) {
rprintf(FINFO,"(using include-only optimization) ");
}
/* set exclude_list to NULL temporarily so check_exclude */
/* will always return true */
ex_list = exclude_list;
exclude_list = NULL;
for (n=0; (ex = ex_list[n]) != NULL; n++) {
if (ex == exclude_the_rest)
break;
p = ex->pattern;
while (*p == '/') {
/* skip the allowed beginning slashes */
p++;
}
/* silently skip files that don't exist to
be more like non-optimized case */
if (access(p,0) == 0)
send_file_name(f,flist,p,0,0);
}
exclude_list = ex_list;
return 1;
}
/* build an exclude structure given a exclude pattern */
static struct exclude_struct *make_exclude(const char *pattern, int include)
static struct exclude_struct *make_exclude(char *pattern, int include)
{
struct exclude_struct *ret;
@@ -54,18 +95,15 @@ static struct exclude_struct *make_exclude(const char *pattern, int include)
if (!ret->pattern) out_of_memory("make_exclude");
if (strpbrk(pattern, "*[?")) {
ret->regular_exp = 1;
ret->fnmatch_flags = FNM_PATHNAME;
if (strstr(pattern, "**")) {
static int tested;
if (!tested) {
tested = 1;
if (fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME)==0) {
rprintf(FERROR,"WARNING: fnmatch FNM_PATHNAME is broken on your system\n");
}
}
ret->fnmatch_flags = 0;
if (!ret->include && (*pattern == '*') && (*(pattern+1) == '\0')) {
exclude_the_rest = ret;
} else {
only_included_files = 0;
}
ret->regular_exp = 1;
ret->fnmatch_flags = strstr(pattern, "**") ? 0 : FNM_PATHNAME;
} else if (!ret->include) {
only_included_files = 0;
}
if (strlen(pattern) > 1 && pattern[strlen(pattern)-1] == '/') {
@@ -87,8 +125,8 @@ static void free_exclude(struct exclude_struct *ex)
free(ex);
}
static int check_one_exclude(char *name, struct exclude_struct *ex,
STRUCT_STAT *st)
static int check_one_exclude(char *name,struct exclude_struct *ex,
STRUCT_STAT *st)
{
char *p;
int match_start=0;
@@ -107,79 +145,47 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
}
if (ex->regular_exp) {
if (fnmatch(pattern, name, ex->fnmatch_flags) == 0) {
if (fnmatch(pattern, name, ex->fnmatch_flags) == 0)
return 1;
}
} else {
int l1 = strlen(name);
int l2 = strlen(pattern);
if (l2 <= l1 &&
strcmp(name+(l1-l2),pattern) == 0 &&
(l1==l2 || (!match_start && name[l1-(l2+1)] == '/'))) {
(l1==l2 || (!match_start && name[l1-(l2+1)] == '/')))
return 1;
}
}
return 0;
}
static void report_exclude_result(char const *name,
struct exclude_struct const *ent,
STRUCT_STAT const *st)
{
/* If a trailing slash is present to match only directories,
* then it is stripped out by make_exclude. So as a special
* case we add it back in here. */
if (verbose >= 2)
rprintf(FINFO, "%s %s %s because of pattern %s%s\n",
ent->include ? "including" : "excluding",
S_ISDIR(st->st_mode) ? "directory" : "file",
name, ent->pattern,
ent->directory ? "/" : "");
}
/*
* Return true if file NAME is defined to be excluded by either
* LOCAL_EXCLUDE_LIST or the globals EXCLUDE_LIST.
*/
int check_exclude(char *name, struct exclude_struct **local_exclude_list,
int check_exclude(char *name,struct exclude_struct **local_exclude_list,
STRUCT_STAT *st)
{
int n;
struct exclude_struct *ent;
if (name && (name[0] == '.') && !name[1])
/* never exclude '.', even if somebody does --exclude '*' */
return 0;
if (exclude_list) {
for (n=0; exclude_list[n]; n++) {
ent = exclude_list[n];
if (check_one_exclude(name, ent, st)) {
report_exclude_result(name, ent, st);
return !ent->include;
}
}
for (n=0; exclude_list[n]; n++)
if (check_one_exclude(name,exclude_list[n],st))
return !exclude_list[n]->include;
}
if (local_exclude_list) {
for (n=0; local_exclude_list[n]; n++) {
ent = local_exclude_list[n];
if (check_one_exclude(name, ent, st)) {
report_exclude_result(name, ent, st);
return !ent->include;
}
}
for (n=0; local_exclude_list[n]; n++)
if (check_one_exclude(name,local_exclude_list[n],st))
return !local_exclude_list[n]->include;
}
return 0;
}
void add_exclude_list(const char *pattern, struct exclude_struct ***list, int include)
void add_exclude_list(char *pattern,struct exclude_struct ***list, int include)
{
int len=0;
if (list && *list)
@@ -193,6 +199,8 @@ void add_exclude_list(const char *pattern, struct exclude_struct ***list, int in
}
free((*list));
*list = NULL;
only_included_files = 1;
exclude_the_rest = NULL;
return;
}
@@ -207,12 +215,12 @@ void add_exclude_list(const char *pattern, struct exclude_struct ***list, int in
(*list)[len+1] = NULL;
}
void add_exclude(const char *pattern, int include)
void add_exclude(char *pattern, int include)
{
add_exclude_list(pattern,&exclude_list, include);
}
struct exclude_struct **make_exclude_list(const char *fname,
struct exclude_struct **make_exclude_list(char *fname,
struct exclude_struct **list1,
int fatal, int include)
{
@@ -221,10 +229,7 @@ struct exclude_struct **make_exclude_list(const char *fname,
char line[MAXPATHLEN];
if (!f) {
if (fatal) {
rsyserr(FERROR, errno,
"failed to open %s file %s",
include ? "include" : "exclude",
fname);
rprintf(FERROR,"%s : %s\n",fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
return list;
@@ -246,7 +251,7 @@ struct exclude_struct **make_exclude_list(const char *fname,
}
void add_exclude_file(const char *fname, int fatal, int include)
void add_exclude_file(char *fname,int fatal,int include)
{
if (!fname || !*fname) return;
@@ -258,12 +263,6 @@ void send_exclude_list(int f)
{
int i;
extern int remote_version;
extern int list_only, recurse;
/* this is a complete hack - blame Rusty */
if (list_only && !recurse) {
add_exclude("/*/*", 0);
}
if (!exclude_list) {
write_int(f,0);
@@ -399,7 +398,7 @@ void add_cvs_excludes(void)
add_exclude(cvs_ignore_list[i], 0);
if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
snprintf(fname,sizeof(fname), "%s/.cvsignore",p);
slprintf(fname,sizeof(fname), "%s/.cvsignore",p);
add_exclude_file(fname,0,0);
}

322
flist.c
View File

@@ -1,7 +1,6 @@
/*
Copyright (C) Andrew Tridgell 1996
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
@@ -18,14 +17,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file flist.c
* Generate and receive file lists
*
* @todo Get rid of the string_area optimization. Efficiently
* allocating blocks is the responsibility of the system's malloc
* library, not of rsync.
*
**/
/* generate and receive file lists */
#include "rsync.h"
@@ -55,107 +47,33 @@ extern int remote_version;
extern int io_error;
extern int sanitize_paths;
extern int read_batch;
extern int write_batch;
static char topsrcname[MAXPATHLEN];
static struct exclude_struct **local_exclude_list;
static struct file_struct null_file;
static void clean_flist(struct file_list *flist, int strip_root);
static int show_build_progress_p(void)
{
extern int do_progress;
return do_progress && verbose && recurse && !am_server;
}
/**
* True if we're local, etc, and should emit progress emssages.
**/
static void emit_build_progress(const struct file_list *flist)
{
rprintf(FINFO,
" %d files...\r",
flist->count);
}
static void finish_build_progress(const struct file_list *flist)
{
if (verbose && recurse && !am_server) {
/* This overwrites the progress line, if any. */
rprintf(FINFO, RSYNC_NAME ": %d files to consider.\n",
flist->count);
}
}
static struct string_area *string_area_new(int size)
{
struct string_area *a;
if (size <= 0) size = ARENA_SIZE;
a = malloc(sizeof(*a));
if (!a) out_of_memory("string_area_new");
a->current = a->base = malloc(size);
if (!a->current) out_of_memory("string_area_new buffer");
a->end = a->base + size;
a->next = NULL;
return a;
}
static void string_area_free(struct string_area *a)
{
struct string_area *next;
for ( ; a ; a = next) {
next = a->next;
free(a->base);
}
}
static char *string_area_malloc(struct string_area **ap, int size)
{
char *p;
struct string_area *a;
/* does the request fit into the current space? */
a = *ap;
if (a->current + size >= a->end) {
/* no; get space, move new string_area to front of the list */
a = string_area_new(size > ARENA_SIZE ? size : ARENA_SIZE);
a->next = *ap;
*ap = a;
}
/* have space; do the "allocation." */
p = a->current;
a->current += size;
return p;
}
static char *string_area_strdup(struct string_area **ap, const char *src)
{
char* dest = string_area_malloc(ap, strlen(src) + 1);
return strcpy(dest, src);
}
static void list_file_entry(struct file_struct *f)
{
char perms[11];
char perms[11] = "----------";
char *perm_map = "rwxrwxrwx";
int i;
if (!f->basename)
/* this can happen if duplicate names were removed */
return;
permstring(perms, f->mode);
for (i=0;i<9;i++) {
if (f->mode & (1<<i)) perms[9-i] = perm_map[8-i];
}
if (S_ISLNK(f->mode)) perms[0] = 'l';
if (S_ISDIR(f->mode)) perms[0] = 'd';
if (S_ISBLK(f->mode)) perms[0] = 'b';
if (S_ISCHR(f->mode)) perms[0] = 'c';
if (S_ISSOCK(f->mode)) perms[0] = 's';
if (S_ISFIFO(f->mode)) perms[0] = 'p';
if (preserve_links && S_ISLNK(f->mode)) {
rprintf(FINFO,"%s %11.0f %s %s -> %s\n",
perms,
@@ -180,7 +98,7 @@ int readlink_stat(const char *Path, STRUCT_STAT *Buffer, char *Linkbuf)
}
if (S_ISLNK(Buffer->st_mode)) {
int l;
if ((l = readlink((char *) Path, Linkbuf, MAXPATHLEN-1))== -1) {
if ((l = readlink(Path,Linkbuf,MAXPATHLEN-1)) == -1) {
return -1;
}
Linkbuf[l] = 0;
@@ -212,18 +130,14 @@ int link_stat(const char *Path, STRUCT_STAT *Buffer)
This function is used to check if a file should be included/excluded
from the list of files based on its name and type etc
*/
static int check_exclude_file(int f,char *fname,STRUCT_STAT *st)
static int match_file_name(char *fname,STRUCT_STAT *st)
{
extern int delete_excluded;
/* f is set to -1 when calculating deletion file list */
if ((f == -1) && delete_excluded) {
return 0;
}
if (check_exclude(fname,local_exclude_list,st)) {
return 1;
}
return 0;
if (check_exclude(fname,local_exclude_list,st)) {
if (verbose > 2)
rprintf(FINFO,"excluding file %s\n",fname);
return 0;
}
return 1;
}
/* used by the one_file_system code */
@@ -239,7 +153,7 @@ static void set_filesystem(char *fname)
static int to_wire_mode(mode_t mode)
{
if (S_ISLNK(mode) && (_S_IFLNK != 0120000)) {
if (S_ISLNK(mode) && (S_IFLNK != 0120000)) {
return (mode & ~(_S_IFMT)) | 0120000;
}
return (int)mode;
@@ -247,8 +161,8 @@ static int to_wire_mode(mode_t mode)
static mode_t from_wire_mode(int mode)
{
if ((mode & (_S_IFMT)) == 0120000 && (_S_IFLNK != 0120000)) {
return (mode & ~(_S_IFMT)) | _S_IFLNK;
if ((mode & (_S_IFMT)) == 0120000 && (S_IFLNK != 0120000)) {
return (mode & ~(_S_IFMT)) | S_IFLNK;
}
return (mode_t)mode;
}
@@ -333,15 +247,8 @@ static void send_file_entry(struct file_struct *file,int f,unsigned base_flags)
#if SUPPORT_HARD_LINKS
if (preserve_hard_links && S_ISREG(file->mode)) {
if (remote_version < 26) {
/* 32-bit dev_t and ino_t */
write_int(f,(int)file->dev);
write_int(f,(int)file->inode);
} else {
/* 64-bit dev_t and ino_t */
write_longint(f, file->dev);
write_longint(f, file->inode);
}
write_int(f,(int)file->dev);
write_int(f,(int)file->inode);
}
#endif
@@ -392,11 +299,7 @@ static void receive_file_entry(struct file_struct **fptr,
memset((char *)file, 0, sizeof(*file));
(*fptr) = file;
if (l2 >= MAXPATHLEN-l1) {
rprintf(FERROR,"overflow: flags=0x%x l1=%d l2=%d lastname=%s\n",
flags, l1, l2, lastname);
overflow("receive_file_entry");
}
if (l2 >= MAXPATHLEN-l1) overflow("receive_file_entry");
strlcpy(thisname,lastname,l1+1);
read_sbuf(f,&thisname[l1],l2);
@@ -456,13 +359,8 @@ static void receive_file_entry(struct file_struct **fptr,
#if SUPPORT_HARD_LINKS
if (preserve_hard_links && S_ISREG(file->mode)) {
if (remote_version < 26) {
file->dev = read_int(f);
file->inode = read_int(f);
} else {
file->dev = read_longint(f);
file->inode = read_longint(f);
}
file->dev = read_int(f);
file->inode = read_int(f);
}
#endif
@@ -515,13 +413,7 @@ static int skip_filesystem(char *fname, STRUCT_STAT *st)
return (st2.st_dev != filesystem_dev);
}
#define STRDUP(ap, p) (ap ? string_area_strdup(ap, p) : strdup(p))
/* IRIX cc cares that the operands to the ternary have the same type. */
#define MALLOC(ap, i) (ap ? (void*) string_area_malloc(ap, i) : malloc(i))
/* create a file_struct for a named file */
struct file_struct *make_file(int f, char *fname, struct string_area **ap,
int noexcludes)
static struct file_struct *make_file(int f, char *fname)
{
struct file_struct *file;
STRUCT_STAT st;
@@ -529,7 +421,7 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap,
char *p;
char cleaned_name[MAXPATHLEN];
char linkbuf[MAXPATHLEN];
extern int module_id;
extern int delete_excluded;
strlcpy(cleaned_name, fname, MAXPATHLEN);
cleaned_name[MAXPATHLEN-1] = 0;
@@ -542,24 +434,12 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap,
memset(sum,0,SUM_LENGTH);
if (readlink_stat(fname,&st,linkbuf) != 0) {
int save_errno = errno;
if ((errno == ENOENT) && copy_links && !noexcludes) {
/* symlink pointing nowhere, see if excluded */
memset((char *)&st, 0, sizeof(st));
if (check_exclude_file(f,fname,&st)) {
/* file is excluded anyway, ignore silently */
return NULL;
}
}
io_error = 1;
rprintf(FERROR,"readlink %s: %s\n",
fname,strerror(save_errno));
rprintf(FERROR,"%s: %s\n",
fname,strerror(errno));
return NULL;
}
/* we use noexcludes from backup.c */
if (noexcludes) goto skip_excludes;
if (S_ISDIR(st.st_mode) && !recurse) {
rprintf(FINFO,"skipping directory %s\n",fname);
return NULL;
@@ -570,15 +450,10 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap,
return NULL;
}
if (check_exclude_file(f,fname,&st))
/* f is set to -1 when calculating deletion file list */
if (((f != -1) || !delete_excluded) && !match_file_name(fname,&st))
return NULL;
if (lp_ignore_nonreadable(module_id) && access(fname, R_OK) != 0)
return NULL;
skip_excludes:
if (verbose > 2)
rprintf(FINFO,"make_file(%d,%s)\n",f,fname);
@@ -595,11 +470,11 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap,
file->dirname = strdup(fname);
lastdir = file->dirname;
}
file->basename = STRDUP(ap, p+1);
file->basename = strdup(p+1);
*p = '/';
} else {
file->dirname = NULL;
file->basename = STRDUP(ap, fname);
file->basename = strdup(fname);
}
file->modtime = st.st_mtime;
@@ -615,12 +490,12 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap,
#if SUPPORT_LINKS
if (S_ISLNK(st.st_mode)) {
file->link = STRDUP(ap, linkbuf);
file->link = strdup(linkbuf);
}
#endif
if (always_checksum) {
file->sum = (char *)MALLOC(ap, MD4_SUM_LENGTH);
file->sum = (char *)malloc(MD4_SUM_LENGTH);
if (!file->sum) out_of_memory("md4 sum");
/* drat. we have to provide a null checksum for non-regular
files in order to be compatible with earlier versions
@@ -657,12 +532,9 @@ void send_file_name(int f,struct file_list *flist,char *fname,
{
struct file_struct *file;
file = make_file(f,fname, &flist->string_area, 0);
file = make_file(f,fname);
if (!file) return;
if (show_build_progress_p() & !(flist->count % 100))
emit_build_progress(flist);
if (!file) return;
if (flist->count >= flist->malloced) {
if (flist->malloced < 1000)
@@ -676,9 +548,6 @@ void send_file_name(int f,struct file_list *flist,char *fname,
out_of_memory("send_file_name");
}
if (write_batch) /* dw */
file->flags = FLAG_DELETE;
if (strcmp(file->basename,"")) {
flist->files[flist->count++] = file;
send_file_entry(file,f,base_flags);
@@ -753,11 +622,7 @@ static void send_directory(int f,struct file_list *flist,char *dir)
}
/*
*
* I *think* f==-1 means that the list should just be built in memory
* and not transmitted. But who can tell? -- mbp
*/
struct file_list *send_file_list(int f,int argc,char *argv[])
{
int i,l;
@@ -768,15 +633,20 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
int64 start_write;
if (verbose && recurse && !am_server && f != -1) {
rprintf(FINFO, RSYNC_NAME ": building file list...\n");
if (verbose > 1)
rprintf(FINFO, "\n");
rprintf(FINFO,"building file list ... ");
rflush(FINFO);
}
start_write = stats.total_written;
flist = flist_new();
flist = (struct file_list *)malloc(sizeof(flist[0]));
if (!flist) out_of_memory("send_file_list");
flist->count=0;
flist->malloced = 1000;
flist->files = (struct file_struct **)malloc(sizeof(flist->files[0])*
flist->malloced);
if (!flist->files) out_of_memory("send_file_list");
if (f != -1) {
io_start_buffering(f);
@@ -802,10 +672,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
}
if (link_stat(fname,&st) != 0) {
if (f != -1) {
io_error=1;
rprintf(FERROR,"link_stat %s : %s\n",fname,strerror(errno));
}
io_error=1;
rprintf(FERROR,"%s : %s\n",fname,strerror(errno));
continue;
}
@@ -873,7 +741,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
if (one_file_system)
set_filesystem(fname);
send_file_name(f,flist,fname,recurse,FLAG_DELETE);
if (!recurse || !send_included_file_names(f,flist))
send_file_name(f,flist,fname,recurse,FLAG_DELETE);
if (olddir != NULL) {
flist_dir = NULL;
@@ -891,7 +760,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
send_file_entry(NULL,f,0);
}
finish_build_progress(flist);
if (verbose && recurse && !am_server && f != -1)
rprintf(FINFO,"done\n");
clean_flist(flist, 0);
@@ -911,8 +781,6 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
io_end_buffering(f);
stats.flist_size = stats.total_written - start_write;
stats.num_files = flist->count;
if (write_batch) /* dw */
write_batch_flist_info(flist->count, flist->files);
}
if (verbose > 2)
@@ -990,10 +858,9 @@ struct file_list *recv_file_list(int f)
}
/* if protocol version is >= 17 then recv the io_error flag */
if (f != -1 && remote_version >= 17 && !read_batch) { /* dw-added readbatch */
if (f != -1 && remote_version >= 17) {
extern int module_id;
extern int ignore_errors;
if (lp_ignore_errors(module_id) || ignore_errors) {
if (lp_ignore_errors(module_id)) {
read_int(f);
} else {
io_error |= read_int(f);
@@ -1022,10 +889,6 @@ oom:
}
/*
* XXX: This is currently the hottest function while building the file
* list, because building f_name()s every time is expensive.
**/
int file_compare(struct file_struct **f1,struct file_struct **f2)
{
if (!(*f1)->basename && !(*f2)->basename) return 0;
@@ -1063,38 +926,16 @@ int flist_find(struct file_list *flist,struct file_struct *f)
/*
* free up one file
*/
void free_file(struct file_struct *file)
static void free_file(struct file_struct *file)
{
if (!file) return;
if (file->basename) free(file->basename);
if (file->link) free(file->link);
if (file->sum) free(file->sum);
*file = null_file;
memset((char *)file, 0, sizeof(*file));
}
/*
* allocate a new file list
*/
struct file_list *flist_new()
{
struct file_list *flist;
flist = (struct file_list *)malloc(sizeof(flist[0]));
if (!flist) out_of_memory("send_file_list");
flist->count=0;
flist->malloced = 1000;
flist->files = (struct file_struct **)malloc(sizeof(flist->files[0])*
flist->malloced);
if (!flist->files) out_of_memory("send_file_list");
#if ARENA_SIZE > 0
flist->string_area = string_area_new(0);
#else
flist->string_area = NULL;
#endif
return flist;
}
/*
* free up all elements in a flist
*/
@@ -1102,14 +943,11 @@ void flist_free(struct file_list *flist)
{
int i;
for (i=1;i<flist->count;i++) {
if (!flist->string_area)
free_file(flist->files[i]);
free_file(flist->files[i]);
free(flist->files[i]);
}
memset((char *)flist->files, 0, sizeof(flist->files[0])*flist->count);
free(flist->files);
if (flist->string_area)
string_area_free(flist->string_area);
memset((char *)flist, 0, sizeof(*flist));
free(flist);
}
@@ -1138,20 +976,10 @@ static void clean_flist(struct file_list *flist, int strip_root)
if (verbose > 1 && !am_server)
rprintf(FINFO,"removing duplicate name %s from file list %d\n",
f_name(flist->files[i-1]),i-1);
/* it's not great that the flist knows the semantics of the
* file memory usage, but i'd rather not add a flag byte
* to that struct. XXX can i use a bit in the flags field? */
if (flist->string_area)
flist->files[i][0] = null_file;
else
free_file(flist->files[i]);
free_file(flist->files[i]);
}
}
/* FIXME: There is a bug here when filenames are repeated more
* than once, because we don't handle freed files when doing
* the comparison. */
if (strip_root) {
/* we need to strip off the root directory in the case
of relative paths, but this must be done _after_
@@ -1175,22 +1003,18 @@ static void clean_flist(struct file_list *flist, int strip_root)
if (verbose <= 3) return;
for (i=0;i<flist->count;i++) {
rprintf(FINFO,"[%d] i=%d %s %s mode=0%o len=%.0f\n",
(int) getpid(), i,
rprintf(FINFO,"[%d] i=%d %s %s mode=0%o len=%d\n",
getpid(), i,
NS(flist->files[i]->dirname),
NS(flist->files[i]->basename),
(int) flist->files[i]->mode,
(double)flist->files[i]->length);
flist->files[i]->mode,
(int)flist->files[i]->length);
}
}
/*
* return the full filename of a flist entry
*
* This function is too expensive at the moment, because it copies
* strings when often we only want to compare them. In any case,
* using strlcat is silly because it will walk the string repeatedly.
*/
char *f_name(struct file_struct *f)
{
@@ -1203,11 +1027,9 @@ char *f_name(struct file_struct *f)
n = (n+1)%10;
if (f->dirname) {
int off;
off = strlcpy(p, f->dirname, MAXPATHLEN);
off += strlcpy(p+off, "/", MAXPATHLEN-off);
off += strlcpy(p+off, f->basename, MAXPATHLEN-off);
strlcpy(p, f->dirname, MAXPATHLEN);
strlcat(p, "/", MAXPATHLEN);
strlcat(p, f->basename, MAXPATHLEN);
} else {
strlcpy(p, f->basename, MAXPATHLEN);
}

443
io.c
View File

@@ -1,8 +1,6 @@
/* -*- c-file-style: "linux" -*-
Copyright (C) 1996-2001 by Andrew Tridgell
/*
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
@@ -20,7 +18,7 @@
*/
/*
socket and pipe IO utilities used in rsync
Utilities used in rsync
tridge, June 1996
*/
@@ -34,29 +32,21 @@ static int io_multiplexing_in;
static int multiplex_in_fd;
static int multiplex_out_fd;
static time_t last_io;
static int no_flush;
extern int bwlimit;
static int eof_error=1;
extern int verbose;
extern int io_timeout;
extern struct stats stats;
static int buffer_f_in = -1;
/** Ignore EOF errors while reading a module listing if the remote
version is 24 or less. */
int kludge_around_eof = False;
static int io_error_fd = -1;
static void read_loop(int fd, char *buf, size_t len);
void setup_readbuffer(int f_in)
{
buffer_f_in = f_in;
}
static void check_timeout(void)
{
extern int am_server, am_daemon;
time_t t;
err_list_push();
if (!io_timeout) return;
@@ -68,146 +58,45 @@ static void check_timeout(void)
t = time(NULL);
if (last_io && io_timeout && (t-last_io) >= io_timeout) {
if (!am_server && !am_daemon) {
rprintf(FERROR,"io timeout after %d seconds - exiting\n",
(int)(t-last_io));
}
rprintf(FERROR,"io timeout after %d second - exiting\n",
(int)(t-last_io));
exit_cleanup(RERR_TIMEOUT);
}
}
/* setup the fd used to propogate errors */
void io_set_error_fd(int fd)
{
io_error_fd = fd;
}
/* read some data from the error fd and write it to the write log code */
static void read_error_fd(void)
{
char buf[200];
size_t n;
int fd = io_error_fd;
int tag, len;
static char *read_buffer;
static char *read_buffer_p;
static int read_buffer_len;
static int read_buffer_size;
static int no_flush;
static int no_flush_read;
/* io_error_fd is temporarily disabled -- is this meant to
* prevent indefinite recursion? */
io_error_fd = -1;
read_loop(fd, buf, 4);
tag = IVAL(buf, 0);
len = tag & 0xFFFFFF;
tag = tag >> 24;
tag -= MPLEX_BASE;
while (len) {
n = len;
if (n > (sizeof(buf)-1))
n = sizeof(buf)-1;
read_loop(fd, buf, n);
rwrite((enum logcode)tag, buf, n);
len -= n;
}
io_error_fd = fd;
}
static void whine_about_eof (void)
{
/**
It's almost always an error to get an EOF when we're trying
to read from the network, because the protocol is
self-terminating.
However, there is one unfortunate cases where it is not,
which is rsync <2.4.6 sending a list of modules on a
server, since the list is terminated by closing the socket.
So, for the section of the program where that is a problem
(start_socket_client), kludge_around_eof is True and we
just exit.
*/
if (kludge_around_eof)
exit_cleanup (0);
else {
rprintf (FERROR,
"%s: connection unexpectedly closed "
"(%.0f bytes read so far)\n",
RSYNC_NAME, (double)stats.total_read);
exit_cleanup (RERR_STREAMIO);
}
}
static void die_from_readerr (int err)
{
/* this prevents us trying to write errors on a dead socket */
io_multiplexing_close();
rprintf(FERROR, "%s: read error: %s\n",
RSYNC_NAME, strerror (err));
exit_cleanup(RERR_STREAMIO);
}
/*!
* Read from a socket with IO timeout. return the number of bytes
* read. If no bytes can be read then exit, never return a number <= 0.
*
* TODO: If the remote shell connection fails, then current versions
* actually report an "unexpected EOF" error here. Since it's a
* fairly common mistake to try to use rsh when ssh is required, we
* should trap that: if we fail to read any data at all, we should
* give a better explanation. We can tell whether the connection has
* started by looking e.g. at whether the remote version is known yet.
*/
static int read_timeout (int fd, char *buf, size_t len)
/* read from a socket with IO timeout. return the number of
bytes read. If no bytes can be read then exit, never return
a number <= 0 */
static int read_timeout(int fd, char *buf, size_t len)
{
int n, ret=0;
no_flush_read++;
io_flush();
no_flush_read--;
while (ret == 0) {
/* until we manage to read *something* */
fd_set fds;
struct timeval tv;
int fd_count = fd+1;
int count;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (io_error_fd != -1) {
FD_SET(io_error_fd, &fds);
if (io_error_fd > fd) fd_count = io_error_fd+1;
}
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
tv.tv_usec = 0;
errno = 0;
count = select(fd_count, &fds, NULL, NULL, &tv);
if (count == 0) {
if (select(fd+1, &fds, NULL, NULL, &tv) != 1) {
check_timeout();
}
if (count <= 0) {
if (errno == EBADF) {
exit_cleanup(RERR_SOCKETIO);
}
continue;
}
if (io_error_fd != -1 && FD_ISSET(io_error_fd, &fds)) {
read_error_fd();
}
if (!FD_ISSET(fd, &fds)) continue;
n = read(fd, buf, len);
if (n > 0) {
@@ -217,27 +106,38 @@ static int read_timeout (int fd, char *buf, size_t len)
if (io_timeout)
last_io = time(NULL);
continue;
} else if (n == 0) {
whine_about_eof ();
return -1; /* doesn't return */
} else if (n == -1) {
if (errno == EINTR || errno == EWOULDBLOCK ||
errno == EAGAIN)
continue;
else
die_from_readerr (errno);
}
if (n == -1 && errno == EINTR) {
continue;
}
if (n == -1 &&
(errno == EAGAIN || errno == EWOULDBLOCK)) {
/* this shouldn't happen, if it does then
sleep for a short time to prevent us
chewing too much CPU */
u_sleep(100);
continue;
}
if (n == 0) {
if (eof_error) {
rprintf(FERROR,"unexpected EOF in read_timeout\n");
}
exit_cleanup(RERR_STREAMIO);
}
rprintf(FERROR,"read error: %s\n", strerror(errno));
exit_cleanup(RERR_STREAMIO);
}
return ret;
}
/*! Continue trying to read len bytes - don't return until len has
been read. */
static void read_loop (int fd, char *buf, size_t len)
/* continue trying to read len bytes - don't return until len
has been read */
static void read_loop(int fd, char *buf, size_t len)
{
while (len) {
int n = read_timeout(fd, buf, len);
@@ -247,20 +147,17 @@ static void read_loop (int fd, char *buf, size_t len)
}
}
/**
* Read from the file descriptor handling multiplexing - return number
* of bytes read.
*
* Never returns <= 0.
*/
/* read from the file descriptor handling multiplexing -
return number of bytes read
never return <= 0 */
static int read_unbuffered(int fd, char *buf, size_t len)
{
static size_t remaining;
int tag, ret = 0;
static int remaining;
char ibuf[4];
int tag, ret=0;
char line[1024];
if (!io_multiplexing_in || fd != multiplex_in_fd)
if (!io_multiplexing_in || fd != multiplex_in_fd)
return read_timeout(fd, buf, len);
while (ret == 0) {
@@ -272,24 +169,23 @@ static int read_unbuffered(int fd, char *buf, size_t len)
continue;
}
read_loop(fd, line, 4);
tag = IVAL(line, 0);
read_loop(fd, ibuf, 4);
tag = IVAL(ibuf, 0);
remaining = tag & 0xFFFFFF;
tag = tag >> 24;
if (tag == MPLEX_BASE)
continue;
if (tag == MPLEX_BASE) continue;
tag -= MPLEX_BASE;
if (tag != FERROR && tag != FINFO) {
rprintf(FERROR, "unexpected tag %d\n", tag);
rprintf(FERROR,"unexpected tag %d\n", tag);
exit_cleanup(RERR_STREAMIO);
}
if (remaining > sizeof(line) - 1) {
rprintf(FERROR, "multiplexing overflow %d\n\n",
if (remaining > sizeof(line)-1) {
rprintf(FERROR,"multiplexing overflow %d\n\n",
remaining);
exit_cleanup(RERR_STREAMIO);
}
@@ -297,7 +193,7 @@ static int read_unbuffered(int fd, char *buf, size_t len)
read_loop(fd, line, remaining);
line[remaining] = 0;
rprintf((enum logcode) tag, "%s", line);
rprintf(tag,"%s", line);
remaining = 0;
}
@@ -306,17 +202,65 @@ static int read_unbuffered(int fd, char *buf, size_t len)
/* This function was added to overcome a deadlock problem when using
* ssh. It looks like we can't allow our receive queue to get full or
* ssh will clag up. Uggh. */
static void read_check(int f)
{
int n = 8192;
if (f == -1) return;
if (read_buffer_len == 0) {
read_buffer_p = read_buffer;
}
if (n > MAX_READ_BUFFER/4)
n = MAX_READ_BUFFER/4;
if (read_buffer_p != read_buffer) {
memmove(read_buffer,read_buffer_p,read_buffer_len);
read_buffer_p = read_buffer;
}
if (n > (read_buffer_size - read_buffer_len)) {
read_buffer_size += n;
read_buffer = (char *)Realloc(read_buffer,read_buffer_size);
if (!read_buffer) out_of_memory("read check");
read_buffer_p = read_buffer;
}
n = read_unbuffered(f,read_buffer+read_buffer_len,n);
read_buffer_len += n;
}
/* do a buffered read from fd. don't return until all N bytes
have been read. If all N can't be read then exit with an error */
static void readfd (int fd, char *buffer, size_t N)
static void readfd(int fd,char *buffer,size_t N)
{
int ret;
size_t total=0;
int total=0;
if ((read_buffer_len < N) && (N < 1024)) {
read_check(buffer_f_in);
}
while (total < N) {
io_flush();
if (read_buffer_len > 0 && buffer_f_in == fd) {
ret = MIN(read_buffer_len,N-total);
memcpy(buffer+total,read_buffer_p,ret);
read_buffer_p += ret;
read_buffer_len -= ret;
total += ret;
continue;
}
ret = read_unbuffered (fd, buffer + total, N-total);
no_flush_read++;
io_flush();
no_flush_read--;
ret = read_unbuffered(fd,buffer + total,N-total);
total += ret;
}
@@ -366,26 +310,30 @@ void read_buf(int f,char *buf,size_t len)
void read_sbuf(int f,char *buf,size_t len)
{
read_buf (f,buf,len);
read_buf(f,buf,len);
buf[len] = 0;
}
unsigned char read_byte(int f)
{
unsigned char c;
read_buf (f, (char *)&c, 1);
read_buf(f,(char *)&c,1);
return c;
}
/* write len bytes to fd */
/* write len bytes to fd, possibly reading from buffer_f_in if set
in order to unclog the pipe. don't return until all len
bytes have been written */
static void writefd_unbuffered(int fd,char *buf,size_t len)
{
size_t total = 0;
int total = 0;
fd_set w_fds, r_fds;
int fd_count, count;
struct timeval tv;
err_list_push();
int reading=0;
int blocked=0;
no_flush++;
@@ -393,75 +341,55 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
FD_ZERO(&w_fds);
FD_ZERO(&r_fds);
FD_SET(fd,&w_fds);
fd_count = fd;
fd_count = fd+1;
if (io_error_fd != -1) {
FD_SET(io_error_fd,&r_fds);
if (io_error_fd > fd_count)
fd_count = io_error_fd;
if (!no_flush_read) {
reading = (buffer_f_in != -1);
}
if (reading) {
FD_SET(buffer_f_in,&r_fds);
if (buffer_f_in > fd)
fd_count = buffer_f_in+1;
}
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
tv.tv_usec = 0;
errno = 0;
count = select(fd_count+1,
io_error_fd != -1?&r_fds:NULL,
count = select(fd_count,
reading?&r_fds:NULL,
&w_fds,NULL,
&tv);
if (count == 0) {
check_timeout();
}
if (count <= 0) {
if (errno == EBADF) {
exit_cleanup(RERR_SOCKETIO);
}
check_timeout();
continue;
}
if (io_error_fd != -1 && FD_ISSET(io_error_fd, &r_fds)) {
read_error_fd();
if (reading && FD_ISSET(buffer_f_in, &r_fds)) {
read_check(buffer_f_in);
}
if (FD_ISSET(fd, &w_fds)) {
int ret;
size_t n = len-total;
ret = write(fd,buf+total,n);
int n = (len-total)>>blocked;
int ret = write(fd,buf+total,n?n:1);
if (ret == -1 && errno == EINTR) {
continue;
}
if (ret == -1 &&
(errno == EWOULDBLOCK || errno == EAGAIN)) {
msleep(1);
(errno == EAGAIN || errno == EWOULDBLOCK)) {
blocked++;
continue;
}
if (ret <= 0) {
rprintf(FERROR,
"error writing %d unbuffered bytes"
" - exiting: %s\n", len,
strerror(errno));
rprintf(FERROR,"erroring writing %d bytes - exiting\n", len);
exit_cleanup(RERR_STREAMIO);
}
/* Sleep after writing to limit I/O bandwidth */
if (bwlimit)
{
tv.tv_sec = 0;
tv.tv_usec = ret * 1000 / bwlimit;
while (tv.tv_usec > 1000000)
{
tv.tv_sec++;
tv.tv_usec -= 1000000;
}
select(0, NULL, NULL, NULL, &tv);
}
blocked = 0;
total += ret;
if (io_timeout)
@@ -480,59 +408,33 @@ void io_start_buffering(int fd)
{
if (io_buffer) return;
multiplex_out_fd = fd;
io_buffer = (char *)malloc(IO_BUFFER_SIZE);
io_buffer = (char *)malloc(IO_BUFFER_SIZE+4);
if (!io_buffer) out_of_memory("writefd");
io_buffer_count = 0;
/* leave room for the multiplex header in case it's needed */
io_buffer += 4;
}
/* write an message to a multiplexed stream. If this fails then rsync
exits */
static void mplex_write(int fd, enum logcode code, char *buf, size_t len)
{
char buffer[4096];
size_t n = len;
SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
if (n > (sizeof(buffer)-4)) {
n = sizeof(buffer)-4;
}
memcpy(&buffer[4], buf, n);
writefd_unbuffered(fd, buffer, n+4);
len -= n;
buf += n;
if (len) {
writefd_unbuffered(fd, buf, len);
}
}
void io_flush(void)
{
int fd = multiplex_out_fd;
err_list_push();
if (!io_buffer_count || no_flush) return;
if (io_multiplexing_out) {
mplex_write(fd, FNONE, io_buffer, io_buffer_count);
SIVAL(io_buffer-4, 0, (MPLEX_BASE<<24) + io_buffer_count);
writefd_unbuffered(fd, io_buffer-4, io_buffer_count+4);
} else {
writefd_unbuffered(fd, io_buffer, io_buffer_count);
}
io_buffer_count = 0;
}
/* XXX: fd is ignored, which seems a little strange. */
void io_end_buffering(int fd)
{
io_flush();
if (!io_multiplexing_out) {
free(io_buffer);
free(io_buffer-4);
io_buffer = NULL;
}
}
@@ -541,9 +443,7 @@ static void writefd(int fd,char *buf,size_t len)
{
stats.total_written += len;
err_list_push();
if (!io_buffer || fd != multiplex_out_fd) {
if (!io_buffer) {
writefd_unbuffered(fd, buf, len);
return;
}
@@ -569,11 +469,6 @@ void write_int(int f,int32 x)
writefd(f,b,4);
}
/*
* Note: int64 may actually be a 32-bit type if ./configure couldn't find any
* 64-bit types on this platform.
*/
void write_longint(int f, int64 x)
{
extern int remote_version;
@@ -608,10 +503,10 @@ void write_byte(int f,unsigned char c)
write_buf(f,(char *)&c,1);
}
int read_line(int f, char *buf, size_t maxlen)
{
eof_error = 0;
while (maxlen) {
buf[0] = 0;
read_buf(f, buf, 1);
@@ -630,6 +525,8 @@ int read_line(int f, char *buf, size_t maxlen)
return 0;
}
eof_error = 1;
return 1;
}
@@ -641,7 +538,7 @@ void io_printf(int fd, const char *format, ...)
int len;
va_start(ap, format);
len = vsnprintf(buf, sizeof(buf), format, ap);
len = vslprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (len < 0) exit_cleanup(RERR_STREAMIO);
@@ -664,23 +561,31 @@ void io_start_multiplex_in(int fd)
{
multiplex_in_fd = fd;
io_flush();
if (read_buffer_len) {
fprintf(stderr,"ERROR: data in read buffer at mplx start\n");
exit_cleanup(RERR_STREAMIO);
}
io_multiplexing_in = 1;
}
/* write an message to the multiplexed error stream */
int io_multiplex_write(enum logcode code, char *buf, size_t len)
/* write an message to the error stream */
int io_multiplex_write(int f, char *buf, size_t len)
{
if (!io_multiplexing_out) return 0;
io_flush();
SIVAL(io_buffer-4, 0, ((MPLEX_BASE + f)<<24) + len);
memcpy(io_buffer, buf, len);
stats.total_written += (len+4);
mplex_write(multiplex_out_fd, code, buf, len);
writefd_unbuffered(multiplex_out_fd, io_buffer-4, len+4);
return 1;
}
/* stop output multiplexing */
void io_multiplexing_close(void)
void io_close_input(int fd)
{
io_multiplexing_out = 0;
buffer_f_in = -1;
}

357
log.c
View File

@@ -1,7 +1,5 @@
/* -*- c-file-style: "linux"; -*-
Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 2000-2001 by Martin Pool <mbp@samba.org>
/*
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
@@ -19,121 +17,18 @@
*/
/*
Logging and utility functions.
tridge, May 1998
logging and utility functions
Mapping to human-readable messages added by Martin Pool
<mbp@samba.org>, Oct 2000.
tridge, May 1998
*/
#include "rsync.h"
static char *logfname;
static FILE *logfile;
static int log_error_fd = -1;
int log_got_error=0;
struct {
int code;
char const *name;
} const rerr_names[] = {
{ RERR_SYNTAX , "syntax or usage error" },
{ RERR_PROTOCOL , "protocol incompatibility" },
{ RERR_FILESELECT , "errors selecting input/output files, dirs" },
{ RERR_UNSUPPORTED, "requested action not supported" },
{ RERR_SOCKETIO , "error in socket IO" },
{ RERR_FILEIO , "error in file IO" },
{ RERR_STREAMIO , "error in rsync protocol data stream" },
{ RERR_MESSAGEIO , "errors with program diagnostics" },
{ RERR_IPC , "error in IPC code" },
{ RERR_SIGNAL , "received SIGUSR1 or SIGINT" },
{ RERR_WAITCHILD , "some error returned by waitpid()" },
{ RERR_MALLOC , "error allocating core memory buffers" },
{ RERR_PARTIAL , "partial transfer" },
{ RERR_TIMEOUT , "timeout in data send/receive" },
{ RERR_CMD_FAILED , "remote shell failed" },
{ RERR_CMD_KILLED , "remote shell killed" },
{ RERR_CMD_RUN, "remote command could not be run" },
{ RERR_CMD_NOTFOUND, "remote command not found" },
{ 0, NULL }
};
/*
* Map from rsync error code to name, or return NULL.
*/
static char const *rerr_name(int code)
{
int i;
for (i = 0; rerr_names[i].name; i++) {
if (rerr_names[i].code == code)
return rerr_names[i].name;
}
return NULL;
}
struct err_list {
struct err_list *next;
char *buf;
int len;
int written; /* how many bytes we have written so far */
};
static struct err_list *err_list_head;
static struct err_list *err_list_tail;
/* add an error message to the pending error list */
static void err_list_add(int code, char *buf, int len)
{
struct err_list *el;
el = (struct err_list *)malloc(sizeof(*el));
if (!el) exit_cleanup(RERR_MALLOC);
el->next = NULL;
el->buf = malloc(len+4);
if (!el->buf) exit_cleanup(RERR_MALLOC);
memcpy(el->buf+4, buf, len);
SIVAL(el->buf, 0, ((code+MPLEX_BASE)<<24) | len);
el->len = len+4;
el->written = 0;
if (err_list_tail) {
err_list_tail->next = el;
} else {
err_list_head = el;
}
err_list_tail = el;
}
/* try to push errors off the error list onto the wire */
void err_list_push(void)
{
if (log_error_fd == -1) return;
while (err_list_head) {
struct err_list *el = err_list_head;
int n = write(log_error_fd, el->buf+el->written, el->len - el->written);
/* don't check for an error if the best way of handling the error is
to ignore it */
if (n == -1) break;
if (n > 0) {
el->written += n;
}
if (el->written == el->len) {
free(el->buf);
err_list_head = el->next;
if (!err_list_head) err_list_tail = NULL;
free(el);
}
}
}
static void logit(int priority, char *buf)
{
if (logfname) {
if (!logfile)
log_open();
if (logfile) {
fprintf(logfile,"%s [%d] %s",
timestring(time(NULL)), (int)getpid(), buf);
fflush(logfile);
@@ -142,11 +37,12 @@ static void logit(int priority, char *buf)
}
}
void log_init(void)
void log_open(void)
{
static int initialised;
int options = LOG_PID;
time_t t;
char *logf;
if (initialised) return;
initialised = 1;
@@ -158,13 +54,13 @@ void log_init(void)
localtime(&t);
/* optionally use a log file instead of syslog */
logfname = lp_log_file();
if (logfname) {
if (*logfname) {
log_open();
return;
}
logfname = NULL;
logf = lp_log_file();
if (logf && *logf) {
extern int orig_umask;
int old_umask = umask(022 | orig_umask);
logfile = fopen(logf, "a");
umask(old_umask);
return;
}
#ifdef LOG_NDELAY
@@ -181,88 +77,60 @@ void log_init(void)
logit(LOG_INFO,"rsyncd started\n");
#endif
}
void log_open()
{
if (logfname && !logfile) {
extern int orig_umask;
int old_umask = umask(022 | orig_umask);
logfile = fopen(logfname, "a");
umask(old_umask);
}
}
void log_close()
{
if (logfile) {
fclose(logfile);
logfile = NULL;
}
}
/* setup the error file descriptor - used when we are a server
that is receiving files */
void set_error_fd(int fd)
{
log_error_fd = fd;
set_nonblocking(log_error_fd);
}
/* this is the underlying (unformatted) rsync debugging function. Call
it with FINFO, FERROR or FLOG */
void rwrite(enum logcode code, char *buf, int len)
/* this is the rsync debugging function. Call it with FINFO, FERROR or FLOG */
void rprintf(int fd, const char *format, ...)
{
va_list ap;
char buf[1024];
int len;
FILE *f=NULL;
extern int am_daemon;
extern int am_server;
extern int quiet;
/* recursion can happen with certain fatal conditions */
if (quiet && code == FINFO) return;
if (quiet != 0 && fd == FINFO) return;
va_start(ap, format);
len = vslprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (len < 0) exit_cleanup(RERR_MESSAGEIO);
if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
buf[len] = 0;
if (code == FLOG) {
if (fd == FLOG) {
if (am_daemon) logit(LOG_INFO, buf);
return;
}
/* first try to pass it off to our sibling */
if (am_server && log_error_fd != -1) {
err_list_add(code, buf, len);
err_list_push();
return;
}
/* if that fails, try to pass it to the other end */
if (am_server && io_multiplex_write(code, buf, len)) {
return;
}
if (am_daemon) {
static int depth;
int priority = LOG_INFO;
if (code == FERROR) priority = LOG_WARNING;
if (fd == FERROR) priority = LOG_WARNING;
if (depth) return;
depth++;
log_init();
logit(priority, buf);
log_open();
if (!io_multiplex_write(fd, buf, strlen(buf))) {
logit(priority, buf);
}
depth--;
return;
}
if (code == FERROR) {
log_got_error = 1;
if (fd == FERROR) {
f = stderr;
}
if (code == FINFO) {
if (fd == FINFO) {
extern int am_server;
if (am_server)
f = stderr;
else
@@ -275,93 +143,8 @@ void rwrite(enum logcode code, char *buf, int len)
if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
}
/* This is the rsync debugging function. Call it with FINFO, FERROR or
* FLOG. */
void rprintf(enum logcode code, const char *format, ...)
{
va_list ap;
char buf[1024];
int len;
va_start(ap, format);
/* Note: might return -1 */
len = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
/* Deal with buffer overruns. Instead of panicking, just
* truncate the resulting string. Note that some vsnprintf()s
* return -1 on truncation, e.g., glibc 2.0.6 and earlier. */
if ((size_t) len > sizeof(buf)-1 || len < 0) {
const char ellipsis[] = "[...]";
/* Reset length, and zero-terminate the end of our buffer */
len = sizeof(buf)-1;
buf[len] = '\0';
/* Copy the ellipsis to the end of the string, but give
* us one extra character:
*
* v--- null byte at buf[sizeof(buf)-1]
* abcdefghij0
* -> abcd[...]00 <-- now two null bytes at end
*
* If the input format string has a trailing newline,
* we copy it into that extra null; if it doesn't, well,
* all we lose is one byte. */
strncpy(buf+len-sizeof(ellipsis), ellipsis, sizeof(ellipsis));
if (format[strlen(format)-1] == '\n') {
buf[len-1] = '\n';
}
}
rwrite(code, buf, len);
}
/* This is like rprintf, but it also tries to print some
* representation of the error code. Normally errcode = errno.
*
* Unlike rprintf, this always adds a newline and there should not be
* one in the format string.
*
* Note that since strerror might involve dynamically loading a
* message catalog we need to call it once before chroot-ing. */
void rsyserr(enum logcode code, int errcode, const char *format, ...)
{
va_list ap;
char buf[1024];
int len;
size_t sys_len;
char *sysmsg;
va_start(ap, format);
/* Note: might return <0 */
len = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if ((size_t) len > sizeof(buf)-1)
exit_cleanup(RERR_MESSAGEIO);
sysmsg = strerror(errcode);
sys_len = strlen(sysmsg);
if ((size_t) len + 3 + sys_len > sizeof(buf) - 1)
exit_cleanup(RERR_MESSAGEIO);
strcpy(buf + len, ": ");
len += 2;
strcpy(buf + len, sysmsg);
len += sys_len;
strcpy(buf + len, "\n");
len++;
rwrite(code, buf, len);
}
void rflush(enum logcode code)
void rflush(int fd)
{
FILE *f = NULL;
extern int am_daemon;
@@ -370,15 +153,15 @@ void rflush(enum logcode code)
return;
}
if (code == FLOG) {
if (fd == FLOG) {
return;
}
if (code == FERROR) {
if (fd == FERROR) {
f = stderr;
}
if (code == FINFO) {
if (fd == FINFO) {
extern int am_server;
if (am_server)
f = stderr;
@@ -394,7 +177,7 @@ void rflush(enum logcode code)
/* a generic logging routine for send/recv, with parameter
substitiution */
static void log_formatted(enum logcode code,
static void log_formatted(int fd,
char *format, char *op, struct file_struct *file,
struct stats *initial_stats)
{
@@ -403,18 +186,14 @@ static void log_formatted(enum logcode code,
char buf[1024];
char buf2[1024];
char *p, *s, *n;
size_t l;
int l;
extern struct stats stats;
extern int am_sender;
extern int am_daemon;
int64 b;
/* We expand % codes one by one in place in buf. We don't
* copy in the terminating nul of the inserted strings, but
* rather keep going until we reach the nul of the format.
* Just to make sure we don't clobber that nul and therefore
* accidentally keep going, we zero the buffer now. */
memset(buf, 0, sizeof buf);
memset(buf,0,sizeof(buf));
strlcpy(buf, format, sizeof(buf));
for (s=&buf[0];
@@ -426,18 +205,18 @@ static void log_formatted(enum logcode code,
case 'h': if (am_daemon) n = client_name(0); break;
case 'a': if (am_daemon) n = client_addr(0); break;
case 'l':
snprintf(buf2,sizeof(buf2),"%.0f",
slprintf(buf2,sizeof(buf2),"%.0f",
(double)file->length);
n = buf2;
break;
case 'p':
snprintf(buf2,sizeof(buf2),"%d",
slprintf(buf2,sizeof(buf2),"%d",
(int)getpid());
n = buf2;
break;
case 'o': n = op; break;
case 'f':
snprintf(buf2, sizeof(buf2), "%s/%s",
slprintf(buf2, sizeof(buf2), "%s/%s",
file->basedir?file->basedir:"",
f_name(file));
clean_fname(buf2);
@@ -456,7 +235,7 @@ static void log_formatted(enum logcode code,
b = stats.total_read -
initial_stats->total_read;
}
snprintf(buf2,sizeof(buf2),"%.0f", (double)b);
slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
n = buf2;
break;
case 'c':
@@ -467,39 +246,30 @@ static void log_formatted(enum logcode code,
b = stats.total_read -
initial_stats->total_read;
}
snprintf(buf2,sizeof(buf2),"%.0f", (double)b);
slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
n = buf2;
break;
}
/* n is the string to be inserted in place of this %
* code; l is its length not including the trailing
* NUL */
if (!n)
continue;
if (!n) continue;
l = strlen(n);
if (l + ((int)(s - &buf[0])) >= sizeof(buf)) {
if (l + ((int)(s - &buf[0])) > sizeof(buf)) {
rprintf(FERROR,"buffer overflow expanding %%%c - exiting\n",
p[0]);
exit_cleanup(RERR_MESSAGEIO);
}
/* Shuffle the rest of the string along to make space for n */
if (l != 2) {
memmove(s+(l-1), s+1, strlen(s+1)+1);
}
/* Copy in n but NOT its nul, because the format sting
* probably continues after this. */
memcpy(p, n, l);
/* Skip over inserted string; continue looking */
s = p+l;
}
rprintf(code,"%s\n", buf);
rprintf(fd,"%s\n", buf);
}
/* log the outgoing transfer of a file */
@@ -530,15 +300,7 @@ void log_recv(struct file_struct *file, struct stats *initial_stats)
}
}
/*
* Called when the transfer is interrupted for some reason.
*
* Code is one of the RERR_* codes from errcode.h, or terminating
* successfully.
*/
/* called when the transfer is interrupted for some reason */
void log_exit(int code, const char *file, int line)
{
if (code == 0) {
@@ -548,20 +310,11 @@ void log_exit(int code, const char *file, int line)
(double)stats.total_read,
(double)stats.total_size);
} else {
const char *name;
name = rerr_name(code);
if (!name)
name = "unexplained error";
rprintf(FERROR,"rsync error: %s (code %d) at %s(%d)\n",
name, code, file, line);
rprintf(FLOG,"transfer interrupted (code %d) at %s(%d)\n",
code, file, line);
}
}
/* log the incoming transfer of a file for interactive use, this
will be called at the end where the client was run

View File

@@ -1,6 +1,5 @@
/* -*- c-file-style: "linux" -*-
Copyright (C) 1996-2000 by Andrew Tridgell
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
This program is free software; you can redistribute it and/or modify
@@ -37,12 +36,14 @@ extern char *compare_dest;
extern int make_backups;
extern char *backup_suffix;
static struct delete_list {
DEV64_T dev;
INO64_T inode;
dev_t dev;
INO_T inode;
} *delete_list;
static int dlist_len, dlist_alloc_len;
/* yuck! This function wouldn't have been necessary if I had the sorting
algorithm right. Unfortunately fixing the sorting algorithm would introduce
a backward incompatibility as file list indexes are sent over the link.
@@ -83,15 +84,14 @@ static void delete_one(struct file_struct *f)
{
if (!S_ISDIR(f->mode)) {
if (robust_unlink(f_name(f)) != 0) {
rprintf(FERROR,"delete_one: unlink %s: %s\n",f_name(f),strerror(errno));
rprintf(FERROR,"unlink %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
rprintf(FINFO,"deleting %s\n",f_name(f));
}
} else {
if (do_rmdir(f_name(f)) != 0) {
if (errno != ENOTEMPTY && errno != EEXIST)
rprintf(FERROR,"delete_one: rmdir %s: %s\n",
f_name(f), strerror(errno));
rprintf(FERROR,"rmdir %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
rprintf(FINFO,"deleting directory %s\n",f_name(f));
}
@@ -104,20 +104,17 @@ static void delete_one(struct file_struct *f)
/* this deletes any files on the receiving side that are not present
on the sending side. For version 1.6.4 I have changed the behaviour
to match more closely what most people seem to expect of this option */
void delete_files(struct file_list *flist)
static void delete_files(struct file_list *flist)
{
struct file_list *local_file_list;
int i, j;
char *name;
extern int module_id;
extern int ignore_errors;
extern int max_delete;
static int deletion_count;
if (cvs_exclude)
add_cvs_excludes();
if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
if (io_error && !lp_ignore_errors(module_id)) {
rprintf(FINFO,"IO error encountered - skipping file deletion\n");
return;
}
@@ -140,7 +137,6 @@ void delete_files(struct file_list *flist)
rprintf(FINFO,"deleting in %s\n", name);
for (i=local_file_list->count-1;i>=0;i--) {
if (max_delete && deletion_count > max_delete) break;
if (!local_file_list->files[i]->basename) continue;
if (remote_version < 19 &&
S_ISDIR(local_file_list->files[i]->mode))
@@ -148,12 +144,10 @@ void delete_files(struct file_list *flist)
if (-1 == flist_find(flist,local_file_list->files[i])) {
char *f = f_name(local_file_list->files[i]);
int k = strlen(f) - strlen(backup_suffix);
/* Hi Andrew, do we really need to play with backup_suffix here? */
if (make_backups && ((k <= 0) ||
(strcmp(f+k,backup_suffix) != 0))) {
(void) make_backup(f);
} else {
deletion_count++;
delete_one(local_file_list->files[i]);
}
}
@@ -179,7 +173,7 @@ static int get_tmpname(char *fnametmp, char *fname)
rprintf(FERROR,"filename too long\n");
return 0;
}
snprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f);
slprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f);
return 1;
}
@@ -192,11 +186,11 @@ static int get_tmpname(char *fnametmp, char *fname)
if (f) {
*f = 0;
snprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX",
slprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX",
fname,f+1);
*f = '/';
} else {
snprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname);
slprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname);
}
return 1;
@@ -229,8 +223,8 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
extern int cleanup_got_literal;
if (verbose > 3) {
rprintf(FINFO,"data recv %d at %.0f\n",
i,(double)offset);
rprintf(FINFO,"data recv %d at %d\n",
i,(int)offset);
}
stats.literal_data += i;
@@ -247,7 +241,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
}
i = -(i+1);
offset2 = i*(OFF_T)n;
offset2 = i*n;
len = n;
if (i == count-1 && remainder != 0)
len = remainder;
@@ -255,15 +249,13 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
stats.matched_data += len;
if (verbose > 3)
rprintf(FINFO,"chunk[%d] of size %d at %.0f offset=%.0f\n",
i,len,(double)offset2,(double)offset);
rprintf(FINFO,"chunk[%d] of size %d at %d offset=%d\n",
i,len,(int)offset2,(int)offset);
if (buf) {
map = map_ptr(buf,offset2,len);
map = map_ptr(buf,offset2,len);
see_token(map, len);
sum_update(map,len);
}
see_token(map, len);
sum_update(map,len);
if (fd != -1 && write_file(fd,map,len) != len) {
rprintf(FERROR,"write failed on %s : %s\n",
@@ -273,7 +265,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
offset += len;
}
end_progress(total_size);
end_progress();
if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
rprintf(FERROR,"write failed on %s : %s\n",
@@ -297,15 +289,12 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
}
/* main routine for receiver process. Receiver process runs on the
same host as the generator process. */
int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
{
int fd1,fd2;
STRUCT_STAT st;
char *fname;
char template[MAXPATHLEN];
char fnametmp[MAXPATHLEN];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
@@ -323,6 +312,12 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
if (!delete_after) {
if (recurse && delete_mode && !local_name && flist->count>0) {
delete_files(flist);
}
}
while (1) {
cleanup_disable();
@@ -373,7 +368,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
if ((fd1 == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
slprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
compare_dest,fname);
fnamecmp = fnamecmpbuf;
fd1 = do_open(fnamecmp, O_RDONLY, 0);
@@ -403,7 +398,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
if (fd1 != -1 && st.st_size > 0) {
buf = map_file(fd1,st.st_size);
if (verbose > 2)
rprintf(FINFO,"recv mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
rprintf(FINFO,"recv mapped %s of size %d\n",fnamecmp,(int)st.st_size);
} else {
buf = NULL;
}
@@ -414,7 +409,17 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
continue;
}
strlcpy(template, fnametmp, sizeof(template));
/* mktemp is deliberately used here instead of mkstemp.
because O_EXCL is used on the open, the race condition
is not a problem or a security hole, and we want to
control the access permissions on the created file. */
if (NULL == do_mktemp(fnametmp)) {
rprintf(FERROR,"mktemp %s failed\n",fnametmp);
receive_data(f_in,buf,-1,NULL,file->length);
if (buf) unmap_file(buf);
if (fd1 != -1) close(fd1);
continue;
}
/* we initially set the perms without the
setuid/setgid bits to ensure that there is no race
@@ -422,21 +427,16 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
the lchown. Thanks to snabb@epipe.fi for pointing
this out. We also set it initially without group
access because of a similar race condition. */
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
if (fd2 == -1) {
rprintf(FERROR,"mkstemp %s failed\n",fnametmp);
receive_data(f_in,buf,-1,NULL,file->length);
if (buf) unmap_file(buf);
continue;
}
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
file->mode & INITACCESSPERMS);
/* in most cases parent directories will already exist
because their information should have been previously
transferred, but that may not be the case with -R */
if (fd2 == -1 && relative_paths && errno == ENOENT &&
create_directory_path(fnametmp) == 0) {
strlcpy(fnametmp, template, sizeof(fnametmp));
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
file->mode & INITACCESSPERMS);
}
if (fd2 == -1) {
rprintf(FERROR,"cannot create %s : %s\n",fnametmp,strerror(errno));
@@ -469,7 +469,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
finish_transfer(fname, fnametmp, file);
cleanup_disable();
if (!recv_ok) {
if (csum_length == SUM_LENGTH) {
rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
@@ -489,7 +489,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
}
if (preserve_hard_links)
do_hard_links();
do_hard_links(flist);
/* now we need to fix any directory permissions that were
modified during the transfer */

174
rsync.h
View File

@@ -1,7 +1,6 @@
/*
Copyright (C) by Andrew Tridgell 1996, 2000
Copyright (C) Andrew Tridgell 1996
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
@@ -18,7 +17,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define False 0
#define True 1
@@ -49,19 +47,8 @@
#define SAME_TIME (1<<7)
/* update this if you make incompatible changes */
#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.
*
* 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 PROTOCOL_VERSION 21
#define MIN_PROTOCOL_VERSION 11
#define MAX_PROTOCOL_VERSION 30
#define RSYNC_PORT 873
@@ -71,15 +58,14 @@
#define CHUNK_SIZE (32*1024)
#define MAX_MAP_SIZE (256*1024)
#define IO_BUFFER_SIZE (4092)
#define MAX_READ_BUFFER (1024*1024)
#define MAX_ARGS 1000
#define MPLEX_BASE 7
/* 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 };
#define FERROR 1
#define FINFO 2
#define FLOG 3
#include "errcode.h"
@@ -93,6 +79,12 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
#include <sys/types.h>
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
#include "lib/getopt.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -185,10 +177,6 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
#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>
@@ -267,44 +255,15 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
#elif HAVE_LONGLONG
#define int64 long long
#else
/* As long as it gets... */
#define int64 off_t
#define NO_INT64
#endif
/* Starting from protocol version 26, we always use 64-bit
* ino_t and dev_t internally, even if this platform does not
* allow files to have 64-bit inums. That's because the
* receiver needs to find duplicate (dev,ino) tuples to detect
* hardlinks, and it might have files coming from a platform
* that has 64-bit inums.
*
* The only exception is if we're on a platform with no 64-bit type at
* all.
*
* Because we use read_longint() to get these off the wire, if you
* transfer devices or hardlinks with dev or inum > 2**32 to a machine
* with no 64-bit types then you will get an overflow error. Probably
* not many people have that combination of machines, and you can
* avoid it by not preserving hardlinks or not transferring device
* nodes. It's not clear that any other behaviour is better.
*
* Note that if you transfer devices from a 64-bit-devt machine (say,
* Solaris) to a 32-bit-devt machine (say, Linux-2.2/x86) then the
* device numbers will be truncated. But it's a kind of silly thing
* to do anyhow.
*
* 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
#if HAVE_SHORT_INO_T
#define INO_T uint32
#else
#define INO_T ino_t
#endif
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
@@ -335,13 +294,9 @@ struct file_struct {
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;
INO_T inode;
dev_t dev;
dev_t rdev;
uid_t uid;
gid_t gid;
char *basename;
@@ -352,20 +307,10 @@ struct file_struct {
};
#define ARENA_SIZE (32 * 1024)
struct string_area {
char *base;
char *end;
char *current;
struct string_area *next;
};
struct file_list {
int count;
int malloced;
struct file_struct **files;
struct string_area *string_area;
};
struct sum_buf {
@@ -377,11 +322,11 @@ struct sum_buf {
};
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 */
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 */
};
struct map_struct {
@@ -391,6 +336,7 @@ struct map_struct {
};
struct exclude_struct {
char *orig;
char *pattern;
int regular_exp;
int fnmatch_flags;
@@ -422,29 +368,9 @@ static inline int flist_up(struct file_list *flist, int i)
}
#include "byteorder.h"
#include "lib/mdfour.h"
#include "lib/permstring.h"
#include "lib/addrinfo.h"
#include "version.h"
#include "proto.h"
/* We have replacement versions of these if they're missing. */
#ifndef HAVE_ASPRINTF
int asprintf(char **ptr, const char *format, ...);
#endif
#ifndef HAVE_VASPRINTF
int vasprintf(char **ptr, const char *format, va_list ap);
#endif
#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)
int snprintf(char *str,size_t count,const char *fmt,...);
#endif
#include "lib/mdfour.h"
#if !HAVE_STRERROR
extern char *sys_errlist[];
@@ -533,22 +459,6 @@ extern int errno;
#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
#endif
/* work out what fcntl flag to use for non-blocking */
#ifdef O_NONBLOCK
# define NONBLOCK_FLAG O_NONBLOCK
#elif defined(SYSV)
# define NONBLOCK_FLAG O_NDELAY
#else
# define NONBLOCK_FLAG FNDELAY
#endif
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001
#endif
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) || S_ISFIFO(mode))
@@ -564,20 +474,12 @@ extern int errno;
#define NS(s) ((s)?(s):"<NULL>")
/* use magic gcc attributes to catch format errors */
void rprintf(enum logcode , const char *, ...)
void rprintf(int , const char *, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
;
/* This is just like rprintf, but it also tries to print some
* representation of the error code. Normally errcode = errno. */
void rsyserr(enum logcode, int, const char *, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 3, 4)))
#endif
;
#ifdef REPLACE_INET_NTOA
#define inet_ntoa rep_inet_ntoa
#endif
@@ -591,20 +493,4 @@ size_t strlcpy(char *d, const char *s, size_t bufsize);
size_t strlcat(char *d, const char *s, size_t bufsize);
#endif
#ifndef WEXITSTATUS
#define WEXITSTATUS(stat) ((int)(((stat)>>8)&0xFF))
#endif
#define exit_cleanup(code) _exit_cleanup(code, __FILE__, __LINE__)
extern int verbose;
#ifndef HAVE_INET_NTOP
const char *
inet_ntop(int af, const void *src, char *dst, size_t size);
#endif /* !HAVE_INET_NTOP */
#ifndef HAVE_INET_PTON
int isc_net_pton(int af, const char *src, void *dst);
#endif

190
socket.c
View File

@@ -33,8 +33,6 @@
#include "rsync.h"
static const char default_name[] = "UNKNOWN";
/* Establish a proxy connection on an open socket to a web roxy by
* using the CONNECT method. */
@@ -568,194 +566,6 @@ void become_daemon(void)
}
}
/**
* Return the IP addr of the client as a string
**/
char *client_addr(int fd)
{
struct sockaddr_storage ss;
socklen_t length = sizeof ss;
static char addr_buf[100];
static int initialised;
if (initialised) return addr_buf;
initialised = 1;
client_sockaddr(fd, &ss, &length);
getnameinfo((struct sockaddr *)&ss, length,
addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
return addr_buf;
}
static int get_sockaddr_family(const struct sockaddr_storage *ss)
{
return ((struct sockaddr *) ss)->sa_family;
}
/**
* Return the DNS name of the client.
*
* The name is statically cached so that repeated lookups are quick,
* so there is a limit of one lookup per customer.
*
* If anything goes wrong, including the name->addr->name check, then
* we just use "UNKNOWN", so you can use that value in hosts allow
* lines.
**/
char *client_name(int fd)
{
struct sockaddr_storage ss;
socklen_t ss_len = sizeof ss;
static char name_buf[100];
static char port_buf[100];
static int initialised;
if (initialised) return name_buf;
strcpy(name_buf, default_name);
initialised = 1;
client_sockaddr(fd, &ss, &ss_len);
if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf, port_buf, sizeof port_buf))
check_name(fd, &ss, ss_len, name_buf, port_buf);
return name_buf;
}
/**
* Get the sockaddr for the client.
**/
void client_sockaddr(int fd,
struct sockaddr_storage *ss,
socklen_t *ss_len)
{
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
/* FIXME: Can we really not continue? */
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
fd, strerror(errno));
exit_cleanup(RERR_SOCKETIO);
}
#ifdef 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
* "::ffff:10.130.1.2". If we use it as-is, then the
* reverse lookup might fail or perhaps something else
* bad might happen. So instead we convert it to an
* equivalent address in the IPv4 address family. */
struct sockaddr_in6 sin6;
struct sockaddr_in *sin;
memcpy(&sin6, ss, sizeof(sin6));
sin = (struct sockaddr_in *)ss;
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
*ss_len = sizeof(struct sockaddr_in);
#ifdef HAVE_SOCKADDR_LEN
sin->sin_len = *ss_len;
#endif
sin->sin_port = sin6.sin6_port;
/* There is a macro to extract the mapped part
* (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));
}
#endif
}
/**
* Look up a name from @p ss into @p name_buf.
**/
int lookup_name(int fd, const struct sockaddr_storage *ss,
socklen_t ss_len,
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_len,
port_buf, port_buf_len,
NI_NAMEREQD | NI_NUMERICSERV);
if (name_err != 0) {
strcpy(name_buf, default_name);
rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
client_addr(fd),
gai_strerror(name_err));
return name_err;
}
return 0;
}
/* Do a forward lookup on name_buf and make sure it corresponds to ss
* -- otherwise we may be being spoofed. If we suspect we are, then
* we don't abort the connection but just emit a warning. */
int check_name(int fd,
const struct sockaddr_storage *ss,
socklen_t ss_len,
char *name_buf,
const char *port_buf)
{
struct addrinfo hints, *res, *res0;
int error;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_flags = AI_CANONNAME;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(name_buf, port_buf, &hints, &res0);
if (error) {
rprintf(FERROR,
RSYNC_NAME ": forward name lookup for %s:%s failed: %s\n",
name_buf, port_buf,
gai_strerror(error));
strcpy(name_buf, default_name);
return error;
}
/* We expect that one of the results will be the same as ss. */
for (res = res0; res; res = res->ai_next) {
if (res->ai_family != get_sockaddr_family(ss))
continue;
if (res->ai_addrlen != ss_len)
continue;
if (memcmp(res->ai_addr, ss, res->ai_addrlen) == 0)
break;
}
if (res == NULL) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": %s is not a known address for \"%s\": "
"spoofed address?\n",
client_addr(fd),
name_buf);
strcpy(name_buf, default_name);
}
freeaddrinfo(res0);
return 0;
}
/*******************************************************************
this is like socketpair but uses tcp. It is used by the Samba

429
util.c
View File

@@ -1,8 +1,6 @@
/* -*- 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>
/*
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
@@ -28,167 +26,102 @@
extern int verbose;
/****************************************************************************
Set a fd into nonblocking mode
Set a fd into nonblocking mode. Uses POSIX O_NONBLOCK if available,
else
if SYSV use O_NDELAY
if BSD use FNDELAY
****************************************************************************/
void set_nonblocking(int fd)
int 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);
}
}
/****************************************************************************
Set a fd into blocking mode
****************************************************************************/
void set_blocking(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);
}
}
/* create a file descriptor pair - like pipe() but use socketpair if
possible (because of blocking issues on pipes)
always set non-blocking
*/
int fd_pair(int fd[2])
{
int ret;
#if HAVE_SOCKETPAIR
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
#ifdef O_NONBLOCK
#define FLAG_TO_SET O_NONBLOCK
#else
ret = pipe(fd);
#ifdef SYSV
#define FLAG_TO_SET O_NDELAY
#else /* BSD */
#define FLAG_TO_SET FNDELAY
#endif
#endif
if (ret == 0) {
set_nonblocking(fd[0]);
set_nonblocking(fd[1]);
}
return ret;
if((val = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
val |= FLAG_TO_SET;
return fcntl( fd, F_SETFL, val);
#undef FLAG_TO_SET
}
void print_child_argv(char **cmd)
/* this is taken from CVS */
int piped_child(char **command,int *f_in,int *f_out)
{
rprintf(FINFO, RSYNC_NAME ": open connection using ");
for (; *cmd; cmd++) {
/* Look for characters that ought to be quoted. This
* is not a great quoting algorithm, but it's
* sufficient for a log message. */
if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
",.-_=+@/") != strlen(*cmd)) {
rprintf(FINFO, "\"%s\" ", *cmd);
} else {
rprintf(FINFO, "%s ", *cmd);
}
}
rprintf(FINFO, "\n");
int pid;
int to_child_pipe[2];
int from_child_pipe[2];
if (pipe(to_child_pipe) < 0 ||
pipe(from_child_pipe) < 0) {
rprintf(FERROR,"pipe: %s\n",strerror(errno));
exit_cleanup(RERR_IPC);
}
pid = do_fork();
if (pid < 0) {
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) {
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]);
umask(orig_umask);
execvp(command[0], command);
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) {
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];
set_nonblocking(*f_in);
set_nonblocking(*f_out);
return pid;
}
/* 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
if blocking_io is set then use blocking io on both fds. That can be
used to cope with badly broken rsh implementations like the one on
solaris.
*/
pid_t piped_child(char **command, int *f_in, int *f_out)
int local_child(int argc, char **argv,int *f_in,int *f_out)
{
pid_t pid;
int pid;
int to_child_pipe[2];
int from_child_pipe[2];
extern int blocking_io;
if (verbose > 0) {
print_child_argv(command);
}
if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
rprintf(FERROR, "pipe: %s\n", strerror(errno));
exit_cleanup(RERR_IPC);
}
pid = do_fork();
if (pid == -1) {
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) {
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]);
umask(orig_umask);
set_blocking(STDIN_FILENO);
if (blocking_io) {
set_blocking(STDOUT_FILENO);
}
execvp(command[0], command);
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) {
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;
}
pid_t local_child(int argc, char **argv,int *f_in,int *f_out)
{
pid_t pid;
int to_child_pipe[2];
int from_child_pipe[2];
extern int read_batch; /* dw */
if (fd_pair(to_child_pipe) < 0 ||
fd_pair(from_child_pipe) < 0) {
if (pipe(to_child_pipe) < 0 ||
pipe(from_child_pipe) < 0) {
rprintf(FERROR,"pipe: %s\n",strerror(errno));
exit_cleanup(RERR_IPC);
}
pid = do_fork();
if (pid == -1) {
if (pid < 0) {
rprintf(FERROR,"fork: %s\n",strerror(errno));
exit_cleanup(RERR_IPC);
}
@@ -197,7 +130,7 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out)
extern int am_sender;
extern int am_server;
am_sender = read_batch ? 0 : !am_sender;
am_sender = !am_sender;
am_server = 1;
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
@@ -464,6 +397,17 @@ int robust_rename(char *from, char *to)
return -1;
return do_rename(from, to);
#endif
}
/* sleep for a while via select */
void u_sleep(int usec)
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = usec;
select(0, NULL, NULL, NULL, &tv);
}
@@ -584,7 +528,10 @@ void glob_expand(char *base1, char **argv, int *argc, int maxargs)
s = strdup(s);
if (!s) out_of_memory("glob_expand");
if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
base = (char *)malloc(strlen(base1)+3);
if (!base) out_of_memory("glob_expand");
sprintf(base," %s/", base1);
q = s;
while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
@@ -611,6 +558,33 @@ void strlower(char *s)
}
}
/* this is like vsnprintf but it always null terminates, so you
can fit at most n-1 chars in */
int vslprintf(char *str, int n, const char *format, va_list ap)
{
int ret = vsnprintf(str, n, format, ap);
if (ret >= n || ret < 0) {
str[n-1] = 0;
return -1;
}
str[ret] = 0;
return ret;
}
/* like snprintf but always null terminates */
int slprintf(char *str, int n, char *format, ...)
{
va_list ap;
int ret;
va_start(ap, format);
ret = vslprintf(str,n,format,ap);
va_end(ap);
return ret;
}
void *Realloc(void *p, int size)
{
if (!p) return (void *)malloc(size);
@@ -832,91 +806,28 @@ int u_strcmp(const char *cs1, const char *cs2)
return (int)*s1 - (int)*s2;
}
static OFF_T last_ofs;
static struct timeval print_time;
static struct timeval start_time;
static OFF_T start_ofs;
static OFF_T last_ofs;
static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
{
return (t2->tv_sec - t1->tv_sec) * 1000
+ (t2->tv_usec - t1->tv_usec) / 1000;
}
/**
* @param ofs Current position in file
* @param size Total size of file
* @param is_last True if this is the last time progress will be
* printed for this file, so we should output a newline. (Not
* necessarily the same as all bytes being received.)
**/
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
int is_last)
{
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;
double remain = rate ? (double) (size-ofs) / rate / 1000.0: 0.0;
int remain_h, remain_m, remain_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);
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)
void end_progress(void)
{
extern int do_progress, am_server;
if (do_progress && !am_server) {
struct timeval now;
gettimeofday(&now, NULL);
rprint_progress(size, size, &now, True);
rprintf(FINFO,"\n");
}
last_ofs = 0;
start_ofs = 0;
print_time.tv_sec = print_time.tv_usec = 0;
start_time.tv_sec = start_time.tv_usec = 0;
last_ofs = 0;
}
void show_progress(OFF_T ofs, OFF_T size)
{
extern int do_progress, am_server;
struct timeval now;
gettimeofday(&now, NULL);
if (!start_time.tv_sec && !start_time.tv_usec) {
start_time.tv_sec = now.tv_sec;
start_time.tv_usec = now.tv_usec;
start_ofs = ofs;
}
if (do_progress
&& !am_server
&& 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;
if (do_progress && !am_server) {
if (ofs > last_ofs + 1000) {
int pct = (int)((100.0*ofs)/size);
rprintf(FINFO,"%.0f (%d%%)\r", (double)ofs, pct);
last_ofs = ofs;
}
}
}
@@ -989,85 +900,3 @@ char *timestring(time_t t)
return(TimeBuf);
}
/**
* Sleep for a specified number of milliseconds.
*
* Always returns TRUE. (In the future it might return FALSE if
* interrupted.)
**/
int msleep(int t)
{
int tdiff=0;
struct timeval tval,t1,t2;
gettimeofday(&t1, NULL);
gettimeofday(&t2, NULL);
while (tdiff < t) {
tval.tv_sec = (t-tdiff)/1000;
tval.tv_usec = 1000*((t-tdiff)%1000);
errno = 0;
select(0,NULL,NULL, NULL, &tval);
gettimeofday(&t2, NULL);
tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
(t2.tv_usec - t1.tv_usec)/1000;
}
return True;
}
/*******************************************************************
Determine if two file modification times are equivalent (either exact
or in the modification timestamp window established by --modify-window)
Returns 0 if the times should be treated as the same, 1 if the
first is later and -1 if the 2nd is later
*******************************************************************/
int cmp_modtime(time_t file1, time_t file2)
{
extern int modify_window;
if (file2 > file1) {
if (file2 - file1 <= modify_window) return 0;
return -1;
}
if (file1 - file2 <= modify_window) return 0;
return 1;
}
#ifdef __INSURE__XX
#include <dlfcn.h>
/*******************************************************************
This routine is a trick to immediately catch errors when debugging
with insure. A xterm with a gdb is popped up when insure catches
a error. It is Linux specific.
********************************************************************/
int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
{
static int (*fn)();
int ret;
char *cmd;
asprintf(&cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'",
getpid(), getpid(), getpid());
if (!fn) {
static void *h;
h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
fn = dlsym(h, "_Insure_trap_error");
}
ret = fn(a1, a2, a3, a4, a5, a6);
system(cmd);
free(cmd);
return ret;
}
#endif

1
version.h Normal file
View File

@@ -0,0 +1 @@
#define VERSION "2.3.3"