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