1 /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
2  *
3  * librsync -- the library for network deltas
4  *
5  * Copyright 2000, 2001, 2014, 2015 by Martin Pool <mbp@sourcefrog.net>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 
22                               /*=
23                                | Is it possible that software is not
24                                | like anything else, that it is meant
25                                | to be discarded: that the whole point
26                                | is to always see it as a soap bubble?
27                                |        -- Alan Perlis
28                                */
29 
30 #include "config.h"
31 #include <assert.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include "librsync.h"
36 #include "whole.h"
37 #include "sumset.h"
38 #include "job.h"
39 #include "buf.h"
40 
41 /** Whole file IO buffer sizes. */
42 LIBRSYNC_EXPORT int rs_inbuflen = 0, rs_outbuflen = 0;
43 
44 /** Run a job continuously, with input to/from the two specified files.
45  *
46  * The job should already be set up, and must be freed by the caller after
47  * return. If rs_inbuflen or rs_outbuflen are set, they will override the
48  * inbuflen and outbuflen arguments.
49  *
50  * \param in_file - input file, or NULL if there is no input.
51  *
52  * \param out_file - output file, or NULL if there is no output.
53  *
54  * \param inbuflen - recommended input buffer size to use.
55  *
56  * \param outbuflen - recommended output buffer size to use.
57  *
58  * \return RS_DONE if the job completed, or otherwise an error result. */
rs_whole_run(rs_job_t * job,FILE * in_file,FILE * out_file,int inbuflen,int outbuflen)59 rs_result rs_whole_run(rs_job_t *job, FILE *in_file, FILE *out_file,
60                        int inbuflen, int outbuflen)
61 {
62     rs_buffers_t buf;
63     rs_result result;
64     rs_filebuf_t *in_fb = NULL, *out_fb = NULL;
65 
66     /* Override buffer sizes if rs_inbuflen or rs_outbuflen are set. */
67     inbuflen = rs_inbuflen ? rs_inbuflen : inbuflen;
68     outbuflen = rs_outbuflen ? rs_outbuflen : outbuflen;
69     if (in_file)
70         in_fb = rs_filebuf_new(in_file, inbuflen);
71     if (out_file)
72         out_fb = rs_filebuf_new(out_file, outbuflen);
73     result =
74         rs_job_drive(job, &buf, in_fb ? rs_infilebuf_fill : NULL, in_fb,
75                      out_fb ? rs_outfilebuf_drain : NULL, out_fb);
76     if (in_fb)
77         rs_filebuf_free(in_fb);
78     if (out_fb)
79         rs_filebuf_free(out_fb);
80     return result;
81 }
82 
rs_sig_file(FILE * old_file,FILE * sig_file,size_t block_len,size_t strong_len,rs_magic_number sig_magic,rs_stats_t * stats)83 rs_result rs_sig_file(FILE *old_file, FILE *sig_file, size_t block_len,
84                       size_t strong_len, rs_magic_number sig_magic,
85                       rs_stats_t *stats)
86 {
87     rs_job_t *job;
88     rs_result r;
89     rs_long_t old_fsize = rs_file_size(old_file);
90 
91     if ((r =
92          rs_sig_args(old_fsize, &sig_magic, &block_len,
93                      &strong_len)) != RS_DONE)
94         return r;
95     job = rs_sig_begin(block_len, strong_len, sig_magic);
96     /* Size inbuf for 4 blocks, outbuf for header + 4 blocksums. */
97     r = rs_whole_run(job, old_file, sig_file, 4 * (int)block_len,
98                      12 + 4 * (4 + (int)strong_len));
99     if (stats)
100         memcpy(stats, &job->stats, sizeof *stats);
101     rs_job_free(job);
102 
103     return r;
104 }
105 
rs_loadsig_file(FILE * sig_file,rs_signature_t ** sumset,rs_stats_t * stats)106 rs_result rs_loadsig_file(FILE *sig_file, rs_signature_t **sumset,
107                           rs_stats_t *stats)
108 {
109     rs_job_t *job;
110     rs_result r;
111 
112     job = rs_loadsig_begin(sumset);
113     /* Set filesize used to estimate signature size. */
114     job->sig_fsize = rs_file_size(sig_file);
115     /* Size inbuf for 1024x 16 byte blocksums. */
116     r = rs_whole_run(job, sig_file, NULL, 1024 * 16, 0);
117     if (stats)
118         memcpy(stats, &job->stats, sizeof *stats);
119     rs_job_free(job);
120 
121     return r;
122 }
123 
rs_delta_file(rs_signature_t * sig,FILE * new_file,FILE * delta_file,rs_stats_t * stats)124 rs_result rs_delta_file(rs_signature_t *sig, FILE *new_file, FILE *delta_file,
125                         rs_stats_t *stats)
126 {
127     rs_job_t *job;
128     rs_result r;
129 
130     job = rs_delta_begin(sig);
131     /* Size inbuf for 1 block, outbuf for literal cmd + 4 blocks. */
132     r = rs_whole_run(job, new_file, delta_file, sig->block_len,
133                      10 + 4 * sig->block_len);
134     if (stats)
135         memcpy(stats, &job->stats, sizeof *stats);
136     rs_job_free(job);
137     return r;
138 }
139 
rs_patch_file(FILE * basis_file,FILE * delta_file,FILE * new_file,rs_stats_t * stats)140 rs_result rs_patch_file(FILE *basis_file, FILE *delta_file, FILE *new_file,
141                         rs_stats_t *stats)
142 {
143     rs_job_t *job;
144     rs_result r;
145 
146     job = rs_patch_begin(rs_file_copy_cb, basis_file);
147     /* Default size inbuf and outbuf 64K. */
148     r = rs_whole_run(job, delta_file, new_file, 64 * 1024, 64 * 1024);
149     if (stats)
150         memcpy(stats, &job->stats, sizeof *stats);
151     rs_job_free(job);
152     return r;
153 }
154