Split code out into separate files and remove some global variables to
authorMartin Pool <mbp@samba.org>
Mon, 8 Apr 2002 04:10:20 +0000 (04:10 +0000)
committerMartin Pool <mbp@samba.org>
Mon, 8 Apr 2002 04:10:20 +0000 (04:10 +0000)
reduce symbol dependencies between files and therefore make it easier
to write unit tests.  The diff is large, but the actual code changes
are pretty small.

.cvsignore
Makefile.in
clientserver.c
generator.c
log.c
main.c
options.c
pipe.c [new file with mode: 0644]
progress.c [new file with mode: 0644]
receiver.c

index a4cd580..cda7639 100644 (file)
@@ -8,6 +8,7 @@ config.log
 config.status
 conftest.c
 conftest.log
+dox
 gmon.out
 rsync
 shconfig
index 4fcf2c1..535dace 100644 (file)
@@ -32,15 +32,16 @@ ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \
 OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o main.o checksum.o match.o syscall.o log.o backup.o
 OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o fileio.o batch.o \
        clientname.o
+OBJS3=progress.o pipe.o
 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
 popt_OBJS=popt/findme.o  popt/popt.o  popt/poptconfig.o \
        popt/popthelp.o popt/poptparse.o
-OBJS=$(OBJS1) $(OBJS2) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
+OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
 
 TLS_OBJ = tls.o syscall.o lib/permstring.o 
 
 # Programs we must have to run the test cases
-CHECK_PROGS = rsync tls getgroups trimslash
+CHECK_PROGS = rsync tls getgroups trimslash t_unsafe
 
 # note that the -I. is needed to handle config.h when using VPATH
 .c.o:
@@ -79,6 +80,10 @@ TRIMSLASH_OBJ = trimslash.o syscall.o
 trimslash: $(TRIMSLASH_OBJ)
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
 
+T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o
+t_unsafe: $(T_UNSAFE_OBJ)
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
+
 # I don't like these rules because CVS can skew the timestamps and
 # produce spurious warnings, and also make "make install" fail if the
 # source directory can no longer be found.  Since we don't rebuild
@@ -171,3 +176,12 @@ rsync.ps: rsync.dvi
 
 rsync.pdf: doc/rsync.texinfo
        texi2dvi -o $@ --pdf $<
+
+
+doxygen: 
+       cd $(srcdir) && rm dox/html/* && doxygen
+
+# for maintainers only
+doxygen-upload: 
+       rsync -avzv $(srcdir)/dox/html/ --delete \
+       samba.org:/home/httpd/html/rsync/doxygen/head/
index 40a4376..9cda2a0 100644 (file)
@@ -27,7 +27,7 @@ extern int read_only;
 extern int verbose;
 extern int rsync_port;
 char *auth_user;
-int sanitize_paths = 0;
+extern int sanitize_paths;
 
 /**
  * Run a client connected to an rsyncd.  The alternative to this
index c1b94fd..8e4ede0 100644 (file)
@@ -239,6 +239,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
        extern int list_only;
        extern int preserve_perms;
        extern int only_existing;
+       extern int orig_umask;
 
        if (list_only) return;
 
@@ -281,7 +282,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
                }
                if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
                        if (!(relative_paths && errno==ENOENT && 
-                             create_directory_path(fname)==0 && 
+                             create_directory_path(fname, orig_umask)==0 && 
                              do_mkdir(fname,file->mode)==0)) {
                                rprintf(FERROR, RSYNC_NAME ": recv_generator: mkdir \"%s\": %s (2)\n",
                                        fname,strerror(errno));
diff --git a/log.c b/log.c
index 411889c..e79bc22 100644 (file)
--- a/log.c
+++ b/log.c
@@ -30,6 +30,7 @@
 static char *logfname;
 static FILE *logfile;
 static int log_error_fd = -1;
+struct stats stats;
 
 int log_got_error=0;
 
diff --git a/main.c b/main.c
index 86eca2c..b946e75 100644 (file)
--- a/main.c
+++ b/main.c
@@ -23,8 +23,7 @@
 
 time_t starttime = 0;
 
-struct stats stats;
-
+extern struct stats stats;
 extern int verbose;
 
 static void show_malloc_stats(void);
index 22d332c..a928316 100644 (file)
--- a/options.c
+++ b/options.c
@@ -88,6 +88,7 @@ int modify_window=0;
 #endif
 int blocking_io=-1;
 
+
 /** Network address family. **/
 #ifdef INET6
 int default_af_hint = 0;       /* Any protocol */
diff --git a/pipe.c b/pipe.c
new file mode 100644 (file)
index 0000000..e2e88ec
--- /dev/null
+++ b/pipe.c
@@ -0,0 +1,127 @@
+#include "rsync.h"
+
+/**
+ * Create a child connected to use on stdin/stdout.
+ *
+ * This is derived from CVS code 
+ * 
+ * Note that in the child STDIN is set to blocking and STDOUT
+ * is set to non-blocking. This is necessary as rsh relies on stdin being blocking
+ *  and ssh relies on stdout being non-blocking
+ *
+ * If blocking_io is set then use blocking io on both fds. That can be
+ * used to cope with badly broken rsh implementations like the one on
+ * Solaris.
+ **/
+pid_t piped_child(char **command, int *f_in, int *f_out)
+{
+       pid_t pid;
+       int to_child_pipe[2];
+       int from_child_pipe[2];
+       extern int blocking_io;
+       
+       if (verbose >= 2) {
+               print_child_argv(command);
+       }
+
+       if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
+               rprintf(FERROR, "pipe: %s\n", strerror(errno));
+               exit_cleanup(RERR_IPC);
+       }
+
+
+       pid = do_fork();
+       if (pid == -1) {
+               rprintf(FERROR, "fork: %s\n", strerror(errno));
+               exit_cleanup(RERR_IPC);
+       }
+
+       if (pid == 0) {
+               extern int orig_umask;
+               if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
+                   close(to_child_pipe[1]) < 0 ||
+                   close(from_child_pipe[0]) < 0 ||
+                   dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
+                       rprintf(FERROR, "Failed to dup/close : %s\n",
+                               strerror(errno));
+                       exit_cleanup(RERR_IPC);
+               }
+               if (to_child_pipe[0] != STDIN_FILENO)
+                       close(to_child_pipe[0]);
+               if (from_child_pipe[1] != STDOUT_FILENO)
+                       close(from_child_pipe[1]);
+               umask(orig_umask);
+               set_blocking(STDIN_FILENO);
+               if (blocking_io) {
+                       set_blocking(STDOUT_FILENO);
+               }
+               execvp(command[0], command);
+               rprintf(FERROR, "Failed to exec %s : %s\n",
+                       command[0], strerror(errno));
+               exit_cleanup(RERR_IPC);
+       }
+
+       if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
+               rprintf(FERROR, "Failed to close : %s\n", strerror(errno));
+               exit_cleanup(RERR_IPC);
+       }
+
+       *f_in = from_child_pipe[0];
+       *f_out = to_child_pipe[1];
+
+       return pid;
+}
+
+pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
+                 int (*child_main)(int, char **))
+{
+       pid_t pid;
+       int to_child_pipe[2];
+       int from_child_pipe[2];
+       extern int read_batch;  /* dw */
+
+       if (fd_pair(to_child_pipe) < 0 ||
+           fd_pair(from_child_pipe) < 0) {
+               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 am_sender;
+               extern int am_server;
+
+               am_sender = read_batch ? 0 : !am_sender;
+               am_server = 1;          
+
+               if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
+                   close(to_child_pipe[1]) < 0 ||
+                   close(from_child_pipe[0]) < 0 ||
+                   dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
+                       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]);
+               child_main(argc, argv);
+       }
+
+       if (close(from_child_pipe[1]) < 0 ||
+           close(to_child_pipe[0]) < 0) {
+               rprintf(FERROR,"Failed to close : %s\n",strerror(errno));   
+               exit_cleanup(RERR_IPC);
+       }
+
+       *f_in = from_child_pipe[0];
+       *f_out = to_child_pipe[1];
+  
+       return pid;
+}
+
+
diff --git a/progress.c b/progress.c
new file mode 100644 (file)
index 0000000..004b5d1
--- /dev/null
@@ -0,0 +1,96 @@
+#include "rsync.h"
+
+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;
+    /* If we've finished transferring this file, show the time taken;
+     * otherwise show expected time to complete.  That's kind of
+     * inconsistent, but people can probably cope.  Hopefully we'll
+     * get more consistent and complete progress reporting soon. --
+     * mbp */
+    double        remain = is_last
+                        ? (double) diff / 1000.0
+                        : rate ? (double) (size-ofs) / rate / 1000.0 : 0.0;
+    int          remain_h, remain_m, remain_s;
+
+    if (rate > 1024*1024) {
+           rate /= 1024.0 * 1024.0;
+           units = "GB/s";
+    } else if (rate > 1024) {
+           rate /= 1024.0;
+           units = "MB/s";
+    } else {
+           units = "kB/s";
+    }
+
+    remain_s = (int) remain % 60;
+    remain_m = (int) (remain / 60.0) % 60;
+    remain_h = (int) (remain / 3600.0);
+    
+    rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
+           (double) ofs, pct, rate, units,
+           remain_h, remain_m, remain_s,
+           is_last ? "\n" : "\r");
+}
+
+void end_progress(OFF_T size)
+{
+       extern int do_progress, am_server;
+
+       if (do_progress && !am_server) {
+               struct timeval now;
+                gettimeofday(&now, NULL);
+                rprint_progress(size, size, &now, True);
+       }
+       last_ofs   = 0;
+        start_ofs  = 0;
+        print_time.tv_sec  = print_time.tv_usec  = 0;
+        start_time.tv_sec  = start_time.tv_usec  = 0;
+}
+
+void show_progress(OFF_T ofs, OFF_T size)
+{
+       extern int 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;
+       }
+}
index dbd8bfd..1428233 100644 (file)
@@ -297,9 +297,10 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
 }
 
 
-/* main routine for receiver process. Receiver process runs on the
-       same host as the generator process. */
-
+/**
+ * main routine for receiver process.
+ *
+ * Receiver process runs on the same host as the generator process. */
 int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
 {  
        int fd1,fd2;
@@ -317,6 +318,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
        extern struct stats stats;              
        extern int preserve_perms;
        extern int delete_after;
+       extern int orig_umask;
        struct stats initial_stats;
 
        if (verbose > 2) {
@@ -434,7 +436,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
                   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) {
+                   create_directory_path(fnametmp, orig_umask) == 0) {
                        strlcpy(fnametmp, template, sizeof(fnametmp));
                        fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
                }