librsync  2.0.2
patch.c
1 /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
2  *
3  * librsync -- the library for network deltas
4  *
5  * Copyright (C) 2000, 2001 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  | This is Tranquility Base.
24  */
25 
26 #include "config.h"
27 
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "librsync.h"
34 #include "util.h"
35 #include "trace.h"
36 #include "netint.h"
37 #include "command.h"
38 #include "sumset.h"
39 #include "prototab.h"
40 #include "stream.h"
41 #include "job.h"
42 
43 static rs_result rs_patch_s_cmdbyte(rs_job_t *);
44 static rs_result rs_patch_s_params(rs_job_t *);
45 static rs_result rs_patch_s_run(rs_job_t *);
46 static rs_result rs_patch_s_literal(rs_job_t *);
47 static rs_result rs_patch_s_copy(rs_job_t *);
48 static rs_result rs_patch_s_copying(rs_job_t *);
49 
50 /** State of trying to read the first byte of a command. Once we've taken that
51  * in, we can know how much data to read to get the arguments. */
52 static rs_result rs_patch_s_cmdbyte(rs_job_t *job)
53 {
54  rs_result result;
55 
56  if ((result = rs_suck_byte(job, &job->op)) != RS_DONE)
57  return result;
58 
59  job->cmd = &rs_prototab[job->op];
60 
61  rs_trace("got command %#04x (%s), len_1=" FMT_SIZE "", job->op,
62  rs_op_kind_name(job->cmd->kind), job->cmd->len_1);
63 
64  if (job->cmd->len_1)
65  job->statefn = rs_patch_s_params;
66  else {
67  job->param1 = job->cmd->immediate;
68  job->statefn = rs_patch_s_run;
69  }
70 
71  return RS_RUNNING;
72 }
73 
74 /** Called after reading a command byte to pull in its parameters and then
75  * setup to execute the command. */
76 static rs_result rs_patch_s_params(rs_job_t *job)
77 {
78  rs_result result;
79  int len = job->cmd->len_1 + job->cmd->len_2;
80  void *p;
81 
82  assert(len);
83 
84  result = rs_scoop_readahead(job, len, &p);
85  if (result != RS_DONE)
86  return result;
87 
88  /* we now must have LEN bytes buffered */
89  result = rs_suck_netint(job, &job->param1, job->cmd->len_1);
90  /* shouldn't fail, since we already checked */
91  assert(result == RS_DONE);
92 
93  if (job->cmd->len_2) {
94  result = rs_suck_netint(job, &job->param2, job->cmd->len_2);
95  assert(result == RS_DONE);
96  }
97 
98  job->statefn = rs_patch_s_run;
99 
100  return RS_RUNNING;
101 }
102 
103 /** Called when we've read in the whole command and we need to execute it. */
104 static rs_result rs_patch_s_run(rs_job_t *job)
105 {
106  rs_trace("running command %#04x", job->op);
107 
108  switch (job->cmd->kind) {
109  case RS_KIND_LITERAL:
110  job->statefn = rs_patch_s_literal;
111  return RS_RUNNING;
112 
113  case RS_KIND_END:
114  return RS_DONE;
115  /* so we exit here; trying to continue causes an error */
116 
117  case RS_KIND_COPY:
118  job->statefn = rs_patch_s_copy;
119  return RS_RUNNING;
120 
121  default:
122  rs_error("bogus command %#04x", job->op);
123  return RS_CORRUPT;
124  }
125 }
126 
127 /** Called when trying to copy through literal data. */
128 static rs_result rs_patch_s_literal(rs_job_t *job)
129 {
130  rs_long_t len = job->param1;
131 
132  rs_trace("LITERAL(len=" FMT_LONG ")", len);
133 
134  if (len < 0) {
135  rs_error("invalid length=" FMT_LONG " on LITERAL command", len);
136  return RS_CORRUPT;
137  }
138 
139  job->stats.lit_cmds++;
140  job->stats.lit_bytes += len;
141  job->stats.lit_cmdbytes += 1 + job->cmd->len_1;
142 
143  rs_tube_copy(job, len);
144 
145  job->statefn = rs_patch_s_cmdbyte;
146  return RS_RUNNING;
147 }
148 
149 static rs_result rs_patch_s_copy(rs_job_t *job)
150 {
151  rs_long_t where, len;
152  rs_stats_t *stats;
153 
154  where = job->param1;
155  len = job->param2;
156 
157  rs_trace("COPY(where=" FMT_LONG ", len=" FMT_LONG ")", where, len);
158 
159  if (len < 0) {
160  rs_error("invalid length=" FMT_LONG " on COPY command", len);
161  return RS_CORRUPT;
162  }
163 
164  if (where < 0) {
165  rs_error("invalid where=" FMT_LONG " on COPY command", where);
166  return RS_CORRUPT;
167  }
168 
169  job->basis_pos = where;
170  job->basis_len = len;
171 
172  stats = &job->stats;
173 
174  stats->copy_cmds++;
175  stats->copy_bytes += len;
176  stats->copy_cmdbytes += 1 + job->cmd->len_1 + job->cmd->len_2;
177 
178  job->statefn = rs_patch_s_copying;
179  return RS_RUNNING;
180 }
181 
182 /** Called when we're executing a COPY command and waiting for all the data to
183  * be retrieved from the callback. */
184 static rs_result rs_patch_s_copying(rs_job_t *job)
185 {
186  rs_result result;
187  size_t desired_len, len;
188  void *ptr;
189  rs_buffers_t *buffs = job->stream;
190 
191  /* copy only as much as will fit in the output buffer, so that we don't
192  have to block or store the input. */
193  desired_len = len =
194  (buffs->avail_out < job->basis_len) ? buffs->avail_out : job->basis_len;
195 
196  if (!len)
197  return RS_BLOCKED;
198 
199  rs_trace("copy " FMT_SIZE " bytes from basis at offset " FMT_LONG "", len,
200  job->basis_pos);
201 
202  ptr = buffs->next_out;
203 
204  result = (job->copy_cb) (job->copy_arg, job->basis_pos, &len, &ptr);
205  if (result != RS_DONE)
206  return result;
207  else
208  rs_trace("copy callback returned %s", rs_strerror(result));
209 
210  rs_trace("got " FMT_SIZE " bytes back from basis callback", len);
211 
212  if (len > desired_len) {
213  rs_trace("warning: copy_cb returned more than the requested length.");
214  len = desired_len;
215  }
216 
217  /* copy back to out buffer only if the callback has used its own buffer */
218  if (ptr != buffs->next_out)
219  memcpy(buffs->next_out, ptr, len);
220 
221  buffs->next_out += len;
222  buffs->avail_out -= len;
223 
224  job->basis_pos += len;
225  job->basis_len -= len;
226 
227  if (!job->basis_len) {
228  /* Done! */
229  job->statefn = rs_patch_s_cmdbyte;
230  }
231 
232  return RS_RUNNING;
233 }
234 
235 /** Called while we're trying to read the header of the patch. */
236 static rs_result rs_patch_s_header(rs_job_t *job)
237 {
238  int v;
239  rs_result result;
240 
241  if ((result = rs_suck_n4(job, &v)) != RS_DONE)
242  return result;
243 
244  if (v != RS_DELTA_MAGIC) {
245  rs_error("got magic number %#x rather than expected value %#x", v,
247  return RS_BAD_MAGIC;
248  } else
249  rs_trace("got patch magic %#x", v);
250 
251  job->statefn = rs_patch_s_cmdbyte;
252 
253  return RS_RUNNING;
254 }
255 
256 rs_job_t *rs_patch_begin(rs_copy_cb * copy_cb, void *copy_arg)
257 {
258  rs_job_t *job = rs_job_new("patch", rs_patch_s_header);
259 
260  job->copy_cb = copy_cb;
261  job->copy_arg = copy_arg;
262 
263  rs_mdfour_begin(&job->output_md4);
264 
265  return job;
266 }
rs_result
rs_result
Definition: librsync.h:161
rs_op_kind_name
Definition: command.h:43
trace.h
RS_DONE
@ RS_DONE
Completed successfully.
Definition: librsync.h:162
rs_job::param1
rs_long_t param1
Lengths of expected parameters.
Definition: job.h:66
rs_job::statefn
rs_result(* statefn)(rs_job_t *)
Callback for each processing step.
Definition: job.h:35
rs_job::basis_pos
rs_long_t basis_pos
Copy from the basis position.
Definition: job.h:92
librsync.h
rs_job::op
unsigned char op
Command byte currently being processed, if any.
Definition: job.h:57
rs_job
Definition: job.h:26
rs_strerror
const char * rs_strerror(rs_result r)
Return an English description of a rs_result value.
Definition: msg.c:49
RS_RUNNING
@ RS_RUNNING
The job is still running, and not yet finished or blocked.
Definition: librsync.h:164
command.h
RS_DELTA_MAGIC
@ RS_DELTA_MAGIC
A delta file.
Definition: librsync.h:74
rs_stats::lit_cmds
int lit_cmds
Number of literal commands.
Definition: librsync.h:194
rs_job::stats
rs_stats_t stats
Encoding statistics.
Definition: job.h:72
rs_stats::lit_bytes
rs_long_t lit_bytes
Number of literal bytes.
Definition: librsync.h:195
RS_CORRUPT
@ RS_CORRUPT
Unbelievable value in stream.
Definition: librsync.h:179
rs_patch_begin
rs_job_t * rs_patch_begin(rs_copy_cb *copy_cb, void *copy_arg)
Apply a delta to a basis file to recreate the new file.
Definition: patch.c:256
RS_BLOCKED
@ RS_BLOCKED
Blocked waiting for more data.
Definition: librsync.h:163
rs_scoop_readahead
rs_result rs_scoop_readahead(rs_job_t *job, size_t len, void **ptr)
Read from scoop without advancing.
Definition: scoop.c:150
rs_buffers_s::next_out
char * next_out
Next output byte should be put there.
Definition: librsync.h:323
rs_buffers_s::avail_out
size_t avail_out
Remaining free space at next_out.
Definition: librsync.h:329
rs_copy_cb
rs_result rs_copy_cb(void *opaque, rs_long_t pos, size_t *len, void **buf)
Callback used to retrieve parts of the basis file.
Definition: librsync.h:430
prototab.h
rs_stats
Performance statistics from a librsync encoding or decoding operation.
Definition: librsync.h:191
RS_BAD_MAGIC
@ RS_BAD_MAGIC
Bad magic number at start of stream.
Definition: librsync.h:174
rs_job::copy_cb
rs_copy_cb * copy_cb
Callback used to copy data from the basis into the output.
Definition: job.h:95
rs_stats::lit_cmdbytes
rs_long_t lit_cmdbytes
Number of bytes used in literal command headers.
Definition: librsync.h:196
rs_tube_copy
void rs_tube_copy(rs_job_t *job, int len)
Queue up a request to copy through len bytes from the input to the output of the stream.
Definition: tube.c:197
rs_buffers_s
Description of input and output buffers.
Definition: librsync.h:300