[Forensics-changes] [SCM] debian-forensics/md5deep branch, debian, updated. debian/3.9.2-1-8-gf6d6370

Michael Prokop mika at debian.org
Thu Jun 14 15:58:05 UTC 2012


The following commit has been merged in the debian branch:
commit beb4f6a10da4e39ea67339cdaac50475ede644e6
Author: Michael Prokop <mika at debian.org>
Date:   Thu Jun 14 17:57:19 2012 +0200

    Merging upstream version 4.2

diff --git a/COPYING b/COPYING
index 4bff23a..1f9bbd1 100644
--- a/COPYING
+++ b/COPYING
@@ -1,20 +1,18 @@
+This program is divided into two parts, the Tiger code and everything 
+else. Let's start with everything else:
 
-This program is divided into two parts, the Tiger+strsep ccode and
-everything else. Let's start with everything else:
-
-This program is a work of the US Government. In accordance with 17 USC
-105, copyright protection is not available for any work of the US
-Government. As such this code is considered public domain. There is NO
-warranty for this program; not even for MERCHANTABILITY or FITNESS FOR A
+This program is a work of the US Government. In accordance with 17 USC 
+105, copyright protection is not available for any work of the US 
+Government. As such this code is considered public domain. There is NO 
+warranty for this program; not even for MERCHANTABILITY or FITNESS FOR A 
 PARTICULAR PURPOSE.
 
-The code for Tiger comes from the GnuPG project and is licensed under
-the General Public License (GPL). The code from strsep comes from the
-gnulib library and is also GPL'ed. 
+The code for Tiger comes from the libgcrypt project and is licensed 
+under the General Public License (GPL).
 
-Because the vast majority of this program is public domain, the license
-of this project as whole remains public domain. The Tiger code itself is
-still licensed under the GPL. Note that this dual licensing scheme does
+Because the vast majority of this program is public domain, the license 
+of this project as whole remains public domain. The Tiger code itself is 
+still licensed under the GPL. Note that this dual licensing scheme does 
 not violate the terms of the GPL. Please see the GPL FAQ, specifically:
 
 http://www.fsf.org/licensing/licenses/gpl-faq.html#CombinePublicDomainWithGPL
diff --git a/ChangeLog b/ChangeLog
index 51d051e..534b331 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,48 @@
+2012-06-09  Jesse Kornblum  <research at jessekornblum.com>:
+
+	* src/tiger.h tiger.c: Replaced with newer code from libgcrypt.
+	* configure.ac: Version bump to 4.2
+
+2012-06-05  Jesse Kornblum  <research at jessekornblum.com>:
+
+	* src/dig.cpp: Cosmetic formatting. Fixed Win32 stat function.
+	* src/display.cpp: Commented out vasprintf, which is now present on mingw
+	* src/hashlist.cpp: Formatting. Revised to handle case where filename is a hash.
+	* src/sha1_version.c: Removed vestigial code
+
+2012-06-04  Jesse Kornblum  <research at jessekornblum.com>:
+
+	* src/hashlist.cpp: Formatting. Addressed bug with filenames with commas in them.
+
+2012-05-20  Jesse Kornblum  <research at jessekornblum.com>:
+
+	* man/md5deep1,hashdeep.1: Fixed typo in -j mode
+
+2012-02-27  Simson Garfinkel  <simsong at Mucha.local>
+
+	* src/dig.cpp (state::decode_file_type): removed from state, since it didn't use any of the instance variables.
+
+2012-02-27  Jesse Kornblum  <research at jessekornblum.com>:
+
+	* main.cpp: Removed -B command line flag from all programs
+
+2012-02-27  Jesse Kornblum  <research at jessekornblum.com>:
+
+	* man/md5deep.1: Added Simson to the AUTHORS section
+	* src/main.cpp: Formatted usage messages
+	* configure.ac: Version bump to 4.1.1
+	* Makefile.am: Added doc to directories cleaned with make nice
+
+2012-02-26  Simson Garfinkel  <simsong at FC15>
+
+	* src/main.h (d): fixed THREAD typo.
+	* src/display.cpp: changed #if so that it checks for MINGW and not __MINGW_H
+	* configure.ac (MINGW): now explicitly sets MINGW if we are compiling under mingw.
+
+2012-02-10  Jesse Kornblum  <research at jessekornblum.com>:
+
+	* doc/start-hashdeep.html: Clarified how to run the programs.
+	
 2012-02-10  Jesse Kornblum  <research at jessekornblum.com>:
 
 	* sample-hashes/sample.{c,jpg}: Added Windows executable with non-executable extension
@@ -9,7 +54,7 @@
 
 	* src/dig.cpp, winpe.h, winpe.cpp, main.cpp: Added check for Windows PE files to expert mode.
 
-2012-01-30  Jesse Kornblum  <research at jessekornblum.com:>
+2012-01-30  Jesse Kornblum  <research at jessekornblum.com>:
 
 	* src/display.cpp: Reverted previous change, but updated test for presence of vasprintf.
 
diff --git a/Makefile.am b/Makefile.am
index 78d6d30..ae3c9db 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -10,7 +10,7 @@ CROSS64_PREFIX = x86_64-w64-mingw32
 EXTRA_DIST = FILEFORMAT config.guess config.sub  m4/ax_pthread.m4 CONFIGURE_FC.sh
 
 nice:
-	rm -f *~ man/*~ src/*~
+	rm -f *~ man/*~ src/*~ doc/*~
 
 preflight:
 	grep RBF */*.{c,cpp,h,1} doc/* AUTHORS README NEWS TODO ChangeLog 
diff --git a/Makefile.in b/Makefile.in
index e8b3f6c..46fe940 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -703,7 +703,7 @@ uninstall-am:
 
 
 nice:
-	rm -f *~ man/*~ src/*~
+	rm -f *~ man/*~ src/*~ doc/*~
 
 preflight:
 	grep RBF */*.{c,cpp,h,1} doc/* AUTHORS README NEWS TODO ChangeLog 
diff --git a/NEWS b/NEWS
index 768a09d..0027ddf 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,19 @@
+** Changes in version 4.2 (11 Jun 2012)
+
+* Bug Fixes
+
+      Fixed padding in Tiger hashes for large files
+
+
+
+** Changes in version 4.1.1 (5 Jun 2012)
+
+* Bug Fixes
+
+      Fixed hashdeep bug for known files with commas in their names.
+      Cleaned up usage message
+
+
 ** Changes in version 4.1.0 (14 Feb 2012)
 
 * New Features
diff --git a/config.h.in b/config.h.in
index 5cdcf12..9622fe4 100644
--- a/config.h.in
+++ b/config.h.in
@@ -210,6 +210,9 @@
    slash. */
 #undef LSTAT_FOLLOWS_SLASHED_SYMLINK
 
+/* We are cross-compiling with MINGW */
+#undef MINGW
+
 /* Name of package */
 #undef PACKAGE
 
diff --git a/configure b/configure
index 807725e..f86ff7d 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.68 for MD5DEEP 4.1.
+# Generated by GNU Autoconf 2.68 for MD5DEEP 4.2.
 #
 # Report bugs to <research at jessekornblum.com>.
 #
@@ -560,8 +560,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='MD5DEEP'
 PACKAGE_TARNAME='md5deep'
-PACKAGE_VERSION='4.1'
-PACKAGE_STRING='MD5DEEP 4.1'
+PACKAGE_VERSION='4.2'
+PACKAGE_STRING='MD5DEEP 4.2'
 PACKAGE_BUGREPORT='research at jessekornblum.com'
 PACKAGE_URL=''
 
@@ -1264,7 +1264,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 MD5DEEP 4.1 to adapt to many kinds of systems.
+\`configure' configures MD5DEEP 4.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1334,7 +1334,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of MD5DEEP 4.1:";;
+     short | recursive ) echo "Configuration of MD5DEEP 4.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1429,7 +1429,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-MD5DEEP configure 4.1
+MD5DEEP configure 4.2
 generated by GNU Autoconf 2.68
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -1947,7 +1947,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 MD5DEEP $as_me 4.1, which was
+It was created by MD5DEEP $as_me 4.2, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -2764,7 +2764,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='md5deep'
- VERSION='4.1'
+ VERSION='4.2'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -4201,6 +4201,9 @@ $as_echo "#define __LINUX__ 1" >>confdefs.h
      CPPFLAGS="-DUNICODE -D_UNICODE -D__MSVCRT_VERSION__=0x0601 -DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -DHAVE_STRUCT_TIMESPEC $CPPFLAGS"
      CXXFLAGS="$CXXFLAGS -Wno-format "  # compiler mingw-4.3.0 is broken on I64u formats
      CXXFLAGS="$CXXFLAGS --static"
+
+$as_echo "#define MINGW 1" >>confdefs.h
+
      mingw="yes"
      ;;
 esac
@@ -7253,7 +7256,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by MD5DEEP $as_me 4.1, which was
+This file was extended by MD5DEEP $as_me 4.2, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -7319,7 +7322,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-MD5DEEP config.status 4.1
+MD5DEEP config.status 4.2
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index 639c223..f624edf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@
 #
 
 AC_PREREQ(2.57)
-AC_INIT([MD5DEEP],[4.1],[research at jessekornblum.com])
+AC_INIT([MD5DEEP],[4.2],[research at jessekornblum.com])
 AC_CONFIG_FILES([Makefile src/Makefile man/Makefile tests/Makefile tests/testfiles/Makefile ])
 AM_INIT_AUTOMAKE
 AC_CONFIG_HEADERS([config.h])
@@ -37,6 +37,7 @@ case $host in
      CPPFLAGS="-DUNICODE -D_UNICODE -D__MSVCRT_VERSION__=0x0601 -DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -DHAVE_STRUCT_TIMESPEC $CPPFLAGS"
      CXXFLAGS="$CXXFLAGS -Wno-format "  # compiler mingw-4.3.0 is broken on I64u formats
      CXXFLAGS="$CXXFLAGS --static"
+     AC_DEFINE([MINGW],1,[We are cross-compiling with MINGW])
      mingw="yes"
      ;;		 		     
 esac
diff --git a/man/hashdeep.1 b/man/hashdeep.1
index 95ae363..e4f92a2 100644
--- a/man/hashdeep.1
+++ b/man/hashdeep.1
@@ -1,4 +1,4 @@
-.TH HASHDEEP "1" "v4.1.0 \- 14 Feb 2012" "AFOSI" "United States Air Force"
+.TH HASHDEEP "1" "v4.2 \- 11 Jun 2012" "AFOSI" "United States Air Force"
 
 .SH NAME
 hashdeep \- Compute, compare, or audit multiple message digests
@@ -9,7 +9,7 @@ hashdeep \- Compute, compare, or audit multiple message digests
 .br
 .B hashdeep
 [-c <alg1>[,<alg2>]] [-k <file>] [-i <size>] [\-f <file>] 
-[\-o <fbcplsde>] [-amxwMXrespblvv] [\-F<bum>] [\-jnn] [\fBFILES\fR]
+[\-o <fbcplsde>] [-amxwMXrespblvv] [\-F<bum>] [\-j <num>] [\fBFILES\fR]
 
 
 .SH DESCRIPTION
@@ -197,7 +197,7 @@ This mostly changes the behvaior of the audit mode, \-a.
 .TP
 \fB-jnn\fR
 Controls multi-threading. By default the program will create one
-producer thread to scna the file system and one hashing thread per CPU
+producer thread to scan the file system and one hashing thread per CPU
 core. Multi-threading causes output filenames to be in
 non-deterministic order, as files that take longer to hash will be
 delayed while they are hashed. If a deterministic order is required,
@@ -261,7 +261,8 @@ only one file with a .txt extension).
 Returns zero on success, one on error. 
 
 .SH AUTHOR
-hashdeep was written by Jesse Kornblum, research at jessekornblum.com.
+hashdeep was written by Jesse Kornblum, research at jessekornblum.com,
+and Simson Garfinkel.
 
 .SH KNOWN ISSUES
 Using the \-r flag cannot be used to recursively process all files 
diff --git a/man/md5deep.1 b/man/md5deep.1
index fc4bcbe..4cf3f31 100644
--- a/man/md5deep.1
+++ b/man/md5deep.1
@@ -1,4 +1,4 @@
-.TH MD5DEEP "1" "v4.1.0 \- 14 Feb 2012" "AFOSI" "United States Air Force"
+.TH MD5DEEP "1" "v4.2 \- 11 Jun 2012" "AFOSI" "United States Air Force"
 
 .SH NAME
 md5deep \- Compute and compare MD5 message digests
@@ -17,8 +17,8 @@ whirlpooldeep \- Compute and compare Whirlpool message digests
 .br
 .B md5deep
 [\-m|\-M|\-x|\-X <file>]  [-a|-A <hash>] [\-f <file>]
-[\-p <size>] [\-i <size>] [\-tnwzresS0lbkqZud] [\-F<bum>] 
-[\-o <fbcplsde>]  [\-jnn] [[\fBFILES\fR]
+[\-p <size>] [\-i <size>] [\-tnwzresS0lbkqZud] [\-F <bum>] 
+[\-o <fbcplsde>]  [\-j <num>] [[\fBFILES\fR]
 
 .SH DESCRIPTION
 .PP
@@ -225,7 +225,7 @@ e \- Windows PE executables
 .TP
 \fB-jnn\fR
 Controls multi-threading. By default the program will create one
-producer thread to scna the file system and one hashing thread per CPU
+producer thread to scan the file system and one hashing thread per CPU
 core. Multi-threading causes output filenames to be in
 non-deterministic order, as files that take longer to hash will be
 delayed while they are hashed. If a deterministic order is required,
@@ -315,7 +315,8 @@ be reported to the developer! See the section "Reporting Bugs" below.
 
 
 .SH AUTHOR
-md5deep was written by Jesse Kornblum, research at jessekornblum.com.
+md5deep was written by Jesse Kornblum, research at jessekornblum.com
+and Simson Garfinkel.
 
 .SH KNOWN ISSUES
 Using the \-r flag cannot be used to recursively process all files 
diff --git a/man/sha1deep.1 b/man/sha1deep.1
index fc4bcbe..4cf3f31 100644
--- a/man/sha1deep.1
+++ b/man/sha1deep.1
@@ -1,4 +1,4 @@
-.TH MD5DEEP "1" "v4.1.0 \- 14 Feb 2012" "AFOSI" "United States Air Force"
+.TH MD5DEEP "1" "v4.2 \- 11 Jun 2012" "AFOSI" "United States Air Force"
 
 .SH NAME
 md5deep \- Compute and compare MD5 message digests
@@ -17,8 +17,8 @@ whirlpooldeep \- Compute and compare Whirlpool message digests
 .br
 .B md5deep
 [\-m|\-M|\-x|\-X <file>]  [-a|-A <hash>] [\-f <file>]
-[\-p <size>] [\-i <size>] [\-tnwzresS0lbkqZud] [\-F<bum>] 
-[\-o <fbcplsde>]  [\-jnn] [[\fBFILES\fR]
+[\-p <size>] [\-i <size>] [\-tnwzresS0lbkqZud] [\-F <bum>] 
+[\-o <fbcplsde>]  [\-j <num>] [[\fBFILES\fR]
 
 .SH DESCRIPTION
 .PP
@@ -225,7 +225,7 @@ e \- Windows PE executables
 .TP
 \fB-jnn\fR
 Controls multi-threading. By default the program will create one
-producer thread to scna the file system and one hashing thread per CPU
+producer thread to scan the file system and one hashing thread per CPU
 core. Multi-threading causes output filenames to be in
 non-deterministic order, as files that take longer to hash will be
 delayed while they are hashed. If a deterministic order is required,
@@ -315,7 +315,8 @@ be reported to the developer! See the section "Reporting Bugs" below.
 
 
 .SH AUTHOR
-md5deep was written by Jesse Kornblum, research at jessekornblum.com.
+md5deep was written by Jesse Kornblum, research at jessekornblum.com
+and Simson Garfinkel.
 
 .SH KNOWN ISSUES
 Using the \-r flag cannot be used to recursively process all files 
diff --git a/man/sha256deep.1 b/man/sha256deep.1
index fc4bcbe..4cf3f31 100644
--- a/man/sha256deep.1
+++ b/man/sha256deep.1
@@ -1,4 +1,4 @@
-.TH MD5DEEP "1" "v4.1.0 \- 14 Feb 2012" "AFOSI" "United States Air Force"
+.TH MD5DEEP "1" "v4.2 \- 11 Jun 2012" "AFOSI" "United States Air Force"
 
 .SH NAME
 md5deep \- Compute and compare MD5 message digests
@@ -17,8 +17,8 @@ whirlpooldeep \- Compute and compare Whirlpool message digests
 .br
 .B md5deep
 [\-m|\-M|\-x|\-X <file>]  [-a|-A <hash>] [\-f <file>]
-[\-p <size>] [\-i <size>] [\-tnwzresS0lbkqZud] [\-F<bum>] 
-[\-o <fbcplsde>]  [\-jnn] [[\fBFILES\fR]
+[\-p <size>] [\-i <size>] [\-tnwzresS0lbkqZud] [\-F <bum>] 
+[\-o <fbcplsde>]  [\-j <num>] [[\fBFILES\fR]
 
 .SH DESCRIPTION
 .PP
@@ -225,7 +225,7 @@ e \- Windows PE executables
 .TP
 \fB-jnn\fR
 Controls multi-threading. By default the program will create one
-producer thread to scna the file system and one hashing thread per CPU
+producer thread to scan the file system and one hashing thread per CPU
 core. Multi-threading causes output filenames to be in
 non-deterministic order, as files that take longer to hash will be
 delayed while they are hashed. If a deterministic order is required,
@@ -315,7 +315,8 @@ be reported to the developer! See the section "Reporting Bugs" below.
 
 
 .SH AUTHOR
-md5deep was written by Jesse Kornblum, research at jessekornblum.com.
+md5deep was written by Jesse Kornblum, research at jessekornblum.com
+and Simson Garfinkel.
 
 .SH KNOWN ISSUES
 Using the \-r flag cannot be used to recursively process all files 
diff --git a/man/tigerdeep.1 b/man/tigerdeep.1
index fc4bcbe..4cf3f31 100644
--- a/man/tigerdeep.1
+++ b/man/tigerdeep.1
@@ -1,4 +1,4 @@
-.TH MD5DEEP "1" "v4.1.0 \- 14 Feb 2012" "AFOSI" "United States Air Force"
+.TH MD5DEEP "1" "v4.2 \- 11 Jun 2012" "AFOSI" "United States Air Force"
 
 .SH NAME
 md5deep \- Compute and compare MD5 message digests
@@ -17,8 +17,8 @@ whirlpooldeep \- Compute and compare Whirlpool message digests
 .br
 .B md5deep
 [\-m|\-M|\-x|\-X <file>]  [-a|-A <hash>] [\-f <file>]
-[\-p <size>] [\-i <size>] [\-tnwzresS0lbkqZud] [\-F<bum>] 
-[\-o <fbcplsde>]  [\-jnn] [[\fBFILES\fR]
+[\-p <size>] [\-i <size>] [\-tnwzresS0lbkqZud] [\-F <bum>] 
+[\-o <fbcplsde>]  [\-j <num>] [[\fBFILES\fR]
 
 .SH DESCRIPTION
 .PP
@@ -225,7 +225,7 @@ e \- Windows PE executables
 .TP
 \fB-jnn\fR
 Controls multi-threading. By default the program will create one
-producer thread to scna the file system and one hashing thread per CPU
+producer thread to scan the file system and one hashing thread per CPU
 core. Multi-threading causes output filenames to be in
 non-deterministic order, as files that take longer to hash will be
 delayed while they are hashed. If a deterministic order is required,
@@ -315,7 +315,8 @@ be reported to the developer! See the section "Reporting Bugs" below.
 
 
 .SH AUTHOR
-md5deep was written by Jesse Kornblum, research at jessekornblum.com.
+md5deep was written by Jesse Kornblum, research at jessekornblum.com
+and Simson Garfinkel.
 
 .SH KNOWN ISSUES
 Using the \-r flag cannot be used to recursively process all files 
diff --git a/man/whirlpooldeep.1 b/man/whirlpooldeep.1
index fc4bcbe..4cf3f31 100644
--- a/man/whirlpooldeep.1
+++ b/man/whirlpooldeep.1
@@ -1,4 +1,4 @@
-.TH MD5DEEP "1" "v4.1.0 \- 14 Feb 2012" "AFOSI" "United States Air Force"
+.TH MD5DEEP "1" "v4.2 \- 11 Jun 2012" "AFOSI" "United States Air Force"
 
 .SH NAME
 md5deep \- Compute and compare MD5 message digests
@@ -17,8 +17,8 @@ whirlpooldeep \- Compute and compare Whirlpool message digests
 .br
 .B md5deep
 [\-m|\-M|\-x|\-X <file>]  [-a|-A <hash>] [\-f <file>]
-[\-p <size>] [\-i <size>] [\-tnwzresS0lbkqZud] [\-F<bum>] 
-[\-o <fbcplsde>]  [\-jnn] [[\fBFILES\fR]
+[\-p <size>] [\-i <size>] [\-tnwzresS0lbkqZud] [\-F <bum>] 
+[\-o <fbcplsde>]  [\-j <num>] [[\fBFILES\fR]
 
 .SH DESCRIPTION
 .PP
@@ -225,7 +225,7 @@ e \- Windows PE executables
 .TP
 \fB-jnn\fR
 Controls multi-threading. By default the program will create one
-producer thread to scna the file system and one hashing thread per CPU
+producer thread to scan the file system and one hashing thread per CPU
 core. Multi-threading causes output filenames to be in
 non-deterministic order, as files that take longer to hash will be
 delayed while they are hashed. If a deterministic order is required,
@@ -315,7 +315,8 @@ be reported to the developer! See the section "Reporting Bugs" below.
 
 
 .SH AUTHOR
-md5deep was written by Jesse Kornblum, research at jessekornblum.com.
+md5deep was written by Jesse Kornblum, research at jessekornblum.com
+and Simson Garfinkel.
 
 .SH KNOWN ISSUES
 Using the \-r flag cannot be used to recursively process all files 
diff --git a/src/dig.cpp b/src/dig.cpp
index 89e5a3f..bf485af 100644
--- a/src/dig.cpp
+++ b/src/dig.cpp
@@ -1,6 +1,6 @@
 // MD5DEEP - dig.c
 //
-// By Jesse Kornblum
+// By Jesse Kornblum and Simson Garfinkel
 //
 // This is a work of the US Government. In accordance with 17 USC 105,
 //  copyright protection is not available for any work of the US Government.
@@ -9,18 +9,146 @@
 // WITHOUT ANY WARRANTY; without even the implied warranty of
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 //
-//
+
 
 /* The functions in this file will recurse through a directory
  * and call hash_file(fn) for every file that needs to be hashes.
  */
 
-// $Id: dig.cpp 618 2012-02-10 12:12:38Z jessekornblum $
+// $Id: dig.cpp 632 2012-06-05 11:00:58Z jessekornblum $
 
 #include "main.h"
 #include "winpe.h"
 #include <iostream>
 
+/*
+ * file stat system
+ */
+
+// Use a stat function to look up while kind of file this is
+// and determine its size if possible
+#ifdef _WIN32
+#define TSTAT(path,buf) _wstat64(path,buf)
+#define TLSTAT(path,buf) _wstat64(path,buf) // no lstat on windows
+#else
+#define TSTAT(path,buf) stat(path,buf)
+#define TLSTAT(path,buf) lstat(path,buf)
+#endif
+
+// Returns TRUE if the directory is '.' or '..', otherwise FALSE
+static bool is_special_dir(const tstring &d)
+{
+    return global::make_utf8(d)=="." || global::make_utf8(d)=="..";
+}
+
+/* Determine the file type of a structure
+ * called by file_type() and should_hash_symlink() 
+ */
+
+file_types file_metadata_t::decode_file_type(const struct __stat64 &sb)
+{
+    if (S_ISREG(sb.st_mode))  return stat_regular;
+    if (S_ISDIR(sb.st_mode))  return stat_directory;
+    if (S_ISBLK(sb.st_mode))  return stat_block;
+    if (S_ISCHR(sb.st_mode))  return stat_character;
+    if (S_ISFIFO(sb.st_mode)) return stat_pipe;
+
+#ifdef S_ISSOCK
+    if (S_ISSOCK(sb.st_mode)) return stat_socket; // not present on WIN32
+#endif
+
+#ifdef S_ISLNK
+    if (S_ISLNK(sb.st_mode)) return stat_symlink; // not present on WIN32
+#endif   
+
+#ifdef S_ISDOOR
+    // Solaris doors are an inter-process communications facility present in Solaris 2.6
+    // http://en.wikipedia.org/wiki/Doors_(computing)
+    if (S_ISDOOR(sb.st_mode)) return stat_door; 
+#endif
+    return stat_unknown;
+}
+
+/**
+ * stat a file and return the appropriate object
+ * This would better be done on an open file handle
+ */
+int file_metadata_t::stat(const tstring &fn,
+			  file_metadata_t *m,
+			  class display &ocb)
+{
+  struct __stat64 sb;
+  if (::TSTAT(fn.c_str(),&sb)) 
+  {
+    ocb.error_filename(fn,"%s",strerror(errno));
+    return -1;
+  }
+  m->fileid.dev = sb.st_dev;
+#ifdef _WIN32
+  BY_HANDLE_FILE_INFORMATION fileinfo;
+  HANDLE filehandle = CreateFile(fn.c_str(),
+				 0,   // desired access
+				 FILE_SHARE_READ,
+				 NULL,  
+				 OPEN_EXISTING,
+				 (FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS),
+				 NULL);
+  // RBF - Error check CreateFile
+  (void)GetFileInformationByHandle(filehandle, &fileinfo);
+  CloseHandle(filehandle);
+  m->fileid.ino = (((uint64_t)fileinfo.nFileIndexHigh)<<32) | (fileinfo.nFileIndexLow);
+#else
+  m->fileid.ino = sb.st_ino;
+#endif
+  m->nlink      = sb.st_nlink;
+  m->size       = sb.st_size;
+  m->ctime      = sb.st_ctime;
+  m->mtime      = sb.st_mtime;
+  m->atime      = sb.st_atime;
+
+  return 0;
+}
+
+
+/* Return the 'decoded' file type of a file.
+ * If an error is found and ocb is provided, send the error to ocb.
+ * If filesize and ctime are provided, give them.
+ * Also return the file size and modification time (may be used elsewhere).
+ */
+
+file_types state::file_type(const tstring &fn,display *ocb,uint64_t *filesize,
+				   timestamp_t *ctime,timestamp_t *mtime,timestamp_t *atime)
+{
+    struct __stat64 sb;
+    memset(&sb,0,sizeof(sb));
+    if (TLSTAT(fn.c_str(),&sb))  {
+	if(ocb) ocb->error_filename(fn,"%s", strerror(errno));
+	return stat_unknown;
+    }
+    if(ctime) *ctime = sb.st_ctime;
+    if(mtime) *mtime = sb.st_mtime;
+    if(atime) *atime = sb.st_atime;
+    if(filesize){
+	if(sb.st_size!=0){
+	    *filesize = sb.st_size;
+	} else {
+	    /*
+	     * The stat() function does not return file size for raw devices.
+	     * If we have no file size, try to use the find_file_size function,
+	     * which calls ioctl.
+	     */
+	    FILE *f = _tfopen(fn.c_str(),_TEXT("rb"));
+	    if(f){
+		*filesize = find_file_size(f,ocb);
+		fclose(f); f = 0;
+	    }
+	}
+    }
+    return file_metadata_t::decode_file_type(sb);
+}
+
+
+
 /****************************************************************
  *** database of directories we've seen.
  *** originally in cycles.c.
@@ -28,7 +156,6 @@
  ****************************************************************/
 
 
-
 void state::done_processing_dir(const tstring &fn_)
 {
     tstring fn = global::get_realpath(fn_);
@@ -330,12 +457,6 @@ void state::clean_name_posix(std::string &fn)
 }
 #endif
 
-// Returns TRUE if the directory is '.' or '..', otherwise FALSE
-static bool is_special_dir(const tstring &d)
-{
-    return global::make_utf8(d)=="." || global::make_utf8(d)=="..";
-}
-
 void state::process_dir(const tstring &fn)
 {
     _TDIR *current_dir;
@@ -360,8 +481,7 @@ void state::process_dir(const tstring &fn)
      * 4. Process them.
      */
     std::vector<tstring> dir_entries;
-    while ((entry = _treaddir(current_dir)) != NULL)   
-    {
+    while ((entry = _treaddir(current_dir)) != NULL) {
       // ignore . and ..
       if (is_special_dir(entry->d_name)) 
 	continue; 
@@ -397,89 +517,6 @@ void state::process_dir(const tstring &fn)
 }
 
 
-/* Determine the file type of a structure
- * called by file_type() and should_hash_symlink() 
- */
-
-state::file_types state::decode_file_type(const struct __stat64 &sb)
-{
-    if (S_ISREG(sb.st_mode))  return stat_regular;
-    if (S_ISDIR(sb.st_mode))  return stat_directory;
-    if (S_ISBLK(sb.st_mode))  return stat_block;
-    if (S_ISCHR(sb.st_mode))  return stat_character;
-    if (S_ISFIFO(sb.st_mode)) return stat_pipe;
-
-#ifdef S_ISSOCK
-    if (S_ISSOCK(sb.st_mode)) return stat_socket; // not present on WIN32
-#endif
-
-#ifdef S_ISLNK
-    if (S_ISLNK(sb.st_mode)) return stat_symlink; // not present on WIN32
-#endif   
-
-#ifdef S_ISDOOR
-    // Solaris doors are an inter-process communications facility present in Solaris 2.6
-    // http://en.wikipedia.org/wiki/Doors_(computing)
-    if (S_ISDOOR(sb.st_mode)) return stat_door; 
-#endif
-    return stat_unknown;
-}
-
-// Use a stat function to look up while kind of file this is
-// and determine its size if possible
-#ifdef _WIN32
-#define TSTAT(path,buf) _wstat64(path,buf)
-#define TLSTAT(path,buf) _wstat64(path,buf) // no lstat on windows
-#else
-#define TSTAT(path,buf) stat(path,buf)
-#define TLSTAT(path,buf) lstat(path,buf)
-#endif
-
-/* This is coming... */
-#if 0
-HFILE filehandle;
-(void)GetFileInformationByHandle((HANDLE)filehandle, &fileinfo);
-file->fileindexhi = fileinfo.nFileIndexHigh;
-file->fileindexlo = fileinfo.nFileIndexLow;
-#endif
-
-/* Return the 'decoded' file type of a file.
- * If an error is found and ocb is provided, send the error to ocb.
- * If filesize and ctime are provided, give them.
- * Also return the file size and modification time (may be used elsewhere).
- */
-state::file_types state::file_type(const tstring &fn,display *ocb,uint64_t *filesize,
-				   timestamp_t *ctime,timestamp_t *mtime,timestamp_t *atime)
-{
-    struct __stat64 sb;
-    memset(&sb,0,sizeof(sb));
-    if (TLSTAT(fn.c_str(),&sb))  {
-	if(ocb) ocb->error_filename(fn,"%s", strerror(errno));
-	return stat_unknown;
-    }
-    if(ctime) *ctime = sb.st_ctime;
-    if(mtime) *mtime = sb.st_mtime;
-    if(atime) *atime = sb.st_atime;
-    if(filesize){
-	if(sb.st_size!=0){
-	    *filesize = sb.st_size;
-	} else {
-	    /*
-	     * The stat() function does not return file size for raw devices.
-	     * If we have no file size, try to use the find_file_size function,
-	     * which calls ioctl.
-	     */
-	    FILE *f = _tfopen(fn.c_str(),_TEXT("rb"));
-	    if(f){
-		*filesize = find_file_size(f,ocb);
-		fclose(f); f = 0;
-	    }
-	}
-    }
-    return decode_file_type(sb);
-}
-
-
 /* Deterine if a symlink should be hashed or not.
  * Returns TRUE if a symlink should be hashed.
  */
@@ -498,7 +535,7 @@ bool state::should_hash_symlink(const tstring &fn, file_types *link_type)
 	return false;
     }
 
-    state::file_types type = decode_file_type(sb);
+    file_types type = file_metadata_t::decode_file_type(sb);
 
     if (type == stat_directory)  {
 	if (mode_recursive){
@@ -526,8 +563,7 @@ bool state::should_hash_winpe(const tstring &fn)
   bool executable_extension = has_executable_extension(fn);
   
   FILE * handle = _tfopen(fn.c_str(),_TEXT("rb"));
-  if (NULL == handle)
-  {
+  if (NULL == handle) {
     ocb.error_filename(fn,"%s", strerror(errno));
     return false;
   }
@@ -552,66 +588,62 @@ bool state::should_hash_winpe(const tstring &fn)
  */
 bool state::should_hash_expert(const tstring &fn, file_types type)
 {
-  file_types link_type=stat_unknown;
-  if (stat_directory == type)
-  {
-    if (mode_recursive)
-      process_dir(fn);
-    else 
-      ocb.error_filename(fn,"Is a directory");
-
-    return false;
-  }
+    file_types link_type=stat_unknown;
+    if (stat_directory == type)  {
+	if (mode_recursive){
+	    process_dir(fn);
+	}
+	else {
+	    ocb.error_filename(fn,"Is a directory");
+	}
+	return false;
+    }
 
-  if (mode_winpe)
-  {
-    // The user could have requested PE files *and* something else
-    // therefore we don't return false here if the file is not a PE.
-    // Note that we have to check for directories first!
-    if (should_hash_winpe(fn))
-      return true;
-  }
+    if (mode_winpe)  {
+	// The user could have requested PE files *and* something else
+	// therefore we don't return false here if the file is not a PE.
+	// Note that we have to check for directories first!
+	if (should_hash_winpe(fn)){
+	    return true;
+	}
+    }
 
-  switch(type)  
-  {
-    // We can't just return s->mode & mode_X because mode_X is
-    // a 64-bit value. When that value gets converted back to int,
-    // the high part of it is lost. 
-    
+    switch(type) {
+	// We can't just return s->mode & mode_X because mode_X is
+	// a 64-bit value. When that value gets converted back to int,
+	// the high part of it is lost. 
+	
 #define RETURN_IF_MODE(A) if (A) return true; break;
-  case stat_directory:
-    // This case should be handled above. This statement is 
-    // here to avoid compiler warnings
-    ocb.internal_error("Did not handle directory entry in should_hash_expert()");
-
-  case stat_regular:   RETURN_IF_MODE(mode_regular);
-  case stat_block:     RETURN_IF_MODE(mode_block);
-  case stat_character: RETURN_IF_MODE(mode_character);
-  case stat_pipe:      RETURN_IF_MODE(mode_pipe);
-  case stat_socket:    RETURN_IF_MODE(mode_socket);
-  case stat_door:      RETURN_IF_MODE(mode_door);
-  case stat_symlink: 
-    
-    //  Although it might appear that we need nothing more than
-    //     return (s->mode & mode_symlink);
-    // that doesn't work. That logic gets into trouble when we're
-    // running in recursive mode on a symlink to a directory.
-    // The program attempts to open the directory entry itself
-    // and gets into an infinite loop.
-    
-    if (!(mode_symlink)) 
-      return false;
-    if (should_hash_symlink(fn,&link_type))
-    {
-      return should_hash_expert(fn,link_type);
+    case stat_directory:
+	// This case should be handled above. This statement is 
+	// here to avoid compiler warnings
+	ocb.internal_error("Did not handle directory entry in should_hash_expert()");
+	
+    case stat_regular:   RETURN_IF_MODE(mode_regular);
+    case stat_block:     RETURN_IF_MODE(mode_block);
+    case stat_character: RETURN_IF_MODE(mode_character);
+    case stat_pipe:      RETURN_IF_MODE(mode_pipe);
+    case stat_socket:    RETURN_IF_MODE(mode_socket);
+    case stat_door:      RETURN_IF_MODE(mode_door);
+    case stat_symlink: 
+	
+	//  Although it might appear that we need nothing more than
+	//     return (s->mode & mode_symlink);
+	// that doesn't work. That logic gets into trouble when we're
+	// running in recursive mode on a symlink to a directory.
+	// The program attempts to open the directory entry itself
+	// and gets into an infinite loop.
+	
+	if (!(mode_symlink)) return false;
+	if (should_hash_symlink(fn,&link_type))    {
+	    return should_hash_expert(fn,link_type);
+	}
+	return false;
+    case stat_unknown:
+	ocb.error_filename(fn,"unknown file type");
+	return false;
     }
     return false;
-  case stat_unknown:
-    ocb.error_filename(fn,"unknown file type");
-    return false;
-  }
-
-  return false;
 }
 
 
@@ -648,20 +680,22 @@ bool state::should_hash(const tstring &fn)
     return true;
 }
 
-/* Search through a directory and its subdirectory for files to hash */
+// Search through a directory and its subdirectory for files to hash 
 void state::dig_normal(const tstring &fn_)
 {
-    tstring fn(fn_);			// local copy will be modified
-    if (opt_debug) ocb.status("*** state::dig_normal(%s)",global::make_utf8(fn).c_str());
+  // local copy will be modified
+  tstring fn(fn_);			
+  if (opt_debug) 
+    ocb.status("*** state::dig_normal(%s)",global::make_utf8(fn).c_str());
 #ifdef _WIN32
-    clean_name_win32(fn);
+  clean_name_win32(fn);
 #else
-    clean_name_posix(fn);
+  clean_name_posix(fn);
 #endif
-    if (opt_debug) ocb.status("*** cleaned:%s",global::make_utf8(fn).c_str());
-    if (should_hash(fn)){
-	ocb.hash_file(fn);
-    }
+  if (opt_debug) 
+    ocb.status("*** cleaned:%s",global::make_utf8(fn).c_str());
+  if (should_hash(fn))
+    ocb.hash_file(fn);
 }
 
 
diff --git a/src/display.cpp b/src/display.cpp
index 28a3192..f0bc76a 100644
--- a/src/display.cpp
+++ b/src/display.cpp
@@ -2,7 +2,7 @@
 #include "utf8.h"
 #include <stdarg.h>
 
-// $Id: display.cpp 618 2012-02-10 12:12:38Z jessekornblum $
+// $Id: display.cpp 632 2012-06-05 11:00:58Z jessekornblum $
 
 /**
  *
@@ -47,37 +47,39 @@ void display::writeln(std::ostream *os,const std::string &str)
     unlock();
 }
 
-#if defined(HAVE_VASPRINTF) && defined(__MINGW_H)
-/* prototype missing under mingw */
+/* special handling for vasprintf under mingw.
+ * Sometimes the function prototype is missing. Sometimes the entire function is missing!
+ */
+#if defined(HAVE_VASPRINTF) && defined(MINGW)
 extern "C" {
     int vasprintf(char **ret,const char *fmt,va_list ap);
 }
 #endif    
 	
-
 /*
- * on mingw the have_vasprintf check succedes, but it really isn't there
+ * If we don't have vasprintf, bring it in.
  */
-#if defined(HAVE_VASPRINTF) && defined(__MINGW_H)
+/*
+#if !defined(HAVE_VASPRINTF) 
 extern "C" {
-    /**
-     * We do not have vasprintf.
-     * We have determined that vsnprintf() does not perform properly on windows.
-     * So we just allocate a huge buffer and then strdup() and hope!
-     */
+    //
+    // We do not have vasprintf.
+    // We have determined that vsnprintf() does not perform properly on windows.
+    // So we just allocate a huge buffer and then strdup() and hope!
+    //
     int vasprintf(char **ret,const char *fmt,va_list ap)
     {
-	/* Figure out how long the result will be */
+	// Figure out how long the result will be 
 	char buf[65536];
 	int size = vsnprintf(buf,sizeof(buf),fmt,ap);
 	if(size<0) return size;
-	/* Now allocate the memory */
+	// Now allocate the memory 
 	*ret = (char *)strdup(buf);
 	return size;
     }
 }
 #endif
-
+*/
 
 void display::status(const char *fmt,...)
 {
diff --git a/src/hash.cpp b/src/hash.cpp
index e78dad4..f62dc96 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -8,7 +8,7 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  *
- * $Id: hash.cpp 595 2012-01-22 00:28:03Z xchatty $
+ * $Id: hash.cpp 627 2012-02-28 04:31:29Z xchatty $
  *
  * 2011 JUN 1 - SLG - Removed #ifdef MD5DEEP, since we now have a single binary for both MD5DEEP and HASHDEEP
  */
@@ -195,6 +195,7 @@ bool file_data_hasher_t::compute_hash(uint64_t request_start,uint64_t request_le
 #define O_BINARY 0
 #endif
 mutex_t file_data_hasher_t::fdh_lock;
+
 void file_data_hasher_t::hash()
 {
     file_data_hasher_t *fdht = this;
@@ -206,8 +207,14 @@ void file_data_hasher_t::hash()
     if(fdht->handle==0){		
 	/* Open the file and print an error if we can't */
 	// stat the file to get the bytes and ctime
-	state::file_type(fdht->file_name_to_hash,ocb,&fdht->stat_bytes,
-			 &fdht->ctime,&fdht->mtime,&fdht->atime);
+	//state::file_type(fdht->file_name_to_hash,ocb,&fdht->stat_bytes,
+	//&fdht->ctime,&fdht->mtime,&fdht->atime);
+	file_metadata_t m;
+	file_metadata_t::stat(fdht->file_name_to_hash,&m,*ocb);
+	fdht->stat_bytes = m.size;
+	fdht->ctime      = m.ctime;
+	fdht->mtime      = m.mtime;
+	fdht->atime      = m.atime;
 
 	if(ocb->opt_verbose>=MORE_VERBOSE){
 	    errno = 0;			// no error
@@ -404,7 +411,6 @@ void file_data_hasher_t::hash()
 	}
     }
 
-
     /**
      * If we had an additional hash context for the file,
      * then we must be in DFXML mode and doing piecewise hashing.
diff --git a/src/hashlist.cpp b/src/hashlist.cpp
index 5cbb542..3fc2fc6 100644
--- a/src/hashlist.cpp
+++ b/src/hashlist.cpp
@@ -1,4 +1,4 @@
-// $Id: hashlist.cpp 578 2012-01-06 12:25:14Z jessekornblum $ 
+// $Id: hashlist.cpp 631 2012-06-05 10:26:56Z jessekornblum $ 
 
 /** hashlist.cpp
  * Implements a list of hashes for local database, searching, etc.
@@ -218,7 +218,12 @@ void hashlist::enable_hashing_algorithms_from_hashdeep_file(class display *ocb,c
     for(std::vector<std::string>::iterator it = algs.begin(); it!=algs.end(); it++){
 	std::string name = *it;
 	lowercase(name);
-	if(name=="filename") continue;
+	if(name=="filename") 
+  {
+    // Special value to denote the filename
+    filename_column = num_columns;
+    continue;
+  }
 	hashid_t id = algorithm_t::get_hashid_for_name(name);
 	if(id==alg_unknown){
 	    if(ocb){
@@ -256,101 +261,128 @@ uint64_t hashlist::total_matched()
 }
 
 
-/**
- * Loads a file of known hashes.
- * First identifies the file type, then reads the file.
- */
-hashlist::loadstatus_t hashlist::load_hash_file(display *ocb,const std::string &fn)
+//
+// Loads a file of known hashes.
+// First identifies the file type, then reads the file.
+ //
+hashlist::loadstatus_t 
+hashlist::load_hash_file(display *ocb,const std::string &fn)
 {
-    loadstatus_t status = loadstatus_ok;
-    hashfile_format type;
+  loadstatus_t status = loadstatus_ok;
+  hashfile_format type;
 
-    FILE *hl_handle = fopen(fn.c_str(),"rb");
-    if (NULL == hl_handle) {
-	if(ocb) ocb->error("%s: %s", fn.c_str(), strerror(errno));
-	return status_file_error;
-    }
+  FILE *hl_handle = fopen(fn.c_str(),"rb");
+  if (NULL == hl_handle)
+  {
+    if (ocb) 
+      ocb->error("%s: %s", fn.c_str(), strerror(errno));
+    return status_file_error;
+  }
   
-    type = identify_format(ocb,fn,hl_handle);
-    if (file_unknown == type)  {
-	if(ocb) ocb->error("%s: Unable to identify file format", fn.c_str());
-	fclose(hl_handle);
-	hl_handle = 0;
-	return status_unknown_filetype;
-    }
+  type = identify_format(ocb,fn,hl_handle);
+  if (file_unknown == type)
+  {
+    if (ocb) 
+      ocb->error("%s: Unable to identify file format", fn.c_str());
+    fclose(hl_handle);
+    hl_handle = 0;
+    return status_unknown_filetype;
+  }
 
-    int contains_bad_lines = FALSE;
-    int record_valid=0;
+  bool contains_bad_lines = false;
+  bool record_valid;
 
-    // We start our counter at line number two for the two lines
-    // of header we've already read
-    uint64_t line_number = 2;
+  // We start our counter at line number two for the two lines
+  // of header we've already read
+  uint64_t line_number = 2;
 
-    /* Redo this to use std::string everywhere */
-    char line[MAX_STRING_LENGTH];	// holds the line we are reading
+  // TODO: Read the line directly into a std::string
+  char line[MAX_STRING_LENGTH];	
+  while (fgets(line,MAX_STRING_LENGTH,hl_handle)) 
+  {
+    line_number++;			
+    
+    // Lines starting with a pound sign are comments and can be ignored
+    if ('#' == line[0])
+      continue;
 
-    while (fgets(line,MAX_STRING_LENGTH,hl_handle)) {
-	line_number++;			// count where we are
+    // C++ typically fails with a bad_alloc, but you can make it return null
+    // http://www.cplusplus.com/reference/std/new/bad_alloc/
+    // http://www.cplusplus.com/reference/std/new/nothrow/
+    file_data_t *t = new (std::nothrow) file_data_t(); 
+    if (NULL == t)
+    {
+      ocb->fatal_error("%s: Out of memory in line %"PRIu64,
+		       fn.c_str(), line_number);
+    }
+    
+    chop_line(line);
+    record_valid = true;
 
-	// Lines starting with a pound sign are comments and can be ignored
-	if ('#' == line[0]){
-	    continue;
-	}
+    // Convert the input line to a string for easier manipulations
+    std::string line_as_string(line);
+    std::vector<std::string> fields = split(line_as_string,',');
 
-	// C++ typically fails with a bad_alloc, but you can make it return null
-	// http://www.cplusplus.com/reference/std/new/bad_alloc/
-	// http://www.cplusplus.com/reference/std/new/nothrow/
-	file_data_t *t = new (std::nothrow) file_data_t(); // C++ new fails with a bad_a
-	if (NULL == t){
-	    ocb->fatal_error("%s: Out of memory in line %"PRIu64, 
-			fn.c_str(), line_number);
-	}
-
-	chop_line(line);
-	record_valid = TRUE;
-
-	// completely rewritten to use STL strings
-	std::vector<std::string> fields = split(std::string(line),',');
-	for(size_t column_number=0;column_number<fields.size();column_number++){
-	    // The first column should always be the file size
-	    std::string word = fields[column_number];
-	    if (column_number==0) {
-		t->file_bytes = (uint64_t)strtoll(word.c_str(),NULL,10);
-		continue;
-	    }
-	    if (column_number==fields.size()-1){
-		t->file_name = word;
-		continue;
-	    }
+    size_t column_number;
+    for (column_number=0 ; column_number<fields.size() ; column_number++)
+    {
+      std::string word = fields[column_number];
 
+      // The first column should always be the file size
+      if (0 == column_number)
+      {
+	t->file_bytes = (uint64_t)strtoll(word.c_str(),NULL,10);
+	continue;
+      }
 
-	    // All other columns should contain a valid hash in hex
-	    if ( !algorithm_t::valid_hash(hash_column[column_number],word)){
-		if(ocb) ocb->error("%s: Invalid %s hash in line %"PRIu64,fn.c_str(), 
-					 hashes[hash_column[column_number]].name.c_str(),
-					 line_number);
-		contains_bad_lines = TRUE;
-		record_valid = FALSE;
-		// Break out (done = true) and then process the next line
-		break;
-	    }
+      if (column_number == filename_column)
+      {
+	// If the filename contained commas, it was split 
+	// incorrectly by the 'split' statememt above. The filename
+	// will be split across more than one column.
+	// As such we need to 'find' everything
+	// in the string starting with the current location.
+	// The result should be closer to the end of the string than
+	// the start, so we can use rfind. (This also avoids a problem
+	// when the filename is the same as one of the hashes, which
+	// happens now and again.)
+	size_t start = line_as_string.rfind(word);
+	t->file_name = line_as_string.substr(start,std::string::npos);
+
+	// This should be the last column, so we break out now.
+	break;
+      }
 
-	    // Convert the hash to a std::string and save it
-	    lowercase(word);
-	    t->hash_hex[hash_column[column_number]] = word;
-	}
-	if ( record_valid) {
-	    add_fdt(t);	/* add the file to the database*/
-	}
+      // All other columns should contain a valid hash in hex
+      if ( !algorithm_t::valid_hash(hash_column[column_number],word))
+      {
+	if (ocb) 
+	  ocb->error("%s: Invalid %s hash in line %"PRIu64,
+		     fn.c_str(), 
+		     hashes[hash_column[column_number]].name.c_str(),
+		     line_number);
+	contains_bad_lines = true;
+	record_valid = false;
+	// Break out (done = true) and then process the next line
+	break;
+      }
+      
+      // Convert the hash to a std::string and save it
+      lowercase(word);
+      t->hash_hex[hash_column[column_number]] = word;
     }
-    fclose(hl_handle);
-    hl_handle = 0;
 
-    if (contains_bad_lines){
-	return status_contains_bad_hashes;
-    }
+    if (record_valid) 
+      add_fdt(t);
+  }
+
+  fclose(hl_handle);
+  hl_handle = 0;
+
+  if (contains_bad_lines)
+    return status_contains_bad_hashes;
     
-    return status;
+  return status;
 }
 
 
diff --git a/src/main.cpp b/src/main.cpp
index 7697c13..eb4897c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,6 +1,6 @@
 /*
  * 
- *  $Id: main.cpp 618 2012-02-10 12:12:38Z jessekornblum $
+ *  $Id: main.cpp 626 2012-02-28 02:50:32Z jessekornblum $
  * 
  * This is the main() function and support functions for hashdeep and md5deep.
  *
@@ -130,65 +130,72 @@ tstring state::generate_filename(const tstring &input)
 // function should produce no more than 22 lines of text.
 void state::usage()
 {
-    if(usage_count==1){
-	ocb.status("%s version %s by %s.",progname.c_str(),VERSION,AUTHOR);
-	ocb.status("%s %s [-c <alg>] [-k <file>] [-amxwMXrespblvv] [-jnn] [-V|-h] [-o <mode>] [FILES]",
-		     CMD_PROMPT,progname.c_str());
-	
-	/* Make a list of the hashes */
-	ocb.status("-c <alg1,[alg2]> - Compute hashes only. Defaults are MD5 and SHA-256");
-	fprintf(stdout,"     legal values: ");
-	for (int i = 0 ; i < NUM_ALGORITHMS ; i++){
-	    fprintf(stdout,"%s%s",hashes[i].name.c_str(),(i+1<NUM_ALGORITHMS) ? "," : NEWLINE);
-	}
+  if (1 == usage_count)
+  {
+    ocb.status("%s version %s by %s.",progname.c_str(),VERSION,AUTHOR);
+    ocb.status("%s %s [OPTION]... [FILES]...",CMD_PROMPT,progname.c_str());
+
+    // Make a list of the hashes
+    ocb.status("-c <alg1,[alg2]> - Compute hashes only. Defaults are MD5 and SHA-256");
+    fprintf(stdout,"                   legal values: ");
+    for (int i = 0 ; i < NUM_ALGORITHMS ; i++)
+    {
+      fprintf(stdout,"%s%s",hashes[i].name.c_str(),(i+1<NUM_ALGORITHMS) ? "," : NEWLINE);
+    }
 	
-	ocb.status("-p <size> - piecewise mode. Files are broken into blocks for hashing");
-	ocb.status("-r  - recursive mode. All subdirectories are traversed");
-	ocb.status("-d  - output in DFXML (Digital Forensics XML)");
-	ocb.status("-k <FN>  - add a file of known hashes");
-	ocb.status("-a  - audit mode. Validates FILES against known hashes. Requires -k");
-	ocb.status("-m  - matching mode. Requires -k");
-	ocb.status("-x  - negative matching mode. Requires -k");
-	ocb.status("-w  - in -m mode, displays which known file was matched");
-	ocb.status("-M and -X act like -m and -x, but display hashes of matching files");
-	ocb.status("-e  - compute estimated time remaining for each file");
-	ocb.status("-s  - silent mode. Suppress all error messages");
-	ocb.status("-b  - prints only the bare name of files; all path information is omitted");
-	ocb.status("-l  - print relative paths for filenames");
-	ocb.status("-i  - only process files smaller than the given threshold");
-	ocb.status("-o  - only process certain types of files. See README/manpage");
-	ocb.status("-v  - verbose mode. Use again to be more verbose; -V display version & exit.");
-	ocb.status("-d  - output in DFXML; -W FILE - write to FILE.");
+    ocb.status("-p <size> - piecewise mode. Files are broken into blocks for hashing");
+    ocb.status("-r        - recursive mode. All subdirectories are traversed");
+    ocb.status("-d        - output in DFXML (Digital Forensics XML)");
+    ocb.status("-k <file> - add a file of known hashes");
+    ocb.status("-a        - audit mode. Validates FILES against known hashes. Requires -k");
+    ocb.status("-m        - matching mode. Requires -k");
+    ocb.status("-x        - negative matching mode. Requires -k");
+    ocb.status("-w        - in -m mode, displays which known file was matched");
+    ocb.status("-M and -X act like -m and -x, but display hashes of matching files");
+    ocb.status("-e        - compute estimated time remaining for each file");
+    ocb.status("-s        - silent mode. Suppress all error messages");
+    ocb.status("-b        - prints only the bare name of files; all path information is omitted");
+    ocb.status("-l        - print relative paths for filenames");
+    ocb.status("-i        - only process files smaller than the given threshold");
+    ocb.status("-o        - only process certain types of files. See README/manpage");
+    ocb.status("-v        - verbose mode. Use again to be more verbose");
+    ocb.status("-d        - output in DFXML; -W FILE - write to FILE.");
 #ifdef HAVE_PTHREAD
-	ocb.status("-jnn run nn threads (default %d)",threadpool::numCPU());
+    ocb.status("-j <num>  - use num threads (default %d)",threadpool::numCPU());
 #else
-	ocb.status("-jnn ignored (compiled without pthreads)");
+    ocb.status("-j <num>  - ignored (compiled without pthreads)");
 #endif	
+  }
 
-    }
-    if(usage_count==2){			// -hh
-	ocb.status("-0 - use a NULL for newline.");
-	ocb.status("-u - escape Unicode");
-	ocb.status("-B - verbose mode; repeat for more verbosity");
-	ocb.status("-C - Macintosh only --- use Common Crypto hash functions");
-	ocb.status("-Fb - I/O mode buffered; -Fu unbuffered; -Fm memory-mapped");
-	ocb.status("-o[bcpflsde] - only process certain types of files:");
-	ocb.status("            b=block dev; c=character dev; p=named pipe");
-	ocb.status("            f=regular file; l=symlink; s=socket; d=door e=Windows PE");
-	ocb.status("-Dnn - set debug level to nn");
-    }
-    if(usage_count==3){			// -hhh - adds debugging information
-	ocb.status("sizeof(off_t)= %d",sizeof(off_t));
+  // -hh makes us more verbose
+  if (2 == usage_count)
+  {			
+    ocb.status("-V        - display version number and exit");
+    ocb.status("-0        - use a NUL (\\0) for newline.");
+    ocb.status("-u        - escape Unicode");
+    ocb.status("-B        - verbose mode; repeat for more verbosity");
+    ocb.status("-C        - OS X only --- use Common Crypto hash functions");
+    ocb.status("-Fb       - I/O mode buffered; -Fu unbuffered; -Fm memory-mapped");
+    ocb.status("-o[bcpflsde] - Expert mode. only process certain types of files:");
+    ocb.status("               b=block dev; c=character dev; p=named pipe");
+    ocb.status("               f=regular file; l=symlink; s=socket; d=door e=Windows PE");
+    ocb.status("-D <num>  - set debug level");
+  }
+  
+  /// -hhh mode includes debugging information.
+  if (3 == usage_count)
+  {
+    ocb.status("sizeof(off_t)= %d",sizeof(off_t));
 #ifdef HAVE_PTHREAD
-	ocb.status("HAVE_PTHREAD");
+    ocb.status("HAVE_PTHREAD");
 #endif
 #ifdef HAVE_PTHREAD_H
-	ocb.status("HAVE_PTHREAD_H");
+    ocb.status("HAVE_PTHREAD_H");
 #endif
 #ifdef HAVE_PTHREAD_WIN32_PROCESS_ATTACH_NP
-	ocb.status("HAVE_PTHREAD_WIN32_PROCESS_ATTACH_NP");
+    ocb.status("HAVE_PTHREAD_WIN32_PROCESS_ATTACH_NP");
 #endif
-    }
+  }
 }
 
 
@@ -198,45 +205,45 @@ void state::md5deep_usage(void)
 {
     if(usage_count==1){
 	ocb.status("%s version %s by %s.",progname.c_str(),VERSION,AUTHOR);
-	ocb.status("%s %s [OPTION]... [FILE]...",CMD_PROMPT,progname.c_str());
+	ocb.status("%s %s [OPTION]... [FILES]...",CMD_PROMPT,progname.c_str());
 	ocb.status("See the man page or README.txt file or use -hh for the full list of options");
 	ocb.status("-p <size> - piecewise mode. Files are broken into blocks for hashing");
-	ocb.status("-r  - recursive mode. All subdirectories are traversed");
-	ocb.status("-e  - show estimated time remaining for each file");
-	ocb.status("-s  - silent mode. Suppress all error messages");
-	ocb.status("-z  - display file size before hash");
+	ocb.status("-r        - recursive mode. All subdirectories are traversed");
+	ocb.status("-e        - show estimated time remaining for each file");
+	ocb.status("-s        - silent mode. Suppress all error messages");
+	ocb.status("-z        - display file size before hash");
 	ocb.status("-m <file> - enables matching mode. See README/man page");
 	ocb.status("-x <file> - enables negative matching mode. See README/man page");
 	ocb.status("-M and -X are the same as -m and -x but also print hashes of each file");
-	ocb.status("-w  - displays which known file generated a match");
-	ocb.status("-n  - displays known hashes that did not match any input files");
+	ocb.status("-w        - displays which known file generated a match");
+	ocb.status("-n        - displays known hashes that did not match any input files");
 	ocb.status("-a and -A add a single hash to the positive or negative matching set");
-	ocb.status("-b  - prints only the bare name of files; all path information is omitted");
-	ocb.status("-l  - print relative paths for filenames");
-	ocb.status("-t  - print GMT timestamp (ctime)");
-	ocb.status("-iSIZE/-ISIZE - only process files smaller/larger than SIZE");
-	ocb.status("-v  - display version number and exit");
-	ocb.status("-d  - output in DFXML; -u - Escape Unicode; -W FILE - write to FILE.");
+	ocb.status("-b        - prints only the bare name of files; all path information is omitted");
+	ocb.status("-l        - print relative paths for filenames");
+	ocb.status("-t        - print GMT timestamp (ctime)");
+	ocb.status("-i/I <size> - only process files smaller/larger than SIZE");
+	ocb.status("-v        - display version number and exit");
+	ocb.status("-d        - output in DFXML; -u - Escape Unicode; -W FILE - write to FILE.");
 #ifdef HAVE_PTHREAD
-	ocb.status("-jnn run nn threads (default %d)",threadpool::numCPU());
+	ocb.status("-j <num>  - use num threads (default %d)",threadpool::numCPU());
 #else
-	ocb.status("-jnn ignored (compiled without pthreads)");
+	ocb.status("-j <num>  - ignored (compiled without pthreads)");
 #endif	
-	ocb.status("-Z - traige mode;   -h - help;   -hh - full help");
+	ocb.status("-Z - triage mode;   -h - help;   -hh - full help");
     }
     if(usage_count==2){			// -hh
-	ocb.status("-S - Silent mode, but warn on bad hashes");
-	ocb.status("-0 - use a NULL for newline.");
-	ocb.status("-k - print asterisk before filename");
-	ocb.status("-u - escape Unicode");
-	ocb.status("-B - verbose mode; repeat for more verbosity");
-	ocb.status("-C - Macintosh only --- use Common Crypto hash functions");
-	ocb.status("-Fb - I/O mode buffered; -Fu unbuffered; -Fm memory-mapped");
-	ocb.status("-ffilename - take list of files to hash from filename");
-	ocb.status("-o[bcpflsde] - only process certain types of files:");
-	ocb.status("            b=block dev; c=character dev; p=named pipe");
-	ocb.status("            f=regular file; l=symlink; s=socket; d=door e=Windows PE");
-	ocb.status("-Dnn - set debug level to nn");
+	ocb.status("-S        - Silent mode, but warn on bad hashes");
+	ocb.status("-0        - use a NUL (\\0) for newline.");
+	ocb.status("-k        - print asterisk before filename");
+	ocb.status("-u        - escape Unicode characters in filenames");
+	ocb.status("-B        - verbose mode; repeat for more verbosity");
+	ocb.status("-C        - OS X only --- use Common Crypto hash functions");
+	ocb.status("-Fb       - I/O mode buffered; -Fu unbuffered; -Fm memory-mapped");
+	ocb.status("-f <file> - take list of files to hash from filename");
+	ocb.status("-o[bcpflsde] - expert mode. Only process certain types of files:");
+	ocb.status("               b=block dev; c=character dev; p=named pipe");
+	ocb.status("               f=regular file; l=symlink; s=socket; d=door e=Windows PE");
+	ocb.status("-D <num>  - set debug level to nn");
     }
     if(usage_count==3){			// -hhh
 	ocb.status("sizeof(off_t)= %d",sizeof(off_t));
@@ -586,7 +593,7 @@ int state::hashdeep_process_command_line(int argc_, char **argv_)
     bool did_usage = false;
   int i;
   
-  while ((i=getopt(argc_,argv_,"abBc:CdeF:f:o:I:i:MmXxtlk:rsp:wvVhW:0D:uj:")) != -1)  {
+  while ((i=getopt(argc_,argv_,"abc:CdeF:f:o:I:i:MmXxtlk:rsp:wvVhW:0D:uj:")) != -1)  {
     switch (i) {
     case 'a': ocb.primary_function = primary_audit;      break;
     case 'C': opt_enable_mac_cc = true; break;
@@ -628,11 +635,11 @@ int state::hashdeep_process_command_line(int argc_, char **argv_)
       // TODO: Add -t mode to hashdeep
       //    case 't': mode |= mode_timestamp;    break;
 
-    case 'b': ocb.mode_barename=true;     break;
-    case 'l': ocb.opt_relative=true;     break;
-    case 'e': ocb.opt_estimate = true;	    break;
-    case 'r': mode_recursive=true;    break;
-    case 's': ocb.opt_silent = true;	    break;
+    case 'b': ocb.mode_barename=true;   break;
+    case 'l': ocb.opt_relative=true;    break;
+    case 'e': ocb.opt_estimate = true;	break;
+    case 'r': mode_recursive=true;	break;
+    case 's': ocb.opt_silent = true;	break;
       
     case 'p':
 	ocb.piecewise_size = find_block_size(optarg);
@@ -672,12 +679,11 @@ int state::hashdeep_process_command_line(int argc_, char **argv_)
 	}
       break;
       
-    case 'B': /* Intentional Fall-Through */
     case 'v':
-	if(++ocb.opt_verbose > INSANELY_VERBOSE){
-	    ocb.error("User request for insane verbosity denied");
-	}
-	break;
+      ++ocb.opt_verbose;
+      if (ocb.opt_verbose > INSANELY_VERBOSE)
+	ocb.error("User request for insane verbosity denied");
+      break;
       
     case 'V':
       ocb.status("%s", VERSION);
@@ -975,13 +981,8 @@ int state::md5deep_process_command_line(int argc_, char **argv_)
 
     while ((i = getopt(argc_,
 		       argv_,
-		       "A:a:bBcCdeF:f:I:i:M:X:x:m:o:tnwzsSp:rhvV0lkqZW:D:uj:")) != -1) { 
+		       "A:a:bcCdeF:f:I:i:M:X:x:m:o:tnwzsSp:rhvV0lkqZW:D:uj:")) != -1) { 
 	switch (i) {
-	case 'B': /* Intentional Fall-Through */
-	    if(++ocb.opt_verbose > INSANELY_VERBOSE){
-		ocb.error("User request for insane verbosity denied");
-	    }
-	    break;
 	case 'C': opt_enable_mac_cc = true; break;
 	case 'D': opt_debug = atoi(optarg);	break;
 	case 'd': ocb.xml_open(stdout);		break;
@@ -1224,6 +1225,7 @@ int state::main(int _argc,char **_argv)
 #endif
 
 #ifdef HAVE_PTHREAD
+    threadpool::win32_init();			// 
     ocb.opt_threadcount = threadpool::numCPU(); // be sure it's set
 #endif
 
diff --git a/src/main.h b/src/main.h
index fd43d96..ae0360b 100644
--- a/src/main.h
+++ b/src/main.h
@@ -12,7 +12,7 @@
  *
  * It then creates all the C++ classes and structures used.
  *
- * $Id: main.h 612 2012-02-08 15:01:56Z jessekornblum $
+ * $Id: main.h 630 2012-06-05 00:32:45Z jessekornblum $
  */
 
 
@@ -186,6 +186,54 @@ typedef time_t		timestamp_t;
 typedef std::string	filename_t;
 #endif
 
+/**
+ * file_metadata_t contains metadata information about a file.
+ * It also includes a stat call that returns the inode information
+ * and link count even on windows, where the API is different than stat.
+ * Note that we only include information we care about in this program
+ * 
+ * this is in dig.cpp.
+ */
+
+
+/* strangely, we define our own file types */
+typedef enum {
+    stat_regular=0,
+    stat_directory,
+    stat_door,
+    stat_block,
+    stat_character,
+    stat_pipe,
+    stat_socket,
+    stat_symlink,
+    stat_unknown=254
+} file_types;
+
+class file_metadata_t {
+public:
+    static file_types decode_file_type(const struct __stat64 &sb);
+
+    // stat a file, print an error and return -1 if it fails, otherwise return 0
+    static int stat(const filename_t &path,file_metadata_t *m,class display &ocb); 
+    class fileid_t {				      // uniquely defines a file on this system
+    public:
+	fileid_t():dev(0),ino(0){};
+	fileid_t(uint64_t dev_,uint64_t ino_):dev(dev_),ino(ino_){};
+	uint64_t	dev;			      // device number
+	uint64_t	ino;			      // inode number
+    };
+    file_metadata_t():fileid(),nlink(0),size(0),ctime(0),mtime(0),atime(0){};
+    file_metadata_t(fileid_t fileid_,uint64_t nlink_,uint64_t size_,timestamp_t ctime_,timestamp_t mtime_,
+		    timestamp_t atime_):fileid(fileid_),nlink(nlink_),size(size_),ctime(ctime_),mtime(mtime_),atime(atime_){};
+    fileid_t	fileid;
+    uint64_t	nlink;
+    uint64_t	size;
+    timestamp_t ctime;
+    timestamp_t mtime;
+    timestamp_t atime;
+    
+};
+
 /** file_data_t contains information about a file.
  * It can be created by hashing an actual file, or by reading a hash file a file of hashes. 
  * The object is simple so that the built in C++ shallow copy will make a proper copy of it.
@@ -418,6 +466,7 @@ public:;
     std::string		last_enabled_algorithms; // a string with the algorithms that were enabled last
     hashid_t		hash_column[NUM_ALGORITHMS]; // maps a column number to a hashid;
 						     // the order columns appear in the file being loaded.
+    uint8_t   filename_column;  // Column number which should contain the filename
     hashfile_format	identify_format(class display *ocb,const std::string &fn,FILE *handle);
     loadstatus_t	load_hash_file(class display *ocb,const std::string &fn); // not tstring! always ASCII
 
@@ -530,7 +579,7 @@ public:
 	opt_display_hash(false),
 	opt_show_matched(false),
 	opt_iomode(iomode::buffered),	// by default, use buffered
-#ifdef HAVE_PTRHEAD
+#ifdef HAVE_PTHREAD
 	opt_threadcount(threadpool::numCPU()),
 	tp(0),
 #else
@@ -734,17 +783,6 @@ inline std::ostream & operator <<(std::ostream &os,const std::wstring &wstr) {
 
 class state {
 public:;
-    typedef enum {
-	stat_regular=0,
-	stat_directory,
-	stat_door,
-	stat_block,
-	stat_character,
-	stat_pipe,
-	stat_socket,
-	stat_symlink,
-	stat_unknown=254
-    } file_types;
 
  state():mode_recursive(false),	// do we recurse?
       mode_warn_only(false),	// for loading hash files
@@ -863,7 +901,6 @@ public:;
      * If an error is found and ocb is provided, send the error to ocb.
      * If filesize and timestamp are provided, give them.
      */
-    static file_types decode_file_type(const struct __stat64 &sb);
     static file_types file_type(const filename_t &fn,class display *ocb,uint64_t *filesize,
 				timestamp_t *ctime,timestamp_t *mtime,timestamp_t *atime);
 #ifdef _WIN32
diff --git a/src/threadpool.cpp b/src/threadpool.cpp
index aa344c2..bf40bcd 100644
--- a/src/threadpool.cpp
+++ b/src/threadpool.cpp
@@ -2,7 +2,7 @@
  *** THREADING SUPPORT
  ****************************************************************/
 
-// $Id: threadpool.cpp 618 2012-02-10 12:12:38Z jessekornblum $
+// $Id: threadpool.cpp 623 2012-02-26 13:56:12Z xchatty $
 
 #include "main.h"
 
@@ -95,6 +95,20 @@ void ERR(int val,const char *msg)
 }
 
 
+/* Run non-portable pthread win32 startup */
+void threadpool::win32_init()
+{
+#ifdef WIN32
+    static bool initialized = false;
+    if(initialized==false){
+	pthread_win32_process_attach_np();
+	pthread_win32_thread_attach_np();
+	initialized=true;
+    }
+#endif
+}
+
+
 /**
  * Create the thread pool.
  * Each thread has its own feature_recorder_set.
@@ -115,12 +129,6 @@ void ERR(int val,const char *msg)
 
 threadpool::threadpool(int numworkers_)
 {
-#ifdef WIN32
-    /* Run non-portable pthread win32 startup */
-    pthread_win32_process_attach_np();
-    pthread_win32_thread_attach_np();
-#endif
-
     numworkers		= numworkers_;
     freethreads		= numworkers;
     if(pthread_cond_init(&TOMAIN,NULL))   ERR(1,"pthread_cond_init #1 failed");
diff --git a/src/threadpool.h b/src/threadpool.h
index 393b3fa..3966e2d 100644
--- a/src/threadpool.h
+++ b/src/threadpool.h
@@ -47,6 +47,7 @@ public:
 
 class threadpool: public std::vector<class worker *> {
 public:
+    static void		win32_init(); // must be called under win32 to initialize posix threads
     mutex_t		M;			// protects the following variables
     volatile unsigned int numworkers;
     volatile unsigned int freethreads;
diff --git a/src/tiger.c b/src/tiger.c
index 3c96028..2d3a181 100644
--- a/src/tiger.c
+++ b/src/tiger.c
@@ -1,77 +1,55 @@
-
-/* MD5DEEP - tiger.c
+/* tiger.c  -  The TIGER hash function
+ * Copyright (C) 1998, 2001, 2002, 2003, 2010 Free Software Foundation, Inc.
  *
- * This code was adapted from GnuPG and is licensed under the
- * GNU General Public License as published by the Free Software Foundation;
- * either version 2 of the license, or (at your option) any later version.
- * Please see COPYING for the license regarding this file
+ * This file is part of Libgcrypt.
  *
- * Some functions have been changed or removed from the GnuPG version.
- * See comments for details.
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
  *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
-/* $Id: tiger.c 501 2011-09-25 17:12:27Z xchatty $ */
+/* See http://www.cs.technion.ac.il/~biham/Reports/Tiger/  */
 
-//#include "main.h"
+#include "common.h"
 #include "tiger.h"
 
-
-/* Test vectors from the NESSIE Project:
-   Note that the original version of this code included test vectors
-   in big endian format. These test vectors are in little endian format.
-   More of them are available at 
-   http://www.cs.technion.ac.il/~biham/Reports/Tiger/test-vectors-nessie-format.dat
-
-  message="" (empty string)
-  hash=3293AC630C13F0245F92BBB1766E16167A4E58492DDE73F3
-
-  message="a"
-  hash=77BEFBEF2E7EF8AB2EC8F93BF587A7FC613E247F5F247809
-
-  message="abc"
-  hash=2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93
-
-  message="message digest"
-  hash=D981F8CB78201A950DCF3048751E441C517FCA1AA55A29F6
-
-  message="abcdefghijklmnopqrstuvwxyz"
-  hash=1714A472EEE57D30040412BFCC55032A0B11602FF37BEEE9
-
-  message="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
-  hash=0F7BF9A19B9C58F2B7610DF7E84F0AC3A71C631E7B53F78E
-
-  message="A...Za...z0...9"
-  hash=8DCEA680A17583EE502BA38A3C368651890FFBCCDC49A8CC
-
-  message=8 times "1234567890"
-  hash=1C14795529FD9F207A958F84C52F11E887FA0CABDFD91BFD
-
-  message=1 million times "a"
-  hash=6DB0E2729CBEAD93D715C6A7D36302E9B3CEE0D2BC314B41
-*/
-
-
-void hash_init_tiger(void * ctx)
-{
-    tiger_init((TIGER_CONTEXT *)ctx);
-}
-
-void hash_update_tiger(void * ctx, const unsigned char *buf, size_t len)
-{
-  tiger_update((TIGER_CONTEXT *)ctx,buf,(size_t)len);
-}
-
-void hash_final_tiger(void * ctx, unsigned char *sum)
-{
-  tiger_final(sum,(TIGER_CONTEXT *)ctx);
-}
-
-
+// Code copied from libgcrypt, version 1.5.0
+// http://directory.fsf.org/wiki/Libgcrypt
+// http://www.gnupg.org/download/#libgcrypt
+
+// Test vectors for the "Fixed" Tiger algorithm
+// Source: http://www.cs.technion.ac.il/~biham/Reports/Tiger/test-vectors-nessie-format.dat
+// Inserted by Jesse Kornblum
+//
+// Set 1, vector#  0:
+// message="" (empty string)
+// hash=3293AC630C13F0245F92BBB1766E16167A4E58492DDE73F3
+//
+// Set 1, vector#  1:
+// message="a"
+// hash=77BEFBEF2E7EF8AB2EC8F93BF587A7FC613E247F5F247809
+//
+// Set 1, vector#  2:
+// message="abc"
+// hash=2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93
+//
+// Set 1, vector#  3:
+// message="message digest"
+// hash=D981F8CB78201A950DCF3048751E441C517FCA1AA55A29F6
+//
+// Set 1, vector#  4:
+// message="abcdefghijklmnopqrstuvwxyz"
+// hash=1714A472EEE57D30040412BFCC55032A0B11602FF37BEEE9
 
 
 static uint64_t sbox1[256] = {
@@ -596,72 +574,136 @@ static uint64_t sbox4[256] = {
 };
 
 
-// print functions are unnessary and have been removed (jk)
 
+// Inserted code
+// From libgcrypt, g10lib.h
+#define wipememory2(_ptr,_set,_len) do { \
+    volatile char *_vptr=(volatile char *)(_ptr); \
+    size_t _vlen=(_len); \
+    while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
+  } while(0)
+#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
+
+void _gcry_burn_stack(int bytes);
+
+
+// Inserted code
+// From libgcrypt, misc.c
+void
+_gcry_burn_stack (int bytes)
+{
+  char buf[64];
+
+  wipememory (buf, sizeof buf);
+  bytes -= sizeof buf;
+  if (bytes > 0)
+    _gcry_burn_stack (bytes);
+}
+
+
+// libgcrypt, tiger.c
+typedef struct
+{
+  uint64_t  a, b, c;
+  unsigned char buf[64];
+  int  count;
+  uint32_t  nblocks;
+  int  variant;  /* 0 = old code, 1 = fixed code, 2 - TIGER2.  */
+} TIGER_CONTEXT;
+
+
+static void
+do_init (void *context, int variant)
+{
+  TIGER_CONTEXT *hd = (TIGER_CONTEXT *)context;
+
+  hd->a = 0x0123456789abcdefLL;
+  hd->b = 0xfedcba9876543210LL;
+  hd->c = 0xf096a5b4c3b2e187LL;
+  hd->nblocks = 0;
+  hd->count = 0;
+  hd->variant = variant;
+}
+
+static void
+tiger_init (void *context)
+{
+  do_init (context, 0);
+}
+
+static void
+tiger1_init (void *context)
+{
+  do_init (context, 1);
+}
+
+static void
+tiger2_init (void *context)
+{
+  do_init (context, 2);
+}
 
-/* I was getting compiler errors for "conflicting types for 'round'
-   from including math.h, so I renamed this function tiger_round (jk) */
-static void 
+static void
 tiger_round( uint64_t *ra, uint64_t *rb, uint64_t *rc, uint64_t x, int mul )
 {
-    uint64_t a = *ra;
-    uint64_t b = *rb;
-    uint64_t c = *rc;
-
-    c ^= x;
-    a -=   sbox1[  c	    & 0xff ] ^ sbox2[ (c >> 16) & 0xff ]
-	 ^ sbox3[ (c >> 32) & 0xff ] ^ sbox4[ (c >> 48) & 0xff ];
-    b +=   sbox4[ (c >>  8) & 0xff ] ^ sbox3[ (c >> 24) & 0xff ]
-	 ^ sbox2[ (c >> 40) & 0xff ] ^ sbox1[ (c >> 56) & 0xff ];
-    b *= mul;
-
-    *ra = a;
-    *rb = b;
-    *rc = c;
+  uint64_t a = *ra;
+  uint64_t b = *rb;
+  uint64_t c = *rc;
+
+  c ^= x;
+  a -= (  sbox1[  c        & 0xff ] ^ sbox2[ (c >> 16) & 0xff ]
+        ^ sbox3[ (c >> 32) & 0xff ] ^ sbox4[ (c >> 48) & 0xff ]);
+  b += (  sbox4[ (c >>  8) & 0xff ] ^ sbox3[ (c >> 24) & 0xff ]
+        ^ sbox2[ (c >> 40) & 0xff ] ^ sbox1[ (c >> 56) & 0xff ]);
+  b *= mul;
+
+  *ra = a;
+  *rb = b;
+  *rc = c;
 }
 
 
 static void
 pass( uint64_t *ra, uint64_t *rb, uint64_t *rc, uint64_t *x, int mul )
 {
-    uint64_t a = *ra;
-    uint64_t b = *rb;
-    uint64_t c = *rc;
-
-    tiger_round( &a, &b, &c, x[0], mul );
-    tiger_round( &b, &c, &a, x[1], mul );
-    tiger_round( &c, &a, &b, x[2], mul );
-    tiger_round( &a, &b, &c, x[3], mul );
-    tiger_round( &b, &c, &a, x[4], mul );
-    tiger_round( &c, &a, &b, x[5], mul );
-    tiger_round( &a, &b, &c, x[6], mul );
-    tiger_round( &b, &c, &a, x[7], mul );
-
-    *ra = a;
-    *rb = b;
-    *rc = c;
+  uint64_t a = *ra;
+  uint64_t b = *rb;
+  uint64_t c = *rc;
+
+  tiger_round( &a, &b, &c, x[0], mul );
+  tiger_round( &b, &c, &a, x[1], mul );
+  tiger_round( &c, &a, &b, x[2], mul );
+  tiger_round( &a, &b, &c, x[3], mul );
+  tiger_round( &b, &c, &a, x[4], mul );
+  tiger_round( &c, &a, &b, x[5], mul );
+  tiger_round( &a, &b, &c, x[6], mul );
+  tiger_round( &b, &c, &a, x[7], mul );
+
+  *ra = a;
+  *rb = b;
+  *rc = c;
 }
 
 
 static void
 key_schedule( uint64_t *x )
 {
-    x[0] -= x[7] ^ 0xa5a5a5a5a5a5a5a5LL;
-    x[1] ^= x[0];
-    x[2] += x[1];
-    x[3] -= x[2] ^ ((~x[1]) << 19 );
-    x[4] ^= x[3];
-    x[5] += x[4];
-    x[6] -= x[5] ^ ((~x[4]) >> 23 );
-    x[7] ^= x[6];
-    x[0] += x[7];
-    x[1] -= x[0] ^ ((~x[7]) << 19 );
-    x[2] ^= x[1];
-    x[3] += x[2];
-    x[4] -= x[3] ^ ((~x[2]) >> 23 );
-    x[5] ^= x[4];
-    x[6] += x[5];
-    x[7] -= x[6] ^ 0x0123456789abcdefLL;
+  x[0] -= x[7] ^ 0xa5a5a5a5a5a5a5a5LL;
+  x[1] ^= x[0];
+  x[2] += x[1];
+  x[3] -= x[2] ^ ((~x[1]) << 19 );
+  x[4] ^= x[3];
+  x[5] += x[4];
+  x[6] -= x[5] ^ ((~x[4]) >> 23 );
+  x[7] ^= x[6];
+  x[0] += x[7];
+  x[1] -= x[0] ^ ((~x[7]) << 19 );
+  x[2] ^= x[1];
+  x[3] += x[2];
+  x[4] -= x[3] ^ ((~x[2]) >> 23 );
+  x[5] ^= x[4];
+  x[6] += x[5];
+  x[7] -= x[6] ^ 0x0123456789abcdefLL;
 }
 
 
@@ -669,187 +711,214 @@ key_schedule( uint64_t *x )
  * Transform the message DATA which consists of 512 bytes (8 words)
  */
 static void
-transform( TIGER_CONTEXT *hd, const unsigned char *data )
+transform ( TIGER_CONTEXT *hd, const unsigned char *data )
 {
-    uint64_t a,b,c,aa,bb,cc;
-    uint64_t x[8];
-  #ifdef WORDS_BIGENDIAN
-    #define MKWORD(d,n) \
+  uint64_t a,b,c,aa,bb,cc;
+  uint64_t x[8];
+#ifdef WORDS_BIGENDIAN
+#define MKWORD(d,n) \
 		(  ((uint64_t)(d)[8*(n)+7]) << 56 | ((uint64_t)(d)[8*(n)+6]) << 48  \
 		 | ((uint64_t)(d)[8*(n)+5]) << 40 | ((uint64_t)(d)[8*(n)+4]) << 32  \
 		 | ((uint64_t)(d)[8*(n)+3]) << 24 | ((uint64_t)(d)[8*(n)+2]) << 16  \
 		 | ((uint64_t)(d)[8*(n)+1]) << 8  | ((uint64_t)(d)[8*(n)	])	 )
-    x[0] = MKWORD(data, 0);
-    x[1] = MKWORD(data, 1);
-    x[2] = MKWORD(data, 2);
-    x[3] = MKWORD(data, 3);
-    x[4] = MKWORD(data, 4);
-    x[5] = MKWORD(data, 5);
-    x[6] = MKWORD(data, 6);
-    x[7] = MKWORD(data, 7);
-    #undef MKWORD
-  #else
-    memcpy( &x[0], data, 64 );
-  #endif
-
-    /* save */
-    a = aa = hd->a;
-    b = bb = hd->b;
-    c = cc = hd->c;
-
-    // print functions have been removed (jk)
-    pass( &a, &b, &c, x, 5);
-    key_schedule( x );
-    pass( &c, &a, &b, x, 7);
-    key_schedule( x );
-    pass( &b, &c, &a, x, 9);
-
-    /* feedforward */
-    a ^= aa;
-    b -= bb;
-    c += cc;
-    /* store */
-    hd->a = a;
-    hd->b = b;
-    hd->c = c;
+  x[0] = MKWORD(data, 0);
+  x[1] = MKWORD(data, 1);
+  x[2] = MKWORD(data, 2);
+  x[3] = MKWORD(data, 3);
+  x[4] = MKWORD(data, 4);
+  x[5] = MKWORD(data, 5);
+  x[6] = MKWORD(data, 6);
+  x[7] = MKWORD(data, 7);
+#undef MKWORD
+#else
+  memcpy( &x[0], data, 64 );
+#endif
+
+  /* save */
+  a = aa = hd->a;
+  b = bb = hd->b;
+  c = cc = hd->c;
+
+  pass( &a, &b, &c, x, 5);
+  key_schedule( x );
+  pass( &c, &a, &b, x, 7);
+  key_schedule( x );
+  pass( &b, &c, &a, x, 9);
+
+  /* feedforward */
+  a ^= aa;
+  b -= bb;
+  c += cc;
+  /* store */
+  hd->a = a;
+  hd->b = b;
+  hd->c = c;
 }
 
-void
-tiger_init( TIGER_CONTEXT *hd )
-{
-    hd->a = 0x0123456789abcdefLL;
-    hd->b = 0xfedcba9876543210LL;
-    hd->c = 0xf096a5b4c3b2e187LL;
-    hd->nblocks = 0;
-    hd->count = 0;
-}
+
 
 /* Update the message digest with the contents
- * of INBUF with length INLEN. */
-void
-tiger_update(TIGER_CONTEXT *hd, const unsigned char *inbuf, size_t inlen)
+ * of INBUF with length INLEN.
+ */
+static void
+tiger_write ( void *context, const void *inbuf_arg, size_t inlen)
 {
-    if( hd->count == 64 ) { /* flush the buffer */
-	transform( hd, hd->buf );
-	hd->count = 0;
-	hd->nblocks++;
-    }
-    if( !inbuf )
-	return;
-    if( hd->count ) {
-	for( ; inlen && hd->count < 64; inlen-- )
-	    hd->buf[hd->count++] = *inbuf++;
-	tiger_update( hd, NULL, 0 );
-	if( !inlen ) {
-	  return;
-	}
+  const unsigned char *inbuf = (const unsigned char *)inbuf_arg;
+  TIGER_CONTEXT *hd = (TIGER_CONTEXT *)context;
 
+  if( hd->count == 64) /* flush the buffer */
+    {
+      transform( hd, hd->buf );
+      _gcry_burn_stack (21*8+11*sizeof(void*));
+      hd->count = 0;
+      hd->nblocks++;
+    }
+  if( !inbuf )
+    return;
+  if( hd->count )
+    {
+      for( ; inlen && hd->count < 64; inlen-- )
+        hd->buf[hd->count++] = *inbuf++;
+      tiger_write( hd, NULL, 0 );
+      if( !inlen )
+        return;
     }
 
-    while( inlen >= 64 ) {
+  while( inlen >= 64 )
+    {
       transform( hd, inbuf );
       hd->count = 0;
       hd->nblocks++;
       inlen -= 64;
       inbuf += 64;
     }
-    for( ; inlen && hd->count < 64; inlen-- )
-	hd->buf[hd->count++] = *inbuf++;
+  _gcry_burn_stack (21*8+11*sizeof(void*));
+  for( ; inlen && hd->count < 64; inlen-- )
+    hd->buf[hd->count++] = *inbuf++;
 }
 
-/* The routine terminates the computation */
-void
-tiger_final(unsigned char hash[24], TIGER_CONTEXT *hd)
+
+
+/* The routine terminates the computation
+ */
+static void
+tiger_final( void *context )
 {
-    uint32_t t, msb, lsb;
-    unsigned char *p;
-    int i, j;
-
-    tiger_update(hd, NULL, 0); /* flush */;
-
-    msb = 0;
-    t = hd->nblocks;
-    if( (lsb = t << 6) < t ) /* multiply by 64 to make a byte count */
-	msb++;
-    msb += t >> 26;
-    t = lsb;
-    if( (lsb = t + hd->count) < t ) /* add the count */
-	msb++;
-    t = lsb;
-    if( (lsb = t << 3) < t ) /* multiply by 8 to make a bit count */
-	msb++;
-    msb += t >> 29;
-
-    if( hd->count < 56 ) { /* enough room */
-	hd->buf[hd->count++] = 0x01; /* pad */
-	while( hd->count < 56 )
-	    hd->buf[hd->count++] = 0;  /* pad */
+  TIGER_CONTEXT *hd = (TIGER_CONTEXT *)context;
+  uint32_t t, msb, lsb;
+  unsigned char *p;
+  unsigned char pad = hd->variant == 2? 0x80 : 0x01;
+
+  tiger_write(hd, NULL, 0); /* flush */;
+
+  t = hd->nblocks;
+  /* multiply by 64 to make a byte count */
+  lsb = t << 6;
+  msb = t >> 26;
+  /* add the count */
+  t = lsb;
+  if( (lsb += hd->count) < t )
+    msb++;
+  /* multiply by 8 to make a bit count */
+  t = lsb;
+  lsb <<= 3;
+  msb <<= 3;
+  msb |= t >> 29;
+
+  if( hd->count < 56 )  /* enough room */
+    {
+      hd->buf[hd->count++] = pad;
+      while( hd->count < 56 )
+        hd->buf[hd->count++] = 0;  /* pad */
+    }
+  else  /* need one extra block */
+    {
+      hd->buf[hd->count++] = pad; /* pad character */
+      while( hd->count < 64 )
+        hd->buf[hd->count++] = 0;
+      tiger_write(hd, NULL, 0);  /* flush */;
+      memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
+    }
+  /* append the 64 bit count */
+  hd->buf[56] = lsb	   ;
+  hd->buf[57] = lsb >>  8;
+  hd->buf[58] = lsb >> 16;
+  hd->buf[59] = lsb >> 24;
+  hd->buf[60] = msb	   ;
+  hd->buf[61] = msb >>  8;
+  hd->buf[62] = msb >> 16;
+  hd->buf[63] = msb >> 24;
+  transform( hd, hd->buf );
+  _gcry_burn_stack (21*8+11*sizeof(void*));
+
+  p = hd->buf;
+#ifdef WORDS_BIGENDIAN
+#define X(a) do { *(uint64_t*)p = hd->a ; p += 8; } while(0)
+#else /* little endian */
+#define X(a) do { *p++ = hd->a >> 56; *p++ = hd->a >> 48; \
+	          *p++ = hd->a >> 40; *p++ = hd->a >> 32; \
+	          *p++ = hd->a >> 24; *p++ = hd->a >> 16; \
+	          *p++ = hd->a >>  8; *p++ = hd->a;       } while(0)
+#endif
+#define Y(a) do { *p++ = hd->a      ; *p++ = hd->a >> 8;  \
+	          *p++ = hd->a >> 16; *p++ = hd->a >> 24; \
+	          *p++ = hd->a >> 32; *p++ = hd->a >> 40; \
+	          *p++ = hd->a >> 48; *p++ = hd->a >> 56; } while(0)
+  if (hd->variant == 0)
+    {
+      X(a);
+      X(b);
+      X(c);
     }
-    else { /* need one extra block */
-	hd->buf[hd->count++] = 0x01; /* pad character */
-	while( hd->count < 64 )
-	    hd->buf[hd->count++] = 0;
-	tiger_update(hd, NULL, 0);  /* flush */;
-	memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
+  else
+    {
+      Y(a);
+      Y(b);
+      Y(c);
     }
-    /* append the 64 bit count */
-    hd->buf[56] = lsb	   ;
-    hd->buf[57] = lsb >>  8;
-    hd->buf[58] = lsb >> 16;
-    hd->buf[59] = lsb >> 24;
-    hd->buf[60] = msb	   ;
-    hd->buf[61] = msb >>  8;
-    hd->buf[62] = msb >> 16;
-    hd->buf[63] = msb >> 24;
-    transform( hd, hd->buf );
-
-    p = hd->buf;
-  #ifdef WORDS_BIGENDIAN
-    #define X(a) do { *(uint64_t *)p = hd->a ; p += 8; } while(0)
-    // Original code - modified by jk to deal with gcc changes
-    //    #define X(a) do { *(u64*)p = hd->##a ; p += 8; } while(0)
-  #else /* little endian */
-    #define X(a) do { *p++ = hd->a >> 56; *p++ = hd->a >> 48; \
-		      *p++ = hd->a >> 40; *p++ = hd->a >> 32; \
-		      *p++ = hd->a >> 24; *p++ = hd->a >> 16; \
-		      *p++ = hd->a >>  8; *p++ = hd->a; } while(0)
-
-    /* Original code - modified by jk to deal with gcc changes
-    #define X(a) do { *p++ = hd->##a >> 56; *p++ = hd->##a >> 48; \
-		      *p++ = hd->##a >> 40; *p++ = hd->##a >> 32; \
-		      *p++ = hd->##a >> 24; *p++ = hd->##a >> 16; \
-		      *p++ = hd->##a >>  8; *p++ = hd->##a; } while(0)
-		      */
-
-  #endif
-    X(a);
-    X(b);
-    X(c);
-  #undef X
-
-    /* unpack the hash */
-    // Modified by jk to produce little endian output like MD5 or SHA-1
-    j=0;
-    for (i=0; i<8; i++)
-      hash[j++] = (hd->a >> 8*i) & 0xff;
-    j=8;
-    for (i=0; i<8; i++)
-      hash[j++] = (hd->b >> 8*i) & 0xff;
-    j=16;
-    for (i=0; i<8; i++)
-      hash[j++] = (hd->c >> 8*i) & 0xff;
-
-
-    /* Original code, produces output in big endian     
-    j=7;
-    for (i=0; i<8; i++)
-      hash[j--] = (hd->a >> 8*i) & 0xff;
-    j=15;
-    for (i=0; i<8; i++)
-      hash[j--] = (hd->b >> 8*i) & 0xff;
-    j=23;
-    for (i=0; i<8; i++)
-      hash[j--] = (hd->c >> 8*i) & 0xff;
-    */
+#undef X
+#undef Y
 }
 
+static unsigned char *
+tiger_read( void *context )
+{
+  TIGER_CONTEXT *hd = (TIGER_CONTEXT *)context;
+
+  return hd->buf;
+}
+
+
+
+
+
+// ------------------------------------------------------------------
+// End Libgcrypt code
+// ------------------------------------------------------------------
+
+void hash_init_tiger(void * ctx)
+{
+  // Variant 0, Unknown
+  // tiger_init(ctx)
+
+  // Variant 1, Tiger
+  tiger1_init(ctx);
+
+  // Variant 2, The Tiger2 Hash
+  // http://www.cs.technion.ac.il/~biham/Reports/Tiger/tiger2-test-vectors-nessie-format.dat
+  //  tiger2_init(ctx);
+}
+
+
+void hash_update_tiger(void * ctx, const unsigned char  *buf, size_t len)
+{
+  tiger_write(ctx,buf,len);
+}
+
+
+void hash_final_tiger(void * ctx, unsigned char *sum)
+{
+  tiger_final(ctx);
+  unsigned char * tmp = tiger_read(ctx);
+  memcpy(sum,tmp,64);
+}
diff --git a/src/tiger.h b/src/tiger.h
index 854cc14..75f7fb1 100644
--- a/src/tiger.h
+++ b/src/tiger.h
@@ -12,29 +12,14 @@
  *
  */
 
-/* $Id: tiger.h 501 2011-09-25 17:12:27Z xchatty $ */
+/* $Id: tiger.h 636 2012-06-09 13:16:59Z jessekornblum $ */
 
 #ifndef __TIGER_H
 #define __TIGER_H
 
-#include "common.h"
 
-__BEGIN_DECLS
-
-
-#define TIGER_BLOCKSIZE 64
-#define TIGER_HASHSIZE 24
 
-typedef struct {
-    uint64_t  a, b, c;
-    unsigned char buf[64];
-    int  count;
-    uint32_t  nblocks;
-} TIGER_CONTEXT;
-
-extern void tiger_init(TIGER_CONTEXT *hd);
-extern void tiger_update(TIGER_CONTEXT *hd, const unsigned char *inbuf, size_t inlen);
-extern void tiger_final(unsigned char hash[24], TIGER_CONTEXT *hd);
+__BEGIN_DECLS
 
 void hash_init_tiger(void * ctx);
 void hash_update_tiger(void * ctx, const unsigned char  *buf, size_t len);

-- 
debian-forensics/md5deep



More information about the forensics-changes mailing list