librsync  2.3.4
patch.c
Go to the documentation of this file.
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 /** \file patch.c
27  * Apply a delta to an old file to generate a new file. */
28 
29 #include "config.h" /* IWYU pragma: keep */
30 #include <assert.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdint.h>
34 #include "librsync.h"
35 #include "job.h"
36 #include "netint.h"
37 #include "scoop.h"
38 #include "command.h"
39 #include "prototab.h"
40 #include "trace.h"
41 
46 static rs_result rs_patch_s_copy(rs_job_t *);
48 
49 /** State of trying to read the first byte of a command. Once we've taken that
50  * in, we can know how much data to read to get the arguments. */
52 {
53  rs_result result;
54 
55  if ((result = rs_suck_byte(job, &job->op)) != RS_DONE)
56  return result;
57  job->cmd = &rs_prototab[job->op];
58  rs_trace("got command %#04x (%s), len_1=%d, len_2=%d", job->op,
59  rs_op_kind_name(job->cmd->kind), job->cmd->len_1, job->cmd->len_2);
60  if (job->cmd->len_1)
62  else {
63  job->param1 = job->cmd->immediate;
64  job->statefn = rs_patch_s_run;
65  }
66  return RS_RUNNING;
67 }
68 
69 /** Called after reading a command byte to pull in its parameters and then
70  * setup to execute the command. */
72 {
73  rs_result result;
74  const size_t len = (size_t)(job->cmd->len_1 + job->cmd->len_2);
75  void *p;
76 
77  assert(len);
78  result = rs_scoop_readahead(job, len, &p);
79  if (result != RS_DONE)
80  return result;
81  /* we now must have LEN bytes buffered */
82  result = rs_suck_netint(job, &job->param1, job->cmd->len_1);
83  /* shouldn't fail, since we already checked */
84  assert(result == RS_DONE);
85  if (job->cmd->len_2) {
86  result = rs_suck_netint(job, &job->param2, job->cmd->len_2);
87  assert(result == RS_DONE);
88  }
89  job->statefn = rs_patch_s_run;
90  return RS_RUNNING;
91 }
92 
93 /** Called when we've read in the whole command and we need to execute it. */
95 {
96  rs_trace("running command %#04x", job->op);
97  switch (job->cmd->kind) {
98  case RS_KIND_LITERAL:
100  return RS_RUNNING;
101  case RS_KIND_END:
102  return RS_DONE;
103  /* so we exit here; trying to continue causes an error */
104  case RS_KIND_COPY:
105  job->statefn = rs_patch_s_copy;
106  return RS_RUNNING;
107  default:
108  rs_error("bogus command %#04x", job->op);
109  return RS_CORRUPT;
110  }
111 }
112 
113 /** Called when trying to copy through literal data. */
115 {
116  const rs_long_t len = job->param1;
117  rs_stats_t *stats = &job->stats;
118 
119  rs_trace("LITERAL(length=" FMT_LONG ")", len);
120  if (len <= 0 || len > SIZE_MAX) {
121  rs_error("invalid length=" FMT_LONG " on LITERAL command", len);
122  return RS_CORRUPT;
123  }
124  stats->lit_cmds++;
125  stats->lit_bytes += len;
126  stats->lit_cmdbytes += 1 + job->cmd->len_1;
127  rs_tube_copy(job, (size_t)len);
129  return RS_RUNNING;
130 }
131 
132 static rs_result rs_patch_s_copy(rs_job_t *job)
133 {
134  const rs_long_t pos = job->param1;
135  const rs_long_t len = job->param2;
136  rs_stats_t *stats = &job->stats;
137 
138  rs_trace("COPY(position=" FMT_LONG ", length=" FMT_LONG ")", pos, len);
139  if (len <= 0) {
140  rs_error("invalid length=" FMT_LONG " on COPY command", len);
141  return RS_CORRUPT;
142  }
143  if (pos < 0) {
144  rs_error("invalid position=" FMT_LONG " on COPY command", pos);
145  return RS_CORRUPT;
146  }
147  stats->copy_cmds++;
148  stats->copy_bytes += len;
149  stats->copy_cmdbytes += 1 + job->cmd->len_1 + job->cmd->len_2;
150  job->basis_pos = pos;
151  job->basis_len = len;
153  return RS_RUNNING;
154 }
155 
156 /** Called when we're executing a COPY command and waiting for all the data to
157  * be retrieved from the callback. */
159 {
160  rs_result result;
161  rs_buffers_t *buffs = job->stream;
162  rs_long_t req = job->basis_len;
163  size_t len = buffs->avail_out;
164  void *ptr = buffs->next_out;
165 
166  /* We are blocked if there is no space left to copy into. */
167  if (!len)
168  return RS_BLOCKED;
169  /* Adjust request to min of amount requested and space available. */
170  if ((rs_long_t)len < req)
171  req = (rs_long_t)len;
172  rs_trace("copy " FMT_LONG " bytes from basis at offset " FMT_LONG "", req,
173  job->basis_pos);
174  len = (size_t)req;
175  result = (job->copy_cb) (job->copy_arg, job->basis_pos, &len, &ptr);
176  if (result != RS_DONE) {
177  rs_trace("copy callback returned %s", rs_strerror(result));
178  return result;
179  }
180  rs_trace("got " FMT_SIZE " bytes back from basis callback", len);
181  /* Actual copied length cannot be greater than requested length. */
182  assert(len <= req);
183  /* Backwards-compatible defensively handle this for NDEBUG builds. */
184  if ((rs_long_t)len > req) {
185  rs_warn("copy_cb() returned more than the requested length");
186  len = (size_t)req;
187  }
188  /* copy back to out buffer only if the callback has used its own buffer */
189  if (ptr != buffs->next_out)
190  memcpy(buffs->next_out, ptr, len);
191  /* Update buffs and copy for copied data. */
192  buffs->next_out += len;
193  buffs->avail_out -= len;
194  job->basis_pos += (rs_long_t)len;
195  job->basis_len -= (rs_long_t)len;
196  if (!job->basis_len) {
197  /* Nothing left to copy, we are done! */
199  }
200  return RS_RUNNING;
201 }
202 
203 /** Called while we're trying to read the header of the patch. */
205 {
206  int v;
207  rs_result result;
208 
209  if ((result = rs_suck_n4(job, &v)) != RS_DONE)
210  return result;
211  if (v != RS_DELTA_MAGIC) {
212  rs_error("got magic number %#x rather than expected value %#x", v,
214  return RS_BAD_MAGIC;
215  } else
216  rs_trace("got patch magic %#x", v);
218  return RS_RUNNING;
219 }
220 
221 rs_job_t *rs_patch_begin(rs_copy_cb * copy_cb, void *copy_arg)
222 {
223  rs_job_t *job = rs_job_new("patch", rs_patch_s_header);
224 
225  job->copy_cb = copy_cb;
226  job->copy_arg = copy_arg;
227  rs_mdfour_begin(&job->output_md4);
228  return job;
229 }
void rs_tube_copy(rs_job_t *job, size_t len)
Queue up a request to copy through len bytes from the input to the output of the stream.
Definition: tube.c:160
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:221
Description of input and output buffers.
Definition: librsync.h:328
rs_copy_cb * copy_cb
Callback used to copy data from the basis into the output.
Definition: job.h:120
logging functions.
rs_long_t lit_cmdbytes
Number of bytes used in literal command headers.
Definition: librsync.h:215
Types of commands present in the encoding stream.
static rs_result rs_patch_s_cmdbyte(rs_job_t *)
State of trying to read the first byte of a command.
Definition: patch.c:51
static rs_result rs_patch_s_literal(rs_job_t *)
Called when trying to copy through literal data.
Definition: patch.c:114
Bad magic number at start of stream.
Definition: librsync.h:193
unsigned char op
Command byte currently being processed, if any.
Definition: job.h:78
size_t avail_out
Remaining free space at next_out.
Definition: librsync.h:357
Unbelievable value in stream.
Definition: librsync.h:198
rs_long_t param1
Lengths of expected parameters.
Definition: job.h:87
static rs_result rs_patch_s_params(rs_job_t *)
Called after reading a command byte to pull in its parameters and then setup to execute the command...
Definition: patch.c:71
LIBRSYNC_EXPORT char const * rs_strerror(rs_result r)
Return an English description of a rs_result value.
Definition: msg.c:46
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:502
char * next_out
Next output byte should be put there.
Definition: librsync.h:351
A delta file.
Definition: librsync.h:71
static rs_result rs_patch_s_copying(rs_job_t *)
Called when we&#39;re executing a COPY command and waiting for all the data to be retrieved from the call...
Definition: patch.c:158
rs_long_t basis_pos
Copy from the basis position.
Definition: job.h:117
rs_result(* statefn)(rs_job_t *)
Callback for each processing step.
Definition: job.h:56
rs_stats_t stats
Encoding statistics.
Definition: job.h:93
Public header for librsync.
int lit_cmds
Number of literal commands.
Definition: librsync.h:213
static rs_result rs_patch_s_header(rs_job_t *job)
Called while we&#39;re trying to read the header of the patch.
Definition: patch.c:204
rs_long_t lit_bytes
Number of literal bytes.
Definition: librsync.h:214
Network-byte-order output to the tube.
Performance statistics from a librsync encoding or decoding operation.
Definition: librsync.h:210
rs_result
Return codes from nonblocking rsync operations.
Definition: librsync.h:180
Generic state-machine interface.
Blocked waiting for more data.
Definition: librsync.h:182
static rs_result rs_patch_s_run(rs_job_t *)
Called when we&#39;ve read in the whole command and we need to execute it.
Definition: patch.c:94
Manage librsync streams of IO.
Delta file commands.
The job is still running, and not yet finished or blocked.
Definition: librsync.h:183
Completed successfully.
Definition: librsync.h:181
rs_result rs_scoop_readahead(rs_job_t *job, size_t len, void **ptr)
Read from scoop without advancing.
Definition: scoop.c:148
The contents of this structure are private.
Definition: job.h:47