$treeview $search $mathjax $extrastylesheet
librsync
2.3.1
$projectbrief
|
$projectbrief
|
$searchbox |
00001 /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- 00002 * 00003 * librsync -- the library for network deltas 00004 * 00005 * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net> 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public License 00009 * as published by the Free Software Foundation; either version 2.1 of 00010 * the License, or (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, but 00013 * WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this program; if not, write to the Free Software 00019 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00020 */ 00021 00022 /*= 00023 | This is Tranquility Base. 00024 */ 00025 00026 #include "config.h" 00027 #include <assert.h> 00028 #include <stdlib.h> 00029 #include <string.h> 00030 #include "librsync.h" 00031 #include "job.h" 00032 #include "netint.h" 00033 #include "stream.h" 00034 #include "command.h" 00035 #include "prototab.h" 00036 #include "trace.h" 00037 00038 static rs_result rs_patch_s_cmdbyte(rs_job_t *); 00039 static rs_result rs_patch_s_params(rs_job_t *); 00040 static rs_result rs_patch_s_run(rs_job_t *); 00041 static rs_result rs_patch_s_literal(rs_job_t *); 00042 static rs_result rs_patch_s_copy(rs_job_t *); 00043 static rs_result rs_patch_s_copying(rs_job_t *); 00044 00045 /** State of trying to read the first byte of a command. Once we've taken that 00046 * in, we can know how much data to read to get the arguments. */ 00047 static rs_result rs_patch_s_cmdbyte(rs_job_t *job) 00048 { 00049 rs_result result; 00050 00051 if ((result = rs_suck_byte(job, &job->op)) != RS_DONE) 00052 return result; 00053 00054 job->cmd = &rs_prototab[job->op]; 00055 00056 rs_trace("got command %#04x (%s), len_1=" FMT_SIZE "", job->op, 00057 rs_op_kind_name(job->cmd->kind), job->cmd->len_1); 00058 00059 if (job->cmd->len_1) 00060 job->statefn = rs_patch_s_params; 00061 else { 00062 job->param1 = job->cmd->immediate; 00063 job->statefn = rs_patch_s_run; 00064 } 00065 00066 return RS_RUNNING; 00067 } 00068 00069 /** Called after reading a command byte to pull in its parameters and then 00070 * setup to execute the command. */ 00071 static rs_result rs_patch_s_params(rs_job_t *job) 00072 { 00073 rs_result result; 00074 int len = job->cmd->len_1 + job->cmd->len_2; 00075 void *p; 00076 00077 assert(len); 00078 00079 result = rs_scoop_readahead(job, len, &p); 00080 if (result != RS_DONE) 00081 return result; 00082 00083 /* we now must have LEN bytes buffered */ 00084 result = rs_suck_netint(job, &job->param1, job->cmd->len_1); 00085 /* shouldn't fail, since we already checked */ 00086 assert(result == RS_DONE); 00087 00088 if (job->cmd->len_2) { 00089 result = rs_suck_netint(job, &job->param2, job->cmd->len_2); 00090 assert(result == RS_DONE); 00091 } 00092 00093 job->statefn = rs_patch_s_run; 00094 00095 return RS_RUNNING; 00096 } 00097 00098 /** Called when we've read in the whole command and we need to execute it. */ 00099 static rs_result rs_patch_s_run(rs_job_t *job) 00100 { 00101 rs_trace("running command %#04x", job->op); 00102 00103 switch (job->cmd->kind) { 00104 case RS_KIND_LITERAL: 00105 job->statefn = rs_patch_s_literal; 00106 return RS_RUNNING; 00107 00108 case RS_KIND_END: 00109 return RS_DONE; 00110 /* so we exit here; trying to continue causes an error */ 00111 00112 case RS_KIND_COPY: 00113 job->statefn = rs_patch_s_copy; 00114 return RS_RUNNING; 00115 00116 default: 00117 rs_error("bogus command %#04x", job->op); 00118 return RS_CORRUPT; 00119 } 00120 } 00121 00122 /** Called when trying to copy through literal data. */ 00123 static rs_result rs_patch_s_literal(rs_job_t *job) 00124 { 00125 rs_long_t len = job->param1; 00126 00127 rs_trace("LITERAL(len=" FMT_LONG ")", len); 00128 00129 if (len < 0) { 00130 rs_error("invalid length=" FMT_LONG " on LITERAL command", len); 00131 return RS_CORRUPT; 00132 } 00133 00134 job->stats.lit_cmds++; 00135 job->stats.lit_bytes += len; 00136 job->stats.lit_cmdbytes += 1 + job->cmd->len_1; 00137 00138 rs_tube_copy(job, len); 00139 00140 job->statefn = rs_patch_s_cmdbyte; 00141 return RS_RUNNING; 00142 } 00143 00144 static rs_result rs_patch_s_copy(rs_job_t *job) 00145 { 00146 rs_long_t where, len; 00147 rs_stats_t *stats; 00148 00149 where = job->param1; 00150 len = job->param2; 00151 00152 rs_trace("COPY(where=" FMT_LONG ", len=" FMT_LONG ")", where, len); 00153 00154 if (len < 0) { 00155 rs_error("invalid length=" FMT_LONG " on COPY command", len); 00156 return RS_CORRUPT; 00157 } 00158 00159 if (where < 0) { 00160 rs_error("invalid where=" FMT_LONG " on COPY command", where); 00161 return RS_CORRUPT; 00162 } 00163 00164 job->basis_pos = where; 00165 job->basis_len = len; 00166 00167 stats = &job->stats; 00168 00169 stats->copy_cmds++; 00170 stats->copy_bytes += len; 00171 stats->copy_cmdbytes += 1 + job->cmd->len_1 + job->cmd->len_2; 00172 00173 job->statefn = rs_patch_s_copying; 00174 return RS_RUNNING; 00175 } 00176 00177 /** Called when we're executing a COPY command and waiting for all the data to 00178 * be retrieved from the callback. */ 00179 static rs_result rs_patch_s_copying(rs_job_t *job) 00180 { 00181 rs_result result; 00182 size_t desired_len, len; 00183 void *ptr; 00184 rs_buffers_t *buffs = job->stream; 00185 00186 /* copy only as much as will fit in the output buffer, so that we don't 00187 have to block or store the input. */ 00188 desired_len = len = 00189 (buffs->avail_out < job->basis_len) ? buffs->avail_out : job->basis_len; 00190 00191 if (!len) 00192 return RS_BLOCKED; 00193 00194 rs_trace("copy " FMT_SIZE " bytes from basis at offset " FMT_LONG "", len, 00195 job->basis_pos); 00196 00197 ptr = buffs->next_out; 00198 00199 result = (job->copy_cb) (job->copy_arg, job->basis_pos, &len, &ptr); 00200 if (result != RS_DONE) 00201 return result; 00202 else 00203 rs_trace("copy callback returned %s", rs_strerror(result)); 00204 00205 rs_trace("got " FMT_SIZE " bytes back from basis callback", len); 00206 00207 if (len > desired_len) { 00208 rs_trace("warning: copy_cb returned more than the requested length."); 00209 len = desired_len; 00210 } 00211 00212 /* copy back to out buffer only if the callback has used its own buffer */ 00213 if (ptr != buffs->next_out) 00214 memcpy(buffs->next_out, ptr, len); 00215 00216 buffs->next_out += len; 00217 buffs->avail_out -= len; 00218 00219 job->basis_pos += len; 00220 job->basis_len -= len; 00221 00222 if (!job->basis_len) { 00223 /* Done! */ 00224 job->statefn = rs_patch_s_cmdbyte; 00225 } 00226 00227 return RS_RUNNING; 00228 } 00229 00230 /** Called while we're trying to read the header of the patch. */ 00231 static rs_result rs_patch_s_header(rs_job_t *job) 00232 { 00233 int v; 00234 rs_result result; 00235 00236 if ((result = rs_suck_n4(job, &v)) != RS_DONE) 00237 return result; 00238 00239 if (v != RS_DELTA_MAGIC) { 00240 rs_error("got magic number %#x rather than expected value %#x", v, 00241 RS_DELTA_MAGIC); 00242 return RS_BAD_MAGIC; 00243 } else 00244 rs_trace("got patch magic %#x", v); 00245 00246 job->statefn = rs_patch_s_cmdbyte; 00247 00248 return RS_RUNNING; 00249 } 00250 00251 rs_job_t *rs_patch_begin(rs_copy_cb * copy_cb, void *copy_arg) 00252 { 00253 rs_job_t *job = rs_job_new("patch", rs_patch_s_header); 00254 00255 job->copy_cb = copy_cb; 00256 job->copy_arg = copy_arg; 00257 00258 rs_mdfour_begin(&job->output_md4); 00259 00260 return job; 00261 }