Line data Source code
1 : /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 : *
3 : * librsync -- the library for network deltas
4 : * $Id: buf.c,v 1.22 2003/12/16 00:10:55 abo Exp $
5 : *
6 : * Copyright (C) 2000, 2001 by Martin Pool <mbp@samba.org>
7 : *
8 : * This program is free software; you can redistribute it and/or
9 : * modify it under the terms of the GNU Lesser General Public License
10 : * as published by the Free Software Foundation; either version 2.1 of
11 : * the License, or (at your option) any later version.
12 : *
13 : * This program is distributed in the hope that it will be useful, but
14 : * WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : * Lesser General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU Lesser General Public
19 : * License along with this program; if not, write to the Free Software
20 : * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 : */
22 :
23 : /*
24 : | Pick a window, Jimmy, you're leaving.
25 : | -- Martin Schwenke, regularly
26 : */
27 :
28 :
29 : /*
30 : * buf.c -- Buffers that map between stdio file streams and librsync
31 : * streams. As the stream consumes input and produces output, it is
32 : * refilled from appropriate input and output FILEs. A dynamically
33 : * allocated buffer of configurable size is used as an intermediary.
34 : */
35 :
36 : #include "../burp.h"
37 : #include "rs_buf.h"
38 : #include "../cmd.h"
39 : #include "../alloc.h"
40 : #include "../asfd.h"
41 : #include "../async.h"
42 : #include "../handy.h"
43 : #include "../iobuf.h"
44 : #include "../log.h"
45 :
46 : /* use fseeko instead of fseek for long file support if we have it */
47 : #ifdef HAVE_FSEEKO
48 : #define fseek fseeko
49 : #endif
50 :
51 24 : rs_filebuf_t *rs_filebuf_new(struct BFILE *bfd,
52 : struct fzp *fzp,
53 : struct asfd *asfd,
54 : size_t buf_len,
55 : size_t data_len)
56 : {
57 24 : rs_filebuf_t *pf=NULL;
58 24 : if(!(pf=(struct rs_filebuf *)calloc_w(1,
59 : sizeof(struct rs_filebuf), __func__))
60 23 : || !(pf->buf=(char *)calloc_w(1, buf_len, __func__)))
61 : goto error;
62 23 : pf->buf_len=buf_len;
63 23 : pf->fzp=fzp;
64 23 : pf->bfd=bfd;
65 23 : pf->bytes=0;
66 23 : pf->data_len=data_len;
67 23 : if(data_len>0)
68 9 : pf->do_known_byte_count=1;
69 : else
70 14 : pf->do_known_byte_count=0;
71 23 : if(!MD5_Init(&(pf->md5)))
72 : {
73 0 : logp("MD5_Init() failed\n");
74 0 : goto error;
75 : }
76 23 : pf->asfd=asfd;
77 23 : return pf;
78 : error:
79 1 : rs_filebuf_free(&pf);
80 1 : return NULL;
81 : }
82 :
83 119130 : void rs_filebuf_free(rs_filebuf_t **fb)
84 : {
85 238260 : if(!fb || !*fb) return;
86 23 : free_w(&((*fb)->buf));
87 23 : free_v((void **)fb);
88 : }
89 :
90 : /*
91 : * If the stream has no more data available, read some from F into
92 : * BUF, and let the stream use that. On return, SEEN_EOF is true if
93 : * the end of file has passed into the stream.
94 : */
95 14 : rs_result rs_infilebuf_fill(__attribute__ ((unused)) rs_job_t *job,
96 : rs_buffers_t *buf, void *opaque)
97 : {
98 14 : int len=0;
99 14 : rs_filebuf_t *fb=(rs_filebuf_t *) opaque;
100 :
101 : //logp("rs_infilebuf_fill\n");
102 :
103 : /* This is only allowed if either the buf has no input buffer
104 : * yet, or that buffer could possibly be BUF. */
105 14 : if(buf->next_in)
106 : {
107 : //logp("infilebuf avail_in %d buf_len %d\n",
108 : // buf->avail_in, fb->buf_len);
109 5 : if(buf->avail_in > fb->buf_len)
110 : {
111 1 : logp("buf->avail_in > fb->buf_len (%lu > %lu) in %s\n",
112 : (unsigned long)buf->avail_in,
113 : (unsigned long)fb->buf_len, __func__);
114 1 : return RS_IO_ERROR;
115 : }
116 4 : if(buf->next_in < fb->buf)
117 : {
118 1 : logp("buf->next_in < fb->buf in %s\n", __func__);
119 1 : return RS_IO_ERROR;
120 : }
121 3 : if(buf->next_in > fb->buf + fb->buf_len)
122 : {
123 1 : logp("buf->next_in > fb->buf + fb->buf_len in %s\n",
124 : __func__);
125 1 : return RS_IO_ERROR;
126 : }
127 : }
128 : else
129 : {
130 9 : if(buf->avail_in)
131 : {
132 1 : logp("buf->avail_in is %lu in %s\n",
133 : (unsigned long)buf->avail_in, __func__);
134 1 : return RS_IO_ERROR;
135 : }
136 : }
137 :
138 10 : if(buf->eof_in)
139 : return RS_DONE;
140 :
141 9 : if(buf->avail_in)
142 : /* Still some data remaining. Perhaps we should read
143 : anyhow? */
144 : return RS_DONE;
145 :
146 9 : if(fb->asfd)
147 : {
148 : static struct iobuf *rbuf=NULL;
149 4 : rbuf=fb->asfd->rbuf;
150 :
151 4 : switch(rbuf->cmd)
152 : {
153 : case CMD_APPEND:
154 2 : memcpy(fb->buf, rbuf->buf, rbuf->len);
155 2 : len=rbuf->len;
156 : break;
157 : case CMD_END_FILE:
158 2 : buf->eof_in=1;
159 2 : return RS_DONE;
160 : default:
161 0 : iobuf_log_unexpected(rbuf, __func__);
162 0 : return RS_IO_ERROR;
163 : }
164 : }
165 5 : else if(fb->bfd)
166 : {
167 2 : if(fb->do_known_byte_count)
168 : {
169 0 : if(fb->data_len>0)
170 : {
171 0 : len=fb->bfd->read(fb->bfd, fb->buf,
172 0 : min(fb->buf_len, fb->data_len));
173 0 : fb->data_len-=len;
174 : }
175 : else
176 : {
177 : // We have already read as much data as the VSS
178 : // header told us to, so set len=0 in order to
179 : // finish up.
180 : len=0;
181 : }
182 : }
183 : else
184 2 : len=fb->bfd->read(fb->bfd, fb->buf, fb->buf_len);
185 2 : if(len==0)
186 : {
187 : //logp("bread: eof\n");
188 2 : buf->eof_in=1;
189 2 : return RS_DONE;
190 : }
191 0 : else if(len<0)
192 : {
193 0 : logp("rs_infilebuf_fill: error in bread: %s\n",
194 0 : strerror(errno));
195 0 : return RS_IO_ERROR;
196 : }
197 : //logp("bread: ok: %d\n", len);
198 0 : fb->bytes+=len;
199 0 : if(!MD5_Update(&(fb->md5), fb->buf, len))
200 : {
201 0 : logp("rs_infilebuf_fill: MD5_Update() failed\n");
202 0 : return RS_IO_ERROR;
203 : }
204 : }
205 3 : else if(fb->fzp)
206 : {
207 2 : if((len=fzp_read(fb->fzp, fb->buf, fb->buf_len))<=0)
208 : {
209 : // This will happen if file size is a multiple of
210 : // input block len.
211 2 : if(fzp_eof(fb->fzp))
212 : {
213 2 : buf->eof_in=1;
214 2 : return RS_DONE;
215 : }
216 : else
217 : {
218 0 : logp("rs_infilebuf_fill: got return %d when trying to read\n", len);
219 0 : return RS_IO_ERROR;
220 : }
221 : }
222 0 : fb->bytes+=len;
223 0 : if(!MD5_Update(&(fb->md5), fb->buf, len))
224 : {
225 0 : logp("rs_infilebuf_fill: MD5_Update() failed\n");
226 0 : return RS_IO_ERROR;
227 : }
228 : }
229 :
230 3 : buf->avail_in = len;
231 3 : buf->next_in = fb->buf;
232 :
233 3 : return RS_DONE;
234 : }
235 :
236 : /*
237 : * The buf is already using BUF for an output buffer, and probably
238 : * contains some buffered output now. Write this out to F, and reset
239 : * the buffer cursor.
240 : */
241 15 : rs_result rs_outfilebuf_drain(__attribute__ ((unused)) rs_job_t *job,
242 : rs_buffers_t *buf, void *opaque)
243 : {
244 15 : rs_filebuf_t *fb=(rs_filebuf_t *)opaque;
245 : size_t wlen;
246 :
247 : //logp("in rs_outfilebuf_drain\n");
248 :
249 : /* This is only allowed if either the buf has no output buffer
250 : * yet, or that buffer could possibly be BUF. */
251 15 : if(!buf->next_out)
252 : {
253 6 : if(buf->avail_out)
254 : {
255 1 : logp("buf->avail_out is %lu in %s\n",
256 : (unsigned long)buf->avail_out, __func__);
257 1 : return RS_IO_ERROR;
258 : }
259 5 : buf->next_out = fb->buf;
260 5 : buf->avail_out = fb->buf_len;
261 5 : return RS_DONE;
262 : }
263 :
264 9 : if(buf->avail_out > fb->buf_len)
265 : {
266 1 : logp("buf->avail_out > fb->buf_len (%lu > %lu) in %s\n",
267 : (unsigned long)buf->avail_out,
268 : (unsigned long)fb->buf_len, __func__);
269 1 : return RS_IO_ERROR;
270 : }
271 8 : if(buf->next_out < fb->buf)
272 : {
273 1 : logp("buf->next_out < fb->buf (%p < %p) in %s\n",
274 : buf->next_out, fb->buf, __func__);
275 1 : return RS_IO_ERROR;
276 : }
277 7 : if(buf->next_out > fb->buf + fb->buf_len)
278 : {
279 1 : logp("buf->next_out > fb->buf + fb->buf_len in %s\n",
280 : __func__);
281 1 : return RS_IO_ERROR;
282 : }
283 :
284 6 : if((wlen=buf->next_out-fb->buf)>0)
285 : {
286 : //logp("wlen: %d\n", wlen);
287 6 : if(fb->asfd)
288 : {
289 6 : size_t w=wlen;
290 : struct iobuf wbuf;
291 6 : iobuf_set(&wbuf, CMD_APPEND, fb->buf, wlen);
292 6 : switch(fb->asfd->append_all_to_write_buffer(
293 : fb->asfd, &wbuf))
294 : {
295 : case APPEND_OK: break;
296 0 : case APPEND_BLOCKED: return RS_BLOCKED;
297 : case APPEND_ERROR:
298 0 : default: return RS_IO_ERROR;
299 : }
300 6 : fb->bytes+=w;
301 : }
302 : else
303 : {
304 0 : size_t result=0;
305 0 : result=fzp_write(fb->fzp, fb->buf, wlen);
306 0 : if(wlen!=result)
307 : {
308 0 : logp("error draining buf to file: %s",
309 0 : strerror(errno));
310 0 : return RS_IO_ERROR;
311 : }
312 : }
313 : }
314 :
315 6 : buf->next_out = fb->buf;
316 6 : buf->avail_out = fb->buf_len;
317 :
318 6 : return RS_DONE;
319 : }
320 :
321 14 : static rs_result rs_async_drive(rs_job_t *job, rs_buffers_t *rsbuf,
322 : rs_driven_cb in_cb, void *in_opaque,
323 : rs_driven_cb out_cb, void *out_opaque)
324 : {
325 : rs_result result;
326 : rs_result iores;
327 :
328 14 : if(!rsbuf->eof_in && in_cb)
329 : {
330 8 : iores=in_cb(job, rsbuf, in_opaque);
331 8 : if(iores!=RS_DONE) return iores;
332 : }
333 :
334 14 : result=rs_job_iter(job, rsbuf);
335 14 : if(result!=RS_DONE && result!=RS_BLOCKED)
336 : return result;
337 :
338 14 : if(out_cb)
339 : {
340 10 : iores=(out_cb)(job, rsbuf, out_opaque);
341 10 : if(iores!=RS_DONE) return iores;
342 : }
343 :
344 14 : return result;
345 : }
346 :
347 14 : rs_result rs_async(rs_job_t *job, rs_buffers_t *rsbuf,
348 : rs_filebuf_t *infb, rs_filebuf_t *outfb)
349 : {
350 14 : return rs_async_drive(job, rsbuf,
351 : infb ? rs_infilebuf_fill : NULL, infb,
352 : outfb ? rs_outfilebuf_drain : NULL, outfb);
353 : }
354 :
355 0 : static rs_result rs_whole_gzrun(
356 : rs_job_t *job, struct fzp *in_file, struct fzp *out_file)
357 : {
358 : rs_buffers_t buf;
359 : rs_result result;
360 0 : rs_filebuf_t *in_fb=NULL;
361 0 : rs_filebuf_t *out_fb=NULL;
362 :
363 0 : if(in_file)
364 0 : in_fb=rs_filebuf_new(NULL,
365 : in_file, NULL, ASYNC_BUF_LEN, -1);
366 0 : if(out_file)
367 0 : out_fb=rs_filebuf_new(NULL,
368 : out_file, NULL, ASYNC_BUF_LEN, -1);
369 :
370 0 : result=rs_job_drive(job, &buf,
371 0 : in_fb ? rs_infilebuf_fill : NULL, in_fb,
372 0 : out_fb ? rs_outfilebuf_drain : NULL, out_fb);
373 :
374 0 : rs_filebuf_free(&in_fb);
375 0 : rs_filebuf_free(&out_fb);
376 0 : return result;
377 : }
378 :
379 0 : rs_result rs_patch_gzfile(struct fzp *basis_file,
380 : struct fzp *delta_file, struct fzp *new_file)
381 : {
382 : rs_job_t *job;
383 : rs_result r;
384 :
385 : // FIX THIS: Seems wrong to just pick out basis_file->fp.
386 : // Should probably pass a fp into rs_patch_gzfile.
387 : // Or, much better would be to investigate whether basis_file always
388 : // needs to be a FILE *. If I copy rs_file_copy_cb from librsync, and
389 : // rewrite it to use a struct fzp, maybe the callers to rs_patch_gzfile
390 : // do not need to mess around inflating files when they do not have
391 : // to.
392 0 : job=rs_patch_begin(rs_file_copy_cb, basis_file->fp);
393 0 : r=rs_whole_gzrun(job, delta_file, new_file);
394 0 : rs_job_free(job);
395 :
396 0 : return r;
397 : }
398 :
399 0 : rs_result rs_sig_gzfile(struct fzp *old_file, struct fzp *sig_file,
400 : size_t new_block_len, size_t strong_len,
401 : struct conf **confs)
402 : {
403 : rs_job_t *job;
404 : rs_result r;
405 0 : job=
406 : rs_sig_begin(new_block_len, strong_len
407 : #ifndef RS_DEFAULT_STRONG_LEN
408 : , rshash_to_magic_number(
409 : get_e_rshash(confs[OPT_RSHASH]))
410 : #endif
411 : );
412 :
413 0 : r=rs_whole_gzrun(job, old_file, sig_file);
414 0 : rs_job_free(job);
415 :
416 0 : return r;
417 : }
418 :
419 0 : rs_result rs_delta_gzfile(rs_signature_t *sig, struct fzp *new_file,
420 : struct fzp *delta_file)
421 : {
422 : rs_job_t *job;
423 : rs_result r;
424 :
425 0 : job=rs_delta_begin(sig);
426 0 : r=rs_whole_gzrun(job, new_file, delta_file);
427 0 : rs_job_free(job);
428 :
429 0 : return r;
430 : }
431 :
432 : #ifndef RS_DEFAULT_STRONG_LEN
433 : rs_magic_number rshash_to_magic_number(enum rshash r)
434 : {
435 : switch(r)
436 : {
437 : case RSHASH_BLAKE2: return RS_BLAKE2_SIG_MAGIC;
438 : default: return RS_MD4_SIG_MAGIC;
439 : }
440 : }
441 : #endif
442 :
443 0 : rs_result rs_loadsig_fzp(struct fzp *fzp, rs_signature_t **sig)
444 : {
445 : rs_result r;
446 : rs_job_t *job;
447 :
448 0 : job=rs_loadsig_begin(sig);
449 0 : r=rs_whole_gzrun(job, fzp, NULL);
450 0 : rs_job_free(job);
451 :
452 0 : return r;
453 : }
|