$treeview $search $mathjax $extrastylesheet
librsync
2.0.2
$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 00028 #include <assert.h> 00029 #include <stdlib.h> 00030 #include <stdio.h> 00031 #include <string.h> 00032 00033 #include "librsync.h" 00034 #include "util.h" 00035 #include "trace.h" 00036 #include "netint.h" 00037 #include "command.h" 00038 #include "sumset.h" 00039 #include "prototab.h" 00040 #include "stream.h" 00041 #include "job.h" 00042 00043 static rs_result rs_patch_s_cmdbyte(rs_job_t *); 00044 static rs_result rs_patch_s_params(rs_job_t *); 00045 static rs_result rs_patch_s_run(rs_job_t *); 00046 static rs_result rs_patch_s_literal(rs_job_t *); 00047 static rs_result rs_patch_s_copy(rs_job_t *); 00048 static rs_result rs_patch_s_copying(rs_job_t *); 00049 00050 /** State of trying to read the first byte of a command. Once we've taken that 00051 * in, we can know how much data to read to get the arguments. */ 00052 static rs_result rs_patch_s_cmdbyte(rs_job_t *job) 00053 { 00054 rs_result result; 00055 00056 if ((result = rs_suck_byte(job, &job->op)) != RS_DONE) 00057 return result; 00058 00059 job->cmd = &rs_prototab[job->op]; 00060 00061 rs_trace("got command %#04x (%s), len_1=" FMT_SIZE "", job->op, 00062 rs_op_kind_name(job->cmd->kind), job->cmd->len_1); 00063 00064 if (job->cmd->len_1) 00065 job->statefn = rs_patch_s_params; 00066 else { 00067 job->param1 = job->cmd->immediate; 00068 job->statefn = rs_patch_s_run; 00069 } 00070 00071 return RS_RUNNING; 00072 } 00073 00074 /** Called after reading a command byte to pull in its parameters and then 00075 * setup to execute the command. */ 00076 static rs_result rs_patch_s_params(rs_job_t *job) 00077 { 00078 rs_result result; 00079 int len = job->cmd->len_1 + job->cmd->len_2; 00080 void *p; 00081 00082 assert(len); 00083 00084 result = rs_scoop_readahead(job, len, &p); 00085 if (result != RS_DONE) 00086 return result; 00087 00088 /* we now must have LEN bytes buffered */ 00089 result = rs_suck_netint(job, &job->param1, job->cmd->len_1); 00090 /* shouldn't fail, since we already checked */ 00091 assert(result == RS_DONE); 00092 00093 if (job->cmd->len_2) { 00094 result = rs_suck_netint(job, &job->param2, job->cmd->len_2); 00095 assert(result == RS_DONE); 00096 } 00097 00098 job->statefn = rs_patch_s_run; 00099 00100 return RS_RUNNING; 00101 } 00102 00103 /** Called when we've read in the whole command and we need to execute it. */ 00104 static rs_result rs_patch_s_run(rs_job_t *job) 00105 { 00106 rs_trace("running command %#04x", job->op); 00107 00108 switch (job->cmd->kind) { 00109 case RS_KIND_LITERAL: 00110 job->statefn = rs_patch_s_literal; 00111 return RS_RUNNING; 00112 00113 case RS_KIND_END: 00114 return RS_DONE; 00115 /* so we exit here; trying to continue causes an error */ 00116 00117 case RS_KIND_COPY: 00118 job->statefn = rs_patch_s_copy; 00119 return RS_RUNNING; 00120 00121 default: 00122 rs_error("bogus command %#04x", job->op); 00123 return RS_CORRUPT; 00124 } 00125 } 00126 00127 /** Called when trying to copy through literal data. */ 00128 static rs_result rs_patch_s_literal(rs_job_t *job) 00129 { 00130 rs_long_t len = job->param1; 00131 00132 rs_trace("LITERAL(len=" FMT_LONG ")", len); 00133 00134 if (len < 0) { 00135 rs_error("invalid length=" FMT_LONG " on LITERAL command", len); 00136 return RS_CORRUPT; 00137 } 00138 00139 job->stats.lit_cmds++; 00140 job->stats.lit_bytes += len; 00141 job->stats.lit_cmdbytes += 1 + job->cmd->len_1; 00142 00143 rs_tube_copy(job, len); 00144 00145 job->statefn = rs_patch_s_cmdbyte; 00146 return RS_RUNNING; 00147 } 00148 00149 static rs_result rs_patch_s_copy(rs_job_t *job) 00150 { 00151 rs_long_t where, len; 00152 rs_stats_t *stats; 00153 00154 where = job->param1; 00155 len = job->param2; 00156 00157 rs_trace("COPY(where=" FMT_LONG ", len=" FMT_LONG ")", where, len); 00158 00159 if (len < 0) { 00160 rs_error("invalid length=" FMT_LONG " on COPY command", len); 00161 return RS_CORRUPT; 00162 } 00163 00164 if (where < 0) { 00165 rs_error("invalid where=" FMT_LONG " on COPY command", where); 00166 return RS_CORRUPT; 00167 } 00168 00169 job->basis_pos = where; 00170 job->basis_len = len; 00171 00172 stats = &job->stats; 00173 00174 stats->copy_cmds++; 00175 stats->copy_bytes += len; 00176 stats->copy_cmdbytes += 1 + job->cmd->len_1 + job->cmd->len_2; 00177 00178 job->statefn = rs_patch_s_copying; 00179 return RS_RUNNING; 00180 } 00181 00182 /** Called when we're executing a COPY command and waiting for all the data to 00183 * be retrieved from the callback. */ 00184 static rs_result rs_patch_s_copying(rs_job_t *job) 00185 { 00186 rs_result result; 00187 size_t desired_len, len; 00188 void *ptr; 00189 rs_buffers_t *buffs = job->stream; 00190 00191 /* copy only as much as will fit in the output buffer, so that we don't 00192 have to block or store the input. */ 00193 desired_len = len = 00194 (buffs->avail_out < job->basis_len) ? buffs->avail_out : job->basis_len; 00195 00196 if (!len) 00197 return RS_BLOCKED; 00198 00199 rs_trace("copy " FMT_SIZE " bytes from basis at offset " FMT_LONG "", len, 00200 job->basis_pos); 00201 00202 ptr = buffs->next_out; 00203 00204 result = (job->copy_cb) (job->copy_arg, job->basis_pos, &len, &ptr); 00205 if (result != RS_DONE) 00206 return result; 00207 else 00208 rs_trace("copy callback returned %s", rs_strerror(result)); 00209 00210 rs_trace("got " FMT_SIZE " bytes back from basis callback", len); 00211 00212 if (len > desired_len) { 00213 rs_trace("warning: copy_cb returned more than the requested length."); 00214 len = desired_len; 00215 } 00216 00217 /* copy back to out buffer only if the callback has used its own buffer */ 00218 if (ptr != buffs->next_out) 00219 memcpy(buffs->next_out, ptr, len); 00220 00221 buffs->next_out += len; 00222 buffs->avail_out -= len; 00223 00224 job->basis_pos += len; 00225 job->basis_len -= len; 00226 00227 if (!job->basis_len) { 00228 /* Done! */ 00229 job->statefn = rs_patch_s_cmdbyte; 00230 } 00231 00232 return RS_RUNNING; 00233 } 00234 00235 /** Called while we're trying to read the header of the patch. */ 00236 static rs_result rs_patch_s_header(rs_job_t *job) 00237 { 00238 int v; 00239 rs_result result; 00240 00241 if ((result = rs_suck_n4(job, &v)) != RS_DONE) 00242 return result; 00243 00244 if (v != RS_DELTA_MAGIC) { 00245 rs_error("got magic number %#x rather than expected value %#x", v, 00246 RS_DELTA_MAGIC); 00247 return RS_BAD_MAGIC; 00248 } else 00249 rs_trace("got patch magic %#x", v); 00250 00251 job->statefn = rs_patch_s_cmdbyte; 00252 00253 return RS_RUNNING; 00254 } 00255 00256 rs_job_t *rs_patch_begin(rs_copy_cb * copy_cb, void *copy_arg) 00257 { 00258 rs_job_t *job = rs_job_new("patch", rs_patch_s_header); 00259 00260 job->copy_cb = copy_cb; 00261 job->copy_arg = copy_arg; 00262 00263 rs_mdfour_begin(&job->output_md4); 00264 00265 return job; 00266 }