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-2004\n\
00041 Netherlands Forensic Institute. All rights reserved.\n";
00042 #endif
00043
00044
00045
00046
00047
00048
00049
00050 #ifdef HAVE_CONFIG_H
00051 #include <config.h>
00052 #endif
00053
00054 #include <assert.h>
00055 #include <ctype.h>
00056 #include <errno.h>
00057 #include <limits.h>
00058 #include <stdarg.h>
00059 #include <stdlib.h>
00060 #include <stdio.h>
00061 #include <string.h>
00062 #include <sys/types.h>
00063 #include <sys/stat.h>
00064 #include <fcntl.h>
00065 #include <unistd.h>
00066
00067 #include "rdd.h"
00068 #include "rdd_internals.h"
00069
00070
00071
00072
00073
00074
00075
00076 #ifdef HAVE_OPENSSL
00077 #include <openssl/crypto.h>
00078 #endif
00079 #if defined(HAVE_LIBZ)
00080 #include <zlib.h>
00081 #else
00082 #error Sorry, need libz to compile
00083 #endif
00084
00085 #include "numparser.h"
00086 #include "reader.h"
00087 #include "commandline.h"
00088 #include "error.h"
00089 #include "hashcontainer.h"
00090 #include "writer.h"
00091 #include "filter.h"
00092 #include "filterset.h"
00093 #include "copier.h"
00094 #include "netio.h"
00095 #include "progress.h"
00096 #include "msgprinter.h"
00097
00098 #define DEFAULT_BLOCK_LEN 262144
00099 #define DEFAULT_MIN_BLOCK_SIZE 32768
00100 #define DEFAULT_HIST_BLOCK_SIZE 262144
00101 #define DEFAULT_CHKSUM_BLOCK_SIZE 32768
00102 #define DEFAULT_BLOCKMD5_SIZE 4096
00103
00104 #define DEFAULT_NRETRY 1
00105 #define DEFAULT_RECOVERY_LEN 4
00106 #define DEFAULT_MAX_READ_ERR 0
00107 #define DEFAULT_RDD_SERVER_PORT 4832
00108
00109 #define bool2str(b) ((b) ? "yes" : "no")
00110 #define str2str(s) ((s) == 0? "<none>" : (s))
00111
00112
00113
00114 typedef enum _rdd_copy_mode_t {
00115 RDD_LOCAL = 0x1,
00116 RDD_CLIENT = 0x2,
00117 RDD_SERVER = 0x4
00118 } rdd_copy_mode_t;
00119
00120 #define ALL_MODES (RDD_LOCAL|RDD_CLIENT|RDD_SERVER)
00121
00122 #define RDD_MAX_OUTPUT_OPTS 16
00123
00124 typedef struct _rdd_output_opt_t {
00125 int ewf;
00126 rdd_count_t splitlen;
00127 char *outpath;
00128 char *server_host;
00129 unsigned int server_port;
00130 } rdd_output_opt_t;
00131
00132
00133
00134 typedef struct _rdd_copy_opts {
00135 int compress;
00136 int quiet;
00137 char *infile;
00138 char *logfile;
00139 char *simfile;
00140 char *crc32file;
00141 char *adler32file;
00142 char *histfile;
00143 char *blockmd5file;
00144 int verbose;
00145 int raw;
00146 unsigned mode;
00147 unsigned int server_port;
00148 int inetd;
00149 int force_overwrite;
00150 int md5;
00151 int sha1;
00152 int sha256;
00153 int sha384;
00154 int sha512;
00155 unsigned nretry;
00156 rdd_count_t blocklen;
00157 rdd_count_t adler32len;
00158 rdd_count_t crc32len;
00159 rdd_count_t histblocklen;
00160 rdd_count_t blockmd5len;
00161 rdd_count_t minblocklen;
00162 rdd_count_t offset;
00163 rdd_count_t count;
00164 unsigned int output_count;
00165 rdd_output_opt_t output[RDD_MAX_OUTPUT_OPTS];
00166 rdd_count_t progresslen;
00167 rdd_count_t max_read_err;
00168 } rdd_copy_opts;
00169
00170 static rdd_copy_opts opts;
00171
00172 static char* compression_types[] = { "no ewf", "none", "fast", "best", "empty-block", NULL};
00173
00174 static char* usage_message = "\n"
00175 "\trdd-copy [local options] --in infile --out <output options>\n"
00176 "\trdd-copy -C [client options] --in infile --out <output options>\n"
00177 "\trdd-copy -S [server options]\n";
00178
00179 static RDD_OPTION opttab[] = {
00180 {"-?", "--help", 0, ALL_MODES, "Print this message", 0, 0},
00181 {0, "--sha1", 0, ALL_MODES, "Compute and print SHA1 hash", 0, 0},
00182 {0, "--sha256", 0, ALL_MODES, "Compute and print SHA256 hash", 0, 0},
00183 {0, "--sha384", 0, ALL_MODES, "Compute and print SHA384 hash", 0, 0},
00184 {0, "--sha512", 0, ALL_MODES, "Compute and print SHA512 hash", 0, 0},
00185 {0, "--md5", 0, ALL_MODES, "Compute and print MD5 hash", 0, 0},
00186 {"-A", "--adler32", "<file>", ALL_MODES, "Compute and store Adler32 checksums in <file>", 0, 0},
00187 {"-a", "--adler32-block-size", "<size>", ALL_MODES, "Adler32 uses <size>-byte blocks", 0, 0},
00188 {"-b", "--block-size", "<count>[kKmMgG]", RDD_LOCAL|RDD_CLIENT, "Read blocks of <count> [KMG]byte at a time", 0, 0},
00189 {"-C", "--client", 0, 0, "Run rdd as a network client", 0, 0},
00190 {"-c", "--count", "<count>[kKmMgG]", ALL_MODES, "Read at most <count> [KMG]bytes", 0, 0},
00191 {0, "--block-md5", "<file>", ALL_MODES, "Store block-wise MD5 hash values in <file>", 0, 0},
00192 {0, "--block-md5-size", "<size>", ALL_MODES, "block-wise MD5 block size", 0, 0},
00193 {"-F", "--fault-simulation", "<file>", RDD_LOCAL|RDD_CLIENT, "simulate read errors specified in <file>", 0, 0},
00194 {"-f", "--force", 0, ALL_MODES, "Ruthlessly overwrite existing files (including log file)", 0, 0},
00195 {"-H", "--histogram", "<file>", ALL_MODES, "Store histogram-derived stats in <file>", 0, 0},
00196 {"-h", "--histogram-block-size", "<size>", ALL_MODES, "Histogramming block size", 0, 0},
00197 {"-i", "--inetd", 0, RDD_SERVER, "rdd is started by (x)inetd", 0, 0},
00198 {"-l", "--log-file", "<file>", ALL_MODES, "Log messages in <file>", 0, 0},
00199 {"-M", "--max-read-err", "<count>", RDD_LOCAL|RDD_CLIENT, "Give up after <count> read errors", 0, 0},
00200 {"-m", "--min-block-size", "<count>[kKmMgG]", RDD_LOCAL|RDD_CLIENT, "Minimum read-block size is <count> [KMG]byte", 0, 0},
00201 {"-n", "--nretry", "<count>", RDD_LOCAL|RDD_CLIENT, "Retry failed reads <count> times", 0, 0},
00202 {"-o", "--offset", "<count>[kKmMgG]", ALL_MODES, "Skip <count> [KMG] input bytes", 0, 0},
00203 {"-P", "--progress", "<sec>", ALL_MODES, "Report progress every <sec> seconds", 0, 0},
00204 {"-p", "--port", "<portnum>", RDD_SERVER, "Set server port to <port>", 0, 0},
00205 {"-q", "--quiet", 0, ALL_MODES, "Do not ask questions", 0, 0},
00206 {"-r", "--raw", 0, RDD_LOCAL|RDD_CLIENT, "Read from a raw device (/dev/raw/raw[0-9])", 0, 0},
00207 {"-S", "--server", 0, 0, "Run rdd as a network server", 0, 0},
00208 {0, "--crc32", "<file>", ALL_MODES, "Compute and store CRC32 checksums in <file>", 0, 0},
00209 {0, "--crc32-block-size", "<size>", ALL_MODES, "CRC32 uses <size>-byte blocks", 0, 0},
00210 {"-V", "--version", 0, ALL_MODES, "Report version number and exit", 0, 0},
00211 {"-v", "--verbose", 0, ALL_MODES, "Be verbose", 0, 0},
00212 {"-z", "--compress", 0, RDD_CLIENT, "Compress data sent across the network", 0, 0},
00213 {"-I", "--in", "<file>", RDD_LOCAL|RDD_CLIENT, "Use <file> as input file" , 0, 0},
00214 {"-O", "--out", "<output options>", RDD_LOCAL|RDD_CLIENT, "Output using <output options> (can be used multiple times)", 0, 0},
00215 {0, 0, 0, 0, 0, 0, 0}
00216 };
00217
00218 static RDD_OPTION output_opttab[] = {
00219 {"-e", "--ewf", "<compression>",RDD_LOCAL|RDD_CLIENT, "Output as Expert Witness Compression Format (EnCase), compression: none, fast, best, empty-block", 0, 0},
00220 {"-s", "--split", "<count>[kKmMgG]", RDD_LOCAL|RDD_CLIENT, "Split output, all files < <count> [KMG]bytes", 0, 0},
00221 {"-N", "--name", "<file>", RDD_LOCAL|RDD_CLIENT, "The output file name", 0, 0},
00222 {"-p", "--port", "<portnum>", RDD_CLIENT, "Set server port to <port>", 0, 0},
00223 {0, 0, 0, 0, 0, 0, 0}
00224 };
00225
00226 #define RDD_OUTPUT_OPTTAB_OPTION_COUNT sizeof(output_opttab)/sizeof(RDD_OPTION)
00227
00228 static RDD_OPTION all_output_opttabs[RDD_OUTPUT_OPTTAB_OPTION_COUNT * RDD_MAX_OUTPUT_OPTS];
00229
00230 static RDD_MSGPRINTER *the_printer;
00231
00232 static void
00233 fatal_rdd_error(int rdd_errno, char *fmt, ...)
00234 {
00235 va_list ap;
00236
00237 va_start(ap, fmt);
00238 rdd_mp_vrddmsg(the_printer, RDD_MSG_ERROR, rdd_errno, fmt, ap);
00239 va_end(ap);
00240 exit(EXIT_FAILURE);
00241 }
00242
00243 static void
00244 logmsg(const char *fmt, ...)
00245 {
00246 va_list ap;
00247
00248 va_start(ap, fmt);
00249 rdd_mp_vmessage(the_printer, RDD_MSG_INFO, fmt, ap);
00250 va_end(ap);
00251 }
00252
00253
00254
00255 static rdd_count_t
00256 scan_size(char *str, unsigned flags)
00257 {
00258 rdd_count_t sz;
00259 int rc;
00260
00261 if ((rc = rdd_parse_bignum((const char *) str, flags, &sz)) != RDD_OK) {
00262 fatal_rdd_error(rc, "bad number %s", str);
00263 }
00264 return sz;
00265 }
00266
00267 static int
00268 check_compress_option(char *arg)
00269 {
00270 int i;
00271
00272
00273 for(i = 1; compression_types[i]; i++){
00274 if(strcmp(compression_types[i], arg) == 0){
00275 return i;
00276 }
00277 }
00278 fatal_rdd_error(RDD_BADARG, "unknown ewf compression %s\n", arg);
00279
00280 return -1;
00281 }
00282
00283 static char *
00284 print_ewf_compress_option()
00285 {
00286 int ewf = opts.output[0].ewf;
00287 if(ewf >= 0 && ewf <= 4){
00288 return compression_types[ewf];
00289 }
00290 fatal_rdd_error(RDD_BADARG, "unknown ewf compression argument %d\n", ewf);
00291 return "";
00292 }
00293
00294 static unsigned
00295 scan_uint(char *str)
00296 {
00297 unsigned n;
00298 int rc;
00299
00300 if ((rc = rdd_parse_uint((const char *) str, &n)) != RDD_OK) {
00301 fatal_rdd_error(rc, "%s", str);
00302 }
00303 return n;
00304 }
00305
00306 static unsigned
00307 scan_tcp_port(char *str)
00308 {
00309 unsigned port;
00310 int rc;
00311
00312 if ((rc = rdd_parse_tcp_port((const char *) str, &port)) != RDD_OK) {
00313 fatal_rdd_error(rc, "%s", str);
00314 }
00315 return port;
00316 }
00317
00318 static void
00319 init_options(void)
00320 {
00321 memset(&opts, 0, sizeof opts);
00322
00323 opts.mode = RDD_LOCAL;
00324 opts.server_port = DEFAULT_RDD_SERVER_PORT;
00325 opts.nretry = DEFAULT_NRETRY;
00326 opts.max_read_err = DEFAULT_MAX_READ_ERR;
00327 opts.blocklen = DEFAULT_BLOCK_LEN;
00328 opts.minblocklen = DEFAULT_MIN_BLOCK_SIZE;
00329 opts.histblocklen = DEFAULT_HIST_BLOCK_SIZE;
00330 opts.adler32len = DEFAULT_CHKSUM_BLOCK_SIZE;
00331 opts.crc32len = DEFAULT_CHKSUM_BLOCK_SIZE;
00332 opts.blockmd5len = DEFAULT_BLOCKMD5_SIZE;
00333 opts.output_count = 0;
00334 int i;
00335 for (i=0; i<RDD_MAX_OUTPUT_OPTS; i++) {
00336 opts.output[i].ewf = 0;
00337 opts.output[i].splitlen = 0;
00338 opts.output[i].outpath = 0;
00339 opts.output[i].server_host = 0;
00340 opts.output[i].server_port = DEFAULT_RDD_SERVER_PORT;
00341 }
00342 }
00343
00344
00345
00346
00347 static void
00348 split_host_file(const char *host_file, char **host, char **file)
00349 {
00350 char *p;
00351 const char *h;
00352 const char *f;
00353 int hlen, flen;
00354
00355 p = strchr(host_file, ':');
00356 if (p == 0) {
00357 h = "localhost";
00358 hlen = strlen(h);
00359 f = host_file;
00360 flen = strlen(f);
00361
00362 } else if (p == host_file) {
00363 h = "localhost";
00364 hlen = strlen(h);
00365 f = p + 1;
00366 flen = strlen(f);
00367 } else {
00368 h = host_file;
00369 hlen = p - host_file;
00370 f = p + 1;
00371 flen = strlen(f);
00372 }
00373 if (flen == 0) {
00374 error("missing file name in target %s", host_file);
00375 }
00376
00377 *host = rdd_malloc(hlen + 1);
00378 memcpy(*host, h, hlen);
00379 (*host)[hlen] = '\000';
00380
00381 *file = rdd_malloc(flen + 1);
00382 memcpy(*file, f, flen);
00383 (*file)[flen] = '\000';
00384 }
00385
00386 static void
00387 process_options()
00388 {
00389 char *arg;
00390
00391 if (rdd_opt_set(opttab, "help")) {
00392 rdd_opt_usage(opttab, output_opttab, EXIT_SUCCESS);
00393 }
00394
00395 if (rdd_opt_set(opttab, "version")) {
00396 fprintf(stdout, "%s version %s\n", PACKAGE, VERSION);
00397 exit(EXIT_SUCCESS);
00398 }
00399
00400 opts.compress = rdd_opt_set(opttab, "compress");
00401 opts.quiet = rdd_opt_set(opttab, "quiet");
00402 rdd_set_quiet(opts.quiet);
00403 #if !defined(HAVE_LIBZ)
00404 error("rdd not configured with compression support");
00405 #endif
00406
00407 opts.raw = rdd_opt_set(opttab, "raw");
00408 #if !defined(__linux)
00409 if (opts.raw) {
00410 error("rdd raw-device support only works on Linux");
00411 }
00412 #endif
00413 opts.inetd = rdd_opt_set(opttab, "inetd");
00414 opts.verbose = rdd_opt_set(opttab, "verbose");
00415
00416 opts.raw = rdd_opt_set(opttab, "raw");
00417 if (opts.raw && opts.mode == RDD_SERVER) {
00418 error("raw-device input cannot be used in server mode");
00419 }
00420
00421 opts.md5 = rdd_opt_set(opttab, "md5");
00422 opts.sha1 = rdd_opt_set(opttab, "sha1");
00423 opts.sha256 = rdd_opt_set(opttab, "sha256");
00424 opts.sha384 = rdd_opt_set(opttab, "sha384");
00425 opts.sha512 = rdd_opt_set(opttab, "sha512");
00426
00427 opts.force_overwrite = rdd_opt_set(opttab, "force");
00428
00429 if (rdd_opt_set_arg(opttab, "in", &arg)) {
00430 opts.infile = arg;
00431 } else {
00432 if (opts.mode != RDD_SERVER) {
00433
00434 rdd_opt_usage(opttab, output_opttab, EXIT_FAILURE);
00435 }
00436 }
00437
00438
00439 int i = 0;
00440 RDD_OPTION * output_option = 0;
00441 while (output_option == 0 && opttab[i].long_name != 0) {
00442 if (!strcmp(opttab[i].long_name, "--out")) {
00443 output_option = &opttab[i];
00444 }
00445 i++;
00446 }
00447 if (output_option == 0) {
00448
00449 error("internal error when looking for output option");
00450 }
00451 opts.output_count = output_option->count;
00452
00453 for (i=0; i<opts.output_count; i++) {
00454 if(rdd_opt_set_arg(&all_output_opttabs[RDD_OUTPUT_OPTTAB_OPTION_COUNT * i], "ewf", &arg)){
00455 opts.output[i].ewf = check_compress_option(arg);
00456 }
00457
00458 if (rdd_opt_set_arg(&all_output_opttabs[RDD_OUTPUT_OPTTAB_OPTION_COUNT * i], "split", &arg)) {
00459 opts.output[i].splitlen = scan_size(arg, 0);
00460 }
00461 if (rdd_opt_set_arg(&all_output_opttabs[RDD_OUTPUT_OPTTAB_OPTION_COUNT * i], "name", &arg)) {
00462 if (opts.mode == RDD_CLIENT) {
00463 split_host_file(arg,
00464 &opts.output[i].server_host,
00465 &opts.output[i].outpath);
00466 } else {
00467 opts.output[i].outpath = arg;
00468 }
00469 }
00470 if (opts.mode == RDD_CLIENT) {
00471 if (rdd_opt_set_arg(&all_output_opttabs[RDD_OUTPUT_OPTTAB_OPTION_COUNT * i], "port", &arg)) {
00472 opts.output[i].server_port = scan_tcp_port(arg);
00473 }
00474 }
00475
00476 }
00477
00478 if (rdd_opt_set_arg(opttab, "fault-simulation", &arg)) {
00479 opts.simfile = arg;
00480 }
00481 if (rdd_opt_set_arg(opttab, "log-file", &arg)) {
00482 opts.logfile = arg;
00483 }
00484 if (rdd_opt_set_arg(opttab, "adler32", &arg)) {
00485 opts.adler32file = arg;
00486 }
00487 if (rdd_opt_set_arg(opttab, "adler32-block-size", &arg)) {
00488 opts.adler32len= scan_size(arg, RDD_POSITIVE);
00489 if (opts.adler32file == 0) {
00490 error("missing Adler-32 output file name "
00491 "(use --adler32)");
00492 }
00493 }
00494 if (rdd_opt_set_arg(opttab, "crc32", &arg)) {
00495 opts.crc32file = arg;
00496 }
00497 if (rdd_opt_set_arg(opttab, "crc32-block-size", &arg)) {
00498 opts.crc32len= scan_size(arg, RDD_POSITIVE);
00499 if (opts.crc32file == 0) {
00500 error("missing CRC-32 output file name "
00501 "(use --crc32)");
00502 }
00503 }
00504 if (rdd_opt_set_arg(opttab, "histogram", &arg)) {
00505 opts.histfile = arg;
00506 }
00507 if (rdd_opt_set_arg(opttab, "histogram-block-size", &arg)) {
00508 opts.histblocklen = scan_size(arg, RDD_POSITIVE);
00509 if (opts.histfile == 0) {
00510 error("missing histogram output file name "
00511 "(use --histogram)");
00512 }
00513 }
00514 if (rdd_opt_set_arg(opttab, "block-md5", &arg)) {
00515 opts.blockmd5file = arg;
00516 }
00517 if (rdd_opt_set_arg(opttab, "block-md5-size", &arg)) {
00518 opts.blockmd5len = scan_size(arg, RDD_POSITIVE);
00519 if (opts.blockmd5file == 0) {
00520 error("missing block-MD5 output file name "
00521 "(use --block-md5)");
00522 }
00523 }
00524 if (rdd_opt_set_arg(opttab, "progress", &arg)) {
00525 opts.progresslen = scan_uint(arg);
00526 }
00527 if (rdd_opt_set_arg(opttab, "nretry", &arg)) {
00528 opts.nretry = scan_uint(arg);
00529 }
00530 if (rdd_opt_set_arg(opttab, "block-size", &arg)) {
00531 opts.blocklen = scan_size(arg, RDD_POSITIVE);
00532 }
00533 if (rdd_opt_set_arg(opttab, "min-block-size", &arg)) {
00534 opts.minblocklen = scan_size(arg, RDD_POSITIVE);
00535 }
00536 if (rdd_opt_set_arg(opttab, "offset", &arg)) {
00537 opts.offset = scan_size(arg, 0);
00538 }
00539 if (rdd_opt_set_arg(opttab, "count", &arg)) {
00540 opts.count = scan_size(arg, RDD_POSITIVE);
00541 }
00542 if (rdd_opt_set_arg(opttab, "max-read-err", &arg)) {
00543 opts.max_read_err = scan_uint(arg);
00544 }
00545 if (rdd_opt_set_arg(opttab, "port", &arg)) {
00546 if (opts.mode == RDD_SERVER) {
00547 opts.server_port = scan_tcp_port(arg);
00548 } else {
00549 error("can only specify general server port in server mode; use --out --port to specify port in client mode");
00550 }
00551 }
00552 }
00553
00554 static void
00555 command_line(int argc, char **argv)
00556 {
00557 RDD_OPTION *od;
00558 unsigned i;
00559 char *opt;
00560 char *arg;
00561
00562
00563
00564
00565 i = 1;
00566 opts.mode = RDD_LOCAL;
00567 if (argc > 1) {
00568 if (streq(argv[i], "-C") || streq(argv[i], "--client")) {
00569 opts.mode = RDD_CLIENT;
00570 i++;
00571 } else if (streq(argv[i], "-S") || streq(argv[i], "--server")) {
00572 opts.mode = RDD_SERVER;
00573 i++;
00574 }
00575 }
00576
00577
00578
00579 RDD_OPTION * current_tab = opttab;
00580 for (; i < (unsigned) argc; i++) {
00581 if ((od = rdd_get_opt_with_arg(current_tab, argv, argc, &i, &opt, &arg)) != 0) {
00582
00583
00584 if (!flag_set(od->valid_modes, opts.mode)) {
00585 error("option %s not valid in %s mode", opt,
00586 opts.mode == RDD_LOCAL ? "local" :
00587 opts.mode == RDD_CLIENT ? "client" :
00588 opts.mode == RDD_SERVER ? "server": "unknown");
00589 }
00590 }
00591 if (od == 0) {
00592 if (current_tab != opttab) {
00593
00594 current_tab = opttab;
00595 --i;
00596 } else {
00597 rdd_opt_usage(opttab, output_opttab, EXIT_FAILURE);
00598 }
00599 } else {
00600
00601 if (!strcmp(od->long_name, "--out")) {
00602 if (od->count > RDD_MAX_OUTPUT_OPTS) {
00603 error("too many output files specified; maximum is %d", RDD_MAX_OUTPUT_OPTS);
00604 }
00605
00606
00607
00608 current_tab = all_output_opttabs + (od->count-1)*RDD_OUTPUT_OPTTAB_OPTION_COUNT;
00609
00610 int j;
00611 for (j=0; j<RDD_OUTPUT_OPTTAB_OPTION_COUNT; j++) {
00612 current_tab[j] = output_opttab[j];
00613 }
00614
00615
00616 }
00617 }
00618
00619 }
00620
00621 process_options();
00622
00623 if (argc - i != 0) {
00624 rdd_opt_usage(opttab, output_opttab, EXIT_FAILURE);
00625 }
00626
00627
00628
00629
00630 if (rdd_opt_set(opttab, "block-size")
00631 && !rdd_opt_set(opttab, "min-block-size")
00632 && opts.blocklen < opts.minblocklen) {
00633 opts.minblocklen = opts.blocklen;
00634 }
00635
00636
00637
00638 if (opts.blocklen >= (rdd_count_t) INT_MAX) {
00639 error("block size (%llu) too large (larger than INT_MAX)",
00640 opts.blocklen);
00641 }
00642 if (opts.minblocklen > opts.blocklen) {
00643 error("minimum block length (%llu) cannot exceed "
00644 "block length (%llu)",
00645 opts.minblocklen, opts.blocklen);
00646 }
00647 for (i=0; i<opts.output_count; i++) {
00648 if (opts.output[i].splitlen > 0 && opts.output[i].splitlen < opts.blocklen) {
00649 error("split size (%llu) must be larger than or "
00650 "equal to block size (%llu) in output #%d",
00651 opts.output[i].splitlen, opts.blocklen, i);
00652 }
00653 if (opts.output[i].splitlen > 0 && opts.output[i].outpath == 0) {
00654 error("--split requires an output file name in output #%d", i);
00655 }
00656 if (opts.output[i].splitlen != 0 && opts.output[i].splitlen < RDD_EWF_MIN_SPLITLEN && opts.output[i].ewf) {
00657 error("--ewf requires a split length of at least 1.0 MiB in output #%d", i);
00658 }
00659 if (compare_paths(opts.infile, opts.output[i].outpath) == 0) {
00660 error("input and output file cannot be the same (output #%d)", i);
00661 }
00662 }
00663 }
00664
00665 static RDD_READER *
00666 open_disk_input(rdd_count_t *inputlen)
00667 {
00668 RDD_READER *reader = 0;
00669 int rc;
00670
00671 rc = rdd_open_file_reader(&reader, opts.infile, opts.raw);
00672 if (rc != RDD_OK) {
00673 fatal_rdd_error(rc, "cannot open %s", opts.infile);
00674 }
00675 if ((rc = rdd_reader_seek(reader, 0)) != RDD_OK) {
00676 fatal_rdd_error(rc, "cannot seek on %s", opts.infile);
00677 }
00678
00679 if (opts.raw) {
00680 rc = rdd_open_aligned_reader(&reader, reader, RDD_SECTOR_SIZE);
00681 if (rc != RDD_OK) {
00682 fatal_rdd_error(rc, "cannot open %s for aligned access",
00683 opts.infile);
00684 }
00685 }
00686
00687 *inputlen = RDD_WHOLE_FILE;
00688 if ((rc = rdd_device_size(opts.infile, inputlen)) != RDD_OK) {
00689 fatal_rdd_error(rc, "%s: cannot determine device size", opts.infile);
00690 }
00691
00692 if (opts.simfile != 0) {
00693 rc = rdd_open_faulty_reader(&reader, reader, opts.simfile);
00694 if (rc != RDD_OK) {
00695 fatal_rdd_error(rc, "cannot initialize fault simulator");
00696 }
00697 }
00698
00699 return reader;
00700 }
00701
00702 static RDD_READER *
00703 open_net_input(rdd_count_t *inputlen)
00704 {
00705 RDD_READER *reader = 0;
00706 int server_sock = -1;
00707 unsigned flags;
00708 int fd = -1;
00709 int rc;
00710
00711 *inputlen = RDD_WHOLE_FILE;
00712
00713
00714 if (opts.inetd) {
00715
00716 fd = STDIN_FILENO;
00717 } else {
00718 rc = rdd_init_server(the_printer, opts.server_port,
00719 &server_sock);
00720 if (rc != RDD_OK) {
00721 fatal_rdd_error(rc, "cannot start rdd-copy server");
00722 }
00723
00724 rc = rdd_await_connection(the_printer, server_sock, &fd);
00725 if (rc != RDD_OK) {
00726 fatal_rdd_error(rc, "no connection");
00727 }
00728 }
00729
00730 rc = rdd_open_fd_reader(&reader, fd);
00731 if (rc != RDD_OK) {
00732 fatal_rdd_error(rc, "cannot open reader on server socket");
00733 }
00734
00738 int compress = 0;
00739 rdd_output_opt_t current_output_opt;
00740 current_output_opt.outpath = "init";
00741 rdd_count_t current_blocklen;
00742 rdd_count_t current_inputlen;
00743 while (current_output_opt.outpath[0] != '\0') {
00744 rc = rdd_recv_info(reader, ¤t_output_opt.outpath, ¤t_inputlen,
00745 ¤t_blocklen, ¤t_output_opt.splitlen, ¤t_output_opt.ewf, &flags);
00746 if (rc != RDD_OK) {
00747 fatal_rdd_error(rc, "bad client request");
00748 }
00749 if (current_output_opt.outpath[0] != '\0') {
00750 if (opts.output_count + 1 >= RDD_MAX_OUTPUT_OPTS) {
00751 error("received too many output file requests");
00752 }
00753 opts.output[opts.output_count] = current_output_opt;
00754 opts.blocklen = current_blocklen;
00755 if ((flags & RDD_NET_COMPRESS) != 0) {
00756 compress = 1;
00757 }
00758 *inputlen = current_inputlen;
00759 ++opts.output_count;
00760 }
00761 }
00762
00763 int i;
00764 if (opts.verbose) {
00765 logmsg("Received rdd request:");
00766 logmsg("\tfile size: %s", rdd_strsize(*inputlen));
00767 logmsg("\tblock size: %llu", opts.blocklen);
00768 for (i=0; i<opts.output_count; i++) {
00769 logmsg("\toutput #%d:", i);
00770 logmsg("\tfile name: %s", opts.output[i].outpath);
00771 logmsg("\tsplit size: %llu", opts.output[i].splitlen);
00772 logmsg("\tewf compression: %s", print_ewf_compress_option());
00773 }
00774 }
00775
00776 if (compress) {
00777 if ((rc = rdd_open_zlib_reader(&reader, reader)) != RDD_OK) {
00778 fatal_rdd_error(rc, "cannot open zlib reader");
00779 }
00780 }
00781
00782 return reader;
00783 }
00784
00785
00786
00787 static RDD_READER *
00788 open_input(rdd_count_t *inputlen)
00789 {
00790 if (opts.mode == RDD_SERVER) {
00791 return open_net_input(inputlen);
00792 } else {
00793 return open_disk_input(inputlen);
00794 }
00795 }
00796
00797 static RDD_WRITER *
00798 open_disk_output(rdd_count_t outputsize, RDD_HASH_CONTAINER * hashcontainer, int output_number)
00799 {
00800 RDD_WRITER *writer = 0;
00801 rdd_write_mode_t wrmode;
00802 int rc;
00803
00804 rdd_output_opt_t * output_opts = &opts.output[output_number];
00805
00806 if (output_opts->outpath == 0) {
00807 return 0;
00808 }
00809
00810 wrmode = (opts.force_overwrite ? RDD_OVERWRITE_ASK : RDD_NO_OVERWRITE);
00811
00812 if (strcmp(output_opts->outpath, "-") == 0) {
00813 if (output_opts->splitlen > 0) {
00814 error("cannot split standard output stream");
00815 }
00816 rc = rdd_open_fd_writer(&writer, STDOUT_FILENO);
00817 if (rc != RDD_OK) {
00818 fatal_rdd_error(rc, "cannot write to standard output?");
00819 }
00820 } else if (output_opts->ewf) {
00821 if (opts.sha256) {
00822 logmsg("Warning: cannot store SHA256 hash in ewf file");
00823 }
00824 if (opts.sha384) {
00825 logmsg("Warning: cannot store SHA384 hash in ewf file");
00826 }
00827 if (opts.sha512) {
00828 logmsg("Warning: cannot store SHA384 hash in ewf file");
00829 }
00830 rc = rdd_open_ewf_writer(&writer, output_opts->outpath, output_opts->splitlen, output_opts->ewf, wrmode, hashcontainer);
00831 if (rc != RDD_OK) {
00832 fatal_rdd_error(rc, "cannot open ewf output file %s",
00833 output_opts->outpath);
00834 }
00835 } else if (output_opts->splitlen > 0) {
00836 rc = rdd_open_part_writer(&writer, output_opts->outpath,
00837 outputsize, output_opts->splitlen, wrmode);
00838 if (rc != RDD_OK) {
00839 fatal_rdd_error(rc, "cannot open multipart output file");
00840 }
00841 } else {
00842 rc = rdd_open_safe_writer(&writer, output_opts->outpath, wrmode);
00843 if (rc != RDD_OK) {
00844 fatal_rdd_error(rc, "cannot open output file %s",
00845 output_opts->outpath);
00846 }
00847 }
00848
00849 return writer;
00850 }
00851
00852 static RDD_WRITER *
00853 connection_exists(RDD_WRITER * writer_list[], int output_number, struct addrinfo * address)
00854 {
00855 int i;
00856 int rc;
00857 int result;
00858 for (i=0; i<output_number; i++) {
00859 if (writer_list[i] != 0) {
00860 rc = rdd_compare_address(writer_list[i], address, &result);
00861 if (rc != RDD_OK) {
00862 fatal_rdd_error(rc, "cannot compare addresses");
00863 }
00864 if (result == 1) {
00865 return writer_list[i];
00866 }
00867 }
00868 }
00869 return 0;
00870 }
00871
00872 static int
00873 send_end_of_output_opts_marker(RDD_WRITER * tcp_writer_list[])
00874 {
00875 int i;
00876 int rc;
00877 int result;
00878 for (i=0; i<opts.output_count; i++) {
00879 if (tcp_writer_list[i] != 0) {
00880
00881 rc = rdd_compare_address(tcp_writer_list[i], 0, &result);
00882 if (rc != RDD_OK) {
00883 fatal_rdd_error(rc, "cannot compare addresses");
00884 }
00885 if (result == 0) {
00886 rc = rdd_send_info(tcp_writer_list[i], "\0", 0, 0, 0, 0, 0);
00887 if (rc != RDD_OK) {
00888 return rc;
00889 }
00890 }
00891 }
00892 }
00893 return RDD_OK;
00894 }
00895
00911 static RDD_WRITER *
00912 open_net_output(rdd_count_t outputsize, RDD_WRITER * tcp_writer_list[], int * num_tcp_writers, int output_number)
00913 {
00914 RDD_WRITER *writer = 0;
00915 unsigned flags = 0;
00916 int rc;
00917 char *server = opts.output[output_number].server_host;
00918 unsigned port = opts.output[output_number].server_port;
00919 int new_writer;
00920
00921 assert(opts.output[output_number].outpath != 0);
00922
00926 struct addrinfo * addr;
00927 rc = rdd_get_address(server, port, &addr);
00928 if (rc != RDD_OK) {
00929 fatal_rdd_error(rc, "could not resolve server address");
00930 }
00931
00932 if ((writer = connection_exists(tcp_writer_list, *num_tcp_writers, addr)) != 0) {
00933
00934 new_writer = 0;
00935 } else {
00936 rc = rdd_open_tcp_writer(&writer, server, port);
00937
00938 if (rc != RDD_OK) {
00939 fatal_rdd_error(rc, "cannot connect to %s:%u", server, port);
00940 }
00941 tcp_writer_list[*num_tcp_writers] = writer;
00942 (*num_tcp_writers)++;
00943 new_writer = 1;
00944 }
00945
00949 flags = (opts.compress ? RDD_NET_COMPRESS : 0);
00950
00951 rc = rdd_send_info(writer, opts.output[output_number].outpath, outputsize,
00952 opts.blocklen, opts.output[output_number].splitlen, opts.output[output_number].ewf, flags);
00953 if (rc != RDD_OK) {
00954 fatal_rdd_error(rc, "cannot send header to %s:%u", server, port);
00955 }
00956
00957
00958 if (new_writer) {
00959 if (opts.compress) {
00960
00961
00962 rc = rdd_open_zlib_writer(&writer, writer);
00963
00964 if (rc != RDD_OK) {
00965 fatal_rdd_error(rc, "cannot compress network traffic "
00966 "to %s:%u", server, port);
00967 }
00968 }
00969 }
00970
00971 if (new_writer) {
00972 return writer;
00973 } else {
00974 return 0;
00975 }
00976 }
00981 static RDD_WRITER *
00982 open_output(rdd_count_t outputsize, RDD_HASH_CONTAINER * hashcontainer, RDD_WRITER * tcp_writer_list[], int * num_tcp_writers, int output_number)
00983 {
00984 if (opts.mode == RDD_CLIENT) {
00985 return open_net_output(outputsize, tcp_writer_list, num_tcp_writers, output_number);
00986 } else {
00987 return open_disk_output(outputsize, hashcontainer, output_number);
00988 }
00989 }
00990
00991 static void
00992 open_logfile(void)
00993 {
00994 RDD_MSGPRINTER *log_printer = 0;
00995 RDD_MSGPRINTER *bcast_printer = 0;
00996 RDD_MSGPRINTER *printers[2];
00997 unsigned nprinter = 0;
00998 int rc = RDD_OK;
00999
01000
01001
01002
01003
01004 if (the_printer != 0 && (opts.verbose || opts.logfile == 0)) {
01005 printers[nprinter++] = the_printer;
01006 }
01007
01008
01009
01010
01011 if (opts.logfile != 0) {
01012 rc = rdd_mp_open_file_printer(&log_printer, opts.logfile, opts.force_overwrite);
01013 if (rc != RDD_OK) {
01014 fatal_rdd_error(rc, "cannot open log file (%s)",
01015 opts.logfile);
01016 }
01017
01018 rc = rdd_mp_open_log_printer(&log_printer, log_printer);
01019 if (rc != RDD_OK) {
01020 fatal_rdd_error(rc, "cannot stack log printer");
01021 }
01022
01023 printers[nprinter++] = log_printer;
01024 }
01025
01026
01027
01028 rc = rdd_mp_open_bcastprinter(&bcast_printer, nprinter, printers);
01029 if (rc != RDD_OK) {
01030 fatal_rdd_error(rc, "cannot open bcast printer");
01031 }
01032 the_printer = bcast_printer;
01033 }
01034
01035 static void
01036 close_printer(void)
01037 {
01038 int rc;
01039
01040 if (the_printer == 0) return;
01041
01042 rc = rdd_mp_close(the_printer, RDD_MP_RECURSE|RDD_MP_READONLY);
01043 if (rc != RDD_OK) {
01044
01045
01046 fprintf(stderr, "cannot close message printer\n");
01047 exit(EXIT_FAILURE);
01048 }
01049
01050 the_printer = 0;
01051 }
01052
01053
01054
01055 static void
01056 log_header(char **argv, int argc)
01057 {
01058 char cmdline[1024];
01059 char *p;
01060 int i;
01061
01062 logmsg("");
01063 logmsg("%s", rdd_ctime());
01064 logmsg("%s version %s", PACKAGE, VERSION);
01065 logmsg("Copyright (c) 2002 Nederlands Forensisch Instituut");
01066 #if defined(RDD_TRACE)
01067 logmsg("Compile-time flag RDD_TRACE is set");
01068 #endif
01069 #if defined(HAVE_LIBZ)
01070 logmsg("zlib version %s", zlibVersion());
01071 logmsg("Copyright (c) 1995-2002 Jean-loup Gailly and Mark Adler");
01072 #endif
01073 #ifdef HAVE_OPENSSL
01074 logmsg("openssl version %s", OPENSSL_VERSION_TEXT);
01075 logmsg("Copyright (c) 1995-1998 Eric Young");
01076 #else
01077 logmsg("NOT using openssl");
01078 #endif
01079
01080 p = cmdline;
01081 snprintf(p, sizeof cmdline, "%s", argv[0]);
01082 cmdline[(sizeof cmdline) - 1] = '\000';
01083 p += strlen(argv[0]);
01084 for (i = 1; i < argc; i++) {
01085 snprintf(p, (sizeof cmdline) - (p - cmdline), " %s", argv[i]);
01086 cmdline[(sizeof cmdline) - 1] = '\000';
01087 p += 1 + strlen(argv[i]);
01088 }
01089 logmsg("%s", cmdline);
01090 }
01091
01092 static void
01093 log_params(rdd_copy_opts *opts)
01094 {
01095 logmsg("========== Parameter settings ==========");
01096 logmsg("mode: %s",
01097 opts->mode == RDD_LOCAL ? "local" :
01098 opts->mode == RDD_CLIENT ? "client" :
01099 "server");
01100 logmsg("verbose: %s", bool2str(opts->verbose));
01101 logmsg("quiet: %s", bool2str(opts->quiet));
01102 logmsg("server port: %u", opts->server_port);
01103 logmsg("input file: %s", str2str(opts->infile));
01104 logmsg("log file: %s", str2str(opts->logfile));
01105 int i;
01106 for (i=0; i<opts->output_count; i++) {
01107 logmsg("output #%d", i);
01108 logmsg("\toutput file: %s", str2str(opts->output[i].outpath));
01109 logmsg("\tsegment size: %llu", opts->output[i].splitlen);
01110 logmsg("\toutput as ewf compression: %s", print_ewf_compress_option());
01111 logmsg("\toutput host: %s", opts->output[i].server_host);
01112 logmsg("\toutput port: %u", opts->output[i].server_port);
01113 }
01114 logmsg("CRC32 file: %s", str2str(opts->crc32file));
01115 logmsg("Adler32 file: %s", str2str(opts->adler32file));
01116 logmsg("Statistics file: %s", str2str(opts->histfile));
01117 logmsg("Block MD5 file: %s", str2str(opts->blockmd5file));
01118 logmsg("raw-device input: %s", bool2str(opts->raw));
01119 logmsg("compress network data: %s", bool2str(opts->compress));
01120 logmsg("use (x)inetd: %s", bool2str(opts->inetd));
01121 logmsg("force overwrite: %s", bool2str(opts->force_overwrite));
01122 logmsg("compute MD5: %s", bool2str(opts->md5));
01123 logmsg("compute SHA1: %s", bool2str(opts->sha1));
01124 logmsg("compute SHA256: %s", bool2str(opts->sha256));
01125 logmsg("compute SHA384: %s", bool2str(opts->sha384));
01126 logmsg("compute SHA512: %s", bool2str(opts->sha512));
01127 logmsg("max #retries: %u", opts->nretry);
01128 logmsg("block size: %llu", opts->blocklen);
01129 logmsg("minimum block size: %llu", opts->minblocklen);
01130 logmsg("Adler32 block size: %llu", opts->adler32len);
01131 logmsg("CRC32 block size: %llu", opts->crc32len);
01132 logmsg("statistics block size: %llu", opts->histblocklen);
01133 logmsg("MD5 block size: %llu", opts->blockmd5len);
01134 logmsg("input offset: %llu", opts->offset);
01135 logmsg("input count: %llu", opts->count);
01136 logmsg("progress reporting interval: %llu", opts->progresslen);
01137 logmsg("max #errors to tolerate: %llu", opts->max_read_err);
01138 logmsg("========================================");
01139 logmsg("");
01140 }
01141
01142 static void
01143 handle_read_error(rdd_count_t offset, unsigned nbyte, void *env)
01144 {
01145 logmsg("read error: offset %llu bytes, count %u bytes",
01146 offset, nbyte);
01147 }
01148
01149 static void
01150 handle_substitution(rdd_count_t offset, unsigned nbyte, void *env)
01151 {
01152 logmsg("input dropped: offset %llu bytes, count %u bytes",
01153 offset, nbyte);
01154 }
01155
01156 static int
01157 handle_progress(rdd_count_t pos, rdd_count_t nsubst, void *env)
01158 {
01159 RDD_PROGRESS *p = (RDD_PROGRESS *) env;
01160 RDD_PROGRESS_INFO info;
01161 double megabytes_per_sec;
01162 double gigabytes_done;
01163 double perc_done;
01164 double secs_left;
01165
01166 int rc;
01167
01168 if ((rc = rdd_progress_update(p, pos, nsubst)) != RDD_OK) {
01169 fatal_rdd_error(rc, "cannot update progress object");
01170 }
01171
01172 rc = rdd_progress_poll(p, &info);
01173 if (rc == RDD_EAGAIN) {
01174 return RDD_OK;
01175 } else if (rc != RDD_OK) {
01176 fatal_rdd_error(rc, "cannot obtain progress information");
01177 }
01178
01179
01180
01181 gigabytes_done = (double) info.pos / (double) (1 << 30);
01182 megabytes_per_sec = info.speed / (double) (1 << 20);
01183
01184 if (info.fraction >= 0.0) {
01185
01186
01187
01188 perc_done = 100.0 * info.fraction;
01189 if (info.speed == 0) {
01190 secs_left = 0;
01191 } else {
01192 secs_left = ((double)(p->input_size - pos)) / info.speed;
01193 }
01194
01195 int days, hours, mins, secs;
01196 rc = timeUnits(secs_left, &secs, &mins, &hours, &days);
01197 if (rc != RDD_OK) {
01198 fatal_rdd_error(rc, "cannot compute time units");
01199 }
01200
01201 fprintf(stderr,
01202 "Estimated time remaining: %d day(s) %d hour(s) %d minute(s) %d second(s)\n",
01203 days, hours, mins, secs);
01204
01205 fprintf(stderr, "%.3f GB done (%6.2f%%), "
01206 "average speed %.3f MB/s"
01207 " (%.0f seconds remaining)"
01208 ", substituted %lu bytes "
01209 "\n",
01210 gigabytes_done, perc_done, megabytes_per_sec
01211 , secs_left
01212 , (long unsigned int) info.nsubst
01213 );
01214 } else {
01215
01216
01217
01218 fprintf(stderr, "%.3f GB done, average speed %.3f MB/s, subsituted %lu bytes\n",
01219 gigabytes_done, megabytes_per_sec, (long unsigned int) info.nsubst);
01220 }
01221
01222 return RDD_OK;
01223 }
01224
01225 static void
01226 add_filter(RDD_FILTERSET *fset, const char *name, RDD_FILTER *f)
01227 {
01228 int rc;
01229
01230 if ((rc = rdd_fset_add(fset, name, f)) != RDD_OK) {
01231 fatal_rdd_error(rc, "cannot install %s filter", name);
01232 }
01233 }
01234
01235 static void
01236 install_filters(RDD_FILTERSET *fset, RDD_WRITER * writers[])
01237 {
01238 RDD_FILTER *f = 0;
01239 int rc;
01240 char writer_name[16];
01241
01242 if ((rc = rdd_fset_init(fset)) != RDD_OK) {
01243 fatal_rdd_error(rc, "cannot create filter fset");
01244 }
01245
01246 int i;
01247 for (i=0; i<opts.output_count; i++) {
01248 if (writers[i] != 0) {
01249 rc = rdd_new_write_streamfilter(&f, writers[i]);
01250 if (rc != RDD_OK) {
01251 fatal_rdd_error(rc, "cannot create write filter");
01252 }
01253 if (snprintf(writer_name, sizeof(writer_name), "writer_%d", i) >= sizeof(writer_name)) {
01254
01255 error("writer name too long");
01256 }
01257 add_filter(fset, writer_name, f);
01258 }
01259 }
01260
01261 if (opts.md5) {
01262 rc = rdd_new_md5_streamfilter(&f);
01263 if (rc != RDD_OK) {
01264 fatal_rdd_error(rc, "cannot create MD5 filter");
01265 }
01266 add_filter(fset, "MD5 stream", f);
01267 }
01268
01269 if (opts.sha1) {
01270 rc = rdd_new_sha1_streamfilter(&f);
01271 if (rc != RDD_OK) {
01272 fatal_rdd_error(rc, "cannot create SHA-1 filter");
01273 }
01274 add_filter(fset, "SHA-1 stream", f);
01275 }
01276
01277 if (opts.sha256) {
01278 rc = rdd_new_sha256_streamfilter(&f);
01279 if (rc != RDD_OK) {
01280 fatal_rdd_error(rc, "cannot create SHA-256 filter");
01281 }
01282 add_filter(fset, "SHA-256 stream", f);
01283 }
01284
01285 if (opts.sha384) {
01286 rc = rdd_new_sha384_streamfilter(&f);
01287 if (rc != RDD_OK) {
01288 fatal_rdd_error(rc, "cannot create SHA-384 filter");
01289 }
01290 add_filter(fset, "SHA-384 stream", f);
01291 }
01292
01293 if (opts.sha512) {
01294 rc = rdd_new_sha512_streamfilter(&f);
01295 if (rc != RDD_OK) {
01296 fatal_rdd_error(rc, "cannot create SHA-512 filter");
01297 }
01298 add_filter(fset, "SHA-512 stream", f);
01299 }
01300
01301 if (opts.blockmd5file != 0) {
01302 rc = rdd_new_md5_blockfilter(&f, opts.blockmd5len,
01303 opts.blockmd5file,
01304 opts.force_overwrite);
01305 if (rc != RDD_OK) {
01306 fatal_rdd_error(rc, "cannot create MD5 block filter");
01307 }
01308 add_filter(fset, "MD5 block", f);
01309 }
01310
01311 if (opts.histfile != 0) {
01312 rc = rdd_new_stats_blockfilter(&f,
01313 opts.histblocklen, opts.histfile,
01314 opts.force_overwrite);
01315 if (rc != RDD_OK) {
01316 fatal_rdd_error(rc, "cannot create statistics filter");
01317 }
01318 add_filter(fset, "statistical block", f);
01319 }
01320
01321 if (opts.adler32file != 0) {
01322 rc = rdd_new_adler32_blockfilter(&f,
01323 opts.adler32len, opts.adler32file,
01324 opts.force_overwrite);
01325 if (rc != RDD_OK) {
01326 fatal_rdd_error(rc, "cannot create Adler32 filter");
01327 }
01328 add_filter(fset, "Adler32 block", f);
01329 }
01330
01331 if (opts.crc32file != 0) {
01332 rc = rdd_new_crc32_blockfilter(&f,
01333 opts.crc32len, opts.crc32file,
01334 opts.force_overwrite);
01335 if (rc != RDD_OK) {
01336 fatal_rdd_error(rc, "cannot create CRC-32 filter");
01337 }
01338 add_filter(fset, "CRC-32 block", f);
01339 }
01340 }
01341
01342 static RDD_COPIER *
01343 create_copier(rdd_count_t input_size, RDD_PROGRESS *progress)
01344 {
01345 RDD_COPIER *copier = 0;
01346 rdd_count_t count = 0;
01347 int rc;
01348
01349
01350
01351 if (opts.offset > input_size) {
01352 error("offset %llu larger than input file size (%s)",
01353 opts.offset, rdd_strsize(input_size));
01354 }
01355
01356
01357
01358 if (input_size == RDD_WHOLE_FILE) {
01359 count = RDD_WHOLE_FILE;
01360 } else {
01361 count = input_size - opts.offset;
01362 }
01363 if (opts.count > 0) {
01364 if (opts.count <= count) {
01365 count = opts.count;
01366 } else {
01367 logmsg("User count (%llu) too large; ignored", opts.count);
01368 }
01369 }
01370 if (opts.verbose) {
01371 logmsg("input size: %s", rdd_strsize(input_size));
01372 logmsg("read size: %s", rdd_strsize(count));
01373 }
01374
01375
01376 if (opts.mode == RDD_SERVER) {
01377 RDD_SIMPLE_PARAMS p;
01378
01379 memset(&p, 0, sizeof p);
01380 if (progress != 0) {
01381 p.progressfun = handle_progress;
01382 p.progressenv = progress;
01383 }
01384
01385 rc = rdd_new_simple_copier(&copier, &p);
01386 if (rc != RDD_OK) {
01387 fatal_rdd_error(rc, "cannot create simple copier");
01388 }
01389 } else {
01390 RDD_ROBUST_PARAMS p;
01391
01392 memset(&p, 0, sizeof p);
01393 p.minblocklen = opts.minblocklen;
01394 p.maxblocklen = opts.blocklen;
01395 p.nretry = opts.nretry;
01396 p.maxsubst = opts.max_read_err;
01397 p.readerrfun = handle_read_error;
01398 p.substfun = handle_substitution;
01399 if (progress != 0) {
01400 p.progressfun = handle_progress;
01401 p.progressenv = progress;
01402 }
01403
01404 rc = rdd_new_robust_copier(&copier,
01405 opts.offset, count, &p);
01406 if (rc != RDD_OK) {
01407 fatal_rdd_error(rc, "cannot create robust copier");
01408 }
01409 }
01410
01411 return copier;
01412 }
01413
01414 static void
01415 process_hash_result(RDD_FILTERSET *fset, const char *hash_name,
01416 const char *filter_name, unsigned mdsize, RDD_HASH_CONTAINER * hashcontainer)
01417 {
01418 unsigned char md[RDD_MAX_DIGEST_LENGTH];
01419 char hexdigest[2*RDD_MAX_DIGEST_LENGTH + 1];
01420 RDD_FILTER *f = 0;
01421 int rc;
01422
01423 memset(md, 0, mdsize);
01424
01425 if (mdsize > (sizeof md)) {
01426 fatal_rdd_error(RDD_ESPACE, "digest size exceeds buffer size");
01427 }
01428
01429 if ((rc = rdd_fset_get(fset, filter_name, &f)) != RDD_OK) {
01430 fatal_rdd_error(rc, "cannot find %s filter", filter_name);
01431 }
01432
01433 if ((rc = rdd_filter_get_result(f, md, mdsize)) != RDD_OK) {
01434 fatal_rdd_error(rc, "cannot get result for %s filter",
01435 filter_name);
01436 }
01437
01438
01439 rc = rdd_buf2hex(md, mdsize, hexdigest, sizeof hexdigest);
01440 if (rc != RDD_OK) {
01441 fatal_rdd_error(rc, "cannot convert binary digest");
01442 }
01443
01444
01445 if ((rc = rdd_set_hash(hashcontainer, hash_name, md)) != RDD_OK) {
01446 fatal_rdd_error(rc, "error storing hash %s", hash_name);
01447 }
01448
01449
01450 logmsg("%s: %s", hash_name, hexdigest);
01451 }
01452
01453 int
01454 main(int argc, char **argv)
01455 {
01456 double start, end;
01457 RDD_READER *reader;
01458 RDD_WRITER * writers[RDD_MAX_OUTPUT_OPTS];
01459 RDD_WRITER * tcp_writers[RDD_MAX_OUTPUT_OPTS];
01460 int num_tcp_writers = 0;
01461 RDD_PROGRESS progress;
01462 RDD_COPIER_RETURN copier_ret;
01463 RDD_COPIER *copier;
01464 RDD_FILTERSET filterset;
01465 RDD_MSGPRINTER *printer = 0;
01466 RDD_HASH_CONTAINER *hashcontainer = 0;
01467 rdd_count_t input_size;
01468 int rc;
01469 int i;
01470
01471
01472
01473 for (i=0; i<RDD_MAX_OUTPUT_OPTS; i++) {
01474 writers[i] = 0;
01475 tcp_writers[i] = 0;
01476 }
01477
01478 set_progname(argv[0]);
01479 rdd_cons_open();
01480 rdd_init();
01481
01482
01483 rc = rdd_mp_open_stdio_printer(&printer, stderr);
01484 if (rc != RDD_OK) {
01485 fprintf(stderr, "cannot open stderr message printer\n");
01486 exit(EXIT_FAILURE);
01487 }
01488 #if 0
01489 rc = rdd_mp_open_log_printer(&printer, printer);
01490 if (rc != RDD_OK) {
01491 exit(EXIT_FAILURE);
01492 }
01493 #endif
01494 the_printer = printer;
01495
01496 init_options();
01497 rdd_opt_init(usage_message);
01498 command_line(argc, argv);
01499 open_logfile();
01500
01501 rdd_catch_signals();
01502
01503 log_header(argv, argc);
01504 log_params(&opts);
01505
01506 if (!opts.md5 && !opts.sha1 && !opts.sha256 && !opts.sha384 && !opts.sha512) {
01507 rdd_quit_if(RDD_NO, "Continue without hashing (yes/no)?");
01508 }
01509 if (opts.logfile == 0) {
01510 rdd_quit_if(RDD_NO, "Continue without logging (yes/no)?");
01511 }
01512
01513 reader = open_input(&input_size);
01514
01515 if ((rc = rdd_new_hashcontainer(&hashcontainer)) != RDD_OK) {
01516 fatal_rdd_error(rc, "cannot create hashes object");
01517 }
01518
01519 for (i=0; i<opts.output_count; i++) {
01520 writers[i] = open_output(RDD_WHOLE_FILE, hashcontainer, tcp_writers, &num_tcp_writers, i);
01521 }
01522
01523 if ((rc = send_end_of_output_opts_marker(tcp_writers)) != RDD_OK) {
01524 fatal_rdd_error(rc, "cannot send end of output opts marker");
01525 }
01526
01527 install_filters(&filterset, writers);
01528
01529 if (opts.progresslen > 0) {
01530 rc = rdd_progress_init(&progress, input_size, opts.progresslen);
01531 if (rc != RDD_OK) {
01532 fatal_rdd_error(rc, "cannot initialize progress object");
01533 }
01534 copier = create_copier(input_size, &progress);
01535 } else {
01536 copier = create_copier(input_size, 0);
01537 }
01538
01539 start = rdd_gettime();
01540 rc = rdd_copy_exec(copier, reader, &filterset, &copier_ret);
01541 if (rc != RDD_OK) {
01542 fatal_rdd_error(rc, "copy failed");
01543 }
01544 end = rdd_gettime();
01545
01546 rdd_mp_message(the_printer, RDD_MSG_INFO, "=== done ***");
01547 rdd_mp_message(the_printer, RDD_MSG_INFO, "seconds: %.3f", end - start);
01548 rdd_mp_message(the_printer, RDD_MSG_INFO, "bytes written: %llu",
01549 copier_ret.nbyte);
01550 rdd_mp_message(the_printer, RDD_MSG_INFO, "bytes lost: %llu",
01551 copier_ret.nlost);
01552 rdd_mp_message(the_printer, RDD_MSG_INFO, "read errors: %lu",
01553 copier_ret.nread_err);
01554 rdd_mp_message(the_printer, RDD_MSG_INFO, "zero-block substitutions: "
01555 "%lu", copier_ret.nsubst);
01556
01557 if (opts.md5) {
01558 process_hash_result(&filterset, RDD_MD5, "MD5 stream", MD5_DIGEST_LENGTH, hashcontainer);
01559 } else {
01560 logmsg("MD5: <none>");
01561 }
01562 if (opts.sha1) {
01563 process_hash_result(&filterset, RDD_SHA1, "SHA-1 stream", SHA_DIGEST_LENGTH, hashcontainer);
01564 } else {
01565 logmsg("SHA1: <none>");
01566 }
01567 if (opts.sha256) {
01568 process_hash_result(&filterset, RDD_SHA256, "SHA-256 stream", SHA256_DIGEST_LENGTH, hashcontainer);
01569 } else {
01570 logmsg("SHA256: <none>");
01571 }
01572 if (opts.sha384) {
01573 process_hash_result(&filterset, RDD_SHA384, "SHA-384 stream", SHA384_DIGEST_LENGTH, hashcontainer);
01574 } else {
01575 logmsg("SHA384: <none>");
01576 }
01577 if (opts.sha512) {
01578 process_hash_result(&filterset, RDD_SHA512, "SHA-512 stream", SHA512_DIGEST_LENGTH, hashcontainer);
01579 } else {
01580 logmsg("SHA512: <none>");
01581 }
01582
01583 if ((rc = rdd_copy_free(copier)) != RDD_OK) {
01584 fatal_rdd_error(rc, "cannot clean up copier");
01585 }
01586
01587 for (i=0; i<opts.output_count; i++) {
01588 if (writers[i] != 0) {
01589 if ((rc = rdd_writer_close(writers[i])) != RDD_OK) {
01590 fatal_rdd_error(rc, "cannot clean up writer");
01591 }
01592 }
01593 }
01594
01595 if ((rc = rdd_fset_clear(&filterset)) != RDD_OK) {
01596 fatal_rdd_error(rc, "cannot clean up filters");
01597 }
01598
01599 if ((rc = rdd_reader_close(reader, 1)) != RDD_OK) {
01600 fatal_rdd_error(rc, "cannot clean up reader");
01601 }
01602
01603 close_printer();
01604
01605 if (copier_ret.nread_err > 0) {
01606 logmsg("%u read errors occurred", copier_ret.nread_err);
01607 exit(EXIT_FAILURE);
01608 }
01609
01610 logmsg("no read errors");
01611
01612
01613 rdd_cons_close();
01614
01615 return 0;
01616 }