if f_in == f_out then don't close one of them
[rsync/rsync.git] / io.c
diff --git a/io.c b/io.c
index f5816ed..b48ae0f 100644 (file)
--- a/io.c
+++ b/io.c
@@ -45,8 +45,8 @@ static int buffer_f_in = -1;
 
 void setup_nonblocking(int f_in,int f_out)
 {
-  set_blocking(f_out,0);
-  buffer_f_in = f_in;
+       set_blocking(f_out,0);
+       buffer_f_in = f_in;
 }
 
 
@@ -61,39 +61,42 @@ static int read_buffer_size;
  * ssh will clag up. Uggh.  */
 static void read_check(int f)
 {
-  int n;
+       int n;
 
-  if (f == -1) return;
+       if (f == -1) return;
 
-  if (read_buffer_len == 0) {
-    read_buffer_p = read_buffer;
-  }
+       if (read_buffer_len == 0) {
+               read_buffer_p = read_buffer;
+       }
 
-  if ((n=num_waiting(f)) <= 0)
-    return;
+       if ((n=num_waiting(f)) <= 0)
+               return;
 
-  /* things could deteriorate if we read in really small chunks */
-  if (n < 10) n = 1024;
+       /* things could deteriorate if we read in really small chunks */
+       if (n < 10) n = 1024;
 
-  if (read_buffer_p != read_buffer) {
-    memmove(read_buffer,read_buffer_p,read_buffer_len);
-    read_buffer_p = read_buffer;
-  }
+       if (n > MAX_READ_BUFFER/4)
+               n = MAX_READ_BUFFER/4;
 
-  if (n > (read_buffer_size - read_buffer_len)) {
-    read_buffer_size += n;
-    if (!read_buffer)
-      read_buffer = (char *)malloc(read_buffer_size);
-    else
-      read_buffer = (char *)realloc(read_buffer,read_buffer_size);
-    if (!read_buffer) out_of_memory("read check");      
-    read_buffer_p = read_buffer;      
-  }
+       if (read_buffer_p != read_buffer) {
+               memmove(read_buffer,read_buffer_p,read_buffer_len);
+               read_buffer_p = read_buffer;
+       }
 
-  n = read(f,read_buffer+read_buffer_len,n);
-  if (n > 0) {
-    read_buffer_len += n;
-  }
+       if (n > (read_buffer_size - read_buffer_len)) {
+               read_buffer_size += n;
+               if (!read_buffer)
+                       read_buffer = (char *)malloc(read_buffer_size);
+               else
+                       read_buffer = (char *)realloc(read_buffer,read_buffer_size);
+               if (!read_buffer) out_of_memory("read check");      
+               read_buffer_p = read_buffer;      
+       }
+
+       n = read(f,read_buffer+read_buffer_len,n);
+       if (n > 0) {
+               read_buffer_len += n;
+       }
 }
 
 static time_t last_io;
@@ -148,7 +151,8 @@ static int readfd(int fd,char *buffer,int N)
                        tv.tv_sec = io_timeout;
                        tv.tv_usec = 0;
 
-                       if (select(fd+1, &fds, NULL, NULL, &tv) != 1) {
+                       if (select(fd+1, &fds, NULL, NULL, 
+                                  io_timeout?&tv:NULL) != 1) {
                                check_timeout();
                        }
                }
@@ -300,7 +304,7 @@ int write_file(int f,char *buf,int len)
 }
 
 
-static int writefd(int fd,char *buf,int len)
+static int writefd_unbuffered(int fd,char *buf,int len)
 {
   int total = 0;
   fd_set w_fds, r_fds;
@@ -333,38 +337,40 @@ static int writefd(int fd,char *buf,int len)
 
 
     if (ret == -1) {
-      read_check(buffer_f_in);
-
-      fd_count = fd+1;
-      FD_ZERO(&w_fds);
-      FD_ZERO(&r_fds);
-      FD_SET(fd,&w_fds);
-      if (buffer_f_in != -1) {
-             FD_SET(buffer_f_in,&r_fds);
-             if (buffer_f_in > fd) 
-                     fd_count = buffer_f_in+1;
-      }
-
-      tv.tv_sec = BLOCKING_TIMEOUT;
-      tv.tv_usec = 0;
-      count = select(fd_count,buffer_f_in == -1? NULL: &r_fds,
-                    &w_fds,NULL,&tv);
-      if (count == -1 && errno != EINTR) {
-             if (verbose > 1) 
-                     rprintf(FERROR,"select error: %s\n", strerror(errno));
-             exit_cleanup(1);
-      }
-
-      if (count == 0) {
-             check_timeout();
-             continue;
-      }
+           if (read_buffer_len < MAX_READ_BUFFER)
+                   read_check(buffer_f_in);
+
+           fd_count = fd+1;
+           FD_ZERO(&w_fds);
+           FD_ZERO(&r_fds);
+           FD_SET(fd,&w_fds);
+           if (buffer_f_in != -1) {
+                   FD_SET(buffer_f_in,&r_fds);
+                   if (buffer_f_in > fd) 
+                           fd_count = buffer_f_in+1;
+           }
+
+           tv.tv_sec = BLOCKING_TIMEOUT;
+           tv.tv_usec = 0;
+           count = select(fd_count,buffer_f_in == -1? NULL: &r_fds,
+                          &w_fds,NULL,&tv);
+
+           if (count == -1 && errno != EINTR) {
+                   if (verbose > 1) 
+                           rprintf(FERROR,"select error: %s\n", strerror(errno));
+                   exit_cleanup(1);
+           }
+
+           if (count == 0) {
+                   check_timeout();
+                   continue;
+           }
       
-      if (FD_ISSET(fd, &w_fds)) {
-             got_select = 1;
-      }
+           if (FD_ISSET(fd, &w_fds)) {
+                   got_select = 1;
+           }
     } else {
-      total += ret;
+           total += ret;
     }
   }
 
@@ -374,6 +380,58 @@ static int writefd(int fd,char *buf,int len)
   return total;
 }
 
+static char *io_buffer;
+static int io_buffer_count;
+
+void io_start_buffering(int fd)
+{
+       io_buffer = (char *)malloc(IO_BUFFER_SIZE);
+       if (!io_buffer) out_of_memory("writefd");
+       io_buffer_count = 0;
+}
+
+void io_end_buffering(int fd)
+{
+       if (io_buffer_count) {
+               if (writefd_unbuffered(fd, io_buffer, 
+                                      io_buffer_count) != 
+                   io_buffer_count) {
+                       rprintf(FERROR,"write failed\n");
+                       exit_cleanup(1);
+               }
+               io_buffer_count = 0;
+       }
+       free(io_buffer);
+       io_buffer = NULL;
+}
+
+static int writefd(int fd,char *buf,int len1)
+{
+       int len = len1;
+
+       if (!io_buffer) return writefd_unbuffered(fd, buf, len);
+
+       while (len) {
+               int n = MIN(len, IO_BUFFER_SIZE-io_buffer_count);
+               if (n > 0) {
+                       memcpy(io_buffer+io_buffer_count, buf, n);
+                       buf += n;
+                       len -= n;
+                       io_buffer_count += n;
+               }
+               
+               if (io_buffer_count == IO_BUFFER_SIZE) {
+                       if (writefd_unbuffered(fd, io_buffer, 
+                                              io_buffer_count) != 
+                           io_buffer_count) {
+                               return -1;
+                       }
+                       io_buffer_count = 0;
+               }
+       }
+
+       return len1;
+}
 
 
 void write_int(int f,int32 x)
@@ -423,10 +481,16 @@ void write_buf(int f,char *buf,int len)
   total_written += len;
 }
 
+/* write a string to the connection */
+void write_sbuf(int f,char *buf)
+{
+       write_buf(f, buf, strlen(buf));
+}
+
 
 void write_byte(int f,unsigned char c)
 {
-  write_buf(f,(char *)&c,1);
+       write_buf(f,(char *)&c,1);
 }
 
 void write_flush(int f)
@@ -434,3 +498,38 @@ void write_flush(int f)
 }
 
 
+int read_line(int f, char *buf, int maxlen)
+{
+       while (maxlen) {
+               read_buf(f, buf, 1);
+               if (buf[0] == '\n') {
+                       buf[0] = 0;
+                       break;
+               }
+               if (buf[0] != '\r') {
+                       buf++;
+                       maxlen--;
+               }
+       }
+       if (maxlen == 0) {
+               *buf = 0;
+               return 0;
+       }
+       return 1;
+}
+
+
+void io_printf(int fd, const char *format, ...)
+{
+       va_list ap;  
+       char buf[1024];
+       int len;
+       
+       va_start(ap, format);
+       len = vslprintf(buf, sizeof(buf)-1, format, ap);
+       va_end(ap);
+
+       if (len < 0) exit_cleanup(1);
+
+       write_sbuf(fd, buf);
+}