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