Signedness security patch from Sebastian Krahmer <krahmer@suse.de> -- v2.4.7pre1
authorMartin Pool <mbp@samba.org>
Fri, 25 Jan 2002 00:56:35 +0000 (00:56 +0000)
committerMartin Pool <mbp@samba.org>
Fri, 25 Jan 2002 00:56:35 +0000 (00:56 +0000)
in some cases we were not sufficiently careful about reading integers
from the network.

NEWS
exclude.c
flist.c
io.c
log.c
receiver.c
rsync.h
util.c
version.h [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index af61025a724105a64dad634c6c3669cc632a2989..658a326b2dc6bb801f86de9377ded32cc021a20c 100644 (file)
--- 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)
index a9d32a3e5fdf0a06f67e4e815b8f8422fedc12a8..f081614cddad11bdbb7dc6d6b8a3b15492c1f1f9 100644 (file)
--- 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 5d1a2590ca82fb7aff7ae396fa0df75a8e517dac..d4c741b6763a16d085cf4d6f76306adcf9793183 100644 (file)
--- 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
    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 9c4ac19d2636c15ebb943991c23a0335a3f9f97c..d99cb1277c9b0389f765a782f692ada76bedf7d2 100644 (file)
--- 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
 /* 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 045f031778a869dab3e8e515f7d8213c9fd23154..073159dc8ff01adb7ec8c54df3fd07ca439660c5 100644 (file)
--- 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
 */
 
 /*
-  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 
    
index 5776ff28b18f69d0a00fd1911212f43ea7584c36..117dba6dfc4d3274d182d98386e81200be016fc2 100644 (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
@@ -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 01d8ccd8ba7a1ff3a5c7cd17964a1b77057063b0..bb7a9a20d5c27cb94696a0c3bc3bc38e4f3b857d 100644 (file)
--- 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
 
 #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
 
 
 #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 f3c126bcf6c44791a4ee1ba47e36d3a0fb483327..b3f1a96dfc0476c91ca368ca059351e01fc7207d 100644 (file)
--- 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 (file)
index 0000000..ba452e9
--- /dev/null
+++ b/version.h
@@ -0,0 +1 @@
+#define VERSION "2.4.7pre1"