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 "../cntr.h"
43 : #include "../handy.h"
44 : #include "../iobuf.h"
45 : #include "../log.h"
46 :
47 : /* use fseeko instead of fseek for long file support if we have it */
48 : #ifdef HAVE_FSEEKO
49 : #define fseek fseeko
50 : #endif
51 :
52 0 : void *rs_alloc(size_t size)
53 : {
54 0 : return calloc_w(1, size, __func__);
55 : }
56 :
57 0 : rs_filebuf_t *rs_filebuf_new(struct asfd *asfd,
58 : BFILE *bfd, struct fzp *fzp, int fd,
59 : size_t buf_len, size_t data_len, struct cntr *cntr)
60 : {
61 0 : rs_filebuf_t *pf=NULL;
62 0 : if(!(pf=(struct rs_filebuf *)calloc_w(1,
63 0 : sizeof(struct rs_filebuf), __func__))) return NULL;
64 :
65 0 : if(!(pf->buf=(char *)calloc_w(1, buf_len, __func__)))
66 0 : goto error;
67 0 : pf->buf_len=buf_len;
68 0 : pf->fzp=fzp;
69 0 : pf->fd=fd;
70 0 : pf->bfd=bfd;
71 0 : pf->bytes=0;
72 0 : pf->data_len=data_len;
73 0 : if(data_len>0)
74 0 : pf->do_known_byte_count=1;
75 : else
76 0 : pf->do_known_byte_count=0;
77 0 : pf->cntr=cntr;
78 0 : if(!MD5_Init(&(pf->md5)))
79 : {
80 0 : logp("MD5_Init() failed\n");
81 0 : goto error;
82 : }
83 0 : pf->asfd=asfd;
84 0 : return pf;
85 : error:
86 0 : rs_filebuf_free(&pf);
87 0 : return NULL;
88 : }
89 :
90 116666 : void rs_filebuf_free(rs_filebuf_t **fb)
91 : {
92 233332 : if(!fb || !*fb) return;
93 0 : free_w(&((*fb)->buf));
94 0 : free_v((void **)fb);
95 : }
96 :
97 : /*
98 : * If the stream has no more data available, read some from F into
99 : * BUF, and let the stream use that. On return, SEEN_EOF is true if
100 : * the end of file has passed into the stream.
101 : */
102 0 : rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf, void *opaque)
103 : {
104 0 : int len=0;
105 0 : rs_filebuf_t *fb=(rs_filebuf_t *) opaque;
106 : struct cntr *cntr;
107 0 : int fd=fb->fd;
108 0 : cntr=fb->cntr;
109 :
110 : //logp("rs_infilebuf_fill\n");
111 :
112 : /* This is only allowed if either the buf has no input buffer
113 : * yet, or that buffer could possibly be BUF. */
114 0 : if(buf->next_in)
115 : {
116 : //logp("infilebuf avail_in %d buf_len %d\n",
117 : // buf->avail_in, fb->buf_len);
118 0 : if(buf->avail_in > fb->buf_len)
119 : {
120 : logp("buf->avail_in > fb->buf_len (%d > %d) in %s\n",
121 0 : buf->avail_in, fb->buf_len, __func__);
122 0 : return RS_IO_ERROR;
123 : }
124 0 : if(buf->next_in < fb->buf)
125 : {
126 0 : logp("buf->next_in < fb->buf in %s\n", __func__);
127 0 : return RS_IO_ERROR;
128 : }
129 0 : if(buf->next_in > fb->buf + fb->buf_len)
130 : {
131 : logp("buf->next_in > fb->buf + fb->buf_len in %s\n",
132 0 : __func__);
133 0 : return RS_IO_ERROR;
134 : }
135 : }
136 : else
137 : {
138 0 : if(buf->avail_in)
139 : {
140 : logp("buf->avail_in is %d in %s\n",
141 0 : buf->avail_in, __func__);
142 0 : return RS_IO_ERROR;
143 : }
144 : }
145 :
146 0 : if(buf->eof_in) return RS_DONE;
147 :
148 0 : if(buf->avail_in)
149 : /* Still some data remaining. Perhaps we should read
150 : anyhow? */
151 0 : return RS_DONE;
152 :
153 0 : if(fd>=0)
154 : {
155 : static struct iobuf *rbuf=NULL;
156 0 : rbuf=fb->asfd->rbuf;
157 :
158 0 : if(fb->asfd->read(fb->asfd)) return RS_IO_ERROR;
159 0 : if(rbuf->cmd==CMD_APPEND)
160 : {
161 : //logp("got '%c' in fd infilebuf: %d\n",
162 : // CMD_APPEND, rbuf->len);
163 0 : memcpy(fb->buf, rbuf->buf, rbuf->len);
164 0 : len=rbuf->len;
165 0 : iobuf_free_content(rbuf);
166 : }
167 0 : else if(rbuf->cmd==CMD_END_FILE)
168 : {
169 0 : iobuf_free_content(rbuf);
170 : //logp("got %c in fd infilebuf\n", CMD_END_FILE);
171 0 : buf->eof_in=1;
172 0 : return RS_DONE;
173 : }
174 0 : else if(rbuf->cmd==CMD_WARNING)
175 : {
176 0 : logp("WARNING: %s\n", rbuf->buf);
177 0 : cntr_add(cntr, rbuf->cmd, 0);
178 0 : iobuf_free_content(rbuf);
179 0 : return RS_DONE;
180 : }
181 : else
182 : {
183 0 : iobuf_log_unexpected(rbuf, __func__);
184 0 : iobuf_free_content(rbuf);
185 0 : return RS_IO_ERROR;
186 : }
187 : }
188 0 : else if(fb->bfd)
189 : {
190 0 : if(fb->do_known_byte_count)
191 : {
192 0 : if(fb->data_len>0)
193 : {
194 : len=fb->bfd->read(fb->bfd, fb->buf,
195 0 : min(fb->buf_len, fb->data_len));
196 0 : fb->data_len-=len;
197 : }
198 : else
199 : {
200 : // We have already read as much data as the VSS
201 : // header told us to, so set len=0 in order to
202 : // finish up.
203 0 : len=0;
204 : }
205 : }
206 : else
207 0 : len=fb->bfd->read(fb->bfd, fb->buf, fb->buf_len);
208 0 : if(len==0)
209 : {
210 : //logp("bread: eof\n");
211 0 : buf->eof_in=1;
212 0 : return RS_DONE;
213 : }
214 0 : else if(len<0)
215 : {
216 0 : logp("rs_infilebuf_fill: error in bread\n");
217 0 : return RS_IO_ERROR;
218 : }
219 : //logp("bread: ok: %d\n", len);
220 0 : fb->bytes+=len;
221 0 : if(!MD5_Update(&(fb->md5), fb->buf, len))
222 : {
223 0 : logp("rs_infilebuf_fill: MD5_Update() failed\n");
224 0 : return RS_IO_ERROR;
225 : }
226 : }
227 0 : else if(fb->fzp)
228 : {
229 0 : if((len=fzp_read(fb->fzp, fb->buf, fb->buf_len))<=0)
230 : {
231 : // This will happen if file size is a multiple of
232 : // input block len.
233 0 : if(fzp_eof(fb->fzp))
234 : {
235 0 : buf->eof_in=1;
236 0 : return RS_DONE;
237 : }
238 : else
239 : {
240 0 : logp("rs_infilebuf_fill: got return %d when trying to read\n", len);
241 0 : return RS_IO_ERROR;
242 : }
243 : }
244 0 : fb->bytes+=len;
245 0 : if(!MD5_Update(&(fb->md5), fb->buf, len))
246 : {
247 0 : logp("rs_infilebuf_fill: MD5_Update() failed\n");
248 0 : return RS_IO_ERROR;
249 : }
250 : }
251 :
252 0 : buf->avail_in = len;
253 0 : buf->next_in = fb->buf;
254 :
255 0 : return RS_DONE;
256 : }
257 :
258 : /*
259 : * The buf is already using BUF for an output buffer, and probably
260 : * contains some buffered output now. Write this out to F, and reset
261 : * the buffer cursor.
262 : */
263 0 : rs_result rs_outfilebuf_drain(rs_job_t *job, rs_buffers_t *buf, void *opaque)
264 : {
265 0 : rs_filebuf_t *fb=(rs_filebuf_t *)opaque;
266 0 : int fd=fb->fd;
267 : size_t wlen;
268 :
269 : //logp("in rs_outfilebuf_drain\n");
270 :
271 : /* This is only allowed if either the buf has no output buffer
272 : * yet, or that buffer could possibly be BUF. */
273 0 : if(!buf->next_out)
274 : {
275 0 : if(buf->avail_out)
276 : {
277 : logp("buf->avail_out is %d in %s\n",
278 0 : buf->avail_out, __func__);
279 0 : return RS_IO_ERROR;
280 : }
281 0 : buf->next_out = fb->buf;
282 0 : buf->avail_out = fb->buf_len;
283 0 : return RS_DONE;
284 : }
285 :
286 0 : if(buf->avail_out > fb->buf_len)
287 : {
288 : logp("buf->avail_out > fb->buf_len (%d > %d) in %s\n",
289 0 : buf->avail_out, fb->buf_len, __func__);
290 0 : return RS_IO_ERROR;
291 : }
292 0 : if(buf->next_out < fb->buf)
293 : {
294 : logp("buf->next_out < fb->buf (%p < %p) in %s\n",
295 0 : buf->next_out, fb->buf, __func__);
296 0 : return RS_IO_ERROR;
297 : }
298 0 : if(buf->next_out > fb->buf + fb->buf_len)
299 : {
300 : logp("buf->next_out > fb->buf + fb->buf_len in %s\n",
301 0 : __func__);
302 0 : return RS_IO_ERROR;
303 : }
304 :
305 0 : if((wlen=buf->next_out-fb->buf)>0)
306 : {
307 : //logp("wlen: %d\n", wlen);
308 0 : if(fd>0)
309 : {
310 0 : size_t w=wlen;
311 : static struct iobuf *wbuf=NULL;
312 0 : if(!wbuf && !(wbuf=iobuf_alloc())) return RS_IO_ERROR;
313 0 : wbuf->cmd=CMD_APPEND;
314 0 : wbuf->buf=fb->buf;
315 0 : wbuf->len=wlen;
316 0 : switch(fb->asfd->append_all_to_write_buffer(
317 0 : fb->asfd, wbuf))
318 : {
319 0 : case APPEND_OK: break;
320 0 : case APPEND_BLOCKED: return RS_BLOCKED;
321 : case APPEND_ERROR:
322 0 : default: return RS_IO_ERROR;
323 : }
324 0 : fb->bytes+=w;
325 : }
326 : else
327 : {
328 0 : size_t result=0;
329 0 : result=fzp_write(fb->fzp, fb->buf, wlen);
330 0 : if(wlen!=result)
331 : {
332 : logp("error draining buf to file: %s",
333 0 : strerror(errno));
334 0 : return RS_IO_ERROR;
335 : }
336 : }
337 : }
338 :
339 0 : buf->next_out = fb->buf;
340 0 : buf->avail_out = fb->buf_len;
341 :
342 0 : return RS_DONE;
343 : }
344 :
345 0 : static rs_result rs_async_drive(rs_job_t *job, rs_buffers_t *rsbuf,
346 : rs_driven_cb in_cb, void *in_opaque,
347 : rs_driven_cb out_cb, void *out_opaque)
348 : {
349 : rs_result result;
350 : rs_result iores;
351 :
352 0 : if(!rsbuf->eof_in && in_cb)
353 : {
354 0 : iores=in_cb(job, rsbuf, in_opaque);
355 0 : if(iores!=RS_DONE) return iores;
356 : }
357 :
358 0 : result=rs_job_iter(job, rsbuf);
359 0 : if(result!=RS_DONE && result!=RS_BLOCKED)
360 0 : return result;
361 :
362 0 : if(out_cb)
363 : {
364 0 : iores=(out_cb)(job, rsbuf, out_opaque);
365 0 : if(iores!=RS_DONE) return iores;
366 : }
367 :
368 0 : return result;
369 : }
370 :
371 0 : rs_result rs_async(rs_job_t *job, rs_buffers_t *rsbuf,
372 : rs_filebuf_t *infb, rs_filebuf_t *outfb)
373 : {
374 : return rs_async_drive(job, rsbuf,
375 : infb ? rs_infilebuf_fill : NULL, infb,
376 0 : outfb ? rs_outfilebuf_drain : NULL, outfb);
377 : }
378 :
379 0 : static rs_result rs_whole_gzrun(struct asfd *asfd,
380 : rs_job_t *job, struct fzp *in_file, struct fzp *out_file,
381 : struct cntr *cntr)
382 : {
383 : rs_buffers_t buf;
384 : rs_result result;
385 0 : rs_filebuf_t *in_fb=NULL;
386 0 : rs_filebuf_t *out_fb=NULL;
387 :
388 0 : if(in_file)
389 : in_fb=rs_filebuf_new(asfd, NULL,
390 0 : in_file, -1, ASYNC_BUF_LEN, -1, cntr);
391 0 : if(out_file)
392 : out_fb=rs_filebuf_new(asfd, NULL,
393 0 : out_file, -1, ASYNC_BUF_LEN, -1, cntr);
394 :
395 : result=rs_job_drive(job, &buf,
396 : in_fb ? rs_infilebuf_fill : NULL, in_fb,
397 0 : out_fb ? rs_outfilebuf_drain : NULL, out_fb);
398 :
399 0 : rs_filebuf_free(&in_fb);
400 0 : rs_filebuf_free(&out_fb);
401 0 : return result;
402 : }
403 :
404 0 : rs_result rs_patch_gzfile(struct asfd *asfd, struct fzp *basis_file,
405 : struct fzp *delta_file, struct fzp *new_file,
406 : struct cntr *cntr)
407 : {
408 : rs_job_t *job;
409 : rs_result r;
410 :
411 : // FIX THIS: Seems wrong to just pick out basis_file->fp.
412 : // Should probably pass a fp into rs_patch_gzfile.
413 : // Or, much better would be to investigate whether basis_file always
414 : // needs to be a FILE *. If I copy rs_file_copy_cb from librsync, and
415 : // rewrite it to use a struct fzp, maybe the callers to rs_patch_gzfile
416 : // do not need to mess around inflating files when they do not have
417 : // to.
418 0 : job=rs_patch_begin(rs_file_copy_cb, basis_file->fp);
419 0 : r=rs_whole_gzrun(asfd, job, delta_file, new_file, cntr);
420 0 : rs_job_free(job);
421 :
422 0 : return r;
423 : }
424 :
425 0 : rs_result rs_sig_gzfile(struct asfd *asfd,
426 : struct fzp *old_file, struct fzp *sig_file,
427 : size_t new_block_len, size_t strong_len,
428 : struct conf **confs)
429 : {
430 : rs_job_t *job;
431 : rs_result r;
432 : job=
433 : rs_sig_begin(new_block_len, strong_len
434 : #ifndef RS_DEFAULT_STRONG_LEN
435 : , rshash_to_magic_number(
436 : get_e_rshash(confs[OPT_RSHASH]))
437 : #endif
438 0 : );
439 :
440 0 : r=rs_whole_gzrun(asfd, job, old_file, sig_file, get_cntr(confs));
441 0 : rs_job_free(job);
442 :
443 0 : return r;
444 : }
445 :
446 0 : rs_result rs_delta_gzfile(struct asfd *asfd,
447 : rs_signature_t *sig, struct fzp *new_file,
448 : struct fzp *delta_file,
449 : struct cntr *cntr)
450 : {
451 : rs_job_t *job;
452 : rs_result r;
453 :
454 0 : job=rs_delta_begin(sig);
455 0 : r=rs_whole_gzrun(asfd, job, new_file, delta_file, cntr);
456 0 : rs_job_free(job);
457 :
458 0 : return r;
459 : }
460 :
461 : #ifndef RS_DEFAULT_STRONG_LEN
462 : rs_magic_number rshash_to_magic_number(enum rshash r)
463 : {
464 : switch(r)
465 : {
466 : case RSHASH_BLAKE2: return RS_BLAKE2_SIG_MAGIC;
467 : default: return RS_MD4_SIG_MAGIC;
468 : }
469 : }
470 : #endif
471 :
472 0 : rs_result rs_loadsig_fzp(struct fzp *fzp,
473 : rs_signature_t **sig, rs_stats_t *stats)
474 : {
475 0 : return rs_loadsig_file(fzp->fp, sig, stats);
476 : }
477 :
478 0 : rs_result rs_loadsig_network_run(struct asfd *asfd,
479 : rs_job_t *job, struct cntr *cntr)
480 : {
481 : rs_buffers_t buf;
482 : rs_result result;
483 0 : rs_filebuf_t *in_fb=NULL;
484 :
485 0 : if(!(in_fb=rs_filebuf_new(asfd, NULL,
486 0 : NULL, asfd->fd, ASYNC_BUF_LEN, -1, cntr)))
487 : {
488 0 : result=RS_MEM_ERROR;
489 0 : goto end;
490 : }
491 :
492 0 : result=rs_job_drive(job, &buf, rs_infilebuf_fill, in_fb, NULL, NULL);
493 :
494 : end:
495 0 : rs_filebuf_free(&in_fb);
496 0 : return result;
497 : }
|