[Forensics-changes] [SCM] debian-forensics/dc3dd branch, debian, updated. debian/7.0.0-1-1-gc1979cd
Christophe Monniez
christophe.monniez at fccu.be
Tue Aug 9 09:41:25 UTC 2011
The following commit has been merged in the debian branch:
commit c1979cd332779a170279c91313ea9cb7d6ec10ce
Author: Christophe Monniez <christophe.monniez at fccu.be>
Date: Tue Aug 9 11:24:17 2011 +0200
Merging upstream version 7.1.614.
diff --git a/.prev-version b/.prev-version
index aea5e0b..66ce77b 100644
--- a/.prev-version
+++ b/.prev-version
@@ -1 +1 @@
-6.12.5
+7.0.0
diff --git a/.version b/.version
index 66ce77b..2e55b50 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-7.0.0
+7.1.614
diff --git a/ChangeLog b/ChangeLog
index bbaad77..40834c1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,344 +1,352 @@
-2009-08-28 Richard Cordovano <rcordovano at users.sourceforge.net>
-
- * Replaced the byte-by-byte verification capability with a verification capability that
- hashes imaging outputs and compares the hashes to the input hash. The new verification capability
- does not require a second read of the device.
- * Enhanced the ability to generate multiple outputs by adding the capability to combine split and unsplit
- outputs.
- * Added the ability for the user to specify a sector size via the command line.
- * Added display/logging of results of device size probes. Size probes are now always performed, providing
- run statistics in most use cases (reading from standard input excepted).
- * Added display/logging of size statistics for each file in an input or output split.
- * Simplified the command line options and removed all legacy dd features not needed for imaging. The simplified
- command line is more rigorously validated to reduce the likelihood of performing a run contrary to user
- intent in order to avoid a second read of a device.
- * Removed the progress=on command line option and the cumbersome INFO signaling protocol for
- obtaining a progress report. Instead, a progress bar is always displayed.
- * Added new DEFAULT_IMAGING_MODE compile flag support (equivalent to command line options:
- recovererrs=on, grouperrs=on, idirect=on).
- * Reduced the use of global variables from 71 to 9, reduced function lengths, and
- removed several instances of code duplication.
- * Introduced a program architecture that replaces a single loop with a jobs abstraction, allowing execution
- of an arbitrary chain of jobs, each composed of one or more tasks that execute in parallel. The new
- program architecture is designed to allow for the transparent addition of multi-step processing
- scenarios such as the new verification capability.
-
-
-2009-05-11 Richard Cordovano <rcordovano at users.sourceforge.net>
-
- * Added ability to generate multiple outputs simultaneously by supporting multiple
- of, vf, and vfjoin command line arguments.
-
-2009-04-01 Andrew Medico <amedico at users.sourceforge.net>
-
- * Put hashing and disk I/O into dedicated threads to increase
- throughput.
-
- As a side effect, removed cbs and conv=ascii/ebcdic/ibm/(un)block/lcase/swab
- command-line options since they don't apply to the goal of disk imaging.
-
- Also removed hashconv option and set behavior to hashconv=after.
-
-
-2009-03-24 Andrew Medico <amedico at users.sourceforge.net>
-
- * Added ability to detect HPA / DCO hidden areas on ATA drives (Linux only)
-
-
-2009-03-16 Andrew Medico <amedico at users.sourceforge.net>
-
- * Fix hashwindow - result buffer was too small, causing incorrect
- output on OS X
-
-
-2009-03-10 Andrew Medico <amedico at users.sourceforge.net>
-
- * Fix blockbench.pl to automatically work on Mac OS X
-
-
-2009-02-02 Andrew Medico <amedico at users.sourceforge.net>
-
- * Print hashes to console when log is enabled
-
-
-2008-12-15 Andrew Medico <amedico at users.sourceforge.net>
-
- * Print version number in startup message
-
-
-2008-12-09 Andrew Medico <amedico at users.sourceforge.net>
-
- * Fix crash when verifying against empty file
-
-
-2008-10-27 Andrew Medico <amedico at users.sourceforge.net>
-
- * Fixed a bug that was causing incorrect hashes to be displayed when
- using ifjoin or reading from standard input. Output data file was
- not affected.
-
-
-2008-10-15 Andrew Medico <amedico at users.sourceforge.net>
-
- * Added wipe= to automatically wipe a device with zeros
-
- * Fix --help formatting so man page gets formatted properly
-
-
-2008-10-06 Andrew Medico <amedico at users.sourceforge.net>
-
- * Fix minor warnings: use correct types and printf formats
-
-
-2008-09-30 Andrew Medico <amedico at users.sourceforge.net>
-
- * Add Cygwin support
-
-
-2008-09-29 Andrew Medico <amedico at users.sourceforge.net>
-
- * Fix a crash when invalid ifjoin/vfjoin patterns given
-
- * Fix error reporting to account for skip= offset when
- conv=sync,noerror not used.
-
- * Refactor redundant code into functions
-
- * Remove obsolete code
-
-
-2008-09-25 Andrew Medico <amedico at users.sourceforge.net>
-
- * Fix a crash when seek=X option was used without conv=notrunc
-
-
-2008-09-11 Andrew Medico <amedico at users.sourceforge.net>
-
- * Fix progress display when skip=X option is used
-
-
-2008-09-05 Andrew Medico <amedico at users.sourceforge.net>
-
- * Removed unused coreutils modules to fix static linking error on Solaris 9
-
-
-2008-09-04 Andrew Medico <amedico at users.sourceforge.net>
-
- * Updated base package to Coreutils version 6.12.
-
-
-2008-08-19 Andrew Medico <amedico at users.sourceforge.net>
-
- * Check that split size is a multiple of block size and print an
- error message at startup, instead of mysteriously failing during
- the run.
-
- * Added "blockbench" script to easily test many block sizes and find
- the fastest option for imaging.
-
-
-2008-07-24 Andrew Medico <amedico at users.sourceforge.net>
-
- * Added ifjoin= and vfjoin= to input or verify against
- split files
-
-
-2008-06-30 Andrew Medico <amedico at users.sourceforge.net>
-
- * In closing log message, indicate if process was aborted, terminated
- normally, or terminated due to errors.
-
-
-2008-06-27 Andrew Medico <amedico at users.sourceforge.net>
-
- * Print hash values so far when process is interrupted
-
-
-2008-06-26 Andrew Medico <amedico at users.sourceforge.net>
-
- * Change count, skip, and seek options to take sector counts
- instead of bytes
-
-
-2008-06-24 Andrew Medico <amedico at users.sourceforge.net>
-
- * Report sector address when errors occur in non-grouped mode
-
-
-2008-06-23 Andrew Medico <amedico at users.sourceforge.net>
-
- * Fix compile-flag printer to handle DEFAULT_SIZEPROBE
-
-
-2008-06-19 Andrew Medico <amedico at users.sourceforge.net>
-
- * Enable dynamic error recovery automatically when conv=sync,noerror
- is specified
-
- * Probe device sector size instead of hard-coding dynamic error
- recovery read size
-
- * Change default block size to 32K
-
- * Report progress and error positions in sectors (probed from device
- size) instead of blocks
-
- * Fix error counting in dynamic error recovery mode
-
-
-2008-06-17 Andrew Medico <amedico at users.sourceforge.net>
-
- * Log compile-time flags to the log file
-
-
-2008-06-16 Andrew Medico <amedico at users.sourceforge.net>
-
- * Add "dynamic" block size mode for better error recovery.
- Now when errors are detected, dc3dd rereads the failed block
- one sector at a time. This lets users run dc3dd in a faster
- large-block mode without losing entire blocks of data when a
- bad sector is encountered.
-
- * When verifying an image, say "X bytes compared" in progress line
- instead of "X bytes copied".
-
-
-2008-06-12 Andrew Medico <amedico at users.sourceforge.net>
-
- * When count is specified, calculate completion percentage
- out of count*ibs, instead of total device size.
-
-
-2008-06-11 Andrew Medico <amedico at users.sourceforge.net>
-
- * When writing a pattern, sizeprobe destination device for
- progress reporting.
-
-
-2008-06-10 Andrew Medico <amedico at users.sourceforge.net>
-
- * Added --flags command line option to display the binary's
- configure flags
-
-
-2008-06-05 Andrew Medico <amedico at users.sourceforge.net>
-
- * Fixed wording of error log when I/O errors are detected
- in errors=group mode
-
- * Save command-line string to log file
-
- * Log start and end times to log file
-
- * Flush log file so it gets written to disk even if the process
- is interrupted
-
-
-2008-02-29 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Fixed default hashing support when a hash log is not
- explicitly defined. For example, if the user configures
- the program with CFLAGS="-DDEFAULT_HASH_MD5" but doesn't
- specify a hash log, the hashes are now sent to stderr.
-
-
-2008-02-12 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Fixed progresscount default. I had included an extra
- underscore yesterday.
-
- * Added ability to change DEFAULT_BLOCKSIZE as promised
- in the documentation.
-
-
-2008-02-11 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Added DEFAULT_ values for some command line flags. These
- values should be passed in the configure CFLAGS options.
- The specific values that can be passed:
- - DEFAULT_HASH_MD5, DEFAULT_HASH_SHA1, DEFAULT_HASH_SHA256,
- DEFAULT_HASH_SHA512 enable hashing algorithms
- - DEFAULT_HASHCONV_BEFORE sets hashconv=before and
- DEFAULT_HASHCONV_AFTER sets hashconv=after
- - DEFAULT_PROGRESS sets progress=on
- - DEFAULT_PROGRESSCOUNT sets progresscount=x
- (e.g. -DDEFAULT_PROGRESSCOUNT=1000000)
- - DEFAULT_SIZEPROBE sets sizeprobe=on
-
- Example:
- ./configure CFLAGS="-O2 -DDEFAULT_HASH_MD5 -DDEFAULT_HASH_SHA1"
-
- It should be noted that any default hashing algorithms are
- ignored if the user specifies a value for hash= on the command
- line. Note that when a default hashing algorithm is specified
- the program CANNOT be run without hashing enabled.
-
- All other values can be overrideen normally on the command line.
-
- * Moved \r out of translated text in progress meter display.
- This should help us avoid ugly errors regarding having \r in there.
-
-
-2008-02-07 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Updated base package to Coreutils version 6.10.
-
-
-2008-01-29 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Changed error handling such that on a partial read
- the entire block is wiped with zeros. See bug 1881387.
-
- * Grouped errors now display the block numbers where
- the error occured, not the offset. See bug 1881383.
-
- * Improved help message for splitformat option.
-
-
-2008-01-19 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Updated documentation to reflect log appends, legal
- values for hashconv
-
-
-2008-01-12 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Updated contact address to dc3dd at dc3.mil.
-
-
-2008-01-10 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Changed log files to append messages rather than overwrite.
-
-
-2008-01-09 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Updated dc3_error_tail to create copies of the args
- passed in just in case they need to be written twice
- (stderr and log file).
-
- * Added check to display grouped errors at end of input
-
-
-2007-12-22 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Fixed sizeprobe code for OS X. It will still need work
- for BSD and other non-Linux, non-Mac platforms.
-
-
-2007-12-21 Jesse Kornblum <jessekornblum at users.sourceforge.net>
-
- * Created new source code tree based on slimmed down version
- of GNU Coreutils suite. Replaced existing ChangeLogs with
- this one. This file will be for changes to the dc3dd suite.
-
- * Replaced NEWS file with news for dc3dd only
-
- * Stripped out unused programs from src and man directories
-
- * Cleaned top level Makefile.am and configure.ac to exclude
- deleted programs.
-
- * Edited man/Makefile.am to only handle dc3dd.1
-
- * Removed old directory and changelogs from coreutils
+2011-03-02 Richard Cordovano <rcordovano at users.sourceforge.net>
+
+ * Added the ability to specify log= and hlog= more than once.
+ * Added phod= and fhod= options. For an output that is a device, using phod= ("partially hashed output device")
+ causes dc3dd to compute hashes of only the bytes dc3dd wrote to the output device. If fhod=
+ ("fully hashed output device") is specified instead, dc3dd will compute hashes of both the bytes dc3dd wrote
+ and of the entire device.
+
+2009-08-28 Richard Cordovano <rcordovano at users.sourceforge.net>
+
+ * Replaced the byte-by-byte verification capability with a verification capability that
+ hashes imaging outputs and compares the hashes to the input hash. The new verification capability
+ does not require a second read of the device.
+ * Enhanced the ability to generate multiple outputs by adding the capability to combine split and unsplit
+ outputs.
+ * Added the ability for the user to specify a sector size via the command line.
+ * Added display/logging of results of device size probes. Size probes are now always performed, providing
+ run statistics in most use cases (reading from standard input excepted).
+ * Added display/logging of size statistics for each file in an input or output split.
+ * Simplified the command line options and removed all legacy dd features not needed for imaging. The simplified
+ command line is more rigorously validated to reduce the likelihood of performing a run contrary to user
+ intent in order to avoid a second read of a device.
+ * Removed the progress=on command line option and the cumbersome INFO signaling protocol for
+ obtaining a progress report. Instead, a progress bar is always displayed.
+ * Added new DEFAULT_IMAGING_MODE compile flag support (equivalent to command line options:
+ recovererrs=on, grouperrs=on, idirect=on).
+ * Reduced the use of global variables from 71 to 9, reduced function lengths, and
+ removed several instances of code duplication.
+ * Introduced a program architecture that replaces a single loop with a jobs abstraction, allowing execution
+ of an arbitrary chain of jobs, each composed of one or more tasks that execute in parallel. The new
+ program architecture is designed to allow for the transparent addition of multi-step processing
+ scenarios such as the new verification capability.
+
+
+2009-05-11 Richard Cordovano <rcordovano at users.sourceforge.net>
+
+ * Added ability to generate multiple outputs simultaneously by supporting multiple
+ of, vf, and vfjoin command line arguments.
+
+2009-04-01 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Put hashing and disk I/O into dedicated threads to increase
+ throughput.
+
+ As a side effect, removed cbs and conv=ascii/ebcdic/ibm/(un)block/lcase/swab
+ command-line options since they don't apply to the goal of disk imaging.
+
+ Also removed hashconv option and set behavior to hashconv=after.
+
+
+2009-03-24 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Added ability to detect HPA / DCO hidden areas on ATA drives (Linux only)
+
+
+2009-03-16 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Fix hashwindow - result buffer was too small, causing incorrect
+ output on OS X
+
+
+2009-03-10 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Fix blockbench.pl to automatically work on Mac OS X
+
+
+2009-02-02 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Print hashes to console when log is enabled
+
+
+2008-12-15 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Print version number in startup message
+
+
+2008-12-09 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Fix crash when verifying against empty file
+
+
+2008-10-27 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Fixed a bug that was causing incorrect hashes to be displayed when
+ using ifjoin or reading from standard input. Output data file was
+ not affected.
+
+
+2008-10-15 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Added wipe= to automatically wipe a device with zeros
+
+ * Fix --help formatting so man page gets formatted properly
+
+
+2008-10-06 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Fix minor warnings: use correct types and printf formats
+
+
+2008-09-30 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Add Cygwin support
+
+
+2008-09-29 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Fix a crash when invalid ifjoin/vfjoin patterns given
+
+ * Fix error reporting to account for skip= offset when
+ conv=sync,noerror not used.
+
+ * Refactor redundant code into functions
+
+ * Remove obsolete code
+
+
+2008-09-25 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Fix a crash when seek=X option was used without conv=notrunc
+
+
+2008-09-11 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Fix progress display when skip=X option is used
+
+
+2008-09-05 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Removed unused coreutils modules to fix static linking error on Solaris 9
+
+
+2008-09-04 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Updated base package to Coreutils version 6.12.
+
+
+2008-08-19 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Check that split size is a multiple of block size and print an
+ error message at startup, instead of mysteriously failing during
+ the run.
+
+ * Added "blockbench" script to easily test many block sizes and find
+ the fastest option for imaging.
+
+
+2008-07-24 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Added ifjoin= and vfjoin= to input or verify against
+ split files
+
+
+2008-06-30 Andrew Medico <amedico at users.sourceforge.net>
+
+ * In closing log message, indicate if process was aborted, terminated
+ normally, or terminated due to errors.
+
+
+2008-06-27 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Print hash values so far when process is interrupted
+
+
+2008-06-26 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Change count, skip, and seek options to take sector counts
+ instead of bytes
+
+
+2008-06-24 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Report sector address when errors occur in non-grouped mode
+
+
+2008-06-23 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Fix compile-flag printer to handle DEFAULT_SIZEPROBE
+
+
+2008-06-19 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Enable dynamic error recovery automatically when conv=sync,noerror
+ is specified
+
+ * Probe device sector size instead of hard-coding dynamic error
+ recovery read size
+
+ * Change default block size to 32K
+
+ * Report progress and error positions in sectors (probed from device
+ size) instead of blocks
+
+ * Fix error counting in dynamic error recovery mode
+
+
+2008-06-17 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Log compile-time flags to the log file
+
+
+2008-06-16 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Add "dynamic" block size mode for better error recovery.
+ Now when errors are detected, dc3dd rereads the failed block
+ one sector at a time. This lets users run dc3dd in a faster
+ large-block mode without losing entire blocks of data when a
+ bad sector is encountered.
+
+ * When verifying an image, say "X bytes compared" in progress line
+ instead of "X bytes copied".
+
+
+2008-06-12 Andrew Medico <amedico at users.sourceforge.net>
+
+ * When count is specified, calculate completion percentage
+ out of count*ibs, instead of total device size.
+
+
+2008-06-11 Andrew Medico <amedico at users.sourceforge.net>
+
+ * When writing a pattern, sizeprobe destination device for
+ progress reporting.
+
+
+2008-06-10 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Added --flags command line option to display the binary's
+ configure flags
+
+
+2008-06-05 Andrew Medico <amedico at users.sourceforge.net>
+
+ * Fixed wording of error log when I/O errors are detected
+ in errors=group mode
+
+ * Save command-line string to log file
+
+ * Log start and end times to log file
+
+ * Flush log file so it gets written to disk even if the process
+ is interrupted
+
+
+2008-02-29 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Fixed default hashing support when a hash log is not
+ explicitly defined. For example, if the user configures
+ the program with CFLAGS="-DDEFAULT_HASH_MD5" but doesn't
+ specify a hash log, the hashes are now sent to stderr.
+
+
+2008-02-12 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Fixed progresscount default. I had included an extra
+ underscore yesterday.
+
+ * Added ability to change DEFAULT_BLOCKSIZE as promised
+ in the documentation.
+
+
+2008-02-11 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Added DEFAULT_ values for some command line flags. These
+ values should be passed in the configure CFLAGS options.
+ The specific values that can be passed:
+ - DEFAULT_HASH_MD5, DEFAULT_HASH_SHA1, DEFAULT_HASH_SHA256,
+ DEFAULT_HASH_SHA512 enable hashing algorithms
+ - DEFAULT_HASHCONV_BEFORE sets hashconv=before and
+ DEFAULT_HASHCONV_AFTER sets hashconv=after
+ - DEFAULT_PROGRESS sets progress=on
+ - DEFAULT_PROGRESSCOUNT sets progresscount=x
+ (e.g. -DDEFAULT_PROGRESSCOUNT=1000000)
+ - DEFAULT_SIZEPROBE sets sizeprobe=on
+
+ Example:
+ ./configure CFLAGS="-O2 -DDEFAULT_HASH_MD5 -DDEFAULT_HASH_SHA1"
+
+ It should be noted that any default hashing algorithms are
+ ignored if the user specifies a value for hash= on the command
+ line. Note that when a default hashing algorithm is specified
+ the program CANNOT be run without hashing enabled.
+
+ All other values can be overrideen normally on the command line.
+
+ * Moved \r out of translated text in progress meter display.
+ This should help us avoid ugly errors regarding having \r in there.
+
+
+2008-02-07 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Updated base package to Coreutils version 6.10.
+
+
+2008-01-29 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Changed error handling such that on a partial read
+ the entire block is wiped with zeros. See bug 1881387.
+
+ * Grouped errors now display the block numbers where
+ the error occured, not the offset. See bug 1881383.
+
+ * Improved help message for splitformat option.
+
+
+2008-01-19 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Updated documentation to reflect log appends, legal
+ values for hashconv
+
+
+2008-01-12 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Updated contact address to dc3dd at dc3.mil.
+
+
+2008-01-10 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Changed log files to append messages rather than overwrite.
+
+
+2008-01-09 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Updated dc3_error_tail to create copies of the args
+ passed in just in case they need to be written twice
+ (stderr and log file).
+
+ * Added check to display grouped errors at end of input
+
+
+2007-12-22 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Fixed sizeprobe code for OS X. It will still need work
+ for BSD and other non-Linux, non-Mac platforms.
+
+
+2007-12-21 Jesse Kornblum <jessekornblum at users.sourceforge.net>
+
+ * Created new source code tree based on slimmed down version
+ of GNU Coreutils suite. Replaced existing ChangeLogs with
+ this one. This file will be for changes to the dc3dd suite.
+
+ * Replaced NEWS file with news for dc3dd only
+
+ * Stripped out unused programs from src and man directories
+
+ * Cleaned top level Makefile.am and configure.ac to exclude
+ deleted programs.
+
+ * Edited man/Makefile.am to only handle dc3dd.1
+
+ * Removed old directory and changelogs from coreutils
diff --git a/Options_Reference.txt b/Options_Reference.txt
index 958237a..79c1c0f 100644
--- a/Options_Reference.txt
+++ b/Options_Reference.txt
@@ -1,6 +1,6 @@
------
+------
usage:
------
+------
./dc3dd [OPTION 1] [OPTION 2] ... [OPTION N]
@@ -16,36 +16,40 @@ usage:
basic options:
--------------
- if=FILE Read input from the device or regular file FILE
- (see note #1 below). This option can only be used
- once and cannot be combined with ifs=, pat=,
- or tpat=.
+ if=DEVICE or FILE Read input from a device or a file (see note #1
+ below for how to read from standard input). This
+ option can only be used once and cannot be
+ combined with ifs=, pat=, or tpat=.
ifs=BASE.FMT Read input from a set of files with base name
BASE and sequential file name extensions
- conforming to the format specifier FMT (see
- note #4 below). This option can only be used once
- and cannot be combined with if=, pat=, or
- tpat=.
- of=FILE Write output to FILE (see note #2 below). This
+ conforming to the format specifier FMT (see note
+ #4 below for how to specify FMT). This option
+ can only be used once and cannot be combined with
+ if=, pat=, or tpat=.
+ of=FILE or DEVICE Write output to a file or device (see note #2
+ below for how to write to standard output). This
+ option can be used more than once (see note #3
+ below for how to generate multiple outputs).
+ hof=FILE or DEVICE Write output to a file or device, hash the
+ output file or device, and verify by comparing
+ the output hash(es) to the input hash(es). This
option can be used more than once (see note #3
- below).
- hof=FILE Write output to FILE and verify FILE after
- writing it by hashing it and comparing the output
- hash(es) to the input hash(es). This option can be
- used more than once (see note #3 below).
+ below for how to generate multiple outputs).
ofs=BASE.FMT Write output to a set of files with base name BASE
and sequential file name extensions generated from
- the format specifier FMT (see note #4 below). This
- option can be used more than once (see note #3
- below). Specify the maximum size of each file
- in the set using ofsz=.
+ the format specifier FMT (see note #4 below for
+ how to specify FMT). This option can be used more
+ than once (see note #3 below for how to generate
+ multiple outputs). Specify the maximum size of
+ each file in the set using ofsz=.
hofs=BASE.FMT Write output to a set of files with base name BASE
and sequential file name extensions generated from
- the format specifier FMT (see note #4 below).
- Verify the files after writing them by hashing
- them and comparing the output hash(es) to the input
- hash(es). This option can be used more than once
- (see note #3 below). Specify the maximum size of
+ the format specifier FMT (see note #4 below for
+ how to specify FMT). Hash the output files and
+ verify by comparing the output hash(es) to the
+ input hash(es). This option can be used more than
+ once (see note #3 below for how to generate
+ multiple outputs). Specify the maximum size of
each file in the set using ofsz=.
ofsz=BYTES Set the maximum size of each file in the sets of
files specified using ofs= or hofs= to
@@ -54,33 +58,45 @@ basic options:
-DDEFAULT_OUTPUT_FILE_SIZE followed by the desired
value in BYTES.
hash=ALGORITHM Compute an ALGORITHM hash of the input and also
- of any outputs specified using hof= or hofs=,
- where ALGORITHM is one of md5, sha1, sha256, or
- sha512. This option may be used once for each
- supported ALGORITHM. Alternatively, hashing can
- be activated at compile time using one or more of
- -DDEFAULT_HASH_MD5,-DDEFAULT_HASH_SHA1,
+ of any outputs specified using hof=, hofs=, phod=,
+ or fhod=, where ALGORITHM is one of md5, sha1,
+ sha256, or sha512. This option may be used once
+ for each supported ALGORITHM. Alternatively,
+ hashing can be activated at compile time using one
+ or more of -DDEFAULT_HASH_MD5,-DDEFAULT_HASH_SHA1,
-DDEFAULT_HASH_SHA256, and -DDEFAULT_HASH_SHA512.
log=FILE Log I/O statistcs, diagnostics, and total hashes
of input and output to FILE. If hlog= is not
specified, piecewise hashes of multiple file
- input and output are also logged to FILE.
+ input and output are also logged to FILE. This
+ option can be used more than once to generate
+ multiple logs.
hlog=FILE Log total hashes and piecewise hashes to FILE.
+ This option can be used more than once to generate
+ multiple logs.
-----------------
advanced options:
-----------------
+ phod=DEVICE The same as hof=DEVICE, except only the bytes
+ written to DEVICE by dc3dd are verified. This
+ option can be used more than once (see note
+ #3 below for how to generate multiple outputs).
+ fhod=DEVICE The same as phod=DEVICE, with additional
+ hashing of the entire output DEVICE. This option
+ can be used more than once (see note #3 below
+ for how to generate multiple outputs).
rec=off By default, zeros are written to the output(s) in
place of bad sectors when the input is a device.
Use this option to cause the program to instead
exit when a bad sector is encountered.
wipe=DEVICE Wipe DEVICE by writing zeros (default) or a
pattern specified by pat= or tpat=.
- vwipe=DEVICE Wipe DEVICE by writing zeros (default) or a
- pattern specified by pat= or tpat=.
- Verify DEVICE after writing it by hashing it
- and comparing the hash(es) to the input hash(es).
+ hwipe=DEVICE Wipe DEVICE by writing zeros (default) or a
+ pattern specified by pat= or tpat=. Verify
+ DEVICE after writing it by hashing it and
+ comparing the hash(es) to the input hash(es).
pat=HEX Use pattern as input, writing HEX to every byte
of the output. This option can only be used once
and cannot be combined with if=, ifs=, or
@@ -89,9 +105,9 @@ advanced options:
repeatedly to the output. This option can only be
used once and cannot be combined with if=, ifs=,
or pat=.
- cnt=SECTORS Input only SECTORS input sectors. Must be used with
- pat= or tpat= if not using the pattern
- with wipe= or vwipe= to wipe a device.
+ cnt=SECTORS Read only SECTORS input sectors. Must be used
+ with pat= or tpat= if not using the pattern with
+ wipe= or hwipe= to wipe a device.
iskip=SECTORS Skip SECTORS sectors at start of the input device
or file.
oskip=SECTORS Skip SECTORS sectors at start of the output
@@ -112,9 +128,8 @@ advanced options:
verb=on Activate verbose reporting, where sectors in/out
are reported for each file in sets of files
specified using ifs=, ofs=, or hofs=.
- Alternatively, verbose reporting may be
- activated at compile time using
- -DDEFAULT_VERBOSE_REPORTING.
+ Alternatively, verbose reporting may be activated
+ at compile time using -DDEFAULT_VERBOSE_REPORTING.
nwspc=on Activate compact reporting, where the use
of white space to divide log output into
logical sections is suppressed. Alternatively,
@@ -124,7 +139,7 @@ advanced options:
progress display reports 1000 bytes instead
of 1024 bytes as 1 KB. Alternatively, base 10
bytes reporting may be activated at compile
- time using -DDEFAULT_DECIMAL_BYTES_REPORTING.
+ time using -DDEFAULT_BASE_TEN_BYTES_REPORTING.
corruptoutput=on For verification testing and demonstration
purposes, corrupt the output file(s) with extra
bytes so a hash mismatch is guaranteed.
@@ -142,16 +157,16 @@ notes:
------
1. To read from stdin, do not specify if=, ifs=, pat=, or tpat=.
-2. To write to stdout, do not specify of=, hof=, ofs=, hofs=, wipe=,
- or vwipe=.
+2. To write to stdout, do not specify of=, hof=, ofs=, hofs=, phod=,
+ fhod=, wipe=, or hwipe=.
3. To write to multiple outputs specify more than one of of=, hof=, ofs=,
- or hofs=, in any combination.
+ hofs=, phod=, or fhod=, in any combination.
4. FMT is a pattern for a sequence of file extensions that can be numerical
starting at zero, numerical starting at one, or alphabetical. Specify FMT
by using a series of zeros, ones, or a's, respectively. The number of
characters used indicates the desired length of the extensions.
For example, a FMT specifier of 1111 indicates four character
- numerical extensions starting with 0001.
+ numerical extensions starting with 0000.
5. BYTES may be followed by the following multiplicative suffixes:
c (1), w (2), b (512), kB (1000), K (1024), MB (1000*1000),
M (1024*1024), GB (1000*1000*1000), G (1024*1024*1024), and
diff --git a/README b/README
index 77b4c7f..c6945f4 100644
--- a/README
+++ b/README
@@ -1,38 +1,22 @@
-dc3dd 7.0.0
+dc3dd 7.1
DCCI
-Richard Cordovano
-2009-09-11
+2010-10-18
+
+Issues:
+-------
+When imaging to a device with verification under Mac OS X, verification
+can fail due to automatic mounting of the target device. One solution is
+to use Disk Arbitrator in conjunction with dc3dd on OS X.
New Features:
-------------
-The command line options supported by dc3dd are significantly changed in
-7.0.0. For a full listing of the command line options, please consult
-Options_Reference.txt or execute dc3dd using the --help option:
-
-$ ./dc3dd --help
-
-The command line is now more rigorously validated to reduce the
-likelihood of performing a run contrary to user intent. This is done
-to minimize reading of the input device. Examples of command lines for
-common uses of dc3dd are provided in Sample_Commands.txt.
-
-Release 7.0.0 replaces the byte-by-byte comparison verification
-capability of prior releases with a verification capability that hashes
-imaging outputs and compares output hash(es) to input hash(es). This
-new verification capability does not require a second read of the input
-device.
-
-It is now possible to specify more than one output file and to mix split
-and unsplit outputs, where splitting an output refers to writing to a
-set of files rather than to a single file.
-
-Devices are now always probed for size, and the size of the device in
-sectors and sector size is reported. It is however, also now possible to
-explicitly specify the sector size dc3dd is to use, overriding the
-probed sector size (for devices) or assumed sector size (for files).
+Log output may be sent to multiple job logs and hash logs. Simply specify
+log=LOG and/or hlog=LOG more than once.
-Progress display is now always on and various options for formatting
-output are now provided.
+Verification of an image restored to a device larger than the image is now
+supported. Specify phod=DEVICE to hash only the bytes dc3dd writes to the
+device. Specify fhod=DEVICE to hash both the bytes dc3dd writes to the
+device and all the bytes that follow, up to the end of the device.
Building dc3dd:
---------------
@@ -40,8 +24,8 @@ dc3dd is distributed as source code and must be compiled before use.
The default configuration can be built and installed to /usr/local/bin
with the following commands:
-$ tar zxvf dc3dd-7.0.0.tar.gz
-$ cd dc3dd-7.0.0
+$ tar zxvf dc3dd-7.1.tar.gz
+$ cd dc3dd-7.1
$ ./configure
$ make
$ sudo make install
diff --git a/Sample_Commands.txt b/Sample_Commands.txt
index c76ea0e..1f7e1a2 100644
--- a/Sample_Commands.txt
+++ b/Sample_Commands.txt
@@ -12,23 +12,28 @@ $ ./dc3dd if=/dev/sda ofs=suspect.img.000 ofsz=650M hash=md5 hash=sha1
log=suspect.txt
Imaging a device to both a single output file and to a set of CD-sized
-output files with generation of md5 and sha1 hashes of the hard device:
+output files with generation of md5 and sha1 hashes of the device:
$ ./dc3dd if=/dev/sda of=suspect.img of=suspect.img ofs=suspect.img.000
ofsz=650M hash=md5 hash=sha1 log=suspect.txt
Imaging a device to both a single output file and to a set of CD-sized
-output files with generation of md5 and sha1 hashes of the hard device
+output files with generation of md5 and sha1 hashes of the device
and md5 and sha1 hashes of the outputs:
$ ./dc3dd if=/dev/sda of=suspect.img hof=suspect.img hofs=suspect.img.000
ofsz=650M hash=md5 hash=sha1 log=suspect.txt
-Restoring a set of image files to a blank drive with verification hashes of the drive after it is written:
-$ ./dc3dd ifs=suspect.img.000 hof=/dev/sdb hash=md5 hash=sha1 log=suspect-restore.txt
+Restoring a set of image files to a device with verification hashes of
+only the bytes dc3dd writes to the device:
+$ ./dc3dd ifs=suspect.img.000 phod=/dev/sdb hash=md5 hash=sha1 log=suspect-restore.txt
+
+Restoring a set of image files to a device with verification hashes of
+both the bytes dc3dd writes to the device and the entire device:
+$ ./dc3dd ifs=suspect.img.000 fhod=/dev/sdb hash=md5 hash=sha1 log=suspect-restore.txt
Wiping a drive:
$ ./dc3dd wipe=/dev/sdb log=wipe.txt
Wiping a drive with verification:
-$ ./dc3dd vwipe=/dev/sdb hash=md5 hash=sha1 log=wipe.txt
+$ ./dc3dd hwipe=/dev/sdb hash=md5 hash=sha1 log=wipe.txt
diff --git a/configure b/configure
index 333de10..b47dafe 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for dc3dd 7.0.0.
+# Generated by GNU Autoconf 2.61 for dc3dd 7.1.614.
#
# Report bugs to <dc3dd at dc3.mil>.
#
@@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='dc3dd'
PACKAGE_TARNAME='dc3dd'
-PACKAGE_VERSION='7.0.0'
-PACKAGE_STRING='dc3dd 7.0.0'
+PACKAGE_VERSION='7.1.614'
+PACKAGE_STRING='dc3dd 7.1.614'
PACKAGE_BUGREPORT='dc3dd at dc3.mil'
ac_unique_file="src/dc3dd.c"
@@ -1586,7 +1586,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures dc3dd 7.0.0 to adapt to many kinds of systems.
+\`configure' configures dc3dd 7.1.614 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1656,7 +1656,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of dc3dd 7.0.0:";;
+ short | recursive ) echo "Configuration of dc3dd 7.1.614:";;
esac
cat <<\_ACEOF
@@ -1770,7 +1770,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-dc3dd configure 7.0.0
+dc3dd configure 7.1.614
generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1784,7 +1784,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by dc3dd $as_me 7.0.0, which was
+It was created by dc3dd $as_me 7.1.614, which was
generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@
@@ -2594,7 +2594,7 @@ fi
# Define the identity of the package.
PACKAGE='dc3dd'
- VERSION='7.0.0'
+ VERSION='7.1.614'
cat >>confdefs.h <<_ACEOF
@@ -64904,7 +64904,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by dc3dd $as_me 7.0.0, which was
+This file was extended by dc3dd $as_me 7.1.614, which was
generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -64957,7 +64957,7 @@ Report bugs to <bug-autoconf at gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-dc3dd config.status 7.0.0
+dc3dd config.status 7.1.614
configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/lib/iconv_open-osf.h b/lib/iconv_open-osf.h
index 0187f23..4d35764 100644
--- a/lib/iconv_open-osf.h
+++ b/lib/iconv_open-osf.h
@@ -1,4 +1,4 @@
-/* ANSI-C code produced by gperf version 3.0.1 */
+/* ANSI-C code produced by gperf version 3.0.4 */
/* Command-line: gperf -m 10 ./iconv_open-osf.gperf */
/* Computed positions: -k'4,$' */
@@ -251,6 +251,9 @@ static const struct mapping mappings[] =
#ifdef __GNUC__
__inline
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
#endif
const struct mapping *
mapping_lookup (register const char *str, register unsigned int len)
diff --git a/man/dc3dd.1 b/man/dc3dd.1
index 6b07a43..8328ea2 100644
--- a/man/dc3dd.1
+++ b/man/dc3dd.1
@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.35.
-.TH DC3DD "1" "February 2010" "dc3dd 7.0.0" "User Commands"
+.TH DC3DD "1" "November 2010" "dc3dd 7.1.CREV" "User Commands"
.SH NAME
dc3dd \- convert and copy a file
.SH DESCRIPTION
diff --git a/src/dc3dd.c b/src/dc3dd.c
index 5f78239..151ee08 100644
--- a/src/dc3dd.c
+++ b/src/dc3dd.c
@@ -1,5 +1,5 @@
// dc3dd -- a dd for digital forensics.
-// Copyright (C) 85, 90, 91, 1995-2009 Free Software Foundation, Inc.
+// Copyright (C) 85, 90, 91, 1995-2008 Free Software Foundation, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -40,10 +40,10 @@
#ifdef __linux__
#include <sys/mount.h>
- # include <sys/mtio.h>
+ #include <sys/mtio.h>
#ifdef USE_HDPARM
- #include <linux/types.h>
- #include "hdparm/hpa_dco.h"
+ #include <linux/types.h>
+ #include "hdparm/hpa_dco.h"
#endif
#elif defined (__APPLE__)
#include <sys/disk.h>
@@ -68,10 +68,10 @@
proper_name("Andrew Medico"), \
proper_name("Richard Cordovano")
-// Keep it smaller than SIZE_MAX - alignment add-on bytes, to allow
-// allocating buffers that size. Keep it smaller than SSIZE_MAX, for the
-// benefit of system calls like read(). And keep it smaller than OFF_T_MAX,
-// for the benefit of lseek().
+// Keep block size smaller than SIZE_MAX - alignment bytes, to allow
+// allocating buffers that size. Keep block size smaller than SSIZE_MAX, for
+// the benefit of system calls like read(). And keep block size smaller than
+// OFF_T_MAX, for the benefit of lseek().
#define MAX_BLOCKSIZE() MIN (SIZE_MAX - (2 * getpagesize() - 1), MIN (SSIZE_MAX, OFF_T_MAX))
#define STRINGIFY(s) #s
@@ -98,57 +98,70 @@ static const long int JOB_PROGRESS_INTERVAL_MILLISECS = 100;
// ENUMS
//-------------------------
-enum IO_STATE
-{
+enum LOGS {
+ ALL_LOGS,
+ JOB_LOGS,
+ HASH_LOGS
+};
+
+enum IO_STATE {
PENDING,
OPEN,
COMPLETE,
FATAL_ERROR
};
-enum EXIT_CODE
-{
+enum EXIT_CODE {
DC3DD_EXIT_CODE_NOT_SET = -1,
DC3DD_EXIT_COMPLETED,
DC3DD_EXIT_ABORTED,
DC3DD_EXIT_FAILED,
};
+enum VERIFICATION_TYPE {
+ NONE,
+ STANDARD,
+ DEVICE_PARTIAL,
+ DEVICE_FULL
+};
+
//-------------------------
// TYPEDEFS
//-------------------------
-typedef struct _file_t
-{
- char* unparsed_name;
- char* name;
+typedef struct _log_t {
+ FILE *file;
+ struct _log_t *next_log;
+} log_t;
+
+typedef struct _file_t {
+ char *unparsed_name;
+ char *name;
+ bool part_of_set;
uintmax_t number;
int flags;
int descriptor;
- bool probed;
intmax_t offset;
- bool is_device;
- bool is_block_device;
+ bool probed;
uintmax_t probed_size_in_bytes;
uintmax_t probed_size_in_sectors;
size_t probed_sector_size;
- uintmax_t size_in_bytes;
- bool part_of_set;
- bool verify_requested;
- struct _file_t* next_file;
-}
-file_t;
-
-typedef struct _settings_t
-{
- char* input_pattern_string;
- char* input_pattern;
+ bool is_device;
+ bool is_block_device;
+ uintmax_t bytes_processed;
+ enum VERIFICATION_TYPE verification;
+ struct _file_t *next_file;
+} file_t;
+
+typedef struct _settings_t {
+ char *input_pattern_string;
+ char *input_pattern;
size_t input_pattern_length;
- file_t* input_file;
- file_t* output_files;
- file_t* wipe_target;
+ file_t *input_file;
+ file_t *output_files;
+ file_t *wipe_target;
size_t sector_size;
- const char* sector_size_source;
+ const char * sector_size_source;
size_t buffer_size;
uintmax_t input_sectors_to_skip;
uintmax_t output_sectors_to_skip;
@@ -159,61 +172,47 @@ typedef struct _settings_t
bool verifying_output;
bool append_output;
bool corrupt_output;
-}
-settings_t;
+} settings_t;
typedef void hash_init_func_t(void* ctx);
typedef void hash_update_func_t(const void* buf, size_t len, void* ctx);
typedef void hash_finish_func_t(void* ctx, void* buf);
-typedef struct _hash_algorithm_t
-{
+typedef struct _hash_algorithm_t {
bool active;
- char* name;
+ char *name;
size_t context_size;
size_t sum_size;
- hash_init_func_t* init;
- hash_update_func_t* update;
- hash_finish_func_t* finish;
-}
-hash_algorithm_t;
-
-typedef struct _hash_t
-{
- hash_algorithm_t* algorithm;
- void* context;
- char* sum;
- char* result;
+ hash_init_func_t *init;
+ hash_update_func_t *update;
+ hash_finish_func_t *finish;
+} hash_algorithm_t;
+
+typedef struct _hash_t {
+ void *context;
+ char *sum;
+ char *result;
uintmax_t bytes_hashed;
- struct _hash_t* current_piece;
- struct _hash_t* pieces;
- uintmax_t piecewise_hash_length;
- struct _hash_t* next_hash;
-}
-hash_t;
+ struct _hash_t *next_hash;
+} hash_t;
-typedef struct _buffer_t
-{
- char* data;
+typedef struct _buffer_t {
+ char *data;
size_t length;
-}
-buffer_t;
+} buffer_t;
-typedef struct _buffer_queue_t
-{
- buffer_t* buffers;
+typedef struct _buffer_queue_t {
+ buffer_t *buffers;
uint number_of_buffers;
uint buffers_used;
uint next_available_buffer;
- pthread_mutex_t* lock;
- pthread_cond_t* not_empty;
- pthread_cond_t* not_full;
+ pthread_mutex_t *lock;
+ pthread_cond_t *not_empty;
+ pthread_cond_t *not_full;
bool done_buffering;
-}
-buffer_queue_t;
+} buffer_queue_t;
-typedef struct _input_t
-{
+typedef struct _input_t {
enum IO_STATE state;
size_t buffer_size;
buffer_t buffer;
@@ -236,67 +235,78 @@ typedef struct _input_t
void (*open)(struct _input_t* input);
void (*produce_bytes)(struct _input_t* input);
void (*close)(struct _input_t* input);
-}
-input_t;
+} input_t;
+
+typedef struct _hash_output_t {
+ hash_algorithm_t *algorithm;
+ hash_t *total_hash;
+ uintmax_t total_hash_length;
+ hash_t *current_piece;
+ hash_t *piecewise_hash;
+ uintmax_t piecewise_hash_length;
+ hash_t *device_hash;
+ struct _hash_output_t *next;
+} hash_output_t;
-typedef struct _output_t
-{
+typedef struct _file_output_t {
+ file_t* current_file;
+ file_t* files;
+ uintmax_t max_file_size;
+ uintmax_t sectors_to_skip;
+ uintmax_t bytes_output;
+ enum VERIFICATION_TYPE verification;
+ hash_output_t* expected_hashes;
+ hash_output_t* actual_hashes;
+ bool append_garbage_bytes; // For testing purposes.
+} file_output_t;
+
+typedef struct _output_t {
enum IO_STATE state;
pthread_t thread;
size_t sector_size;
uintmax_t buffer_size;
buffer_queue_t* buffer_queue;
- uintmax_t bytes_output;
- hash_t* hash;
- file_t* current_file;
- file_t* files;
- uintmax_t max_file_size;
- uintmax_t sectors_to_skip;
- bool append_garbage_bytes;
+ hash_output_t *hash;
+ file_output_t *file;
void (*open)(struct _output_t* output);
void (*consume_bytes)(struct _output_t* output, buffer_t* buffer);
void (*close)(struct _output_t* output);
- struct _output_t* expected_hashes;
- struct _output_t* actual_hashes;
struct _output_t* next_output;
-}
-output_t;
+} output_t;
-typedef struct _task_t
-{
+typedef struct _task_t {
pthread_t thread;
- pthread_mutex_t* signalling_lock;
- input_t* input;
- output_t* outputs;
+ pthread_mutex_t *signaling_lock;
+ input_t *input;
+ output_t *outputs;
+ file_output_t *verification_target;
bool completed;
bool aborted;
enum EXIT_CODE exit_code;
- struct _task_t* next_task;
-}
-task_t;
+ struct _task_t *next_task;
+} task_t;
-typedef struct _job_t
-{
+typedef struct _job_t {
pthread_t monitor_thread;
task_t* tasks;
long int progress_interval_in_ms;
void (*report_progress)(struct _job_t* job, bool final);
enum EXIT_CODE exit_code;
struct _job_t* next_job;
-}
-job_t;
+} job_t;
//-------------------------
// GLOBAL VARIABLES
//-------------------------
-char* program_name = NULL;
+char *program_name = NULL;
static xtime_t start_time;
-static FILE* log = NULL;
-static FILE* hash_log = NULL;
+static log_t *job_logs = NULL;
+static log_t *hash_logs = NULL;
+static log_t *all_logs = NULL;
static bool progress_displayed = false;
-static pthread_mutex_t signalling_lock;
-static pthread_cond_t* interrupted = 0;
+static pthread_mutex_t signaling_lock;
+static pthread_cond_t *interrupted = 0;
#ifdef DEFAULT_VERBOSE_REPORTING
static bool verbose_reporting = true;
@@ -316,12 +326,13 @@ static int progress_bytes_reporting_flag = 0;
static int progress_bytes_reporting_flag = human_base_1024;
#endif
-// A single lock is used for both the logs and the console so that the order of
-// output will be the same everywhere.
+// A single lock is used for both the job_logs and the console so that the
+// ordering of the log messages will be the same on the console and in the
+// logs.
static pthread_mutex_t reporting_lock;
-static hash_algorithm_t hash_algorithms[] =
-{
+// Currently supporting MD5, SHA1, SHA256, and SHA512.
+static hash_algorithm_t hash_algorithms[] = {
{
#ifdef DEFAULT_HASH_MD5
true,
@@ -334,9 +345,8 @@ static hash_algorithm_t hash_algorithms[] =
(hash_init_func_t*)md5_init_ctx,
(hash_update_func_t*)md5_process_bytes,
(hash_finish_func_t*)md5_finish_ctx,
- },
-
- {
+ },
+ {
#ifdef DEFAULT_HASH_SHA1
true,
#else
@@ -348,9 +358,8 @@ static hash_algorithm_t hash_algorithms[] =
(hash_init_func_t*)sha1_init_ctx,
(hash_update_func_t*)sha1_process_bytes,
(hash_finish_func_t*)sha1_finish_ctx,
- },
-
- {
+ },
+ {
#ifdef DEFAULT_HASH_SHA256
true,
#else
@@ -362,9 +371,8 @@ static hash_algorithm_t hash_algorithms[] =
(hash_init_func_t*)sha256_init_ctx,
(hash_update_func_t*)sha256_process_bytes,
(hash_finish_func_t*)sha256_finish_ctx,
- },
-
- {
+ },
+ {
#ifdef DEFAULT_HASH_SHA512
true,
#else
@@ -376,8 +384,8 @@ static hash_algorithm_t hash_algorithms[] =
(hash_init_func_t*)sha512_init_ctx,
(hash_update_func_t*)sha512_process_bytes,
(hash_finish_func_t*)sha512_finish_ctx,
- }
- };
+ }
+};
//-------------------------
// FUNCTIONS
@@ -386,35 +394,52 @@ static hash_algorithm_t hash_algorithms[] =
void usage(int status);
static void
-flush_logs()
-{
- fflush(stderr);
- if (log != NULL)
- {
- fflush(log);
- }
- if (hash_log != NULL)
- {
- fflush(hash_log);
+terminate_logging() {
+ pthread_mutex_lock(&reporting_lock);
+
+ for (log_t *log = all_logs; log; log = log->next_log) {
+ fflush(log->file);
+ fclose(log->file);
}
+
+ pthread_mutex_unlock(&reporting_lock);
+ pthread_mutex_destroy(&reporting_lock);
}
static void
-terminate_logging()
-{
- // Close the logs and tear down the reporting mutex.
- pthread_mutex_lock(&reporting_lock);
- flush_logs();
- if (log)
- {
- fclose(log);
- }
- if (hash_log)
- {
- fclose(hash_log);
+flush_logs() {
+ fflush(stderr);
+ for (log_t *log = all_logs; log; log = log->next_log)
+ fflush(log->file);
+}
+
+static void
+write_to_logs(const char *message, enum LOGS target) {
+ log_t *logs = NULL;
+ switch (target) {
+ case ALL_LOGS:
+ logs = all_logs;
+ break;
+ case JOB_LOGS:
+ logs = job_logs;
+ break;
+ case HASH_LOGS:
+ logs = hash_logs ? hash_logs : job_logs;
+ break;
}
+
+ for (log_t *log = logs; log; log = log->next_log)
+ fputs(message, log->file);
+}
+
+static void
+report(const char *message, enum LOGS target) {
+ pthread_mutex_lock(&reporting_lock);
+
+ fputs(message, stderr);
+ write_to_logs(message, target);
+
pthread_mutex_unlock(&reporting_lock);
- pthread_mutex_destroy(&reporting_lock);
}
// Begin code copied (and modified) from ../lib/error.c
@@ -422,56 +447,52 @@ terminate_logging()
#define __strerror_r strerror_r
static void
-report_errno_message(int errnum)
-{
- char const *s;
+append_system_error_message(int errnum) {
+ char const *s = NULL;
+ // Attempt to get the current error string.
#if defined HAVE_STRERROR_R || _LIBC
char errbuf[DISPLAY_MESSAGE_LENGTH];
-#if STRERROR_R_CHAR_P || _LIBC
+ #if STRERROR_R_CHAR_P || _LIBC
s = __strerror_r(errnum, errbuf, sizeof errbuf);
-# else
+ #else
if (__strerror_r(errnum, errbuf, sizeof errbuf) == 0)
- {
s = errbuf;
- }
else
- {
- s = 0;
- }
-# endif
+ s = NULL;
+ #endif
#else
s = strerror(errnum);
#endif
+ // Use a generic error string if the attempt to get the system error
+ // system string failed.
#if !_LIBC
if (!s)
- {
s = _("system error");
- }
#endif
#if _LIBC
__fxprintf(NULL, ": %s", s);
#else
fprintf(stderr, ": %s", s);
- if (log != NULL)
- {
- fprintf(log, ": %s", s);
- }
#endif
+ for (log_t* log = job_logs; log; log = log->next_log)
+ fprintf(log->file, ": %s", s);
}
static void
-report_error_tail(int status, int errnum, const char *message, va_list args)
+write_error_message(int errnum, const char *message, va_list args)
{
va_list arg2;
va_copy(arg2, args);
+ // Write the error message.
#if _LIBC
if (_IO_fwide (stderr, 0) > 0)
{
-# define ALLOCA_LIMIT 2000
+ // Write the message using wide chars.
+ #define ALLOCA_LIMIT 2000
size_t len = strlen(message) + 1;
wchar_t *wmessage = NULL;
mbstate_t st;
@@ -482,15 +503,11 @@ report_error_tail(int status, int errnum, const char *message, va_list args)
while (1)
{
if (__libc_use_alloca(len * sizeof (wchar_t)))
- {
wmessage = (wchar_t *)alloca(len * sizeof (wchar_t));
- }
else
{
if (!use_malloc)
- {
wmessage = NULL;
- }
wchar_t *p = (wchar_t *)realloc(wmessage, len * sizeof (wchar_t));
if (p == NULL)
@@ -502,14 +519,12 @@ report_error_tail(int status, int errnum, const char *message, va_list args)
wmessage = p;
use_malloc = true;
}
+
memset(&st, '\0', sizeof (st));
tmp = message;
-
res = mbsrtowcs(wmessage, &tmp, len, &st);
if (res != len)
- {
break;
- }
if (__builtin_expect(len >= SIZE_MAX / 2, 0))
{
@@ -517,7 +532,7 @@ report_error_tail(int status, int errnum, const char *message, va_list args)
break;
}
- len *= 2;
+ len *= 2;
}
if (res == (size_t)-1)
@@ -532,49 +547,37 @@ report_error_tail(int status, int errnum, const char *message, va_list args)
}
__vfwprintf(stderr, wmessage, args);
- if (log != NULL)
- {
- __vfwprintf(log, wmessage, arg2);
- }
+ for (log_t *log = job_logs; log; log = log->next_log)
+ __vfwprintf(log->file, wmessage, arg2);
if (use_malloc)
- {
free(wmessage);
- }
}
else
#endif
{
+ // Write the message using standard chars.
vfprintf(stderr, message, args);
- if (log != NULL)
- {
- vfprintf(log, message, arg2);
- }
+ for (log_t *log = job_logs; log; log = log->next_log)
+ vfprintf(log->file, message, arg2);
}
va_end(args);
++error_message_count;
if (errnum)
- {
- report_errno_message(errnum);
- }
-
+ append_system_error_message(errnum);
+
+ // Finish off the error message with a newline.
#if _LIBC
- __fxprintf(NULL, "\n");
+ __fxprintf(NULL, "\n");
#else
putc('\n', stderr);
- if (log != NULL)
- {
- putc('\n', log);
- fflush(log);
- }
#endif
-
fflush(stderr);
- if(status)
- {
- usage(status);
+ for (log_t *log = job_logs; log; log = log->next_log) {
+ putc('\n', log->file);
+ fflush(log->file);
}
}
@@ -583,98 +586,42 @@ report_error(int status, int errnum, const char *message, ...)
{
pthread_mutex_lock(&reporting_lock);
-#if defined _LIBC && defined __libc_ptf_call
+ // Disable thread cancellation and lock stderr.
+#ifdef _LIBC
+ #ifdef __libc_ptf_call
int state = PTHREAD_CANCEL_ENABLE;
__libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), 0);
-#endif
-
- fflush (stdout);
-
-#ifdef _LIBC
+ #endif
_IO_flockfile (stderr);
#endif
+
+ // Prefix the error message with an attention grabbing character sequence.
#if _LIBC
__fxprintf (NULL, "%s[!!] ", progress_displayed ? "\n" : "");
#else
fprintf (stderr, "%s[!!] ", progress_displayed ? "\n" : "");
#endif
-
- if (log)
- {
- fputs("[!!] ", log);
- }
+ write_to_logs("[!!] ", JOB_LOGS);
va_list args;
va_start(args, message);
- report_error_tail(status, errnum, message, args);
+ write_error_message(errnum, message, args);
+ // Enable thread cancellation and unlock stderr.
#ifdef _LIBC
_IO_funlockfile (stderr);
-# ifdef __libc_ptf_call
+ # ifdef __libc_ptf_call
__libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
+ #endif
#endif
-#endif
-
- pthread_mutex_unlock(&reporting_lock);
-}
-
-// End code copied (and modified) from ../lib/error.c
-
-static void
-report_to_log(const char* message)
-{
- pthread_mutex_lock(&reporting_lock);
-
- // Write the message to the console and to the log, if it exists.
- fputs(message, stderr);
- if (log)
- {
- fputs(message, log);
- }
pthread_mutex_unlock(&reporting_lock);
-}
-
-static void
-report_to_hash_log_or_log(char* message)
-{
- pthread_mutex_lock(&reporting_lock);
-
- // Write the message to the console, and to the hash log, if it exists.
- // If the hash log does not exist, write the message to the log,
- // if it exists.
- fputs(message, stderr);
- if (hash_log)
- {
- fputs(message, hash_log);
- }
- else if (log)
- {
- fputs(message, log);
- }
- pthread_mutex_unlock(&reporting_lock);
+ if (status)
+ usage(status);
}
-static void
-report_to_all(char* message)
-{
- pthread_mutex_lock(&reporting_lock);
-
- // Write the message to the console, and to the log and hash log,
- // if they exist.
- fputs(message, stderr);
- if (log)
- {
- fputs(message, log);
- }
- if (hash_log)
- {
- fputs(message, hash_log);
- }
-
- pthread_mutex_unlock(&reporting_lock);
-}
+// End code copied (and modified) from ../lib/error.c
static char*
get_formatted_time_string()
@@ -684,17 +631,14 @@ get_formatted_time_string()
struct tm tm;
struct tm* ret = localtime_r(&t, &tm);
if (ret == NULL)
- {
report_error(DC3DD_EXIT_ABORTED, errno, "localtime() failed");
- }
// Put it in string form.
const size_t len = 32; // More than enough to hold 'YYYY-MM-DD HH:MM:SS -0000'
char* time_str = (char*)malloc(len);
if (strftime(time_str, len, "%F %T %z", &tm) == 0)
- {
report_error(DC3DD_EXIT_ABORTED, 0, "strftime() returned 0");
- }
+
return time_str;
}
@@ -703,8 +647,7 @@ report_exit_message(int exit_code)
{
// Translate the exit code into a printable word.
const char* verb = NULL;
- switch (exit_code)
- {
+ switch (exit_code) {
case DC3DD_EXIT_COMPLETED:
verb = _("completed");
break;
@@ -718,13 +661,12 @@ report_exit_message(int exit_code)
break;
}
- // Write the exit message to all logs (i.e., console, log, hash log).
- // The message acts as a sort of footer for the run.
+ // Write the exit message to all logs as a sort of footer for the run.
char* formatted_stop_time = get_formatted_time_string();
char message[DISPLAY_MESSAGE_LENGTH];
sprintf(message, _("%s %s at %s\n\n"), PROGRAM_NAME, verb, formatted_stop_time);
free(formatted_stop_time);
- report_to_all(message);
+ report(message, ALL_LOGS);
flush_logs();
}
@@ -733,7 +675,7 @@ report_program_error(const char* assertion)
{
char internal_error[DISPLAY_MESSAGE_LENGTH];
sprintf(internal_error, _("%s: internal error %s at line %d"), program_name, assertion, __LINE__);
- report_to_log(internal_error);
+ write_to_logs(internal_error, JOB_LOGS);
report_exit_message(DC3DD_EXIT_ABORTED);
terminate_logging();
emit_bug_reporting_address();
@@ -743,31 +685,27 @@ report_program_error(const char* assertion)
static void
report_output_hashes(output_t* output)
{
- // Report the parallel hash lists stashed in the output struct.
char message[DISPLAY_MESSAGE_LENGTH];
- output_t* actual_hash_output = output->actual_hashes;
- output_t* expected_hash_output = output->expected_hashes;
- while (actual_hash_output && expected_hash_output)
- {
- hash_t* actual_hash = actual_hash_output->hash;
- hash_t* expected_hash = expected_hash_output->hash;
- // Report total hash match/mismatch.
+ // Report the parallel hash lists stashed in the output struct.
+ hash_output_t *actual_hash = output->file->actual_hashes;
+ hash_output_t *expected_hash = output->file->expected_hashes;
+ while (actual_hash && expected_hash) {
+ // Report the verification hash match/mismatch.
sprintf(message, _(" %s %s (%s)\n"),
- STREQ(actual_hash->result, expected_hash->result) ? _("[ok]") : _("[MISMATCH]"),
- actual_hash->result,
+ STREQ(actual_hash->total_hash->result, expected_hash->total_hash->result)
+ ? _("[ok]") : _("[MISMATCH]"),
+ actual_hash->total_hash->result,
actual_hash->algorithm->name);
- report_to_all(message);
+ report(message, ALL_LOGS);
- // Report piecewise hashes of files, if any.
- if (output->files)
- {
+ // Report piecewise hashes, if any.
+ if (output->file->files) {
uintmax_t start_sector = 0;
- file_t* file = output->files;
- hash_t* actual_piece = actual_hash->pieces;
- hash_t* expected_piece = expected_hash->pieces;
- while (file && actual_piece && expected_piece)
- {
+ file_t* file = output->file->files;
+ hash_t* actual_piece = actual_hash->piecewise_hash;
+ hash_t* expected_piece = expected_hash->piecewise_hash;
+ while (file && actual_piece && expected_piece) {
// For a file set, report piecewise hash matches/mismatches,
// indented two levels.
sprintf(message, _(" %s %s, sectors %"PRIuMAX" - %"PRIuMAX", %s\n"),
@@ -776,7 +714,7 @@ report_output_hashes(output_t* output)
start_sector,
start_sector + actual_piece->bytes_hashed / output->sector_size - 1,
quote(file->name));
- report_to_hash_log_or_log(message);
+ report(message, HASH_LOGS);
start_sector += actual_piece->bytes_hashed / output->sector_size;
file = file->next_file;
@@ -785,8 +723,34 @@ report_output_hashes(output_t* output)
}
}
- actual_hash_output = actual_hash_output->next_output;
- expected_hash_output = expected_hash_output->next_output;
+ actual_hash = actual_hash->next;
+ expected_hash = expected_hash->next;
+ }
+
+ if (output->file->verification == DEVICE_FULL) {
+ hash_output_t *actual_hash = output->file->actual_hashes;
+ hash_output_t *expected_hash = output->file->expected_hashes;
+
+ // Compute the the number of bytes hashed beyond those that dc3dd wrote.
+ uintmax_t additional_bytes =
+ actual_hash->device_hash->bytes_hashed - actual_hash->total_hash->bytes_hashed;
+ uintmax_t sectors = additional_bytes / output->sector_size;
+ uintmax_t leftover_bytes = additional_bytes % output->sector_size;
+
+ // Write the results of the computation as a header for the additional hashes.
+ if (leftover_bytes == 0)
+ sprintf(message, _(" additional %"PRIuMAX" sectors of device hashed\n"), sectors);
+ else
+ sprintf(message, _(" additional %"PRIuMAX" sectors + %"PRIuMAX" bytes of device hashed\n "),
+ sectors, leftover_bytes);
+ report(message, ALL_LOGS);
+
+ while (actual_hash && expected_hash) {
+ sprintf(message, _(" %s (device total %s)\n"), actual_hash->device_hash->result, actual_hash->algorithm->name);
+ report(message, ALL_LOGS);
+ actual_hash = actual_hash->next;
+ expected_hash = expected_hash->next;
+ }
}
}
@@ -794,24 +758,21 @@ static void
report_input_hashes(output_t* output)
{
char message[DISPLAY_MESSAGE_LENGTH];
+
+ // Report the verification hash.
sprintf(message, _(" %s (%s)\n"),
- output->hash->result, output->hash->algorithm->name);
- report_to_all(message);
+ output->hash->total_hash->result, output->hash->algorithm->name);
+ report(message, ALL_LOGS);
- if (output->hash->pieces != NULL)
- {
- uintmax_t start_sector = 0;
- hash_t* piece = output->hash->pieces;
- while (piece)
- {
- sprintf(message, _(" %s, sectors %"PRIuMAX" - %"PRIuMAX"\n"),
- piece->result,
- start_sector,
- start_sector + piece->bytes_hashed / output->sector_size - 1);
- report_to_hash_log_or_log(message);
- start_sector += piece->bytes_hashed / output->sector_size;
- piece = piece->next_hash;
- }
+ // Report any piecewise hashes.
+ uintmax_t start_sector = 0;
+ for (hash_t *piece = output->hash->piecewise_hash; piece; piece = piece->next_hash) {
+ sprintf(message, _(" %s, sectors %"PRIuMAX" - %"PRIuMAX"\n"),
+ piece->result,
+ start_sector,
+ start_sector + piece->bytes_hashed / output->sector_size - 1);
+ report(message, HASH_LOGS);
+ start_sector += piece->bytes_hashed / output->sector_size;
}
}
@@ -819,90 +780,78 @@ static void
report_files_IO(file_t* files, size_t sector_size, bool is_input)
{
char message[DISPLAY_MESSAGE_LENGTH];
- file_t* file = files;
- while (file)
- {
- uintmax_t sectors = file->size_in_bytes / sector_size;
- uintmax_t leftover_bytes = file->size_in_bytes % sector_size;
+
+ for (file_t *file = files; file; file = file->next_file) {
+ uintmax_t sectors = file->bytes_processed / sector_size;
+ uintmax_t leftover_bytes = file->bytes_processed % sector_size;
if (leftover_bytes == 0)
- {
sprintf(message,
_(" %"PRIuMAX" sectors %s %s\n"),
sectors, is_input ? _("in from") : _("out to"),
quote(file->name));
- }
else
- {
sprintf(message,
_(" %"PRIuMAX" sectors + %"PRIuMAX" bytes %s %s\n"),
sectors, leftover_bytes,
is_input ? _("in from") : _("out to"), quote(file->name));
- }
- report_to_log(message);
- file = file->next_file;
+ report(message, JOB_LOGS);
}
}
static void
report_file_IO(file_t* file, uintmax_t bytes, size_t sector_size, bool is_input)
{
- // Write the file name.
char message[DISPLAY_MESSAGE_LENGTH];
+
+ // Write the file name.
sprintf(message, "%s results for %s %s:\n",
is_input ? _("input") : _("output"),
file->is_device ? _("device") : file->part_of_set ? _("files") : _("file"),
quote(file->unparsed_name));
- report_to_all(message);
+ report(message, ALL_LOGS);
// Write the number of the sectors read or written.
uintmax_t sectors = bytes / sector_size;
uintmax_t leftover_bytes = bytes % sector_size;
if (leftover_bytes == 0)
- {
sprintf(message, _(" %"PRIuMAX" sectors %s\n"), sectors, is_input ? _("in") : _("out"));
- }
else
- {
sprintf(message, _(" %"PRIuMAX" sectors + %"PRIuMAX" bytes %s\n"),
sectors, leftover_bytes, is_input ? _("in") : _("out"));
- }
- report_to_log(message);
+ report(message, JOB_LOGS);
}
static void
report_file_output(output_t* output)
{
- report_file_IO(output->current_file, output->bytes_output, output->sector_size, false);
+ file_output_t *file_output = output->file;
+ report_file_IO(file_output->current_file, file_output->bytes_output, output->sector_size, false);
if (verbose_reporting)
- {
- report_files_IO(output->files, output->sector_size, false);
- }
+ report_files_IO(file_output->files, output->sector_size, false);
}
static void
report_input(input_t* input)
{
char message[DISPLAY_MESSAGE_LENGTH];
- if (input->current_file)
- {
+ if (input->current_file) {
+ // Report file input stats.
report_file_IO(input->current_file, input->bytes_input, input->sector_size, true);
- if (input->current_file->is_device)
- {
+
+ if (input->current_file->is_device) {
sprintf(message, _(" %"PRIuMAX" bad sectors replaced by zeros\n"), input->bad_sectors);
- report_to_log(message);
+ report(message, JOB_LOGS);
}
if (verbose_reporting)
- {
report_files_IO(input->files, input->sector_size, true);
- }
}
- else
- {
+ else {
+ // Report pattern input stats.
sprintf(message, _("input results for pattern %s:\n"), quote(input->pattern_string));
- report_to_all(message);
+ report(message, ALL_LOGS);
sprintf(message, _(" %"PRIuMAX" sectors in\n"), input->bytes_input / input->sector_size);
- report_to_all(message);
+ report(message, ALL_LOGS);
}
}
@@ -923,41 +872,31 @@ report_results(job_t* jobs)
// as well as the console.
imaging_job->report_progress(imaging_job, true);
if (verification_job)
- {
verification_job->report_progress(verification_job, true);
- }
- if (!compact_reporting) report_to_all("\n");
+ if (!compact_reporting) report("\n", ALL_LOGS);
// Report input stats and hashes.
report_input(imaging_task->input);
- output_t* output = imaging_task->outputs;
- while (output)
- {
+ for (output_t* output = imaging_task->outputs; output; output = output->next_output)
if (output->hash)
- {
report_input_hashes(output);
- }
- output = output->next_output;
- }
- if (!compact_reporting) report_to_all("\n");
+ if (!compact_reporting)
+ report("\n", ALL_LOGS);
// Report output stats and hashes.
- output = imaging_task->outputs;
- while (output)
- {
- if (output->current_file)
+ for (output_t* output = imaging_task->outputs; output; output = output->next_output)
+ if (output->file)
{
report_file_output(output);
- if (output->current_file->verify_requested &&
+ if (output->file->verification != NONE &&
verification_job &&
verification_job->exit_code == DC3DD_EXIT_COMPLETED)
{
report_output_hashes(output);
}
- if (!compact_reporting) report_to_all("\n");
+ if (!compact_reporting)
+ report("\n", ALL_LOGS);
}
- output = output->next_output;
- }
pthread_mutex_unlock(&reporting_lock);
}
@@ -965,38 +904,36 @@ report_results(job_t* jobs)
static void
report_verification_progress(job_t* job, bool final)
{
+ // Calculate percent complete using the ratio of the bytes input for all of
+ // the tasks to the bytes to be input for all of the tasks. Synchronization
+ // of this read-only access to the task thread data is not required since
+ // exact calculations are not required for the progress bar.
uintmax_t bytes_input = 0;
uintmax_t bytes_to_input = 0;
- task_t* task = job->tasks;
- while (task)
- {
- // Synchronization of this read-only access to the task thread data is not required
- // since exact calculations are not required for the progress bar.
+ for (task_t* task = job->tasks; task; task = task->next_task) {
bytes_input += task->input->bytes_input;
bytes_to_input += task->input->bytes_to_input;
- task = task->next_task;
}
float percent_complete = bytes_to_input ? 100.0f * (float)bytes_input / (float)bytes_to_input : 100.0f;
pthread_mutex_lock(&reporting_lock);
+
fprintf(stderr, "%79s", "\r");
- if (bytes_to_input > 0)
- {
+ if (bytes_to_input > 0) {
fprintf(stderr, _("output hashing (%2.0f%%)%s"), percent_complete, final ? "\n" : "\r");
- if (log && final)
- {
- fprintf(log, _("output hashing (%2.0f%%)\n"), percent_complete);
- }
+ if (final)
+ for (log_t* log = job_logs; log; log = log->next_log)
+ fprintf(log->file, _("output hashing (%2.0f%%)\n"), percent_complete);
}
- else
- {
+ else {
fprintf(stderr, _("output hashing (??%%)%s"), final ? "\n" : "\r");
- if (log && final)
- {
- fputs(_("output hashing (??%%)\n"), log);
- }
+ if (final)
+ for (log_t *log = job_logs; log; log = log->next_log)
+ fputs(_("output hashing (??%%)\n"), log->file);
}
+
progress_displayed = true;
+
pthread_mutex_unlock(&reporting_lock);
}
@@ -1018,36 +955,28 @@ report_imaging_progress(job_t* job, bool final)
task->input->bytes_input,
human_readable(task->input->bytes_input, hbuf, human_opts, 1, 1));
fputs(stats, stderr);
- if (log && final)
- {
- fputs(stats, log);
- }
+ if (final)
+ write_to_logs(stats, JOB_LOGS);
- if (task->input->bytes_to_input != INFINITE_BYTES)
- {
+ if (task->input->bytes_to_input != INFINITE_BYTES) {
// Oddly, the %% format specifier has no effect if this is done with sprintf().
float percent_complete =
100.0f * ((float)task->input->bytes_input / (float)task->input->bytes_to_input);
fprintf(stderr, " (%2.0f%%)", percent_complete);
- if (log && final)
- {
- fprintf(log, " (%2.0f%%)", percent_complete);
- }
+ if (final)
+ for (log_t *log = job_logs; log; log = log->next_log)
+ fprintf(log->file, " (%2.0f%%)", percent_complete);
}
- else
- {
+ else {
fputs(" (??%)", stderr);
- if (log && final)
- {
- fputs(" (??%)", log);
- }
+ if (final)
+ write_to_logs(" (??%)", JOB_LOGS);
}
double delta_s = 0.0;
char const *bytes_per_second = NULL;
xtime_t now = gethrxtime();
- if (start_time < now)
- {
+ if (start_time < now) {
double XTIME_PRECISIONe0 = XTIME_PRECISION;
uintmax_t delta_xtime = now;
delta_xtime -= start_time;
@@ -1055,8 +984,7 @@ report_imaging_progress(job_t* job, bool final)
bytes_per_second =
human_readable(task->input->bytes_input, hbuf, human_opts, XTIME_PRECISION, delta_xtime);
}
- else
- {
+ else {
delta_s = 0.0;
bytes_per_second = _("Infinity B");
}
@@ -1072,101 +1000,97 @@ report_imaging_progress(job_t* job, bool final)
// bug we now use SI symbols even though they're a bit more
// confusing in English.
fprintf (stderr, _(", %g s, %s/s %s"), delta_s, bytes_per_second, final ? "\n" : "\r");
- if (log && final)
- {
- fprintf (log, _(", %g s, %s/s\n"), delta_s, bytes_per_second);
- }
+ if (final)
+ for (log_t *log = job_logs; log; log = log->next_log)
+ fprintf (log->file, _(", %g s, %s/s\n"), delta_s, bytes_per_second);
progress_displayed = true;
+
pthread_mutex_unlock(&reporting_lock);
}
static void
-add_to_task_list(task_t** head, task_t* new_task)
+add_to_log_list(log_t **list, log_t *new_log)
{
- if (*head)
- {
- task_t* task = *head;
- while (task)
- {
- if (task->next_task == NULL)
- {
- task->next_task = new_task;
+ if (*list) {
+ for (log_t *log = *list; log; log = log->next_log)
+ if (!log->next_log) {
+ log->next_log = new_log;
break;
}
- task = task->next_task;
- }
}
else
- {
- *head = new_task;
+ *list = new_log;
+}
+
+static void
+add_to_task_list(task_t **list, task_t *new_task)
+{
+ if (*list) {
+ for (task_t *task = *list; task; task = task->next_task)
+ if (!task->next_task) {
+ task->next_task = new_task;
+ break;
+ }
}
+ else
+ *list = new_task;
}
static void
-add_to_output_list(output_t** head, output_t* new_output)
+add_to_output_list(output_t **list, output_t *new_output)
{
- if (*head)
- {
- output_t* output = *head;
- while (output)
- {
- if (output->next_output == NULL)
- {
+ if (*list) {
+ for (output_t *output = *list; output; output = output->next_output)
+ if (!output->next_output) {
output->next_output = new_output;
break;
}
- output = output->next_output;
- }
}
else
- {
- *head = new_output;
+ *list = new_output;
+}
+
+static void
+add_to_hash_output_list(hash_output_t **list, hash_output_t *new_item)
+{
+ if (*list) {
+ for (hash_output_t *item = *list; item; item = item->next)
+ if (!item->next) {
+ item->next= new_item;
+ break;
+ }
}
+ else
+ *list = new_item;
}
static void
-add_to_file_list(file_t** head, file_t* new_file)
+add_to_file_list(file_t **list, file_t *new_file)
{
- if (*head)
- {
- file_t* file = *head;
- while (file)
- {
- if (file->next_file == NULL)
- {
+ if (*list) {
+ for (file_t *file = *list; file; file = file->next_file)
+ if (!file->next_file) {
file->next_file = new_file;
break;
}
- file = file->next_file;
- }
}
else
- {
- *head = new_file;
- }
+ *list = new_file;
}
static void
-add_to_hash_list(hash_t** head, hash_t* new_hash)
+add_to_hash_list(hash_t **list, hash_t *new_hash)
{
- if (*head)
- {
- hash_t* hash = *head;
- while (hash)
- {
- if (hash->next_hash == NULL)
- {
+ if (*list) {
+ for (hash_t *hash = *list; hash; hash = hash->next_hash)
+ if (!hash->next_hash) {
hash->next_hash = new_hash;
break;
}
- hash = hash->next_hash;
- }
}
else
- {
- *head = new_hash;
- }
+ *list = new_hash;
}
static void
@@ -1290,30 +1214,32 @@ generate_file_name(const char* unparsed_name, uint file_number)
}
static file_t*
-make_file(const char* name, int number, int flags, bool part_of_set, bool verify_requested)
+make_file(const char *name, int number, int flags, bool part_of_set, enum VERIFICATION_TYPE verification)
{
- file_t* file = NULL;
- char* file_name = part_of_set ? generate_file_name(name, number) : strdup(name);
- if (file_name)
+ file_t *file = NULL;
+
+ char *file_name = part_of_set ? generate_file_name(name, number) : strdup(name);
+ if (file_name)
{
file = (file_t*)malloc(sizeof(file_t));
file->unparsed_name = strdup(name);
file->name = file_name;
+ file->part_of_set = part_of_set;
file->number = number;
file->flags = flags;
file->descriptor = FILE_DESCRIPTOR_NOT_SET;
file->offset = 0;
- file->is_device = false;
- file->is_block_device = false;
- file->size_in_bytes = 0;
file->probed = false;
file->probed_size_in_bytes = 0;
file->probed_size_in_sectors = 0;
file->probed_sector_size = 0;
- file->part_of_set= part_of_set;
- file->verify_requested= verify_requested;
+ file->is_device = false;
+ file->is_block_device = false;
+ file->bytes_processed = 0;
+ file->verification = verification;
file->next_file = NULL;
}
+
return file;
}
@@ -1322,30 +1248,23 @@ close_file_output(output_t* output)
{
pthread_mutex_destroy(output->buffer_queue->lock);
- if (output->current_file->descriptor >=0)
- {
- if (output->append_garbage_bytes)
- {
+ file_output_t *file = output->file;
+ if (file->current_file->descriptor >=0) {
+ if (file->append_garbage_bytes) {
memset(output->buffer_queue->buffers[0].data, '\0', output->buffer_size);
- ssize_t bytes_written = write(output->current_file->descriptor,
+ ssize_t bytes_written = write(file->current_file->descriptor,
output->buffer_queue->buffers[0].data, output->buffer_size);
if (bytes_written <= 0)
- {
- report_error(0, errno, _("corrupting %s"), quote(output->current_file->name));
- }
+ report_error(0, errno, _("corrupting %s"), quote(file->current_file->name));
}
- if (close(output->current_file->descriptor) == 0)
- {
+ if (close(file->current_file->descriptor) == 0) {
if (output->state != FATAL_ERROR)
- {
// If not already in an error state, the output was completed.
output->state = COMPLETE;
- }
}
- else
- {
- report_error(0, errno, _("closing %s"), quote(output->current_file->name));
+ else {
+ report_error(0, errno, _("closing %s"), quote(file->current_file->name));
output->state = FATAL_ERROR;
}
}
@@ -1354,40 +1273,35 @@ close_file_output(output_t* output)
static void
open_next_output_file(output_t* output)
{
- if (close(output->current_file->descriptor) == 0)
- {
- output->current_file->descriptor = FILE_DESCRIPTOR_NOT_SET;
+ file_output_t *file = output->file;
+ if (close(file->current_file->descriptor) == 0) {
+ file->current_file->descriptor = FILE_DESCRIPTOR_NOT_SET;
file_t* next_file = make_file(
- output->current_file->unparsed_name,
- output->current_file->number + 1,
- output->current_file->flags,
+ file->current_file->unparsed_name,
+ file->current_file->number + 1,
+ file->current_file->flags,
true,
- output->current_file->verify_requested);
- if (next_file)
- {
+ file->current_file->verification);
+ if (next_file) {
next_file->descriptor = open(next_file->name, next_file->flags, OUTPUT_FILE_PERMS);
- if (next_file->descriptor >= 0)
- {
- output->current_file = next_file;
- add_to_file_list(&output->files, next_file);
+ if (next_file->descriptor >= 0) {
+ file->current_file = next_file;
+ add_to_file_list(&file->files, next_file);
}
- else
- {
+ else {
report_error(0, errno, _("opening %s"), quote(next_file->name));
output->state = FATAL_ERROR;
}
}
- else
- {
- report_error(0, 0 , _("file extensions exhausted for %s"), output->current_file->unparsed_name);
+ else {
+ report_error(0, 0 , _("file extensions exhausted for %s"), file->current_file->unparsed_name);
output->state = FATAL_ERROR;
}
}
- else
- {
- output->current_file->descriptor = FILE_DESCRIPTOR_NOT_SET;
- report_error(0, errno, _("closing %s"), quote(output->current_file->name));
+ else {
+ file->current_file->descriptor = FILE_DESCRIPTOR_NOT_SET;
+ report_error(0, errno, _("closing %s"), quote(file->current_file->name));
output->state = FATAL_ERROR;
}
}
@@ -1397,10 +1311,11 @@ write_bytes_to_file(output_t* output, char const *buffer, size_t bytes_to_write)
{
size_t total_bytes_written = 0;
+ file_output_t *file = output->file;
while (total_bytes_written < bytes_to_write)
{
ssize_t bytes_written = write(
- output->current_file->descriptor,
+ file->current_file->descriptor,
buffer + total_bytes_written,
bytes_to_write - total_bytes_written);
@@ -1408,7 +1323,7 @@ write_bytes_to_file(output_t* output, char const *buffer, size_t bytes_to_write)
{
if (errno != EINTR)
{
- report_error(0, errno, _("writing to %s"), quote(output->current_file->name));
+ report_error(0, errno, _("writing to %s"), quote(file->current_file->name));
output->state = FATAL_ERROR;
break;
}
@@ -1419,14 +1334,14 @@ write_bytes_to_file(output_t* output, char const *buffer, size_t bytes_to_write)
// a device's end. (Example: Linux 1.2.13 on /dev/fd0.)
// Set errno to ENOSPC for a sensible diagnostic.
errno = ENOSPC;
- report_error(0, errno, _("writing to %s"), quote(output->current_file->name));
+ report_error(0, errno, _("writing to %s"), quote(file->current_file->name));
output->state = FATAL_ERROR;
break;
}
else
{
total_bytes_written += (size_t)bytes_written;
- output->current_file->size_in_bytes += (size_t)total_bytes_written;
+ file->current_file->bytes_processed += (size_t)total_bytes_written;
}
}
@@ -1438,7 +1353,8 @@ write_bytes_to_files(output_t* output, char const *buffer, size_t bytes_to_write
{
size_t bytes_written = 0;
- intmax_t bytes_left_for_file = output->max_file_size - output->current_file->size_in_bytes;
+ file_output_t *file = output->file;
+ intmax_t bytes_left_for_file = file->max_file_size - file->current_file->bytes_processed;
if (bytes_to_write <= bytes_left_for_file)
{
// Write all of the bytes in the buffer to the current file.
@@ -1467,42 +1383,36 @@ write_bytes_to_files(output_t* output, char const *buffer, size_t bytes_to_write
static void
write_bytes_to_image(output_t* output, buffer_t* buffer)
{
- if (output->current_file->part_of_set)
- {
- output->bytes_output += write_bytes_to_files(output, buffer->data, buffer->length);
- }
+ if (output->file->current_file->part_of_set)
+ output->file->bytes_output += write_bytes_to_files(output, buffer->data, buffer->length);
else
- {
- output->bytes_output += write_bytes_to_file(output, buffer->data, buffer->length);
- }
+ output->file->bytes_output += write_bytes_to_file(output, buffer->data, buffer->length);
}
static ssize_t
read_bytes(int file_descriptor, char *buffer, size_t bytes_to_read)
{
- for (;;)
- {
+ for (;;) {
ssize_t bytes_read;
bytes_read = read(file_descriptor, buffer, bytes_to_read);
if (!(bytes_read < 0 && errno == EINTR))
- {
return bytes_read;
- }
}
}
static void
skip_output_sectors(output_t* output)
{
- if (output->sectors_to_skip > 0)
+ file_output_t *file = output->file;
+ if (file->sectors_to_skip > 0)
{
- uintmax_t bytes_to_skip = output->sectors_to_skip * output->sector_size;
+ uintmax_t bytes_to_skip = file->sectors_to_skip * output->sector_size;
if (bytes_to_skip <= OFF_T_MAX)
{
- if (lseek(output->current_file->descriptor, bytes_to_skip, SEEK_CUR) < 0)
+ if (lseek(file->current_file->descriptor, bytes_to_skip, SEEK_CUR) < 0)
{
report_error(0, errno, _("lseek() on %s failed while skipping sectors"),
- quote(output->current_file->name));
+ quote(file->current_file->name));
output->state = FATAL_ERROR;
}
}
@@ -1516,7 +1426,7 @@ skip_output_sectors(output_t* output)
size_t bytes_to_read =
bytes_to_skip >= output->buffer_size ? output->buffer_size : bytes_to_skip;
ssize_t bytes_read =
- read_bytes(output->current_file->descriptor, buffer, bytes_to_read);
+ read_bytes(file->current_file->descriptor, buffer, bytes_to_read);
if (bytes_read > 0)
{
bytes_to_skip -= bytes_read;
@@ -1525,7 +1435,7 @@ skip_output_sectors(output_t* output)
{
char message[DISPLAY_MESSAGE_LENGTH];
sprintf(message, _("encountered end of file reading %s to skip sectors"),
- quote(output->current_file->name));
+ quote(file->current_file->name));
report_error(0, 0, message);
output->state = FATAL_ERROR;
break;
@@ -1533,7 +1443,7 @@ skip_output_sectors(output_t* output)
else
{
report_error(0, errno, _("reading %s while skipping sectors"),
- quote(output->current_file->name));
+ quote(file->current_file->name));
output->state = FATAL_ERROR;
break;
}
@@ -1546,18 +1456,19 @@ skip_output_sectors(output_t* output)
static void
open_file_output(output_t* output)
{
- pthread_mutex_init(output->buffer_queue->lock, NULL);
+ //pthread_mutex_init(output->buffer_queue->lock, NULL);
- output->current_file->descriptor =
- open(output->current_file->name, output->current_file->flags, OUTPUT_FILE_PERMS);
- if (output->current_file->descriptor >= 0)
+ file_output_t *file = output->file;
+ file->current_file->descriptor =
+ open(file->current_file->name, file->current_file->flags, OUTPUT_FILE_PERMS);
+ if (file->current_file->descriptor >= 0)
{
output->state = OPEN;
skip_output_sectors(output);
}
else
{
- report_error(0, errno,_("opening %s"), quote(output->current_file->name));
+ report_error(0, errno,_("opening %s"), quote(file->current_file->name));
output->state = FATAL_ERROR;
}
}
@@ -1573,34 +1484,43 @@ static void
connect_to_std_out(output_t* output)
{
pthread_mutex_init(output->buffer_queue->lock, NULL);
- output->current_file->descriptor = STDOUT_FILENO;
+ output->file->current_file->descriptor = STDOUT_FILENO;
output->state = OPEN;
}
static void
-get_hash_result(hash_t* hash)
+get_hash_result(hash_t* hash, size_t sum_size)
{
static char hex[] = "0123456789abcdef";
- for (size_t p = 0; p < hash->algorithm->sum_size ; p++)
+ for (size_t p = 0; p < sum_size ; p++)
{
hash->result[2 * p] = hex[(hash->sum[p] >> 4) & 0xf];
hash->result[2 * p + 1] = hex[hash->sum[p] & 0xf];
}
- hash->result[2 * hash->algorithm->sum_size] = 0;
+ hash->result[2 * sum_size] = 0;
}
static void
close_hash(output_t* output)
{
- output->hash->algorithm->finish(output->hash->context, output->hash->sum);
- get_hash_result(output->hash);
- if (output->hash->current_piece != NULL)
- {
- output->hash->current_piece->algorithm->finish(output->hash->current_piece->context,
- output->hash->current_piece->sum);
- get_hash_result(output->hash->current_piece);
+ hash_output_t * hash = output->hash;
+
+ // Finish the total hash.
+ hash->algorithm->finish(hash->total_hash->context, hash->total_hash->sum);
+ get_hash_result(hash->total_hash, hash->algorithm->sum_size);
+
+ // Finish the piecewise hash.
+ if (hash->current_piece) {
+ hash->algorithm->finish(hash->current_piece->context, hash->current_piece->sum);
+ get_hash_result(hash->current_piece, hash->algorithm->sum_size);
+ }
+
+ // Finish the hash of the device that received the device.
+ if (hash->device_hash) {
+ hash->algorithm->finish(hash->device_hash->context, hash->device_hash->sum);
+ get_hash_result(hash->device_hash, hash->algorithm->sum_size);
}
pthread_mutex_destroy(output->buffer_queue->lock);
@@ -1611,15 +1531,11 @@ static hash_t*
make_hash(hash_algorithm_t* algorithm)
{
hash_t* hash = (hash_t*)malloc(sizeof(hash_t));
- hash->algorithm = algorithm;
hash->context = malloc(algorithm->context_size);
hash->sum = (char*)malloc(algorithm->sum_size);
hash->result = (char*)malloc(2 * algorithm->sum_size + 1);
hash->result[0] = 0;
hash->bytes_hashed = 0;
- hash->current_piece = NULL;
- hash->pieces = NULL;
- hash->piecewise_hash_length = 0;
hash->next_hash = NULL;
return hash;
}
@@ -1632,23 +1548,23 @@ piecewise_hash_bytes(output_t* output, const char* buf, size_t buf_length)
if (bytes_left_for_piece == 0)
{
- output->hash->current_piece->algorithm->finish(output->hash->current_piece->context,
+ output->hash->algorithm->finish(output->hash->current_piece->context,
output->hash->current_piece->sum);
- get_hash_result(output->hash->current_piece);
- output->hash->current_piece = make_hash(output->hash->current_piece->algorithm);
- add_to_hash_list(&output->hash->pieces, output->hash->current_piece);
- output->hash->current_piece->algorithm->init(output->hash->current_piece->context);
+ get_hash_result(output->hash->current_piece, output->hash->algorithm->sum_size);
+ output->hash->current_piece = make_hash(output->hash->algorithm);
+ add_to_hash_list(&output->hash->piecewise_hash, output->hash->current_piece);
+ output->hash->algorithm->init(output->hash->current_piece->context);
bytes_left_for_piece = output->hash->piecewise_hash_length;
}
if (buf_length <= bytes_left_for_piece)
{
- output->hash->current_piece->algorithm->update(buf, buf_length, output->hash->current_piece->context);
+ output->hash->algorithm->update(buf, buf_length, output->hash->current_piece->context);
output->hash->current_piece->bytes_hashed += buf_length;
}
else
{
- output->hash->current_piece->algorithm->update(buf, bytes_left_for_piece,
+ output->hash->algorithm->update(buf, bytes_left_for_piece,
output->hash->current_piece->context);
output->hash->current_piece->bytes_hashed += bytes_left_for_piece;
piecewise_hash_bytes(output, buf + bytes_left_for_piece, buf_length - bytes_left_for_piece);
@@ -1658,10 +1574,25 @@ piecewise_hash_bytes(output_t* output, const char* buf, size_t buf_length)
static void
hash_bytes(output_t* output, buffer_t* buffer)
{
- output->hash->algorithm->update(buffer->data, buffer->length, output->hash->context);
- if (output->hash->current_piece != NULL)
- {
+ hash_output_t *hash = output->hash;
+ hash->algorithm->update(buffer->data, buffer->length, hash->total_hash->context);
+ hash->total_hash->bytes_hashed += buffer->length;
+ if (hash->current_piece)
piecewise_hash_bytes(output, buffer->data, buffer->length);
+}
+
+static void
+hash_device_bytes(output_t* output, buffer_t* buffer)
+{
+ hash_output_t *hash = output->hash;
+ hash->algorithm->update(buffer->data, buffer->length, hash->device_hash->context);
+ hash->device_hash->bytes_hashed += buffer->length;
+ uintmax_t bytes_remaining = hash->total_hash_length - hash->total_hash->bytes_hashed;
+ if (bytes_remaining > 0) {
+ if (bytes_remaining < buffer->length)
+ buffer->length = bytes_remaining;
+ hash->algorithm->update(buffer->data, buffer->length, hash->total_hash->context);
+ hash->total_hash->bytes_hashed += buffer->length;
}
}
@@ -1670,11 +1601,14 @@ open_hash(output_t* output)
{
pthread_mutex_init(output->buffer_queue->lock, NULL);
- output->hash->algorithm->init(output->hash->context);
- if (output->hash->current_piece != NULL)
- {
- output->hash->current_piece->algorithm->init(output->hash->current_piece->context);
- }
+ hash_output_t *hash = output->hash;
+ hash->algorithm->init(output->hash->total_hash->context);
+
+ if (hash->current_piece != NULL)
+ hash->algorithm->init(hash->current_piece->context);
+
+ if (hash->device_hash != NULL)
+ hash->algorithm->init(hash->device_hash->context);
output->state = OPEN;
}
@@ -1684,13 +1618,20 @@ wait_for_buffer(buffer_queue_t* buffer_queue)
{
// This function is called by an output thread each time it
// finishes consuming some input bytes furnished by an input (i.e., task) thread.
+
+ uint buffers_used = 0;
+
pthread_mutex_lock(buffer_queue->lock);
if (buffer_queue->buffers_used == 0 && !buffer_queue->done_buffering)
{
pthread_cond_wait(buffer_queue->not_empty, buffer_queue->lock);
}
+
+ buffers_used = buffer_queue->buffers_used;
+
pthread_mutex_unlock(buffer_queue->lock);
- return buffer_queue->buffers_used > 0;
+
+ return buffers_used > 0;
}
static void*
@@ -1750,7 +1691,7 @@ advance_input(input_t* input, uintmax_t bytes_read)
if (input->current_file)
{
input->current_file->offset += bytes_read;
- input->current_file->size_in_bytes += bytes_read;
+ input->current_file->bytes_processed += bytes_read;
input->current_sector += bytes_read / input->sector_size;
}
input->bytes_input += bytes_read;
@@ -2002,7 +1943,7 @@ open_next_input_file(input_t* input)
input->current_file->number + 1,
input->current_file->flags,
true,
- false);
+ input->current_file->verification);
if (next_file)
{
@@ -2060,7 +2001,7 @@ skip_device_input_sectors(input_t* input)
// Correct bytes input, since bytes skipped, not input
input->bytes_input -= input->sector_size;
- input->current_file->size_in_bytes -= input->sector_size;
+ input->current_file->bytes_processed -= input->sector_size;
}
else if (bytes_read == 0 || errno == ENOSPC)
{
@@ -2092,7 +2033,7 @@ skip_device_input_sectors(input_t* input)
{
// Correct bytes input, since bytes skipped, not input
input->bytes_input -= input->sector_size;
- input->current_file->size_in_bytes -= input->sector_size;
+ input->current_file->bytes_processed -= input->sector_size;
}
}
else
@@ -2124,7 +2065,7 @@ skip_file_input_sectors(input_t* input)
// Correct bytes input, since bytes skipped, not input
input->bytes_input -= bytes_read;
- input->current_file->size_in_bytes -= bytes_read;
+ input->current_file->bytes_processed -= bytes_read;
bytes_to_skip -= bytes_read;
}
@@ -2162,18 +2103,13 @@ skip_input_sectors(input_t* input)
// Correct bytes input, since bytes skipped, not input
input->bytes_input -= bytes_to_skip;
- input->current_file->size_in_bytes -= bytes_to_skip;
+ input->current_file->bytes_processed -= bytes_to_skip;
}
- else
- {
+ else {
if (input->current_file->is_device)
- {
skip_device_input_sectors(input);
- }
else
- {
skip_file_input_sectors(input);
- }
}
}
}
@@ -2332,11 +2268,9 @@ get_file_stats(file_t* file)
static bool
probe_file(file_t* file)
{
- if (!file->probed)
- {
+ if (!file->probed) {
get_file_stats(file);
- if (file->probed && file->part_of_set)
- {
+ if (file->probed && file->part_of_set) {
// Generate the set of potential file names and attempt to
// open the set of files. Stop when file extensions are exhausted
// or the next file does not exist. Note that there is an assumption
@@ -2348,34 +2282,26 @@ probe_file(file_t* file)
next_file.probed_size_in_bytes = 0;
next_file.probed_sector_size = 0;
next_file.name = generate_file_name(file->unparsed_name, ++next_file.number);
- while (next_file.name)
- {
+ while (next_file.name) {
next_file.descriptor = open(next_file.name, O_RDONLY, 0);
- if (next_file.descriptor >= 0)
- {
+ if (next_file.descriptor >= 0) {
// This is another file in the set, get its size.
get_file_stats(&next_file);
if (next_file.probed)
- {
file->probed_size_in_bytes += next_file.probed_size_in_bytes;
- }
- else
- {
+ else {
report_error(0, 0, _("probe of %s failed"), quote(next_file.name));
file->probed = false;
}
- if (close(next_file.descriptor) != 0)
- {
+ if (close(next_file.descriptor) != 0) {
report_error(0, errno, _("closing %s after size probe"), quote(next_file.name));
file->probed = false;
}
free(next_file.name);
if (!file->probed)
- {
break;
- }
}
else
{
@@ -2395,30 +2321,29 @@ static void
open_file_input(input_t* input)
{
input->current_file->descriptor = open(input->current_file->name, input->current_file->flags, 0);
- if (input->current_file->descriptor >= 0)
- {
- if (probe_file(input->current_file))
- {
+ if (input->current_file->descriptor >= 0) {
+ if (probe_file(input->current_file)) {
input->state = OPEN;
- input->bytes_to_input = input->current_file->probed_size_in_bytes;
- if (input->max_sectors_to_input != INFINITE_SECTORS)
- {
- uintmax_t max_bytes_to_input = input->max_sectors_to_input * input->sector_size;
- if (max_bytes_to_input < input->bytes_to_input)
- {
- input->bytes_to_input = max_bytes_to_input;
+
+ // If bytes to input is not pre-determined, calculate bytes to input
+ // from input size.
+ if (input->bytes_to_input == 0) {
+ input->bytes_to_input = input->current_file->probed_size_in_bytes;
+ if (input->max_sectors_to_input != INFINITE_SECTORS) {
+ uintmax_t max_bytes_to_input = input->max_sectors_to_input * input->sector_size;
+ if (max_bytes_to_input < input->bytes_to_input)
+ input->bytes_to_input = max_bytes_to_input;
}
- }
+ }
+
skip_input_sectors(input);
}
- else
- {
+ else {
report_error(0, errno, _("probing %s for bytes to input"), quote(input->current_file->name));
input->state = FATAL_ERROR;
}
}
- else
- {
+ else {
report_error(0, errno, _("opening %s"), quote(input->current_file->name));
input->state = FATAL_ERROR;
}
@@ -2471,7 +2396,7 @@ open_pattern_input(input_t* input)
static void
set_exit_code(task_t* task)
{
- pthread_mutex_lock(task->signalling_lock);
+ pthread_mutex_lock(task->signaling_lock);
task->completed = true;
if (task->aborted)
{
@@ -2500,7 +2425,7 @@ set_exit_code(task_t* task)
}
}
}
- pthread_mutex_unlock(task->signalling_lock);
+ pthread_mutex_unlock(task->signaling_lock);
}
static void
@@ -2539,48 +2464,41 @@ wait_for_output_threads(task_t* task)
static void
produce_bytes(task_t* task)
{
- input_t* input = task->input;
- // Produce an input buffer and copy it to each output buffer queue.
- input->produce_bytes(input);
- if (input->buffer.length > 0)
- {
- output_t* output = task->outputs;
- while (output)
- {
- // Wait for an empty buffer in the buffer buffer queue for this
- // output.
- buffer_queue_t* buffer_queue = output->buffer_queue;
- pthread_mutex_lock(buffer_queue->lock);
- if (buffer_queue->buffers_used == buffer_queue->number_of_buffers)
- {
- pthread_cond_wait(buffer_queue->not_full, buffer_queue->lock);
- }
- pthread_mutex_unlock(buffer_queue->lock);
-
- // Copy the input buffer into the buffer queue.
- memcpy(buffer_queue->buffers[buffer_queue->next_available_buffer].data,
- input->buffer.data, input->buffer.length);
- buffer_queue->buffers[buffer_queue->next_available_buffer].length = input->buffer.length;
-
- // Notify the output thread that another buffer is available.
- // This will release the output thread if it is blocked waiting
- // for bytes to output.
- pthread_mutex_lock(buffer_queue->lock);
- buffer_queue->next_available_buffer =
- (buffer_queue->next_available_buffer + 1) % buffer_queue->number_of_buffers;
- ++buffer_queue->buffers_used;
- pthread_cond_signal(buffer_queue->not_empty);
- pthread_mutex_unlock(buffer_queue->lock);
-
- output = output->next_output;
- }
- }
+ // Produce an input buffer and copy it to each output buffer queue.
+ input_t *input = task->input;
+ input->produce_bytes(input);
+ if (input->buffer.length > 0) {
+ for (output_t *output = task->outputs; output; output = output->next_output) {
+ // Wait for an empty buffer in the buffer queue for this
+ // output.
+ buffer_queue_t *buffer_queue = output->buffer_queue;
+ pthread_mutex_lock(buffer_queue->lock);
+ if (buffer_queue->buffers_used == buffer_queue->number_of_buffers)
+ pthread_cond_wait(buffer_queue->not_full, buffer_queue->lock);
+ pthread_mutex_unlock(buffer_queue->lock);
+
+ // Copy the input buffer into the buffer queue.
+ memcpy(buffer_queue->buffers[buffer_queue->next_available_buffer].data,
+ input->buffer.data, input->buffer.length);
+ buffer_queue->buffers[buffer_queue->next_available_buffer].length = input->buffer.length;
+
+ // Notify the output thread that another buffer is available.
+ // This will release the output thread if it is blocked waiting
+ // for bytes to output.
+ pthread_mutex_lock(buffer_queue->lock);
+ buffer_queue->next_available_buffer =
+ (buffer_queue->next_available_buffer + 1) % buffer_queue->number_of_buffers;
+ ++buffer_queue->buffers_used;
+ pthread_cond_signal(buffer_queue->not_empty);
+ pthread_mutex_unlock(buffer_queue->lock);
+ }
+ }
}
static bool
is_task_completed(task_t* task)
{
- pthread_mutex_lock(task->signalling_lock);
+ pthread_mutex_lock(task->signaling_lock);
// Check for task killed.
task->completed = task->aborted;
@@ -2612,7 +2530,7 @@ is_task_completed(task_t* task)
}
}
- pthread_mutex_unlock(task->signalling_lock);
+ pthread_mutex_unlock(task->signaling_lock);
return task->completed;
}
@@ -2657,17 +2575,30 @@ open_IO(task_t* task)
}
static void*
-execute_task(void* arg)
-{
- // This is the thread function for task (i.e., input) threads.
+execute_task(void* arg) {
task_t* task = (task_t*)arg;
- if (open_IO(task))
- {
+
+ if (task->verification_target) {
+ if (task->verification_target->verification == DEVICE_PARTIAL)
+ // If this task is a verification of only the bytes dc3dd wrote to a
+ // device, limit the size of the input to the number of bytes written
+ // to the verification target during imaging.
+ task->input->bytes_to_input = task->verification_target->bytes_output;
+
+ if (task->verification_target->verification == DEVICE_FULL)
+ // If this task is a verification of both the bytes dc3dd wrote to a
+ // device and the entire device, limit the total hash(es) to the number of
+ // bytes written to the verification target during imaging.
+ for (output_t *output = task->outputs; output; output = output->next_output) {
+ if (output->hash)
+ output->hash->total_hash_length = task->verification_target->bytes_output;
+ }
+ }
+
+ if (open_IO(task)) {
start_output_threads(task);
- while (!is_task_completed(task))
- {
+ while (!is_task_completed(task))
produce_bytes(task);
- }
wait_for_output_threads(task);
close_IO(task);
}
@@ -2676,36 +2607,25 @@ execute_task(void* arg)
}
static void
-abort_job(job_t* job)
-{
- task_t* task = job->tasks;
- while (task)
- {
- pthread_mutex_lock(task->signalling_lock);
+abort_job(job_t *job) {
+ for (task_t *task = job->tasks; task; task = task->next_task) {
+ pthread_mutex_lock(task->signaling_lock);
task->aborted = true;
- pthread_mutex_unlock(task->signalling_lock);
- task = task->next_task;
+ pthread_mutex_unlock(task->signaling_lock);
}
}
static bool
-job_is_active(job_t* job)
-{
+job_is_active(job_t* job) {
bool is_active = false;
- task_t* task = job->tasks;
- while (task)
- {
- pthread_mutex_lock(task->signalling_lock);
+ for (task_t *task = job->tasks; task; task = task->next_task) {
+ pthread_mutex_lock(task->signaling_lock);
is_active = !task->completed && !task->aborted;
- pthread_mutex_unlock(task->signalling_lock);
+ pthread_mutex_unlock(task->signaling_lock);
if (is_active)
- {
break;
- }
-
- task = task->next_task;
}
return is_active;
@@ -2735,10 +2655,10 @@ monitor_job(void *arg)
// Wait until either the signal handling thread receives an interrupt or
// it's time for another progress check and report.
- pthread_mutex_lock(&signalling_lock);
- if (pthread_cond_timedwait(interrupted, &signalling_lock, &next_progress_check_time) == ETIMEDOUT)
+ pthread_mutex_lock(&signaling_lock);
+ if (pthread_cond_timedwait(interrupted, &signaling_lock, &next_progress_check_time) == ETIMEDOUT)
{
- pthread_mutex_unlock(&signalling_lock);
+ pthread_mutex_unlock(&signaling_lock);
job->report_progress(job, false);
if (!job_is_active(job))
{
@@ -2769,9 +2689,9 @@ await_interrupt_signal(void* arg)
sigaddset(&set, SIGINT);
sigwait(&set, &sig);
- pthread_mutex_lock(&signalling_lock);
+ pthread_mutex_lock(&signaling_lock);
pthread_cond_signal(interrupted);
- pthread_mutex_unlock(&signalling_lock);
+ pthread_mutex_unlock(&signaling_lock);
pthread_exit(NULL);
}
@@ -2784,7 +2704,7 @@ execute_job(job_t* job)
task_t* task = job->tasks;
while (task)
{
- pthread_mutex_init(task->signalling_lock, NULL);
+ pthread_mutex_init(task->signaling_lock, NULL);
start_thread(&task->thread, execute_task, task);
task = task->next_task;
}
@@ -2797,7 +2717,7 @@ execute_job(job_t* job)
while (task)
{
pthread_join(task->thread, NULL);
- pthread_mutex_destroy(task->signalling_lock);
+ pthread_mutex_destroy(task->signaling_lock);
task = task->next_task;
}
@@ -2829,7 +2749,7 @@ execute_jobs(job_t* jobs)
pthread_sigmask(SIG_BLOCK, &set, 0);
// Set up synchronization for signal handling and kick off the signal handling thread.
- pthread_mutex_init(&signalling_lock, NULL);
+ pthread_mutex_init(&signaling_lock, NULL);
interrupted = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
pthread_cond_init(interrupted, NULL);
pthread_t signal_handling_thread;
@@ -2849,7 +2769,7 @@ execute_jobs(job_t* jobs)
// Shut down the signal handling thread and tear down synchronization.
pthread_cancel(signal_handling_thread);
- pthread_mutex_destroy(&signalling_lock);
+ pthread_mutex_destroy(&signaling_lock);
return exit_code;
}
@@ -2867,12 +2787,13 @@ make_job(task_t* tasks, void (*report_progress)(job_t*, bool))
}
static task_t*
-make_task(input_t* input, output_t* outputs)
+make_task(input_t *input, output_t *outputs, file_output_t *verification_target)
{
- task_t* task = (task_t*)malloc(sizeof(task_t));
- task->signalling_lock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+ task_t *task = (task_t*)malloc(sizeof(task_t));
+ task->signaling_lock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
task->input = input;
task->outputs = outputs;
+ task->verification_target = verification_target;
task->completed = false;
task->aborted = false;
task->exit_code = DC3DD_EXIT_CODE_NOT_SET;
@@ -2893,12 +2814,18 @@ make_buffer_queue(size_t size_in_bytes, size_t number_of_buffers)
buffer_queue->number_of_buffers = number_of_buffers;
buffer_queue->buffers_used = 0;
buffer_queue->next_available_buffer = 0;
+
buffer_queue->lock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+ pthread_mutex_init(buffer_queue->lock, NULL);
+
buffer_queue->not_empty = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
pthread_cond_init(buffer_queue->not_empty, NULL);
+
buffer_queue->not_full = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
pthread_cond_init(buffer_queue->not_full, NULL);
+
buffer_queue->done_buffering = false;
+
return buffer_queue;
}
@@ -2910,86 +2837,100 @@ make_output(settings_t* settings)
output->sector_size = settings->sector_size;
output->buffer_size = settings->buffer_size;
output->buffer_queue = make_buffer_queue(output->buffer_size, NUM_BUFFERS);
- output->bytes_output = 0;
output->hash = NULL;
- output->current_file = NULL;
- output->files = NULL;
- output->max_file_size = settings->max_output_file_size;
- output->sectors_to_skip = settings->output_sectors_to_skip;
- output->append_garbage_bytes = settings->corrupt_output;
+ output->file = NULL;
output->open = NULL;
output->consume_bytes = NULL;
output->close = NULL;
- output->expected_hashes = NULL;
- output->actual_hashes = NULL;
output->next_output = NULL;
return output;
}
static output_t*
-make_file_output(settings_t* settings, file_t* file, output_t* expected_hashes)
+make_file_output(settings_t* settings, file_t* file, hash_output_t* expected_hashes)
{
- output_t* output = make_output(settings);
- output->current_file = file;
- output->files = output->current_file->part_of_set? file : NULL;
if (settings->append_output || settings->output_sectors_to_skip)
- {
- output->current_file->flags |= O_APPEND;
- }
+ file->flags |= O_APPEND;
else
- {
- output->current_file->flags |= (O_CREAT | O_TRUNC);
- }
+ file->flags |= (O_CREAT | O_TRUNC);
+
+ // Construct the "base part."
+ output_t* output = make_output(settings);
+
+ // Select the open, consume bytes, and close functions based on file type.
output->consume_bytes = write_bytes_to_image;
- if (STREQ(output->current_file->name, "stdout"))
- {
+ if (STREQ(file->name, "stdout")) {
output->open = connect_to_std_out;
output->close = disconnect_from_std_out;
- }
- else
- {
+ } else {
output->open = open_file_output;
output->close = close_file_output;
}
- output->expected_hashes = expected_hashes;
+
+ // Construct the "derived part."
+ output->file = (file_output_t*)malloc(sizeof(file_output_t));
+ output->file->current_file = file;
+ output->file->files = file->part_of_set ? file : NULL;
+ output->file->max_file_size = settings->max_output_file_size;
+ output->file->sectors_to_skip = settings->output_sectors_to_skip;
+ output->file->bytes_output = 0;
+ output->file->verification = file->verification;
+ output->file->append_garbage_bytes = settings->corrupt_output;
+ output->file->expected_hashes = expected_hashes;
+ output->file->actual_hashes = NULL;
+
return output;
}
static output_t*
-make_hash_output(settings_t* settings, hash_algorithm_t* algorithm)
+make_hash_output(settings_t *settings, hash_algorithm_t *algorithm, enum VERIFICATION_TYPE verification)
{
- hash_t* hash = make_hash(algorithm);
- if (settings->splitting_output && settings->verifying_output)
- {
- hash->current_piece = make_hash(algorithm);
- hash->pieces = hash->current_piece;
- hash->piecewise_hash_length = settings->max_output_file_size;
- }
-
- output_t* output = make_output(settings);
- output->hash = hash;
+ output_t* output = make_output(settings);
+ output->hash = (hash_output_t*)malloc(sizeof(hash_output_t));
+ output->hash->algorithm = algorithm;
+ output->hash->total_hash = make_hash(algorithm);
+ output->hash->total_hash_length = INFINITE_BYTES;
+ output->hash->current_piece = NULL;
+ output->hash->piecewise_hash = NULL;
+ output->hash->piecewise_hash_length = 0;
+ output->hash->device_hash = verification == DEVICE_FULL ? make_hash(algorithm) : NULL;
+ output->hash->next = NULL;
output->open = open_hash;
- output->consume_bytes = hash_bytes;
+ output->consume_bytes = verification == DEVICE_FULL ? hash_device_bytes : hash_bytes;
output->close = close_hash;
+
+ if (settings->splitting_output && settings->verifying_output) {
+ output->hash->current_piece = make_hash(algorithm);
+ output->hash->piecewise_hash = output->hash->current_piece;
+ output->hash->piecewise_hash_length = settings->max_output_file_size;
+ }
+
return output;
}
static output_t*
-make_hash_outputs(settings_t* settings)
+make_hash_outputs(settings_t *settings, enum VERIFICATION_TYPE verification)
{
- output_t* hash_outputs = NULL;
+ output_t *hash_outputs = NULL;
- for (uint8_t i = 0 ; i < NUM_HASHES ; ++i)
- {
- if (hash_algorithms[i].active)
- {
- add_to_output_list(&hash_outputs, make_hash_output(settings, &hash_algorithms[i]));
+ for (uint8_t i = 0 ; i < NUM_HASHES ; ++i) {
+ if (hash_algorithms[i].active) {
+ add_to_output_list(&hash_outputs, make_hash_output(settings, &hash_algorithms[i], verification));
}
}
return hash_outputs;
}
+static void
+make_hash_outputs_list(output_t *outputs, hash_output_t **hash_outputs)
+{
+ for (output_t *output = outputs; output; output = output->next_output) {
+ if (output->hash)
+ add_to_hash_output_list(hash_outputs, output->hash);
+ }
+}
+
static input_t*
make_input(settings_t* settings)
{
@@ -2997,6 +2938,7 @@ make_input(settings_t* settings)
input->state = PENDING;
input->sector_size = settings->sector_size;
input->max_sectors_to_input = settings->max_sectors_to_input;
+ input->bytes_to_input = 0;
input->bytes_input = 0;
input->current_file = NULL;
input->files = NULL;
@@ -3021,48 +2963,36 @@ make_input(settings_t* settings)
input->buffer.data = (char*)ptr_align(input->buffer.data, getpagesize());
input->buffer.length = 0;
- if (settings->input_file)
- {
+ // Select the open, produce_bytes, and close functions based on input type.
+ if (settings->input_file) {
input->current_file = settings->input_file;
if (input->current_file->part_of_set)
- {
input->files = input->current_file;
- }
- if (STREQ(input->current_file->name, "stdin"))
- {
+ if (STREQ(input->current_file->name, "stdin")) {
input->open = connect_to_std_in;
input->produce_bytes = read_bytes_from_file;
input->close = disconnect_from_std_in;
}
- else
- {
+ else {
input->open = open_file_input;
// This ASSUMES that probe_file() was called on settings->input_file
// before calling this function.
- if (input->current_file->is_device)
- {
+ if (input->current_file->is_device) {
if (input->recover_errors)
- {
input->current_file->flags |= O_DIRECT;
- }
input->produce_bytes = read_bytes_from_device;
}
else if (input->current_file->part_of_set)
- {
input->produce_bytes = read_bytes_from_files;
- }
else
- {
input->produce_bytes = read_bytes_from_file;
- }
input->close = close_file_input;
}
}
- else
- {
+ else {
input->pattern_string = strdup(settings->input_pattern_string);
input->pattern = strdup(settings->input_pattern);
input->pattern_length = settings->input_pattern_length;
@@ -3082,30 +3012,28 @@ add_verification_job(job_t* job, settings_t* settings)
// Make a verification task for each output to be verified.
task_t* verification_tasks = NULL;
- output_t* output = imaging_task->outputs;
- while (output)
- {
- if (output->current_file && output->current_file->verify_requested)
- {
+ for (output_t* output = imaging_task->outputs; output; output = output->next_output) {
+ if (output->file && output->file->verification != NONE) {
// Make an input file corresponding to the output file
// and swap it into the already initialized and validated settings.
- // However, make sure to clear max sectors to input, since the size of the
- // verification target is now the determinant of bytes to input.
- settings->input_file = make_file(output->current_file->unparsed_name,
- 0, O_RDONLY, output->current_file->part_of_set, false);
- settings->max_sectors_to_input = INFINITE_BYTES;
+ settings->input_file = make_file(output->file->current_file->unparsed_name,
+ 0, O_RDONLY, output->file->current_file->part_of_set, output->file->verification);
input_t* input = make_input(settings);
+ // If output sectors were skipped, those sectors need to be skipped
+ // for verification, too.
+ if (output->file->sectors_to_skip > 0)
+ input->sectors_to_skip = output->file->sectors_to_skip;
+
// Prepare the output hashes and cache a pointer to the list
// for later comparision with the list of input hashes cached
// in the output when the imaging job was created.
- output_t* output_hashes = make_hash_outputs(settings);
- output->actual_hashes = output_hashes;
+ output_t *output_hashes = make_hash_outputs(settings, output->file->verification);
+ make_hash_outputs_list(output_hashes, &output->file->actual_hashes);
- task_t* verification_task = make_task(input, output_hashes);
+ task_t* verification_task = make_task(input, output_hashes, output->file);
add_to_task_list(&verification_tasks, verification_task);
}
- output = output->next_output;
}
job->next_job = make_job(verification_tasks, report_verification_progress);
@@ -3115,36 +3043,36 @@ static job_t*
make_imaging_job(settings_t* settings)
{
input_t* input = make_input(settings);
- output_t* input_hashes = make_hash_outputs(settings);
+
+ output_t* input_hashes = make_hash_outputs(settings, NONE);
+ hash_output_t* expected_hashes = NULL;
+ make_hash_outputs_list(input_hashes, &expected_hashes);
// Make the file outputs.
output_t* outputs = NULL;
if (settings->wipe_target)
{
- add_to_output_list(&outputs, make_file_output(settings, settings->wipe_target, input_hashes));
+ add_to_output_list(&outputs, make_file_output(settings, settings->wipe_target, expected_hashes));
}
else
{
file_t* file = settings->output_files;
while (file)
{
- output_t* output = make_file_output(settings, file, input_hashes);
+ output_t* output = make_file_output(settings, file, expected_hashes);
add_to_output_list(&outputs, output);
file = file->next_file;
- // Cache a pointer to the input hashes for verification purposes.
- output->expected_hashes = input_hashes;
-
// Unlink the file for tidiness, and so that the next_file pointer
// can be used to make a list of files (if splitting the output).
- output->current_file->next_file = NULL;
+ output->file->current_file->next_file = NULL;
}
}
// Append the hash outputs for the input hashes to the file outputs.
add_to_output_list(&outputs, input_hashes);
- task_t* task = make_task(input, outputs);
+ task_t* task = make_task(input, outputs, NULL);
return make_job(task, report_imaging_progress);
}
@@ -3165,12 +3093,12 @@ make_jobs(settings_t* settings)
static void
check_device_for_hpa_dco(file_t* device)
{
- if (device->is_device)
+ if (device->type == DEVICE)
{
device->descriptor = open(device->name, O_RDONLY, device->perms);
if (device->descriptor >= 0)
{
- report_to_log(_("checking for HPA/DCO: "));
+ report(_("checking for HPA/DCO: "), JOB_LOGS);
int err = 0;
__u16 *id = (void *)-1;
@@ -3197,7 +3125,7 @@ check_device_for_hpa_dco(file_t* device)
if (!dci || !id || !native)
{
- report_to_log(_("device doesn't support ATA commands\n"));
+ report(_("device doesn't support ATA commands\n"), JOB_LOGS);
return;
}
@@ -3218,19 +3146,19 @@ check_device_for_hpa_dco(file_t* device)
if (hpa && dco)
{
- report_to_log(_("HPA and DCO found\n"));
+ report(_("HPA and DCO found\n"), JOB_LOGS);
}
else if (hpa)
{
- report_to_log(_("HPA found\n"));
+ report(_("HPA found\n"), JOB_LOGS);
}
else if (dco)
{
- report_to_log(_("DCO found\n"));
+ report(_("DCO found\n"), JOB_LOGS);
}
else
{
- report_to_log(_("none\n"));
+ report(_("none\n"), JOB_LOGS);
}
char limits[DISPLAY_MESSAGE_LENGTH];
@@ -3238,17 +3166,17 @@ check_device_for_hpa_dco(file_t* device)
if (hpa)
{
sprintf(limits, _("HPA limit: %11llu sectors\n"));
- report_to_log(limits, true);
+ report(limits, JOB_LOGS);
}
if (dco)
{
sprintf(limits, _("DCO limit: %11llu sectors\n"));
- report_to_log(limits);
+ report(limits, JOB_LOGS);
}
sprintf(limits, _("full size: %11llu sectors\n"), maximum_lba);
- report_to_log(limits);
+ report(limits), JOB_LOGS;
}
if (close(device->descriptor) == 0)
@@ -3271,7 +3199,7 @@ report_device_size(file_t* device)
{
char stats[DISPLAY_MESSAGE_LENGTH];
sprintf(stats, _("device size: %"PRIuMAX" sectors (probed)\n"), device->probed_size_in_sectors);
- report_to_log(stats);
+ report(stats, JOB_LOGS);
#if USE_HDPARM
#ifdef __linux__
@@ -3296,20 +3224,16 @@ report_device_size(file_t* device)
}
static void
-report_input_size(settings_t* settings)
+report_input_size(settings_t *settings)
{
if (settings->wipe_target)
- {
report_device_size(settings->wipe_target);
- }
else if (settings->input_file && settings->input_file->is_device)
- {
report_device_size(settings->input_file);
- }
char message[DISPLAY_MESSAGE_LENGTH];
sprintf(message, "sector size: %zd bytes (%s)\n", settings->sector_size, settings->sector_size_source);
- report_to_log(message);
+ report(message, JOB_LOGS);
flush_logs();
}
@@ -3387,79 +3311,64 @@ probe_file_for_validation(file_t* file)
}
static void
-add_wipe_target(settings_t* settings, const char* device_name, bool verify_requested)
+add_wipe_target(settings_t* settings, const char* device_name, enum VERIFICATION_TYPE verification)
{
// Note the early outs for command line errors since evidence should not
// be handled any more than necessary, and glossing over a malformed
// command line is therefore undesirable - the user's choices need to be
// exactly specified before a run is undertaken.
+
if (settings->wipe_target)
- {
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot specify wipe= or vwipe= more than once"));
- }
+ report_error(DC3DD_EXIT_ABORTED, 0, _("cannot specify wipe= or hwipe= more than once"));
if (settings->output_files)
- {
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or vwipe= and of=, hof=, ofs= or hofs="));
- }
+ report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or hwipe= and of=, hof=, ofs= or hofs="));
- settings->wipe_target = make_file(device_name, 0, O_WRONLY, false, verify_requested);
+ settings->wipe_target = make_file(device_name, 0, O_WRONLY, false, verification);
DC3DD_ASSERT(settings->wipe_target != NULL);
// Make sure the wipe target is valid.
probe_file_for_validation(settings->wipe_target);
if (!settings->wipe_target->is_device)
- {
report_error(DC3DD_EXIT_ABORTED, errno, _("%s not recognized as a device, cannot wipe"),
quote(settings->wipe_target->name));
- }
if (settings->wipe_target->probed_size_in_bytes <= 0)
- {
report_error(DC3DD_EXIT_ABORTED, errno, _("%s size probe failed, cannot wipe"),
quote(settings->wipe_target->name));
- }
- if (verify_requested)
- {
+ if (verification != NONE)
settings->verifying_output = true;
- }
}
static void
-add_output_file(settings_t* settings, const char* file_name, bool part_of_set, bool verify_requested)
+add_output_file(settings_t *settings, const char *file_name, bool part_of_set,
+ enum VERIFICATION_TYPE verification)
{
- // Note the early outs for command line errors since evidence should not
- // be handled any more than necessary, and glossing over a malformed
- // command line is therefore undesirable - the user's choices need to be
- // exactly specified before a run is undertaken.
-
- if (verify_requested)
- {
+ if (verification != NONE) {
if (STREQ(file_name, "/dev/null"))
- {
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot specify hof=/dev/null"));
- }
+ report_error(DC3DD_EXIT_ABORTED, 0,
+ _("cannot output to /dev/null if using hof=, hofs=, phod=, or fhod="));
else
- {
settings->verifying_output = true;
- }
}
if (part_of_set)
- {
settings->splitting_output = true;
- }
- file_t* file = make_file(file_name, 0, O_WRONLY, part_of_set, verify_requested);
- if (file)
- {
+ file_t* file = make_file(file_name, 0, O_WRONLY, part_of_set, verification);
+ if (file) {
+ if (verification == DEVICE_PARTIAL || verification == DEVICE_FULL) {
+ probe_file_for_validation(file);
+ if (!file->is_device)
+ report_error(DC3DD_EXIT_ABORTED, errno,
+ _("%s not recognized as a device, cannot specify %s"),
+ quote(file->name), verification == DEVICE_PARTIAL ? "phod=" : "fhod=");
+ }
add_to_file_list(&settings->output_files, file);
}
else
- {
report_error(DC3DD_EXIT_ABORTED, 0, _("%s not valid BASE.FMT specifier for %s"),
- quote(file_name), verify_requested ? "hofs=" : "ofs=");
- }
+ quote(file_name), verification != NONE ? "hofs=" : "ofs=");
}
static void
@@ -3471,9 +3380,7 @@ add_input_text_pattern(settings_t* settings, const char* pattern)
// exactly specified before a run is undertaken.
if (settings->input_file || settings->input_pattern)
- {
report_error(DC3DD_EXIT_ABORTED, 0, _("use only one of pat=, tpat=, if=, ifs="));
- }
settings->input_pattern_string = strdup(pattern);
settings->input_pattern = strdup(pattern);
@@ -3552,34 +3459,22 @@ add_input_pattern(settings_t* settings, const char* pattern)
}
static void
-add_input_file(settings_t* settings, const char* file_name, bool part_of_set)
+add_input_file(settings_t *settings, const char *file_name, bool part_of_set)
{
- // Note the early outs for command line errors since evidence should not
- // be handled any more than necessary, and glossing over a malformed
- // command line is therefore undesirable - the user's choices need to be
- // exactly specified before a run is undertaken.
if (settings->input_file || settings->input_pattern)
- {
report_error(DC3DD_EXIT_ABORTED, 0, _("use only one of pat=, tpat=, if=, ifs="));
- }
- if (STREQ(file_name, "/dev/zero"))
- {
+ if (STREQ(file_name, "/dev/zero"))
add_input_pattern(settings, "00");
- }
else
{
- settings->input_file = make_file(file_name, 0, O_RDONLY, part_of_set, false);
+ settings->input_file = make_file(file_name, 0, O_RDONLY, part_of_set, NONE);
if (!settings->input_file)
- {
report_error(DC3DD_EXIT_ABORTED, 0 , _("%s not valid BASE.FMT form for ifs="), file_name);
- }
if (!STREQ(file_name, "stdin"))
- {
probe_file_for_validation(settings->input_file);
- }
}
}
@@ -3698,7 +3593,7 @@ validate_hashing_settings(settings_t* settings)
if (settings->verifying_output && !hash_specified)
{
report_error(DC3DD_EXIT_ABORTED, 0,
- _("hof=, hofs=, or vwipe= specified without hash algorithm(s) selection"));
+ _("hof=, hofs=, or hwipe= specified without hash algorithm(s) selection"));
}
}
@@ -3720,7 +3615,9 @@ validate_size_settings(settings_t* settings)
{
settings->sector_size_source = _("set");
}
- else if (settings->input_file && settings->input_file->is_device && settings->input_file->probed_sector_size > 0)
+ else if (settings->input_file &&
+ settings->input_file->is_device &&
+ settings->input_file->probed_sector_size > 0)
{
settings->sector_size = settings->input_file->probed_sector_size;
settings->sector_size_source = _("probed");
@@ -3748,6 +3645,7 @@ validate_size_settings(settings_t* settings)
_("if iskip= is specified, if= must specify an input file or device of at least that size"));
}
+
if (settings->output_sectors_to_skip)
{
file_t* file = settings->output_files;
@@ -3827,7 +3725,7 @@ validate_IO_options(settings_t* settings)
{
if (settings->max_output_file_size != INFINITE_BYTES)
{
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or vwipe= and ofsz="));
+ report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or hwipe= and ofsz="));
}
if (settings->max_sectors_to_input == INFINITE_SECTORS)
@@ -3838,27 +3736,27 @@ validate_IO_options(settings_t* settings)
}
else
{
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or vwipe= and cnt="));
+ report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or hwipe= and cnt="));
}
if (settings->input_sectors_to_skip)
{
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or vwipe= and iskip="));
+ report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or hwipe= and iskip="));
}
if (settings->output_sectors_to_skip)
{
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or vwipe= and oskip="));
+ report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or hwipe= and oskip="));
}
if (settings->append_output)
{
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or vwipe= and app=on"));
+ report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or hwipe= and app=on"));
}
if (settings->sector_size)
{
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or vwipe= and ssz="));
+ report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or hwipe= and ssz="));
}
}
@@ -3903,12 +3801,12 @@ validate_IO_combination(settings_t* settings)
if (settings->wipe_target && settings->output_files)
{
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or vwipe= and of=, hof=, ofs= or hofs="));
+ report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or hwipe= and of=, hof=, ofs= or hofs="));
}
if (settings->wipe_target && settings->input_file)
{
- report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or vwipe= and if= or ifs="));
+ report_error(DC3DD_EXIT_ABORTED, 0, _("cannot combine wipe= or hwipe= and if= or ifs="));
}
if (settings->wipe_target && !settings->input_pattern)
@@ -3926,7 +3824,7 @@ validate_IO_combination(settings_t* settings)
if (!settings->wipe_target && !settings->output_files)
{
// No outputs specified, default to writing to stdout.
- add_output_file(settings, "stdout", false, false);
+ add_output_file(settings, "stdout", false, NONE);
}
DC3DD_ASSERT((settings->wipe_target && settings->input_pattern) ||
@@ -3972,105 +3870,83 @@ make_settings()
}
static settings_t*
-parse_args(int argc, char* const* argv)
-{
+parse_args(int argc, char *const *argv) {
settings_t* settings = make_settings();
- for (int i = optind; i < argc; ++i)
- {
+ // Note that parsing and validation of the command line is very strict
+ // since evidence should not be handled any more than necessary. It is
+ // therefore best if the user's choices are exactly specified before a
+ // run is performed.
+ for (int i = optind; i < argc; ++i) {
// Split the argument into a name/value pair.
- char const* name = argv[i];
- char const* val = strchr(name, '=');
- if (!val)
- {
- // Note the early out for command line errors since evidence should not
- // be handled any more than necessary, and glossing over a malformed
- // command line is therefore undesirable - the user's choices need to be
- // exactly specified before a run is undertaken.
+ char const *name = argv[i];
+ char const *val = strchr(name, '=');
+ if (!val) {
report_error(DC3DD_EXIT_ABORTED, 0, _("unrecognized option %s"), quote(name));
}
++val;
- if (option_is(name, "if"))
- {
+ if (option_is(name, "if")) {
add_input_file(settings, val, false);
}
- else if (option_is(name, "ifs"))
- {
+ else if (option_is(name, "ifs")) {
add_input_file(settings, val, true);
}
- else if (option_is(name,"pat"))
- {
+ else if (option_is(name,"pat")) {
add_input_pattern(settings, val);
}
- else if (option_is(name,"tpat"))
- {
+ else if (option_is(name,"tpat")) {
add_input_text_pattern(settings, val);
}
- else if (option_is(name, "of"))
- {
- add_output_file(settings, val, false, false);
+ else if (option_is(name, "of")) {
+ add_output_file(settings, val, false, NONE);
}
- else if (option_is(name, "hof"))
- {
- add_output_file(settings, val, false, true);
+ else if (option_is(name, "hof")) {
+ add_output_file(settings, val, false, STANDARD);
}
- else if (option_is(name, "ofs"))
- {
- add_output_file(settings, val, true, false);
+ else if (option_is(name, "phod")) {
+ add_output_file(settings, val, false, DEVICE_PARTIAL);
+ }
+ else if (option_is(name, "fhod")) {
+ add_output_file(settings, val, false, DEVICE_FULL);
+ }
+ else if (option_is(name, "ofs")) {
+ add_output_file(settings, val, true, NONE);
}
- else if (option_is(name, "hofs"))
- {
- add_output_file(settings, val, true, true);
+ else if (option_is(name, "hofs")) {
+ add_output_file(settings, val, true, STANDARD);
}
- else if (option_is(name,"hash"))
- {
+ else if (option_is(name,"hash")) {
activate_hash(val);
}
- else if (option_is(name,"log") || option_is(name, "hlog"))
- {
+ else if (option_is(name,"log") || option_is(name, "hlog")) {
// Arg already parsed in initiate_logging().
}
- else if (option_is(name,"rec"))
- {
- // i.e., rec=off
+ else if (option_is(name,"rec")) {
settings->recover_errors = false;
}
- else if (option_is(name, "app"))
- {
- // i.e., app=on
+ else if (option_is(name, "app")) {
settings->append_output = true;
}
- else if (option_is(name, "wipe"))
- {
+ else if (option_is(name, "wipe")) {
add_wipe_target(settings, val, false);
}
- else if (option_is(name, "vwipe"))
- {
+ else if (option_is(name, "hwipe")) {
add_wipe_target(settings, val, true);
}
- else if (option_is(name, "verb"))
- {
- // i.e., verb=on
+ else if (option_is(name, "verb")) {
verbose_reporting = true;
}
- else if (option_is(name, "nwspc"))
- {
- // i.e., nwspc=on
+ else if (option_is(name, "nwspc")) {
compact_reporting = true;
}
- else if (option_is(name, "b10"))
- {
- // i.e., dbr=on
+ else if (option_is(name, "b10")) {
progress_bytes_reporting_flag = 0;
}
- else if (option_is(name, "corruptoutput"))
- {
- // i.e., corruptoutput=on
+ else if (option_is(name, "corruptoutput")) {
settings->corrupt_output = true;
}
- else
- {
+ else {
parse_quantifier(settings, name, val);
}
}
@@ -4169,39 +4045,36 @@ report_compile_flags(FILE* file, bool newlines)
}
static void
-report_settings(int argc, char* const* argv)
+report_command_line(int argc, char* const* argv)
{
// Report compiled-in options.
fputs(_("compiled options:"), stderr);
report_compile_flags(stderr, false);
- if (log != NULL)
- {
- fputs(_("compiled options:"), log);
- report_compile_flags(log, false);
+ for (log_t* log = job_logs; log; log = log->next_log) {
+ fputs(_("compiled options:"), log->file);
+ report_compile_flags(log->file, false);
}
- if (hash_log != NULL)
- {
- fputs(_("compiled options:"), hash_log);
- report_compile_flags(hash_log, false);
+ for (log_t* log = hash_logs; log; log = log->next_log) {
+ fputs(_("compiled options:"), log->file);
+ report_compile_flags(log->file, false);
}
// Report the command line.
char* command_line = make_cmd_line_string(argc, argv);
char message[DISPLAY_MESSAGE_LENGTH];
sprintf(message, _("command line: %s\n"), command_line);
- report_to_all(message);
+ report(message, ALL_LOGS);
free(command_line);
flush_logs();
}
static void
-report_start_message()
+report_startup_message()
{
- // Save the program start time in a global for later use in
- // progress messages.
+ // Save the program start time for later use in progress messages.
start_time = gethrxtime();
- // Write the start message to all logs (i.e., console, log, hash log).
+ // Write the start message to all job_logs (i.e., console, log, hash log).
// The message acts as a sort of header for the run. The leading newline
// character acts to separate the output from multiple runs when
// appending to an existing log.
@@ -4209,69 +4082,64 @@ report_start_message()
char message[DISPLAY_MESSAGE_LENGTH];
sprintf(message, "\n%s %s started at %s\n", PROGRAM_NAME, VERSION, formatted_start_time);
free(formatted_start_time);
- report_to_all(message);
+ report(message, ALL_LOGS);
flush_logs();
}
static void
-open_log(const char* arg, const char* arg_name, FILE** log)
+open_log(const char *arg, const char *arg_name, log_t **logs)
{
- // Check for duplication of a log argument in the command line.
- // Note the early out for command line errors since evidence should not
- // be handled any more than necessary, and glossing over a malformed
- // command line is therefore undesirable - the user's choices need to be
- // exactly specified before a run is undertaken.
- char message[DISPLAY_MESSAGE_LENGTH];
- if (*log != NULL)
- {
- sprintf(message, _("cannot specify %s more than once"), arg_name);
- report_error(DC3DD_EXIT_ABORTED, 0, message);
- }
-
// Extract the log file name from the command line argument.
- const char* val = strchr(arg, '=');
- if (!val)
- {
+ const char *val = strchr(arg, '=');
+ if (!val) {
+ char message[DISPLAY_MESSAGE_LENGTH];
sprintf(message, _("%s specified with no file name"), arg_name);
report_error(DC3DD_EXIT_ABORTED, 0, message);
}
++val;
- // Open the log in append mode to support use cases where the
+ // Open the log file in append mode to support use cases where the
// imaging is performed using multiple runs (e.g., using skips
// etc., to work around errors) and a "cumulative" record of
// the runs is desired.
- *log = fopen(val, "a");
- if (*log == NULL)
- {
+ FILE *file = fopen(val, "a");
+ if (!file)
report_error(DC3DD_EXIT_ABORTED, errno, _("opening log %s"), quote(val));
- }
+
+ // Add the log to the logs list specified by the caller.
+ log_t* log = (log_t*)malloc(sizeof(log_t));
+ log->file = file;
+ log->next_log = NULL;
+ add_to_log_list(logs, log);
+
+ // Add the log to the master logs list.
+ log = (log_t*)malloc(sizeof(log_t));
+ log->file = file;
+ log->next_log = NULL;
+ add_to_log_list(&all_logs, log);
}
static void
initiate_logging(int argc, char* const* argv)
{
- // Use PTHREAD_MUTEX_RECURSIVE to initialize the global mutex for
- // synchronizing reporting output to the log(s) and console, so that nested
- // calls to functions like report_to_log() that lock the mutex are safe.
+ // Initialize a mutex for synchronizing output to the log(s) and console.
+ // Use PTHREAD_MUTEX_RECURSIVE so that nested calls to functions that lock
+ // the mutex are safe.
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&reporting_lock, &attr);
pthread_mutexattr_destroy(&attr);
- // Look for command line options specifying logs.
+ // Look for command line options specifying job_logs.
const char* arg = NULL;
- for (int i = optind; i < argc; ++i)
- {
+ for (int i = optind; i < argc; ++i) {
arg = argv[i];
- if (option_is(arg, "log"))
- {
- open_log(arg, "log=", &log);
+ if (option_is(arg, "log")) {
+ open_log(arg, "log=", &job_logs);
}
- else if (option_is(arg, "hlog"))
- {
- open_log(arg, "hlog=", &hash_log);
+ else if (option_is(arg, "hlog")) {
+ open_log(arg, "hlog=", &hash_logs);
}
}
}
@@ -4279,64 +4147,65 @@ initiate_logging(int argc, char* const* argv)
void
usage(int status)
{
- if (status != EXIT_SUCCESS)
- {
+ if (status != EXIT_SUCCESS) {
fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name);
}
- else
- {
+ else {
fputs(_("------\n"), stderr);
fputs(_("usage:\n"), stderr);
fputs(_("------\n\n"), stderr);
fprintf(stderr, _("\t%s [OPTION 1] [OPTION 2] ... [OPTION N]\n"), program_name);
fputs("\n", stderr);
- fprintf(stderr, _("\t\t*or*\n"), program_name);
+ fprintf(stderr, _("\t\t*or*\n"));
fputs("\n", stderr);
fprintf(stderr, _("\t%s [HELP OPTION]\n"), program_name);
fputs("\n", stderr);
- fprintf(stderr, _("\twhere each OPTION is selected from the basic or advanced\n"), program_name);
- fprintf(stderr, _("\toptions listed below, or HELP OPTION is selected from the\n"), program_name);
- fprintf(stderr, _("\thelp options listed below.\n\n"), program_name);
+ fprintf(stderr, _("\twhere each OPTION is selected from the basic or advanced\n"));
+ fprintf(stderr, _("\toptions listed below, or HELP OPTION is selected from the\n"));
+ fprintf(stderr, _("\thelp options listed below.\n\n"));
fputs(_("--------------\n"), stderr);
fputs(_("basic options:\n"), stderr);
fputs(_("--------------\n\n"), stderr);
- fprintf(stderr, "\t%-21s%s\n", _("if=FILE"), _("Read input from the device or regular file FILE"));
- fprintf(stderr, "\t%-21s%s\n", "", _("(see note #1 below). This option can only be used"));
- fprintf(stderr, "\t%-21s%s\n", "", _("once and cannot be combined with ifs=, pat=,"));
- fprintf(stderr, "\t%-21s%s\n", "", _("or tpat=."));
- if (!O_DIRECT)
- {
+ fprintf(stderr, "\t%-21s%s\n", _("if=DEVICE or FILE"), _("Read input from a device or a file (see note #1"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("below for how to read from standard input). This"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("option can only be used once and cannot be"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("combined with ifs=, pat=, or tpat=."));
+ if (!O_DIRECT) {
fprintf(stderr, "\t%-21s%s\n", "", _("If FILE is a device, use rdisk for"));
fprintf(stderr, "\t%-21s%s\n", "", _("direct (unbuffered) input to enable read error"));
fprintf(stderr, "\t%-21s%s\n", "", _("recovery unless rec=off is specified."));
}
fprintf(stderr, "\t%-21s%s\n", _("ifs=BASE.FMT"), _("Read input from a set of files with base name"));
fprintf(stderr, "\t%-21s%s\n", "", _("BASE and sequential file name extensions"));
- fprintf(stderr, "\t%-21s%s\n", "", _("conforming to the format specifier FMT (see"));
- fprintf(stderr, "\t%-21s%s\n", "", _("note #4 below). This option can only be used once"));
- fprintf(stderr, "\t%-21s%s\n", "", _("and cannot be combined with if=, pat=, or"));
- fprintf(stderr, "\t%-21s%s\n", "", _("tpat=."));
- fprintf(stderr, "\t%-21s%s\n", _("of=FILE"), _("Write output to FILE (see note #2 below). This"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("conforming to the format specifier FMT (see note"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("#4 below for how to specify FMT). This option"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("can only be used once and cannot be combined with"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("if=, pat=, or tpat=."));
+ fprintf(stderr, "\t%-21s%s\n", _("of=FILE or DEVICE"), _("Write output to a file or device (see note #2"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("below for how to write to standard output). This"));
fprintf(stderr, "\t%-21s%s\n", "", _("option can be used more than once (see note #3"));
- fprintf(stderr, "\t%-21s%s\n", "", _("below)."));
- fprintf(stderr, "\t%-21s%s\n", _("hof=FILE"), _("Write output to FILE and verify FILE after writing"));
- fprintf(stderr, "\t%-21s%s\n", "", _("it by hashing it and comparing the output hash(es)"));
- fprintf(stderr, "\t%-21s%s\n", "", _("to the input hash(es). This option can be used more"));
- fprintf(stderr, "\t%-21s%s\n", "", _("than once (see note #3 below)."));
+ fprintf(stderr, "\t%-21s%s\n", "", _("below for how to generate multiple outputs)."));
+ fprintf(stderr, "\t%-21s%s\n", _("hof=FILE or DEVICE"), _("Write output to a file or device, hash the"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("output file or device, and verify by comparing"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("the output hash(es) to the input hash(es). This"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("option can be used more than once (see note #3"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("below for how to generate multiple outputs)."));
fprintf(stderr, "\t%-21s%s\n", _("ofs=BASE.FMT"), _("Write output to a set of files with base name BASE"));
fprintf(stderr, "\t%-21s%s\n", "", _("and sequential file name extensions generated from"));
- fprintf(stderr, "\t%-21s%s\n", "", _("the format specifier FMT (see note #4 below). This"));
- fprintf(stderr, "\t%-21s%s\n", "", _("option can be used more than once (see note #3"));
- fprintf(stderr, "\t%-21s%s\n", "", _("below). Specify the maximum size of each file"));
- fprintf(stderr, "\t%-21s%s\n", "", _("in the set using ofsz=."));
+ fprintf(stderr, "\t%-21s%s\n", "", _("the format specifier FMT (see note #4 below for"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("how to specify FMT). This option can be used more"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("than once (see note #3 below for how to generate"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("multiple outputs). Specify the maximum size of"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("each file in the set using ofsz=."));
fprintf(stderr, "\t%-21s%s\n", _("hofs=BASE.FMT"), _("Write output to a set of files with base name BASE"));
fprintf(stderr, "\t%-21s%s\n", "", _("and sequential file name extensions generated from"));
- fprintf(stderr, "\t%-21s%s\n", "", _("the format specifier FMT (see note #4 below)."));
- fprintf(stderr, "\t%-21s%s\n", "", _("Verify the files after writing them by hashing"));
- fprintf(stderr, "\t%-21s%s\n", "", _("them and comparing the output hash(es) to the input"));
- fprintf(stderr, "\t%-21s%s\n", "", _("hash(es). This option can be used more than once"));
- fprintf(stderr, "\t%-21s%s\n", "", _("(see note #3 below). Specify the maximum size of"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("the format specifier FMT (see note #4 below for"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("how to specify FMT). Hash the output files and"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("verify by comparing the output hash(es) to the"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("input hash(es). This option can be used more than"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("once (see note #3 below for how to generate"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("multiple outputs). Specify the maximum size of"));
fprintf(stderr, "\t%-21s%s\n", "", _("each file in the set using ofsz=."));
fprintf(stderr, "\t%-21s%s\n", _("ofsz=BYTES"), _("Set the maximum size of each file in the sets of"));
fprintf(stderr, "\t%-21s%s\n", "", _("files specified using ofs= or hofs= to"));
@@ -4345,32 +4214,44 @@ usage(int status)
fprintf(stderr, "\t%-21s%s\n", "", _("-DDEFAULT_OUTPUT_FILE_SIZE followed by the desired"));
fprintf(stderr, "\t%-21s%s\n", "", _("value in BYTES."));
fprintf(stderr, "\t%-21s%s\n", _("hash=ALGORITHM"), _("Compute an ALGORITHM hash of the input and also"));
- fprintf(stderr, "\t%-21s%s\n", "", _("of any outputs specified using hof= or hofs=,"));
- fprintf(stderr, "\t%-21s%s\n", "", _("where ALGORITHM is one of md5, sha1, sha256, or"));
- fprintf(stderr, "\t%-21s%s\n", "", _("sha512. This option may be used once for each"));
- fprintf(stderr, "\t%-21s%s\n", "", _("supported ALGORITHM. Alternatively, hashing can"));
- fprintf(stderr, "\t%-21s%s\n", "", _("be activated at compile time using one or more of"));
- fprintf(stderr, "\t%-21s%s\n", "", _("-DDEFAULT_HASH_MD5,-DDEFAULT_HASH_SHA1,"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("of any outputs specified using hof=, hofs=, phod=,"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("or fhod=, where ALGORITHM is one of md5, sha1,"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("sha256, or sha512. This option may be used once"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("for each supported ALGORITHM. Alternatively,"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("hashing can be activated at compile time using one"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("or more of -DDEFAULT_HASH_MD5,-DDEFAULT_HASH_SHA1,"));
fprintf(stderr, "\t%-21s%s\n", "", _("-DDEFAULT_HASH_SHA256, and -DDEFAULT_HASH_SHA512."));
fprintf(stderr, "\t%-21s%s\n", _("log=FILE"), _("Log I/O statistcs, diagnostics, and total hashes"));
fprintf(stderr, "\t%-21s%s\n", "", _("of input and output to FILE. If hlog= is not"));
fprintf(stderr, "\t%-21s%s\n", "", _("specified, piecewise hashes of multiple file"));
- fprintf(stderr, "\t%-21s%s\n", "", _("input and output are also logged to FILE."));
- fprintf(stderr, "\t%-21s%s\n\n", _("hlog=FILE"), _("Log total hashes and piecewise hashes to FILE."));
+ fprintf(stderr, "\t%-21s%s\n", "", _("input and output are also logged to FILE. This"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("option can be used more than once to generate"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("multiple logs."));
+ fprintf(stderr, "\t%-21s%s\n", _("hlog=FILE"), _("Log total hashes and piecewise hashes to FILE."));
+ fprintf(stderr, "\t%-21s%s\n", "", _("This option can be used more than once to generate"));
+ fprintf(stderr, "\t%-21s%s\n\n", "", _("multiple logs."));
fputs(_("-----------------\n"), stderr);
fputs(_("advanced options:\n"), stderr);
fputs(_("-----------------\n\n"), stderr);
+ fprintf(stderr, "\t%-21s%s\n", _("phod=DEVICE"), _("The same as hof=DEVICE, except only the bytes"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("written to DEVICE by dc3dd are verified. This"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("option can be used more than once (see note"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("#3 below for how to generate multiple outputs)."));
+ fprintf(stderr, "\t%-21s%s\n", _("fhod=DEVICE"), _("The same as phod=DEVICE, with additional"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("hashing of the entire output DEVICE. This option"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("can be used more than once (see note #3 below"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("for how to generate multiple outputs)."));
fprintf(stderr, "\t%-21s%s\n", _("rec=off"), _("By default, zeros are written to the output(s) in"));
fprintf(stderr, "\t%-21s%s\n", "", _("place of bad sectors when the input is a device."));
fprintf(stderr, "\t%-21s%s\n", "", _("Use this option to cause the program to instead"));
fprintf(stderr, "\t%-21s%s\n", "", _("exit when a bad sector is encountered."));
fprintf(stderr, "\t%-21s%s\n", _("wipe=DEVICE"), _("Wipe DEVICE by writing zeros (default) or a"));
fprintf(stderr, "\t%-21s%s\n", "", _("pattern specified by pat= or tpat=."));
- fprintf(stderr, "\t%-21s%s\n", _("vwipe=DEVICE"), _("Wipe DEVICE by writing zeros (default) or a"));
- fprintf(stderr, "\t%-21s%s\n", "", _("pattern specified by pat= or tpat=."));
- fprintf(stderr, "\t%-21s%s\n", "", _("Verify DEVICE after writing it by hashing it"));
- fprintf(stderr, "\t%-21s%s\n", "", _("and comparing the hash(es) to the input hash(es)."));
+ fprintf(stderr, "\t%-21s%s\n", _("hwipe=DEVICE"), _("Wipe DEVICE by writing zeros (default) or a"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("pattern specified by pat= or tpat=. Verify"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("DEVICE after writing it by hashing it and"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("comparing the hash(es) to the input hash(es)."));
fprintf(stderr, "\t%-21s%s\n", _("pat=HEX"), _("Use pattern as input, writing HEX to every byte"));
fprintf(stderr, "\t%-21s%s\n", "", _("of the output. This option can only be used once"));
fprintf(stderr, "\t%-21s%s\n", "", _("and cannot be combined with if=, ifs=, or"));
@@ -4379,9 +4260,9 @@ usage(int status)
fprintf(stderr, "\t%-21s%s\n", "", _("repeatedly to the output. This option can only be"));
fprintf(stderr, "\t%-21s%s\n", "", _("used once and cannot be combined with if=, ifs=,"));
fprintf(stderr, "\t%-21s%s\n", "", _("or pat=."));
- fprintf(stderr, "\t%-21s%s\n", _("cnt=SECTORS"), _("Input only SECTORS input sectors. Must be used with"));
- fprintf(stderr, "\t%-21s%s\n", "", _("pat= or tpat= if not using the pattern"));
- fprintf(stderr, "\t%-21s%s\n", "", _("with wipe= or vwipe= to wipe a device."));
+ fprintf(stderr, "\t%-21s%s\n", _("cnt=SECTORS"), _("Read only SECTORS input sectors. Must be used"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("with pat= or tpat= if not using the pattern with"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("wipe= or hwipe= to wipe a device."));
fprintf(stderr, "\t%-21s%s\n", _("iskip=SECTORS"), _("Skip SECTORS sectors at start of the input device"));
fprintf(stderr, "\t%-21s%s\n", "", _("or file."));
fprintf(stderr, "\t%-21s%s\n", _("oskip=SECTORS"), _("Skip SECTORS sectors at start of the output"));
@@ -4402,9 +4283,8 @@ usage(int status)
fprintf(stderr, "\t%-21s%s\n", _("verb=on"), _("Activate verbose reporting, where sectors in/out"));
fprintf(stderr, "\t%-21s%s\n", "", _("are reported for each file in sets of files"));
fprintf(stderr, "\t%-21s%s\n", "", _("specified using ifs=, ofs=, or hofs=."));
- fprintf(stderr, "\t%-21s%s\n", "", _("Alternatively, verbose reporting may be"));
- fprintf(stderr, "\t%-21s%s\n", "", _("activated at compile time using"));
- fprintf(stderr, "\t%-21s%s\n", "", _("-DDEFAULT_VERBOSE_REPORTING."));
+ fprintf(stderr, "\t%-21s%s\n", "", _("Alternatively, verbose reporting may be activated"));
+ fprintf(stderr, "\t%-21s%s\n", "", _("at compile time using -DDEFAULT_VERBOSE_REPORTING."));
fprintf(stderr, "\t%-21s%s\n", _("nwspc=on"), _("Activate compact reporting, where the use"));
fprintf(stderr, "\t%-21s%s\n", "", _("of white space to divide log output into"));
fprintf(stderr, "\t%-21s%s\n", "", _("logical sections is suppressed. Alternatively,"));
@@ -4430,16 +4310,16 @@ usage(int status)
fputs(_("notes:\n"), stderr);
fputs(_("------\n\n"), stderr);
fputs(_("1. To read from stdin, do not specify if=, ifs=, pat=, or tpat=.\n"), stderr);
- fputs(_("2. To write to stdout, do not specify of=, hof=, ofs=, hofs=, wipe=,\n"), stderr);
- fputs(_(" or vwipe=.\n"), stderr);
+ fputs(_("2. To write to stdout, do not specify of=, hof=, ofs=, hofs=, phod=,\n"), stderr);
+ fputs(_(" fhod=, wipe=, or hwipe=.\n"), stderr);
fputs(_("3. To write to multiple outputs specify more than one of of=, hof=, ofs=,\n"), stderr);
- fputs(_(" or hofs=, in any combination.\n"), stderr);
+ fputs(_(" hofs=, phod=, or fhod=, in any combination.\n"), stderr);
fputs(_("4. FMT is a pattern for a sequence of file extensions that can be numerical\n"), stderr);
fputs(_(" starting at zero, numerical starting at one, or alphabetical. Specify FMT\n"), stderr);
fputs(_(" by using a series of zeros, ones, or a's, respectively. The number of\n"), stderr);
fputs(_(" characters used indicates the desired length of the extensions.\n"), stderr);
fputs(_(" For example, a FMT specifier of 1111 indicates four character\n"), stderr);
- fputs(_(" numerical extensions starting with 0001.\n"), stderr);
+ fputs(_(" numerical extensions starting with 0000.\n"), stderr);
fputs(_("5. BYTES may be followed by the following multiplicative suffixes:\n"), stderr);
fputs(_(" c (1), w (2), b (512), kB (1000), K (1024), MB (1000*1000),\n"), stderr);
fputs(_(" M (1024*1024), GB (1000*1000*1000), G (1024*1024*1024), and\n"), stderr);
@@ -4460,36 +4340,43 @@ usage(int status)
int
main (int argc, char **argv)
{
- // Set up for localization.
initialize_main(&argc, &argv);
program_name = argv[0];
+
+ // Set up localization support.
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- // Handle command line "help options" (i.e., --flags, --help, --version).
- if (argc == 2 && STREQ(argv[1], "--flags"))
- {
+ // Handle the --flags command line option.
+ if (argc == 2 && STREQ(argv[1], "--flags")) {
printf("%s compiled with:\n", PROGRAM_NAME);
report_compile_flags(stdout, true);
exit(DC3DD_EXIT_COMPLETED);
}
+
+ // Handle the --help and --version command line options.
parse_long_options(argc, argv, PROGRAM_NAME, PACKAGE, VERSION, usage, AUTHORS, (char const*)NULL);
- if (getopt_long(argc, argv, "", NULL, NULL) != -1)
- {
+ if (getopt_long(argc, argv, "", NULL, NULL) != -1) {
usage(DC3DD_EXIT_FAILED);
}
- // Do the requested imaging.
initiate_logging(argc, argv);
- report_start_message();
- report_settings(argc, argv);
+
+ // Report startup info.
+ report_startup_message();
+ report_command_line(argc, argv);
+
+ // Do the requested jobs.
settings_t* settings = parse_settings(argc, argv);
report_input_size(settings);
job_t* jobs = make_jobs(settings);
int exit_code = execute_jobs(jobs);
+
+ // Report results.
report_results(jobs);
report_exit_message(exit_code);
+
terminate_logging();
return exit_code;
diff --git a/tests/test-damaged-device-imaging.sh b/tests/test-damaged-device-imaging.sh
index 0f2e1d4..71f2ff5 100755
--- a/tests/test-damaged-device-imaging.sh
+++ b/tests/test-damaged-device-imaging.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-source "test-helpers.sh"
+source "helpers.sh"
if [ "$1" == "" ]
then
diff --git a/tests/test-device-imaging.sh b/tests/test-device-imaging.sh
index b47a558..6eae887 100755
--- a/tests/test-device-imaging.sh
+++ b/tests/test-device-imaging.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-source "test-helpers.sh"
+source "helpers.sh"
if [ "$1" == "" ]
then
@@ -19,8 +19,9 @@ REF_SECTORS=1952767
REF_SECTOR_SIZE=512
DC3DD="../src/dc3dd"
-TEST_IMG="/tmp/test.img"
-TEST_LOG="/tmp/test.log"
+TEST_IMG="/tmp/dev_img_test.img"
+TEST_LOG0="/tmp/dev_img_test0.log"
+TEST_LOG1="/tmp/dev_img_test1.log"
init()
{
@@ -28,12 +29,15 @@ init()
echo "Getting reference image size..."
REF_IMG_BYTES=`stat -c %s "$REF_IMG"`
+ echo "$REF_IMG_BYTES"
echo "Getting reference image md5 hash..."
REF_IMG_MD5_HASH=`md5sum "$REF_IMG" | cut -f 1 -d \ `
+ echo "$REF_IMG_MD5_HASH"
echo "Getting reference image sha1 hash..."
REF_IMG_SHA1_HASH=`sha1sum "$REF_IMG" | cut -f 1 -d \ `
+ echo "$REF_IMG_SHA1_HASH"
echo "Writing reference image to device..."
umount "$DEVICE"
@@ -61,8 +65,8 @@ init()
cleanup()
{
# Clean up files from any previous runs.
- rm "$TEST_IMG" "$TEST_LOG" "$TEST_IMG".* "$TEST_LOG".*
- if [ -e "$TEST_IMG" -o -e "$TEST_LOG" ]
+ rm "$TEST_IMG" "$TEST_LOG0" "$TEST_LOG1"
+ if [ -e "$TEST_IMG" -o -e "$TEST_LOG0" -o -e "$TEST_LOG1" ]
then
echo "Failed to remove test output files"
exit 1
@@ -71,21 +75,24 @@ cleanup()
basic()
{
- echo "Testing imaging of a device..."
+ echo "Testing imaging of a device with multiple logs..."
cleanup
- "$DC3DD" if="$DEVICE" of="$TEST_IMG" hash=md5 hash=sha1 log="$TEST_LOG"
+ "$DC3DD" if="$DEVICE" of="$TEST_IMG" hash=md5 hash=sha1 log="$TEST_LOG0" log="$TEST_LOG1"
if [ $? -ne 0 ]
then
- echo "basic: basic imaging run failed"
+ echo "basic: run failed"
exit 1
fi
echo "Checking results..."
- check_output_file "basic:" "$TEST_IMG" "$REF_IMG_BYTES" "$REF_IMG_MD5_HASH" "$REF_IMG_SHA1_HASH"
- check_input_with_errors_logging "basic:" "$TEST_LOG" "$REF_SECTOR_SIZE" "(probed)" "$REF_IMG_BYTES" "$REF_SECTORS" "0"
- check_input_hash_logging "basic:" "$TEST_LOG" "$REF_IMG_MD5_HASH" "$REF_IMG_SHA1_HASH"
- check_single_output_logging "basic:" "$TEST_LOG" "$REF_SECTORS"
+ check_output_file "basic" "$TEST_IMG" "$REF_IMG_BYTES" "$REF_IMG_MD5_HASH" "$REF_IMG_SHA1_HASH"
+ check_input_logging "basic" "$TEST_LOG0" "$REF_SECTOR_SIZE" "(probed)" "$REF_IMG_BYTES" "$REF_SECTORS" "0"
+ check_input_logging "basic" "$TEST_LOG1" "$REF_SECTOR_SIZE" "(probed)" "$REF_IMG_BYTES" "$REF_SECTORS" "0"
+ check_input_hash_logging "basic" "$TEST_LOG0" "$REF_IMG_MD5_HASH" "$REF_IMG_SHA1_HASH"
+ check_input_hash_logging "basic" "$TEST_LOG1" "$REF_IMG_MD5_HASH" "$REF_IMG_SHA1_HASH"
+ check_single_output_logging "basic" "$TEST_LOG0" "$REF_SECTORS"
+ check_single_output_logging "basic" "$TEST_LOG1" "$REF_SECTORS"
echo "Results ok"
echo
}
@@ -95,10 +102,10 @@ wipe()
echo "Testing a verified wipe of a device with zeros..."
cleanup
- "$DC3DD" vwipe="$DEVICE" hash=md5 hash=sha1 log="$TEST_LOG"
+ "$DC3DD" hwipe="$DEVICE" hash=md5 hash=sha1 log="$TEST_LOG0"
if [ $? -ne 0 ]
then
- echo "wipe 00: run failed"
+ echo "wipe: run failed"
exit 10
fi
@@ -117,10 +124,10 @@ wipe()
fi
echo "Checking results..."
- check_input_logging "wipe" "$TEST_LOG" "$REF_SECTOR_SIZE" "(probed)" "$REF_IMG_BYTES" "$REF_SECTORS"
- check_input_hash_logging "wipe" "$TEST_LOG" "$PAT_MD5_HASH" "$PAT_SHA1_HASH"
- check_single_output_logging "wipe" "$TEST_LOG" "$REF_SECTORS"
- check_output_hash_logging "wipe" "$DEVICE" "$TEST_LOG"
+ check_input_logging "wipe" "$TEST_LOG0" "$REF_SECTOR_SIZE" "(probed)" "$REF_IMG_BYTES" "$REF_SECTORS"
+ check_input_hash_logging "wipe" "$TEST_LOG0" "$PAT_MD5_HASH" "$PAT_SHA1_HASH"
+ check_single_output_logging "wipe" "$TEST_LOG0" "$REF_SECTORS"
+ check_output_hash_logging "wipe" "$DEVICE" "$TEST_LOG0"
echo "Results ok"
echo
}
diff --git a/tests/test-file-imaging.sh b/tests/test-file-imaging.sh
index 7d9362e..75dab44 100755
--- a/tests/test-file-imaging.sh
+++ b/tests/test-file-imaging.sh
@@ -4,13 +4,13 @@
# Requires mktemp and stat from coreutils
# ***************************************
-source "test-helpers.sh"
+source "helpers.sh"
DC3DD="../src/dc3dd"
REF_SECTOR_SIZE=512
-REF_FILE="/tmp/ref-good.img"
+REF_FILE="/tmp/ref-random-good.img"
REF_FILE_SECTORS=452767
REF_FILE_BYTES="0"
REF_FILE_MD5_HASH=""
@@ -546,6 +546,8 @@ validation()
echo "Invalid combination of if and ifs not detected properly"
exit 13
fi
+ echo "Results ok"
+ echo
}
init
--
debian-forensics/dc3dd
More information about the forensics-changes
mailing list