new exit/cleanup code
[rsync/rsync.git] / io.c
1 /* 
2    Copyright (C) Andrew Tridgell 1996
3    Copyright (C) Paul Mackerras 1996
4    
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /*
21   Utilities used in rsync 
22
23   tridge, June 1996
24   */
25 #include "rsync.h"
26
27 static int total_written = 0;
28 static int total_read = 0;
29
30 extern int verbose;
31
32 int write_total(void)
33 {
34   return total_written;
35 }
36
37 int read_total(void)
38 {
39   return total_read;
40 }
41
42 static int buffer_f_in = -1;
43
44 void setup_nonblocking(int f_in,int f_out)
45 {
46   set_blocking(f_out,0);
47   buffer_f_in = f_in;
48 }
49
50
51 static char *read_buffer = NULL;
52 static char *read_buffer_p = NULL;
53 static int read_buffer_len = 0;
54 static int read_buffer_size = 0;
55
56
57 /* This function was added to overcome a deadlock problem when using
58  * ssh.  It looks like we can't allow our receive queue to get full or
59  * ssh will clag up. Uggh.  */
60 static void read_check(int f)
61 {
62   int n;
63
64   if (read_buffer_len == 0) {
65     read_buffer_p = read_buffer;
66   }
67
68   if ((n=num_waiting(f)) <= 0)
69     return;
70
71   if (read_buffer_p != read_buffer) {
72     memmove(read_buffer,read_buffer_p,read_buffer_len);
73     read_buffer_p = read_buffer;
74   }
75
76   if (n > (read_buffer_size - read_buffer_len)) {
77     read_buffer_size += n;
78     if (!read_buffer)
79       read_buffer = (char *)malloc(read_buffer_size);
80     else
81       read_buffer = (char *)realloc(read_buffer,read_buffer_size);
82     if (!read_buffer) out_of_memory("read check");      
83     read_buffer_p = read_buffer;      
84   }
85
86   n = read(f,read_buffer+read_buffer_len,n);
87   if (n > 0) {
88     read_buffer_len += n;
89   }
90 }
91
92
93 static int readfd(int fd,char *buffer,int N)
94 {
95   int  ret;
96   int total=0;  
97  
98   while (total < N)
99     {
100       if (read_buffer_len > 0) {
101         ret = MIN(read_buffer_len,N-total);
102         memcpy(buffer+total,read_buffer_p,ret);
103         read_buffer_p += ret;
104         read_buffer_len -= ret;
105       } else {
106         while ((ret = read(fd,buffer + total,N - total)) == -1) {
107           fd_set fds;
108
109           if (errno != EAGAIN && errno != EWOULDBLOCK)
110             return -1;
111           FD_ZERO(&fds);
112           FD_SET(fd, &fds);
113           select(fd+1, &fds, NULL, NULL, NULL);
114         }
115       }
116
117       if (ret <= 0)
118         return total;
119       total += ret;
120     }
121   return total;
122 }
123
124
125 int read_int(int f)
126 {
127   int ret;
128   char b[4];
129   if ((ret=readfd(f,b,4)) != 4) {
130     if (verbose > 1) 
131       fprintf(stderr,"Error reading %d bytes : %s\n",
132               4,ret==-1?strerror(errno):"EOF");
133     exit_cleanup(1);
134   }
135   total_read += 4;
136   return IVAL(b,0);
137 }
138
139 void read_buf(int f,char *buf,int len)
140 {
141   int ret;
142   if ((ret=readfd(f,buf,len)) != len) {
143     if (verbose > 1) 
144       fprintf(stderr,"Error reading %d bytes : %s\n",
145               len,ret==-1?strerror(errno):"EOF");
146     exit_cleanup(1);
147   }
148   total_read += len;
149 }
150
151 unsigned char read_byte(int f)
152 {
153   char c;
154   read_buf(f,&c,1);
155   return (unsigned char)c;
156 }
157
158
159 static char last_byte=0;
160 static int last_sparse = 0;
161
162 int sparse_end(int f)
163 {
164 #if SPARSE_FILES
165   if (last_sparse) {
166     lseek(f,-1,SEEK_CUR);
167     return (write(f,&last_byte,1) == 1 ? 0 : -1);
168   }
169 #endif  
170   return 0;
171 }
172
173 int write_sparse(int f,char *buf,int len)
174 {
175   int l=0;
176
177 #if SPARSE_FILES
178   for (l=0;l<len && buf[l]==0;l++) ;
179
180   if (l > 0)
181     lseek(f,l,SEEK_CUR);
182
183   last_byte = buf[len-1];
184 #endif
185
186   if (l == len) {
187     last_sparse = 1;
188     return len;
189   } 
190
191   last_sparse = 0;
192
193   return (l + write(f,buf+l,len-l));
194 }
195
196 int read_write(int fd_in,int fd_out,int size)
197 {
198   static char *buf=NULL;
199   static int bufsize = CHUNK_SIZE;
200   int total=0;
201   
202   if (!buf) {
203     buf = (char *)malloc(bufsize);
204     if (!buf) out_of_memory("read_write");
205   }
206
207   while (total < size) {
208     int n = MIN(size-total,bufsize);
209     read_buf(fd_in,buf,n);
210     if (write_sparse(fd_out,buf,n) != n)
211       return total;
212     total += n;
213   }
214   return total;
215 }
216
217
218 static int writefd(int fd,char *buf,int len)
219 {
220   int total = 0;
221   fd_set fds;
222   struct timeval tv;
223
224   if (buffer_f_in == -1) 
225     return write(fd,buf,len);
226
227   while (total < len) {
228     int ret = write(fd,buf+total,len-total);
229
230     if (ret == 0) return total;
231
232     if (ret == -1 && !(errno == EWOULDBLOCK || errno == EAGAIN)) 
233       return -1;
234
235     if (ret == -1) {
236       read_check(buffer_f_in);
237
238       FD_ZERO(&fds);
239       FD_SET(fd,&fds);
240       tv.tv_sec = BLOCKING_TIMEOUT;
241       tv.tv_usec = 0;
242       select(fd+1,NULL,&fds,NULL,&tv);
243     } else {
244       total += ret;
245     }
246   }
247
248   return total;
249 }
250
251
252
253 void write_int(int f,int x)
254 {
255   int ret;
256   char b[4];
257   SIVAL(b,0,x);
258   if ((ret=writefd(f,b,4)) != 4) {
259     fprintf(stderr,"write_int failed : %s\n",
260             ret==-1?strerror(errno):"EOF");
261     exit_cleanup(1);
262   }
263   total_written += 4;
264 }
265
266 void write_buf(int f,char *buf,int len)
267 {
268   int ret;
269   if ((ret=writefd(f,buf,len)) != len) {
270     fprintf(stderr,"write_buf failed : %s\n",
271             ret==-1?strerror(errno):"EOF");
272     exit_cleanup(1);
273   }
274   total_written += len;
275 }
276
277
278 void write_byte(int f,unsigned char c)
279 {
280   write_buf(f,(char *)&c,1);
281 }
282
283 void write_flush(int f)
284 {
285 }
286
287