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