00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef lint
00039 static char copyright[] =
00040 "@(#) Copyright (c) 2002\n\
00041 Netherlands Forensic Institute. All rights reserved.\n";
00042 #endif
00043
00044
00045
00046
00047
00048
00049
00050
00051 #ifdef HAVE_CONFIG_H
00052 #include <config.h>
00053 #endif
00054
00055 #include <assert.h>
00056 #include <string.h>
00057 #include <stdio.h>
00058 #include <stdlib.h>
00059
00060 #include "rdd.h"
00061 #include "rdd_internals.h"
00062 #include "commandline.h"
00063 #include "reader.h"
00064 #include "writer.h"
00065 #include "filter.h"
00066 #include "filterset.h"
00067 #include "copier.h"
00068 #include "error.h"
00069 #include "netio.h"
00070 #include "alignedbuf.h"
00071 #include "progress.h"
00072
00073 #define KNOWN_INPUT_SIZE(s) ((s)->count != RDD_WHOLE_FILE)
00074
00075 typedef enum _read_mode_t { READ_OK, READ_ERROR, READ_RECOVERY } read_mode_t;
00076
00077 typedef struct _RDD_ROBUST_COPIER {
00078 read_mode_t mode;
00079 rdd_count_t offset;
00080 rdd_count_t count;
00081 unsigned minblocklen;
00082 unsigned maxblocklen;
00083 unsigned curblocklen;
00084 unsigned recovery_threshold;
00085
00086 int verbose;
00087
00088 unsigned nretry;
00089 unsigned maxsubst;
00090
00091 rdd_count_t nbyte;
00092 rdd_count_t nlost;
00093 unsigned nread_err;
00094 unsigned nsubst;
00095
00096 unsigned nok;
00097 unsigned ntry;
00098
00099 rdd_readerrhandler_t readerrfun;
00100 void *readerrenv;
00101 rdd_substhandler_t substfun;
00102 void *substenv;
00103 rdd_proghandler_t progressfun;
00104 void *progressenv;
00105
00106 RDD_ALIGNEDBUF readbuf;
00107 } RDD_ROBUST_COPIER;
00108
00109 static int robust_exec(RDD_COPIER *c, RDD_READER *r,
00110 RDD_FILTERSET *fset,
00111 RDD_COPIER_RETURN *ret);
00112 static int robust_free(RDD_COPIER *c);
00113
00114 static RDD_COPY_OPS robust_ops = {
00115 robust_exec,
00116 robust_free
00117 };
00118
00119 int
00120 rdd_new_robust_copier(RDD_COPIER **self,
00121 rdd_count_t offset, rdd_count_t count,
00122 RDD_ROBUST_PARAMS *p)
00123 {
00124 RDD_COPIER *c = 0;
00125 RDD_ROBUST_COPIER *state = 0;
00126 int rc = RDD_OK;
00127
00128 if (p->maxblocklen <= 0) return RDD_BADARG;
00129 if (p->minblocklen <= 0) return RDD_BADARG;
00130 if (p->minblocklen > p->maxblocklen) return RDD_BADARG;
00131
00132 rc = rdd_new_copier(&c, &robust_ops, sizeof(RDD_ROBUST_COPIER));
00133 if (rc != RDD_OK) {
00134 goto error;
00135 }
00136 state = (RDD_ROBUST_COPIER *) c->state;
00137
00138 state->mode = READ_OK;
00139 state->offset = offset;
00140 state->count = count;
00141 state->minblocklen = p->minblocklen;
00142 state->maxblocklen = p->maxblocklen;
00143 state->curblocklen = p->maxblocklen;
00144 state->recovery_threshold =
00145 (p->maxblocklen + p->minblocklen - 1) / p->minblocklen;
00146
00147 state->readerrfun = p->readerrfun;
00148 state->readerrenv = p->readerrenv;
00149 state->substfun = p->substfun;
00150 state->substenv = p->substenv;
00151 state->progressfun = p->progressfun;
00152 state->progressenv = p->progressenv;
00153 state->verbose = 1;
00154
00155 state->nretry = p->nretry;
00156 state->maxsubst = p->maxsubst;
00157
00158 state->nbyte = 0;
00159 state->nlost = 0;
00160 state->nread_err = 0;
00161 state->nsubst = 0;
00162
00163 state->nok = 0;
00164 state->ntry = 0;
00165
00166
00167
00168
00169
00170 rc = rdd_new_alignedbuf(&state->readbuf, p->maxblocklen,
00171 RDD_SECTOR_SIZE);
00172 if (rc != RDD_OK) {
00173 goto error;
00174 }
00175
00176 #if 0
00177 progress_init(&state->progress, state->count, 10);
00178 rdd_copy_set_progress_handler(state, progress_update, &state->progress);
00179 #endif
00180
00181 *self = c;
00182 return RDD_OK;
00183
00184 error:
00185 *self = 0;
00186 if (state != 0) free(state);
00187 if (c != 0) free(c);
00188 return rc;
00189 }
00190
00191 static void
00192 handle_eof(RDD_ROBUST_COPIER *state)
00193 {
00194 if (KNOWN_INPUT_SIZE(state)) {
00195
00196
00197 error("unexpected end-of-file after %llu bytes "
00198 "(expected %s bytes)",
00199 state->nbyte, rdd_strsize(state->count));
00200 }
00201 }
00202
00203 static void
00204 handle_read_ok(RDD_ROBUST_COPIER *state, unsigned rsize, unsigned nread)
00205 {
00206
00207
00208 if (KNOWN_INPUT_SIZE(state) && nread != rsize) {
00209 bug("rdd: read fewer bytes (%u) than expected (%u)",
00210 nread, rsize);
00211 }
00212
00213
00214
00215 switch (state->mode) {
00216 case READ_OK:
00217 if (nread >= state->curblocklen
00218 && state->curblocklen < state->maxblocklen) {
00219 unsigned oldsize = state->curblocklen;
00220 state->curblocklen *= 2;
00221 if (state->curblocklen > state->maxblocklen) {
00222 state->curblocklen = state->maxblocklen;
00223 }
00224 if (state->verbose) {
00225 errlognl("increasing block size %u -> %u: "
00226 "offset %llu bytes",
00227 oldsize, state->curblocklen,
00228 state->offset + state->nbyte);
00229 }
00230 }
00231 break;
00232 case READ_ERROR:
00233 state->mode = READ_RECOVERY;
00234 state->nok = 0;
00235 if (state->verbose) {
00236 errlognl("entered READ_RECOVERY mode, "
00237 "block size %u bytes, offset %llu bytes",
00238 state->curblocklen,
00239 state->offset + state->nbyte);
00240 }
00241 break;
00242 case READ_RECOVERY:
00243 if (++state->nok >= state->recovery_threshold) {
00244 state->mode = READ_OK;
00245 if (state->verbose) {
00246 errlognl("entered READ_OK mode, "
00247 "block size %u bytes, "
00248 "offset %llu bytes",
00249 state->curblocklen,
00250 state->offset + state->nbyte);
00251 }
00252 }
00253 break;
00254 }
00255 }
00256
00257
00258
00259
00260
00261
00262
00263 static int
00264 handle_read_error(RDD_ROBUST_COPIER *state, RDD_READER *reader,
00265 unsigned char *buf, unsigned rsize)
00266 {
00267 int rc = RDD_EAGAIN;
00268
00269 state->nread_err++;
00270
00271 switch (state->mode) {
00272 case READ_OK:
00273 case READ_RECOVERY:
00274 state->mode = READ_ERROR;
00275 state->curblocklen = state->minblocklen;
00276 state->ntry = 0;
00277 if (state->verbose) {
00278 errlognl("entered READ_ERROR mode, "
00279 "block size %u bytes, offset %llu bytes",
00280 state->curblocklen,
00281 state->offset + state->nbyte);
00282 }
00283 break;
00284 case READ_ERROR:
00285 if (++state->ntry >= state->nretry) {
00286
00287
00288
00289
00290 errlognl("read error: offset %llu bytes, count %u bytes",
00291 state->offset + state->nbyte, rsize);
00292
00293 rc = rdd_reader_skip(reader, rsize);
00294 if (rc != RDD_OK) {
00295 errlognl("cannot skip bad data block, aborting");
00296 return RDD_ABORTED;
00297 }
00298
00299 state->mode = READ_RECOVERY;
00300 state->nok = 0;
00301 if (state->verbose) {
00302 errlognl("entered READ_RECOVERY mode, "
00303 "block size %u bytes, "
00304 "offset %llu bytes",
00305 state->curblocklen,
00306 state->offset + state->nbyte);
00307 }
00308
00309 rc = RDD_EREAD;
00310 }
00311 break;
00312 }
00313
00314 return rc;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 static int
00336 robust_exec(RDD_COPIER *c, RDD_READER *reader, RDD_FILTERSET *fset,
00337 RDD_COPIER_RETURN *ret)
00338 {
00339 RDD_ROBUST_COPIER *s = (RDD_ROBUST_COPIER *) c->state;
00340 RDD_READER *areader = 0;
00341 uint32_t rsize;
00342 unsigned nread;
00343 unsigned char *buf = 0;
00344 int aborted = 0;
00345 int rc = RDD_OK;
00346
00347 ret->nbyte = 0;
00348 ret->nlost = 0;
00349 ret->nread_err = 0;
00350 ret->nsubst = 0;
00351
00352 if ((rc = rdd_open_atomic_reader(&areader, reader)) != RDD_OK) {
00353 return rc;
00354 }
00355
00356 if (s->offset > 0) {
00357 if ((rc = rdd_reader_skip(areader, s->offset)) != RDD_OK) {
00358 return rc;
00359 }
00360 }
00361
00362 while (s->nbyte < s->count) {
00363 if (s->nbyte + s->curblocklen < s->count) {
00364
00365 rsize = s->curblocklen;
00366 } else {
00367
00368 rsize = (uint32_t) (s->count - s->nbyte);
00369 }
00370
00371 buf = s->readbuf.aligned;
00372 nread = 0;
00373 rc = rdd_reader_read(areader, buf, rsize, &nread);
00374 if (rc == RDD_OK && nread == 0) {
00375 handle_eof(s);
00376 break;
00377 } else if (rc == RDD_OK && nread > 0) {
00378 handle_read_ok(s, rsize, nread);
00379 rc = rdd_fset_push(fset, buf, nread);
00380 if (rc != RDD_OK) {
00381 return rc;
00382 }
00383 s->nbyte += nread;
00384 } else if (rc == RDD_EREAD) {
00385
00386
00387
00388 rc = handle_read_error(s, areader, buf, rsize);
00389
00390 if (s->readerrfun != 0) {
00391 (*s->readerrfun)(s->offset + s->nbyte,
00392 rsize, s->readerrenv);
00393 }
00394
00395 switch (rc) {
00396 case RDD_EREAD:
00397 if (s->maxsubst > 0
00398 && (s->nsubst+1) >= s->maxsubst){
00399 return RDD_ABORTED;
00400 }
00401
00402
00403
00404
00405 memset(buf, 0, rsize);
00406 s->nlost += rsize;
00407 rc = rdd_fset_push(fset, buf, rsize);
00408 if (rc != RDD_OK) {
00409 return rc;
00410 }
00411
00412 if (s->substfun != 0) {
00413 (*s->substfun)(s->offset + s->nbyte,
00414 rsize, s->substenv);
00415 }
00416
00417 s->nbyte += rsize;
00418 s->nsubst++;
00419 break;
00420 case RDD_EAGAIN:
00421 break;
00422 default:
00423 return rc;
00424 }
00425 } else {
00426 return RDD_EREAD;
00427 }
00428
00429
00430 if (s->progressfun != 0) {
00431 rc = (*s->progressfun)(s->nbyte, s->nlost, s->progressenv);
00432 if (rc == RDD_ABORTED) {
00433 aborted = 1;
00434 break;
00435 } else if (rc != RDD_OK) {
00436 return rc;
00437 }
00438 }
00439 }
00440
00441 if (s->progressfun != 0) {
00442 ((RDD_PROGRESS *)s->progressenv)->period=0;
00443 ((RDD_PROGRESS *)s->progressenv)->poll_delta=0;
00444
00445 rc = (*s->progressfun)(s->nbyte, s->nlost, s->progressenv);
00446 if (rc == RDD_ABORTED) {
00447 aborted = 1;
00448 } else if (rc != RDD_OK) {
00449 return rc;
00450 }
00451 }
00452
00453 if ((rc = rdd_fset_close(fset)) != RDD_OK) {
00454 return rc;
00455 }
00456
00457
00458
00459
00460
00461 if ((rc = rdd_reader_close(areader, 0)) != RDD_OK) {
00462 return rc;
00463 }
00464
00465 ret->nbyte = s->nbyte;
00466 ret->nlost = s->nlost;
00467 ret->nread_err = s->nread_err;
00468 ret->nsubst = s->nsubst;
00469
00470 return aborted ? RDD_ABORTED : RDD_OK;
00471 }
00472
00473 static int
00474 robust_free(RDD_COPIER *c)
00475 {
00476 RDD_ROBUST_COPIER *state = (RDD_ROBUST_COPIER *) c->state;
00477
00478 return rdd_free_alignedbuf(&state->readbuf);
00479 }