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