summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Pool <mbp@samba.org>2002-01-25 00:56:35 +0000
committerMartin Pool <mbp@samba.org>2002-01-25 00:56:35 +0000
commit5c6e0ee27cddc273db7f9afa3b3aedf58827e749 (patch)
tree84914ba1063050c380ea769feb5ff993f0499713
parent0d9582499579ffc8507e56d60b28f0efc44f5f65 (diff)
downloadrsync-5c6e0ee27cddc273db7f9afa3b3aedf58827e749.tar.gz
Signedness security patch from Sebastian Krahmer <krahmer@suse.de> --v2.4.7pre1
in some cases we were not sufficiently careful about reading integers from the network.
-rw-r--r--NEWS29
-rw-r--r--exclude.c74
-rw-r--r--flist.c170
-rw-r--r--io.c233
-rw-r--r--log.c294
-rw-r--r--receiver.c50
-rw-r--r--rsync.h143
-rw-r--r--util.c276
-rw-r--r--version.h1
9 files changed, 343 insertions, 927 deletions
diff --git a/NEWS b/NEWS
index af61025a..658a326b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,34 +1,7 @@
-rsync 2.5.2 (???)
+rsync 2.4.7 (???)
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)
diff --git a/exclude.c b/exclude.c
index a9d32a3e..f081614c 100644
--- a/exclude.c
+++ b/exclude.c
@@ -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;
@@ -31,7 +28,7 @@ extern int delete_mode;
static struct exclude_struct **exclude_list;
/* 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;
@@ -87,8 +84,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;
@@ -124,62 +121,32 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
}
-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)
@@ -207,12 +174,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 +188,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 +210,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;
@@ -399,7 +363,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);
}
diff --git a/flist.c b/flist.c
index 5d1a2590..d4c741b6 100644
--- a/flist.c
+++ b/flist.c
@@ -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,9 +47,6 @@ 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;
@@ -66,35 +55,6 @@ 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;
@@ -148,14 +108,24 @@ static char *string_area_strdup(struct string_area **ap, const char *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 +150,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 +182,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 +205,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 +213,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 +299,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
@@ -456,13 +415,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
@@ -516,8 +470,7 @@ static int skip_filesystem(char *fname, STRUCT_STAT *st)
}
#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))
+#define MALLOC(ap, i) (ap ? 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,
@@ -529,6 +482,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 delete_excluded;
extern int module_id;
strlcpy(cleaned_name, fname, MAXPATHLEN);
@@ -542,18 +496,9 @@ 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));
+ fname,strerror(errno));
return NULL;
}
@@ -570,7 +515,8 @@ 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;
@@ -659,10 +605,7 @@ void send_file_name(int f,struct file_list *flist,char *fname,
file = make_file(f,fname, &flist->string_area, 0);
- 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 +619,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 +693,6 @@ 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,9 +703,7 @@ 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);
}
@@ -891,7 +824,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 +845,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,7 +922,7 @@ 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) {
@@ -1022,10 +954,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;
@@ -1148,10 +1076,6 @@ static void clean_flist(struct file_list *flist, int strip_root)
}
}
- /* 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_
@@ -1176,10 +1100,10 @@ static void clean_flist(struct file_list *flist, int strip_root)
for (i=0;i<flist->count;i++) {
rprintf(FINFO,"[%d] i=%d %s %s mode=0%o len=%.0f\n",
- (int) getpid(), i,
+ getpid(), i,
NS(flist->files[i]->dirname),
NS(flist->files[i]->basename),
- (int) flist->files[i]->mode,
+ flist->files[i]->mode,
(double)flist->files[i]->length);
}
}
@@ -1187,10 +1111,6 @@ static void clean_flist(struct file_list *flist, int strip_root)
/*
* 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 +1123,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);
}
diff --git a/io.c b/io.c
index 9c4ac19d..d99cb127 100644
--- a/io.c
+++ b/io.c
@@ -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
@@ -29,24 +27,18 @@
/* if no timeout is specified then use a 60 second select timeout */
#define SELECT_TIMEOUT 60
+extern int bwlimit;
+
static int io_multiplexing_out;
static int io_multiplexing_in;
static int multiplex_in_fd;
static int multiplex_out_fd;
static time_t last_io;
-static int no_flush;
-
-extern int bwlimit;
+static int eof_error=1;
extern int verbose;
extern int io_timeout;
extern struct stats stats;
-
-/** 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);
@@ -55,8 +47,6 @@ static void check_timeout(void)
{
extern int am_server, am_daemon;
time_t t;
-
- err_list_push();
if (!io_timeout) return;
@@ -69,7 +59,7 @@ static void check_timeout(void)
if (last_io && io_timeout && (t-last_io) >= io_timeout) {
if (!am_server && !am_daemon) {
- rprintf(FERROR,"io timeout after %d seconds - exiting\n",
+ rprintf(FERROR,"io timeout after %d second - exiting\n",
(int)(t-last_io));
}
exit_cleanup(RERR_TIMEOUT);
@@ -86,12 +76,10 @@ void io_set_error_fd(int fd)
static void read_error_fd(void)
{
char buf[200];
- size_t n;
+ int n;
int fd = io_error_fd;
int tag, len;
- /* io_error_fd is temporarily disabled -- is this meant to
- * prevent indefinite recursion? */
io_error_fd = -1;
read_loop(fd, buf, 4);
@@ -103,8 +91,7 @@ static void read_error_fd(void)
while (len) {
n = len;
- if (n > (sizeof(buf)-1))
- n = sizeof(buf)-1;
+ if (n > (sizeof(buf)-1)) n = sizeof(buf)-1;
read_loop(fd, buf, n);
rwrite((enum logcode)tag, buf, n);
len -= n;
@@ -114,68 +101,21 @@ static void read_error_fd(void)
}
-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);
-}
-
+static int no_flush;
-/*!
- * 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;
io_flush();
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);
@@ -189,16 +129,11 @@ static int read_timeout (int fd, char *buf, size_t len)
errno = 0;
- count = select(fd_count, &fds, NULL, NULL, &tv);
-
- if (count == 0) {
- check_timeout();
- }
-
- if (count <= 0) {
+ if (select(fd_count, &fds, NULL, NULL, &tv) < 1) {
if (errno == EBADF) {
exit_cleanup(RERR_SOCKETIO);
}
+ check_timeout();
continue;
}
@@ -217,27 +152,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);
}
- }
- return ret;
-}
+ if (n == -1 && errno == EINTR) {
+ continue;
+ }
+
+ if (n == -1 &&
+ (errno == EWOULDBLOCK || errno == EAGAIN)) {
+ continue;
+ }
+ if (n == 0) {
+ if (eof_error) {
+ rprintf(FERROR,"unexpected EOF in read_timeout\n");
+ }
+ exit_cleanup(RERR_STREAMIO);
+ }
+ /* this prevents us trying to write errors on a dead socket */
+ io_multiplexing_close();
+
+ rprintf(FERROR,"read error: %s\n", strerror(errno));
+ exit_cleanup(RERR_STREAMIO);
+ }
-/*! 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)
+ 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)
{
while (len) {
int n = read_timeout(fd, buf, len);
@@ -247,20 +193,16 @@ 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;
+ 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) {
@@ -278,18 +220,17 @@ static int read_unbuffered(int fd, char *buf, size_t len)
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 +238,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((enum logcode)tag,"%s", line);
remaining = 0;
}
@@ -305,18 +246,17 @@ static int read_unbuffered(int fd, char *buf, size_t len)
}
-
/* 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;
while (total < N) {
io_flush();
- ret = read_unbuffered (fd, buffer + total, N-total);
+ ret = read_unbuffered(fd,buffer + total,N-total);
total += ret;
}
@@ -366,27 +306,25 @@ 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 */
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();
-
no_flush++;
while (total < len) {
@@ -411,14 +349,11 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
&w_fds,NULL,
&tv);
- if (count == 0) {
- check_timeout();
- }
-
if (count <= 0) {
if (errno == EBADF) {
exit_cleanup(RERR_SOCKETIO);
}
+ check_timeout();
continue;
}
@@ -427,8 +362,8 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
}
if (FD_ISSET(fd, &w_fds)) {
- int ret;
- size_t n = len-total;
+ int ret, n = len-total;
+
ret = write(fd,buf+total,n);
if (ret == -1 && errno == EINTR) {
@@ -442,10 +377,7 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
}
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);
}
@@ -490,7 +422,7 @@ void io_start_buffering(int fd)
static void mplex_write(int fd, enum logcode code, char *buf, size_t len)
{
char buffer[4096];
- size_t n = len;
+ int n = len;
SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
@@ -513,9 +445,6 @@ static void mplex_write(int fd, enum logcode code, char *buf, size_t len)
void io_flush(void)
{
int fd = multiplex_out_fd;
-
- err_list_push();
-
if (!io_buffer_count || no_flush) return;
if (io_multiplexing_out) {
@@ -526,8 +455,6 @@ void io_flush(void)
io_buffer_count = 0;
}
-
-/* XXX: fd is ignored, which seems a little strange. */
void io_end_buffering(int fd)
{
io_flush();
@@ -537,12 +464,21 @@ void io_end_buffering(int fd)
}
}
+/* some OSes have a bug where an exit causes the pending writes on
+ a socket to be flushed. Do an explicit shutdown to try to prevent this */
+void io_shutdown(void)
+{
+ if (multiplex_out_fd != -1) close(multiplex_out_fd);
+ if (io_error_fd != -1) close(io_error_fd);
+ multiplex_out_fd = -1;
+ io_error_fd = -1;
+}
+
+
static void writefd(int fd,char *buf,size_t len)
{
stats.total_written += len;
- err_list_push();
-
if (!io_buffer || fd != multiplex_out_fd) {
writefd_unbuffered(fd, buf, len);
return;
@@ -569,11 +505,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 +539,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 +561,8 @@ int read_line(int f, char *buf, size_t maxlen)
return 0;
}
+ eof_error = 1;
+
return 1;
}
@@ -641,7 +574,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);
@@ -678,6 +611,14 @@ int io_multiplex_write(enum logcode code, char *buf, size_t len)
return 1;
}
+/* write a message to the special error fd */
+int io_error_write(int f, enum logcode code, char *buf, size_t len)
+{
+ if (f == -1) return 0;
+ mplex_write(f, code, buf, len);
+ return 1;
+}
+
/* stop output multiplexing */
void io_multiplexing_close(void)
{
diff --git a/log.c b/log.c
index 045f0317..073159dc 100644
--- a/log.c
+++ b/log.c
@@ -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
@@ -182,30 +78,11 @@ void log_init(void)
#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
@@ -229,14 +106,12 @@ void rwrite(enum logcode code, char *buf, int len)
return;
}
- /* first try to pass it off to our sibling */
- if (am_server && log_error_fd != -1) {
- err_list_add(code, buf, len);
- err_list_push();
+ /* first try to pass it off the our sibling */
+ if (am_server && io_error_write(log_error_fd, code, buf, len)) {
return;
}
- /* if that fails, try to pass it to the other end */
+ /* then try to pass it to the other end */
if (am_server && io_multiplex_write(code, buf, len)) {
return;
}
@@ -250,7 +125,7 @@ void rwrite(enum logcode code, char *buf, int len)
depth++;
- log_init();
+ log_open();
logit(priority, buf);
depth--;
@@ -258,7 +133,6 @@ void rwrite(enum logcode code, char *buf, int len)
}
if (code == FERROR) {
- log_got_error = 1;
f = stderr;
}
@@ -277,90 +151,22 @@ void rwrite(enum logcode code, char *buf, int len)
}
-/* 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, ...)
+/* 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;
- size_t sys_len;
- char *sysmsg;
va_start(ap, format);
- /* Note: might return <0 */
- len = vsnprintf(buf, sizeof(buf), format, ap);
+ len = vslprintf(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++;
+ if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
rwrite(code, buf, len);
}
-
-
void rflush(enum logcode code)
{
FILE *f = NULL;
@@ -403,18 +209,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 +228,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 +258,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,35 +269,26 @@ 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;
}
@@ -530,15 +323,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 +333,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
diff --git a/receiver.c b/receiver.c
index 5776ff28..117dba6d 100644
--- a/receiver.c
+++ b/receiver.c
@@ -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
@@ -38,8 +37,8 @@ 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;
@@ -83,15 +82,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));
}
@@ -179,7 +177,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 +190,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;
@@ -305,7 +303,6 @@ 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];
@@ -373,7 +370,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);
@@ -414,7 +411,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 +429,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));
@@ -489,7 +491,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 */
diff --git a/rsync.h b/rsync.h
index 01d8ccd8..bb7a9a20 100644
--- a/rsync.h
+++ b/rsync.h
@@ -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,18 +47,7 @@
#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 PROTOCOL_VERSION 24
#define MIN_PROTOCOL_VERSION 15
#define MAX_PROTOCOL_VERSION 30
@@ -76,10 +63,7 @@
#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 };
+enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3};
#include "errcode.h"
@@ -93,6 +77,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 +175,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 +253,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 +292,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;
@@ -377,11 +330,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 +344,7 @@ struct map_struct {
};
struct exclude_struct {
+ char *orig;
char *pattern;
int regular_exp;
int fnmatch_flags;
@@ -422,29 +376,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[];
@@ -542,13 +476,6 @@ extern int errno;
# 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))
@@ -570,14 +497,6 @@ extern int errno;
#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
@@ -596,15 +515,3 @@ size_t strlcat(char *d, const char *s, size_t bufsize);
#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
diff --git a/util.c b/util.c
index f3c126bc..b3f1a96d 100644
--- a/util.c
+++ b/util.c
@@ -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
@@ -84,26 +82,6 @@ int fd_pair(int fd[2])
}
-void print_child_argv(char **cmd)
-{
- 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");
-}
-
-
/* this is derived from CVS code
note that in the child STDIN is set to blocking and STDOUT
@@ -114,71 +92,66 @@ void print_child_argv(char **cmd)
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)
-{
- pid_t 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);
- }
+int piped_child(char **command,int *f_in,int *f_out)
+{
+ int pid;
+ int to_child_pipe[2];
+ int from_child_pipe[2];
+ extern int blocking_io;
+
+ 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 < 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);
+ 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);
- }
+ 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];
+ *f_in = from_child_pipe[0];
+ *f_out = to_child_pipe[1];
- return pid;
+ return pid;
}
-pid_t local_child(int argc, char **argv,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 read_batch; /* dw */
if (fd_pair(to_child_pipe) < 0 ||
fd_pair(from_child_pipe) < 0) {
@@ -188,7 +161,7 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out)
pid = do_fork();
- if (pid == -1) {
+ if (pid < 0) {
rprintf(FERROR,"fork: %s\n",strerror(errno));
exit_cleanup(RERR_IPC);
}
@@ -197,7 +170,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 ||
@@ -584,7 +557,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 +587,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 +835,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 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");
-}
+static OFF_T last_ofs;
void end_progress(OFF_T size)
{
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,"%.0f (100%%)\n", (double)size);
}
- 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;
+ }
}
}
@@ -990,13 +930,10 @@ char *timestring(time_t t)
}
-/**
- * Sleep for a specified number of milliseconds.
- *
- * Always returns TRUE. (In the future it might return FALSE if
- * interrupted.)
- **/
-int msleep(int t)
+/*******************************************************************
+sleep for a specified number of milliseconds
+********************************************************************/
+void msleep(int t)
{
int tdiff=0;
struct timeval tval,t1,t2;
@@ -1015,8 +952,6 @@ int msleep(int t)
tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
(t2.tv_usec - t1.tv_usec)/1000;
}
-
- return True;
}
@@ -1028,6 +963,7 @@ int msleep(int t)
*******************************************************************/
int cmp_modtime(time_t file1, time_t file2)
{
+ time_t diff;
extern int modify_window;
if (file2 > file1) {
@@ -1051,9 +987,9 @@ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
{
static int (*fn)();
int ret;
- char *cmd;
+ char cmd[1024];
- 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'",
+ sprintf(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) {
@@ -1066,8 +1002,6 @@ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
system(cmd);
- free(cmd);
-
return ret;
}
#endif
diff --git a/version.h b/version.h
new file mode 100644
index 00000000..ba452e92
--- /dev/null
+++ b/version.h
@@ -0,0 +1 @@
+#define VERSION "2.4.7pre1"