diff --git a/.gitignore b/.gitignore
index 65e597955bd834de82e3ed34dd1ce2438f070ad0..6dedcd0144a08e36bffd5295c4cd79c39d057a68 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,128 +1,139 @@
-# NetBeans user-specific settings
-/bindings/java/nbproject/private/
-
-# Bindings dependecies and build folders
-/bindings/java/lib/
-/bindings/java/build/
-/bindings/java/dist
-/bindings/java/test/output/results
-/bindings/java/test/output/gold/dummy
-/bindings/java/test/output/gold/*_BU.txt
-/bindings/java/test/output/gold/*_CPP.txt
-/bindings/java/test/output/gold/*_CPP_SRT.txt
-/bindings/java/test/input
-/bindings/java/nbproject/genfiles.properties
-/bindings/java/nbproject/nbjdk.properties
-/bindings/java/nbproject/jdk.xml
-/bindings/java/nbproject/nbjdk.xml
-/bindings/java/libts*
-*~
-*.class
-/bindings/java/build/
-/bindings/java/dist/
-/bindings/java/nbproject/*
-!/bindings/java/nbproject/project.xml
-!/bindings/java/nbproject/project.properties
-
-# Windows build folders
-/win32/Debug_NoLibs/
-/win32/*/Debug_NoLibs/
-/win32/Debug/
-/win32/*/Debug/
-/win32/Release/
-/win32/*/Release/
-/win32/*/*.user
-win32/ipch
-win32/tsk-win.opensdf
-framework/msvcpp/framework/Debug/
-framework/msvcpp/framework/Release/
-framework/msvcpp/*/*.user
-framework/msvcpp/*/Debug/
-framework/msvcpp/*/Release/
-framework/msvcpp/BuildLog.txt
-framework/msvcpp/*/ipch
-framework/runtime/
-framework/SampleConfig/to_install/
-
-# IntelliSense data
-/win32/*.ncb
-/win32/*.sdf
-framework/msvcpp/framework/*.ncb
-framework/msvcpp/framework/*sdf
-
-# Visual Studio user options
-/win32/tsk-win.suo
-framework/msvcpp/framework/*.suo
-*.sln.cache
-
-# Make crud
-*.o
-*.lo
-*.la
-*.jar
-Makefile
-.deps
-.libs
-
-#javadoc generated
-/bindings/java/javadoc
-
-# Files generated by running configure
-*.in
-stamp-h1
-tsk/tsk_config.h
-tsk/tsk_incs.h
-tools/fstools/blkcalc
-aclocal.m4
-autom4te.cache
-config.log
-config.status
-configure
-libtool
-m4/libtool.m4
-m4/lt*.m4
-config/*
-
-
-# Executables
-samples/callback_cpp_style
-samples/callback_style
-samples/posix_cpp_style
-samples/posix_style
-tests/fs_attrlist_apis
-tests/fs_fname_apis
-tests/fs_thread_test
-tests/read_apis
-tools/autotools/tsk_comparedir
-tools/autotools/tsk_gettimes
-tools/autotools/tsk_loaddb
-tools/autotools/tsk_recover
-tools/fiwalk/plugins/jpeg_extract
-tools/fiwalk/src/fiwalk
-tools/fiwalk/src/test_arff
-tools/fstools/blkcat
-tools/fstools/blkls
-tools/fstools/blkstat
-tools/fstools/fcat
-tools/fstools/ffind
-tools/fstools/fls
-tools/fstools/fsstat
-tools/fstools/icat
-tools/fstools/ifind
-tools/fstools/ils
-tools/fstools/istat
-tools/fstools/jcat
-tools/fstools/jls
-tools/hashtools/hfind
-tools/imgtools/img_cat
-tools/imgtools/img_stat
-tools/sorter/sorter
-tools/srchtools/sigfind
-tools/srchtools/srch_strings
-tools/timeline/mactime
-tools/vstools/mmcat
-tools/vstools/mmls
-tools/vstools/mmstat
-
-# EMACS backup files
-*~
+# NetBeans user-specific settings
+/bindings/java/nbproject/private/
+
+# Bindings dependecies and build folders
+/bindings/java/lib/
+/bindings/java/build/
+/bindings/java/dist
+/bindings/java/test/output/results
+/bindings/java/test/output/gold/dummy
+/bindings/java/test/output/gold/*_BU.txt
+/bindings/java/test/output/gold/*_CPP.txt
+/bindings/java/test/output/gold/*_CPP_SRT.txt
+/bindings/java/test/input
+/bindings/java/nbproject/genfiles.properties
+/bindings/java/nbproject/nbjdk.properties
+/bindings/java/nbproject/jdk.xml
+/bindings/java/nbproject/nbjdk.xml
+/bindings/java/libts*
+*~
+*.class
+/bindings/java/build/
+/bindings/java/dist/
+/bindings/java/nbproject/*
+!/bindings/java/nbproject/project.xml
+!/bindings/java/nbproject/project.properties
+
+# Windows build folders
+/win32/Debug_NoLibs/
+/win32/*/Debug_NoLibs/
+/win32/Debug/
+/win32/*/Debug/
+/win32/Release/
+/win32/*/Release/
+/win32/*/*.user
+win32/ipch
+win32/BuildErrors.txt
+framework/msvcpp/framework/Debug/
+framework/msvcpp/framework/Release/
+framework/msvcpp/*/*.user
+framework/msvcpp/*/Debug/
+framework/msvcpp/*/Release/
+framework/msvcpp/BuildLog.txt
+framework/msvcpp/*/ipch
+framework/runtime/
+framework/SampleConfig/to_install/
+framework/modules/*/win32/Debug/
+framework/modules/*/win32/Release/
+framework/modules/*/win32/*.user
+framework/modules/c_InterestingFilesModule/tsk
+
+# Release files
+release/sleuthkit-*
+
+# IntelliSense data
+/win32/*.ncb
+/win32/*.sdf
+framework/msvcpp/framework/*.ncb
+framework/msvcpp/framework/*sdf
+
+# Visual Studio user options
+/win32/tsk-win.suo
+framework/msvcpp/framework/*.suo
+*.sln.cache
+
+# Make crud
+*.o
+*.lo
+*.la
+*.jar
+Makefile
+.deps
+.libs
+
+#javadoc generated
+/bindings/java/javadoc
+
+# Files generated by running configure
+*.in
+stamp-h1
+tsk/tsk_config.h
+tsk/tsk_incs.h
+tools/fstools/blkcalc
+aclocal.m4
+autom4te.cache
+config.log
+config.status
+configure
+libtool
+m4/libtool.m4
+m4/lt*.m4
+config/*
+
+
+# Executables
+samples/callback_cpp_style
+samples/callback_style
+samples/posix_cpp_style
+samples/posix_style
+samples/*.exe
+tests/fs_attrlist_apis
+tests/fs_fname_apis
+tests/fs_thread_test
+tests/read_apis
+tests/*.exe
+tools/autotools/tsk_comparedir
+tools/autotools/tsk_gettimes
+tools/autotools/tsk_loaddb
+tools/autotools/tsk_recover
+tools/fiwalk/plugins/jpeg_extract
+tools/fiwalk/src/fiwalk
+tools/fiwalk/src/test_arff
+tools/fstools/blkcat
+tools/fstools/blkls
+tools/fstools/blkstat
+tools/fstools/fcat
+tools/fstools/ffind
+tools/fstools/fls
+tools/fstools/fsstat
+tools/fstools/icat
+tools/fstools/ifind
+tools/fstools/ils
+tools/fstools/istat
+tools/fstools/jcat
+tools/fstools/jls
+tools/hashtools/hfind
+tools/imgtools/img_cat
+tools/imgtools/img_stat
+tools/sorter/sorter
+tools/srchtools/sigfind
+tools/srchtools/srch_strings
+tools/timeline/mactime
+tools/vstools/mmcat
+tools/vstools/mmls
+tools/vstools/mmstat
+tools/*/*.exe
+tools/*/*/*.exe
+
+# EMACS backup files
+*~
\ No newline at end of file
diff --git a/Makefile.am b/Makefile.am
index a3f2f2c1e6655249867b8f8801083069399815ac..33390d34bbf3ed82f0ef5f3d0cd8ef71943d311b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -61,10 +61,14 @@ ACLOCAL_AMFLAGS = -I m4
 if CPPUNIT
   UNIT_TESTS=unit_tests
 endif
+
 if X_JNI
-  JNI=bindings/java/jni
+  JAVA_BINDINGS=bindings/java/jni bindings/java
+else   
+  JAVA_BINDINGS=
 endif
-SUBDIRS = tsk tools tests samples man $(UNIT_TESTS) $(JNI) 
+
+SUBDIRS = tsk tools tests samples man $(UNIT_TESTS) $(JAVA_BINDINGS) 
 
 nobase_include_HEADERS = tsk/libtsk.h tsk/tsk_incs.h \
     tsk/base/tsk_base.h tsk/base/tsk_os.h \
diff --git a/bindings/java/Makefile.am b/bindings/java/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..fa70d5ca8236a1b6e1c426022d1b5c7dbfd5db9d
--- /dev/null
+++ b/bindings/java/Makefile.am
@@ -0,0 +1,24 @@
+Z_PATH=@Z_PATH@
+EWF_PATH=@EWF_PATH@
+ANT_PROPS=
+
+if X_ZLIB
+  ANT_PROPS+=-Dlib.z.path=$(Z_PATH)
+endif
+
+if X_LIBEWF
+  ANT_PROPS+=-Dlib.ewf.path=$(EWF_PATH)
+endif
+
+tsk_jar = $(top_builddir)/bindings/java/dist/Tsk_DataModel.jar
+jardir = $(prefix)/share/java
+jar_DATA = $(tsk_jar)
+
+
+$(tsk_jar): 
+	ant dist $(ANT_PROPS) 
+
+CLEANFILES = $(tsk_jar)
+
+clean-local:
+	ant clean
diff --git a/bindings/java/build-unix.xml b/bindings/java/build-unix.xml
index f1451406e997aa20fa597b9ae4fc8433ead1f7ac..81edd272efaf026818a45c2597e07c798e7624e0 100644
--- a/bindings/java/build-unix.xml
+++ b/bindings/java/build-unix.xml
@@ -30,6 +30,9 @@
         <available file="./jni/.libs/libtsk_jni.so" property="tsk_so.present"/>
 		<available file="./jni/.libs/libtsk_jni.a" property="present"/>
 		<fail unless="present" message="Run make install on The Sleuthkit."/>
+   	<!-- Default location to find zlib and libewf. Overwritten by properties in makefile -->	
+	<property name="lib.z.path" value="/usr/lib"/>
+	<property name="lib.ewf.path" value="/usr/local/lib"/>
     </target>
 
     <!-- OS X -->
@@ -42,16 +45,16 @@
         <property environment="env"/>
 		<property name="jni.dylib" location="${basedir}/jni/.libs/libtsk_jni.dylib" />
 		<property name="jni.jnilib" value="libtsk_jni.jnilib" />
-		<property name="zlib.jni" location="/usr/lib/libz.dylib"/>
-		<property name="libewf.jni" location="/usr/local/lib/libewf.dylib"/>
+		<property name="zlib.jni" location="${lib.z.path}/libz.dylib"/>
+		<property name="libewf.jni" location="${lib.ewf.path}/libewf.dylib"/>
 		<!-- x86_64 -->
         <copy file="${jni.dylib}" tofile="${x86_64}/mac/${jni.jnilib}"/>
 		<copy file="${zlib.jni}" tofile="${x86_64}/mac/zlib.dylib"/>
 		<copy file="${libewf.jni}" tofile="${x86_64}/mac/libewf.dylib"/>
 		<!-- amd64 -->
 		<copy file="${jni.dylib}" tofile="${amd64}/mac/${jni.jnilib}"/>
-		<copy file="${zlib.jni}" tofile="${x86_64}/mac/zlib.dylib"/>
-		<copy file="${libewf.jni}" tofile="${x86_64}/mac/libewf.dylib"/>
+		<copy file="${zlib.jni}" tofile="${amd64}/mac/zlib.dylib"/>
+		<copy file="${libewf.jni}" tofile="${amd64}/mac/libewf.dylib"/>
     </target>
 
     <!-- Non-OS X -->
@@ -63,18 +66,32 @@
 	<target name="copyLinuxLibs" depends="testTSKLibs" if="tsk_so.present">
 		<property environment="env"/>
 		<property name="jni.so" location="${basedir}/jni/.libs/libtsk_jni.so" />
+		<property name="zlib.so" location="${lib.z.path}/libz.so"/>
+		<property name="libewf.so" location="${lib.ewf.path}/libewf.so"/>
 		<!-- x86_64 -->
 		<copy file="${jni.so}" tofile="${x86_64}/linux/libtsk_jni.so"/>
+		<copy file="${zlib.so}" tofile="${x86_64}/linux/libz.so"/>
+		<copy file="${libewf.so}" tofile="${x86_64}/linux/libewf.so"/>
 		<!-- amd64 -->
 		<copy file="${jni.so}" tofile="${amd64}/linux/libtsk_jni.so"/>
+		<copy file="${zlib.so}" tofile="${amd64}/linux/libz.so"/>
+		<copy file="${libewf.so}" tofile="${amd64}/linux/libewf.so"/>
 		<!-- x86 -->
 		<copy file="${jni.so}" tofile="${x86}/linux/libtsk_jni.so"/>
+		<copy file="${zlib.so}" tofile="${x86}/linux/libz.so"/>
+		<copy file="${libewf.so}" tofile="${x86}/linux/libewf.so"/>
 		<!-- i386 -->
 		<copy file="${jni.so}" tofile="${i386}/linux/libtsk_jni.so"/>
+		<copy file="${zlib.so}" tofile="${i386}/linux/libz.so"/>
+		<copy file="${libewf.so}" tofile="${i386}/linux/libewf.so"/>
 		<!-- i586 -->
 		<copy file="${jni.so}" tofile="${i586}/linux/libtsk_jni.so"/>
+		<copy file="${zlib.so}" tofile="${i586}/linux/libz.so"/>
+		<copy file="${libewf.so}" tofile="${i586}/linux/libewf.so"/>
 		<!-- i686 -->
 		<copy file="${jni.so}" tofile="${i686}/linux/libtsk_jni.so"/>
+		<copy file="${zlib.so}" tofile="${i686}/linux/libz.so"/>
+		<copy file="${libewf.so}" tofile="${i686}/linux/libewf.so"/>
 	</target>
 
 	<target name="copyLibs" depends="copyLinuxLibs,copyMacLibs" />
diff --git a/bindings/java/src/org/sleuthkit/datamodel/LibraryUtils.java b/bindings/java/src/org/sleuthkit/datamodel/LibraryUtils.java
index dd7e506dfec352291f7cbccc0c340a4988a84831..d56ae1b52309e6d3ebd60d6c1baddf6627de180b 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/LibraryUtils.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/LibraryUtils.java
@@ -77,34 +77,40 @@ public static boolean loadAuxilliaryLibs() {
         if (LibraryUtils.isWindows()) {
             loaded = LibraryUtils.loadCRTLibs();
 		}
-		
-		if (! LibraryUtils.isLinux()) {
-			
-			for(LibraryUtils.Lib lib : LibraryUtils.getLibs()) {
-				loaded = LibraryUtils.loadLibFromJar(lib);
-				if (!loaded) {
-					System.out.println("SleuthkitJNI: failed to load " + lib.getLibName());
-				} else {
-					System.out.println("SleuthkitJNI: loaded " + lib.getLibName());
-				}
+
+		// Always try to load from jar first.
+		for(Lib lib : LibraryUtils.getLibs()) {
+			// Always try to load from jar first.
+			loaded = LibraryUtils.loadLibFromJar(lib);
+			if (!loaded) {
+				// if that fails, try to load from system
+				loaded = loadLibFromSystem(lib);
 			}
-		} else {
-			System.out.println("In unix path.");
-			// Unix platform
-			for (Lib lib : LibraryUtils.getLibs()) {
-				try {
-					System.out.println("Lib name: " + lib.getUnixName());
-					System.loadLibrary(lib.getUnixName());
-					System.out.println("SleuthkitJNI: loaded " + lib.getLibName());
-				} catch (UnsatisfiedLinkError e) {
-					loaded = false;
-					System.out.println("SleuthkitJNI: failed to load " + lib.getLibName());
-				}
+			if (!loaded) {
+				System.out.println("SleuthkitJNI: failed to load " + lib.getLibName());
+			} else {
+				System.out.println("SleuthkitJNI: loaded " + lib.getLibName());
 			}
 		}
 		return loaded;
 	}
 	
+	/**
+	 * Try to load the given Library from the System path.
+	 * 
+	 * @param lib
+	 * @return 
+	 */
+	private static boolean loadLibFromSystem(Lib lib) {
+		String libName = (isWindows() ? lib.getLibName() : lib.getUnixName());
+		try {
+			System.loadLibrary(libName);
+		} catch (UnsatisfiedLinkError e) {
+			return false;
+		}
+		return true;
+	}
+	
 	/**
 	 * Load the Sleuthkit JNI.
 	 * 
@@ -167,6 +173,8 @@ private static String getPlatform() {
 			os = "win";
 		} else if(LibraryUtils.isMac()) {
 			os = "mac";
+		} else if(LibraryUtils.isLinux()) {
+			os = "linux";
 		}
 		// os.arch represents the architecture of the JVM, not the os
 		String arch = System.getProperty("os.arch");
@@ -232,7 +240,7 @@ private static boolean loadLibFromJar(Lib library) {
 		
 		// copy library to temp folder and load it
 		try {
-			java.io.File libTemp = new java.io.File(System.getProperty("java.io.tmpdir") + libName + libExt);
+			java.io.File libTemp = new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + libName + libExt);
 
 			if(libTemp.exists()) {
 				// Delete old file
diff --git a/bindings/java/src/org/sleuthkit/datamodel/TskData.java b/bindings/java/src/org/sleuthkit/datamodel/TskData.java
index 971e3de0682dc46e5a307f59e6d62150c2c5bd14..7c214dbf50a6f428882035d7b28377bfac4d6bb4 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/TskData.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/TskData.java
@@ -413,8 +413,8 @@ public enum TSK_FS_TYPE_ENUM {
         TSK_FS_TYPE_HFS (0x00001000),   ///< HFS file system
         TSK_FS_TYPE_HFS_DETECT (0x00001000),    ///< HFS auto detection
         TSK_FS_TYPE_EXT4 (0x00002000),  ///< Ext4 file system
-        TSK_FS_TYPE_YAFFS2(0x00003000),  ///< YAFFS2 file system
-        TSK_FS_TYPE_YAFFS2_DETECT(0x00003000),   ///< YAFFS2 auto detection
+        TSK_FS_TYPE_YAFFS2(0x00004000),  ///< YAFFS2 file system
+        TSK_FS_TYPE_YAFFS2_DETECT(0x00004000),   ///< YAFFS2 auto detection
         TSK_FS_TYPE_UNSUPP (0xffffffff);        ///< Unsupported file system
 		
 		private int value;
diff --git a/configure.ac b/configure.ac
index 64ba753c7ff04a52c939b01d1913632ad6c06531..f1d6d10d26ca73f50215d3beb1ff70eb8c576668 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11,7 +11,8 @@ m4_include([m4/cppunit.m4])
 m4_include([m4/ax_jni_include_dir.m4])
 m4_include([m4/ac_prog_javac_works.m4])
 m4_include([m4/ac_prog_javac.m4])
-
+m4_include([m4/ac_prog_java_works.m4])
+m4_include([m4/ac_prog_java.m4])
 
 AC_CONFIG_SRCDIR([tsk/base/tsk_base.h])
 AC_CONFIG_HEADERS([tsk/tsk_config.h])
@@ -87,6 +88,10 @@ if test -d /usr/local/include; then
     LDFLAGS="$LDFLAGS -L/usr/local/lib"
 fi
 
+dnl Add enable/disable option
+AC_ARG_ENABLE([java],
+    [AS_HELP_STRING([--disable-java], [Do not build the java bindings or jar file])])
+ 
 dnl Checks for libraries.
 
 
@@ -173,6 +178,13 @@ AS_IF(
 )
 AS_IF([test "x$ac_cv_lib_z_inflate" = "xyes"], [ax_zlib=yes], [ax_zlib=no])
 
+AM_CONDITIONAL([X_ZLIB],[test "x$with_zlib" != "xno" && test "x$with_zlib" != "xyes"])
+AS_IF([test "x$with_zlib" != "xno"],
+   [Z_PATH="${with_zlib}/lib"],
+   [AC_MSG_NOTICE([failed to make Z_PATH])]
+)
+AC_SUBST(Z_PATH, $Z_PATH)
+
 dnl needed for sqllite
 AC_CHECK_LIB(dl, dlopen)
 
@@ -198,25 +210,41 @@ AS_IF([test "x$with_libewf" != "xno"],
     )]
     dnl Check for the header file first to make sure they have the dev install
     [AC_CHECK_HEADERS([libewf.h],
-      [AC_CHECK_LIB([ewf], [libewf_get_version])]
+      [AC_CHECK_LIB([ewf], [libewf_get_version], [], [NO_LIBEWF=true])]
     )]
 )
 AS_IF([test "x$ac_cv_lib_ewf_libewf_get_version" = "xyes"], [ax_libewf=yes], [ax_libewf=no])
 
+AM_CONDITIONAL([X_LIBEWF],[test "x$with_libewf" != "xno" && test "x$with_libewf" != "xyes"])
+AS_IF([test "x$with_libewf" != "xno"],
+   [EWF_PATH="${with_libewf}/lib"],
+)
+AC_SUBST(EWF_PATH, $EWF_PATH)
+   
+dnl sqlite requires pthread libraries - this was copied from its configure.ac
+dnl AC_SEARCH_LIBS(pthread_create, pthread)
+AC_SEARCH_LIBS(dlopen, dl)
+
 dnl Test for java/jni so that we can compile the java bindings
-AC_PROG_JAVAC
-if test "x$JAVAC" != x; then
-    AX_JNI_INCLUDE_DIR
-    for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
-    do
-        JNI_CPPFLAGS="$JNI_CPPFLAGS -I$JNI_INCLUDE_DIR"
-    done
-    dnl Export the paths so that the makefile gets them
-    AC_SUBST(JNI_CPPFLAGS, $JNI_CPPFLAGS)
-fi
-AM_CONDITIONAL([X_JNI],[test "x$JNI_CPPFLAGS" != x])
+AS_IF([test "x$enable_java" != "xno"], [
+    AC_PROG_JAVAC
+    if test "x$JAVAC" != x; then
+        AX_JNI_INCLUDE_DIR
+        for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
+        do
+            JNI_CPPFLAGS="$JNI_CPPFLAGS -I$JNI_INCLUDE_DIR"
+        done
+        dnl Export the paths so that the makefile gets them
+        AC_SUBST(JNI_CPPFLAGS, $JNI_CPPFLAGS)
+    fi
+    AC_PROG_JAVA
+]) dnl test enable_java
+
+dnl Test is ant is available
+AC_PATH_PROG([ANT_FOUND], [ant], [])
+AM_CONDITIONAL([X_JNI],[test "x$JNI_CPPFLAGS" != x && test "x$ANT_FOUND" != x && test "x$JAVA" != x])
 
-AS_IF([test "x$JNI_CPPFLAGS" != x], [ax_java_support=yes], [ax_java_support=no])
+AS_IF([test "x$JNI_CPPFLAGS" != x && test "x$ANT_FOUND" != x && test "x$JAVA" != x], [ax_java_support=yes], [ax_java_support=no])
 
 AC_CONFIG_COMMANDS([tsk/tsk_incs.h],
     [echo "#ifndef _TSK_INCS_H" > tsk/tsk_incs.h
@@ -274,6 +302,7 @@ AC_CONFIG_FILES([
     tests/Makefile
     samples/Makefile
     man/Makefile
+    bindings/java/Makefile 
     bindings/java/jni/Makefile
     unit_tests/Makefile
     unit_tests/base/Makefile])
diff --git a/framework/modules/c_InterestingFilesModule/InterestingFilesModule.cpp b/framework/modules/c_InterestingFilesModule/InterestingFilesModule.cpp
index be6e0f1013c2003f513227e2a5206d9079ae9746..81435a3e34de9a519473715e9135add9f2bbe6af 100644
--- a/framework/modules/c_InterestingFilesModule/InterestingFilesModule.cpp
+++ b/framework/modules/c_InterestingFilesModule/InterestingFilesModule.cpp
@@ -22,6 +22,7 @@
 #include "Poco/AutoPtr.h"
 #include "Poco/Path.h"
 #include "Poco/File.h"
+#include "Poco/NumberParser.h"
 #include "Poco/DOM/DOMParser.h"
 #include "Poco/DOM/Document.h"
 #include "Poco/DOM/NodeList.h"
@@ -45,6 +46,7 @@ namespace
     const std::string INTERESTING_FILE_SET_ELEMENT_TAG = "INTERESTING_FILE_SET"; 
     const std::string NAME_ATTRIBUTE = "name";
     const std::string DESCRIPTION_ATTRIBUTE_TAG = "description";
+    const std::string IGNORE_KNOWN_TAG = "ignoreKnown";
     const std::string NAME_ELEMENT_TAG = "NAME";
     const std::string EXTENSION_ELEMENT_TAG = "EXTENSION";
     const std::string PATH_FILTER_ATTRIBUTE = "pathFilter";
@@ -54,6 +56,17 @@ namespace
 
     std::string configFilePath;
 
+    // The following variables track whether we should ignore known
+    // files (and what type of known files to ignore) at a global 
+    // level. These settings can be overridden on an individual
+    // file set.
+
+    // Whether we should ignore known files.
+    bool ignoreKnown = false;
+
+    // What type of known files to ignore.
+    TskImgDB::KNOWN_STATUS knownType = TskImgDB::IMGDB_FILES_KNOWN;
+
     /** 
      * An interesting files set is defined by a set name, a set description, 
      * and one or more SQL WHERE clauses that specify what files belong to the
@@ -61,9 +74,12 @@ namespace
      */
     struct InterestingFilesSet
     {
-        InterestingFilesSet() : name(""), description("") {}
+        InterestingFilesSet() 
+            : name(""), description(""), ignoreKnown(false), knownType(TskImgDB::IMGDB_FILES_KNOWN) {}
         std::string name;
         std::string description;
+        bool ignoreKnown;
+        TskImgDB::KNOWN_STATUS knownType;
         vector<std::string> conditions;
     };
 
@@ -113,6 +129,25 @@ namespace
         Poco::replaceInPlace(stringToChange, "*", "%");
     }
 
+    /**
+     * Verifies that the given attribute value is a valid integer value
+     * for a known type and converts the value to its corresponding enum.
+     */
+    TskImgDB::KNOWN_STATUS parseKnownType(const std::string& attributeValue)
+    {
+        const std::string MSG_PREFIX(MODULE_NAME + std::string("::parseKnownType : "));
+
+        int knownType = Poco::NumberParser::parse(attributeValue);
+        if (knownType > TskImgDB::IMGDB_FILES_UNKNOWN || knownType < TskImgDB::IMGDB_FILES_KNOWN)
+        {
+            std::ostringstream msg;
+            msg << MSG_PREFIX << "Invalid value for ignoreKnown.";
+            throw TskException(msg.str());
+        }
+
+        return static_cast<TskImgDB::KNOWN_STATUS>(knownType);
+    }
+
     /** 
      * Adds optional file type (file, directory) and path substring filters to 
      * an SQL WHERE clause for a file search condition.
@@ -188,13 +223,12 @@ namespace
     }
 
     /**
-      * Creates an SQL WHERE clause for a file query from a file name
-      * condition.
+      * Creates an SQL condition to find files based on file name.
       *
       * @param conditionDefinition A file name condition XML element.
-      * @param conditions The WHERE clause is added to this collection.
+      * @return The constructed SQL condition.
       */
-    void compileFileNameSearchCondition(const Poco::XML::Node *conditionDefinition, std::vector<std::string> &conditions)
+    std::string compileFileNameSearchCondition(const Poco::XML::Node *conditionDefinition)
     {
         const std::string MSG_PREFIX = "InterestingFilesModule::compileFileNameSearchCondition : ";
 
@@ -207,29 +241,29 @@ namespace
         }
 
         std::stringstream conditionBuilder;
+
         if (hasGlobWildcards(name))
         {
             convertGlobWildcardsToSQLWildcards(name);
-            conditionBuilder << "WHERE UPPER(name) LIKE UPPER(" << TskServices::Instance().getImgDB().quote(name) << ") ESCAPE '#' ";
+            conditionBuilder << "UPPER(name) LIKE UPPER(" << TskServices::Instance().getImgDB().quote(name) << ") ESCAPE '#' ";
         }
         else
         {
-            conditionBuilder << "WHERE UPPER(name) = UPPER(" +  TskServices::Instance().getImgDB().quote(name) + ")";
+            conditionBuilder << "UPPER(name) = UPPER(" +  TskServices::Instance().getImgDB().quote(name) + ")";
         }
 
         addPathAndTypeFilterOptions(conditionDefinition, conditionBuilder);
-        conditionBuilder << " ORDER BY file_id";
-        conditions.push_back(conditionBuilder.str());
+
+        return conditionBuilder.str();
     }
 
     /**
-      * Creates an SQL WHERE clause for a file query from a file extension
-      * condition.
+      * Creates an SQL condition to find files based on extension.
       *
       * @param conditionDefinition A file extension condition XML element.
-      * @param conditions The WHERE clause is added to this collection.
+      * @returns The SQL condition.
       */
-    void compileExtensionSearchCondition(const Poco::XML::Node *conditionDefinition, std::vector<std::string> &conditions)
+    std::string compileExtensionSearchCondition(const Poco::XML::Node *conditionDefinition)
     {
         const std::string MSG_PREFIX = "InterestingFilesModule::compileExtensionSearchCondition : ";
 
@@ -253,11 +287,11 @@ namespace
         // @@@ TODO: In combination with glob wildcards this may create some unxepected matches.
         // For example, ".htm*" will become "%.htm%" which will match "file.htm.txt" and the like.
         std::stringstream conditionBuilder;
-        conditionBuilder << "WHERE UPPER(name) LIKE UPPER('%" << extension << "') ESCAPE '#' ";
+        conditionBuilder << "UPPER(name) LIKE UPPER('%" << extension << "') ESCAPE '#' ";
+
+        addPathAndTypeFilterOptions(conditionDefinition, conditionBuilder);
 
-        addPathAndTypeFilterOptions(conditionDefinition, conditionBuilder);            
-        conditionBuilder << " ORDER BY file_id";
-        conditions.push_back(conditionBuilder.str());
+        return conditionBuilder.str();
     }
 
     /** 
@@ -314,6 +348,20 @@ namespace
                             LOGWARN(msg.str());
                         }
                     }
+                    else if (attributeName == IGNORE_KNOWN_TAG)
+                    {
+                        if (!attributeValue.empty())
+                        {
+                            fileSet.knownType = parseKnownType(attributeValue);
+                            fileSet.ignoreKnown = true;
+                        }
+                        else
+                        {
+                            std::ostringstream msg;
+                            msg << MSG_PREFIX << "ignored " << INTERESTING_FILE_SET_ELEMENT_TAG << "'" << IGNORE_KNOWN_TAG << "' attribute without a value"; 
+                            LOGWARN(msg.str());
+                        }
+                    }
                     else
                     {
                         std::ostringstream msg;
@@ -358,6 +406,15 @@ namespace
             throw TskException(msg.str());
         }
 
+        std::string conditionBase;
+
+        // If we want to ignore known files either on an individual file set
+        // or globally we need to join with the file_hashes table.
+        if (fileSet.ignoreKnown || ignoreKnown)
+            conditionBase = " JOIN file_hashes ON (files.file_id = file_hashes.file_id) WHERE ";
+        else
+            conditionBase = " WHERE ";
+
         // Get the search conditions.
         Poco::AutoPtr<Poco::XML::NodeList>conditionDefinitions = fileSetDefinition->childNodes();
         for (unsigned long i = 0; i < conditionDefinitions->length(); ++i)
@@ -366,13 +423,17 @@ namespace
             if (conditionDefinition->nodeType() == Poco::XML::Node::ELEMENT_NODE) 
             {
                 const std::string &conditionType = Poco::XML::fromXMLString(conditionDefinition->nodeName());
+                std::stringstream conditionBuilder;
+
+                conditionBuilder << conditionBase;
+
                 if (conditionType == NAME_ELEMENT_TAG)
                 {
-                    compileFileNameSearchCondition(conditionDefinition, fileSet.conditions);
+                    conditionBuilder << compileFileNameSearchCondition(conditionDefinition);
                 }
                 else if (conditionType == EXTENSION_ELEMENT_TAG)
                 {
-                    compileExtensionSearchCondition(conditionDefinition, fileSet.conditions);
+                    conditionBuilder << compileExtensionSearchCondition(conditionDefinition);
                 }
                 else
                 {
@@ -380,6 +441,14 @@ namespace
                     msg << MSG_PREFIX << "unrecognized " << INTERESTING_FILE_SET_ELEMENT_TAG << " child element '" << conditionType << "'"; 
                     throw TskException(msg.str());
                 }
+
+                if (fileSet.ignoreKnown)
+                    conditionBuilder << " AND file_hashes.known != " << fileSet.knownType;
+                else if (ignoreKnown)
+                    conditionBuilder << " AND file_hashes.known != " << knownType;
+
+                conditionBuilder << " ORDER BY files.file_id";
+                fileSet.conditions.push_back(conditionBuilder.str());
             }
 
         }
@@ -468,6 +537,23 @@ extern "C"
                 {
                     Poco::XML::InputSource inputSource(configStream);
                     Poco::AutoPtr<Poco::XML::Document> configDoc = Poco::XML::DOMParser().parse(&inputSource);
+
+                    Poco::XML::Element * rootElement = configDoc->documentElement();
+                    if (rootElement == NULL)
+                    {
+                        std::ostringstream msg;
+                        msg << MSG_PREFIX << "Root element of config file is NULL.";
+                        throw TskException(msg.str());
+                    }
+
+                    const std::string& ignoreKnownValue = Poco::XML::fromXMLString(rootElement->getAttribute(IGNORE_KNOWN_TAG));
+
+                    if (!ignoreKnownValue.empty())
+                    {
+                        knownType = parseKnownType(ignoreKnownValue);
+                        ignoreKnown = true;
+                    }
+
                     Poco::AutoPtr<Poco::XML::NodeList> fileSetDefinitions = configDoc->getElementsByTagName(INTERESTING_FILE_SET_ELEMENT_TAG);
                     for (unsigned long i = 0; i < fileSetDefinitions->length(); ++i) 
                     {
diff --git a/framework/modules/c_InterestingFilesModule/README.txt b/framework/modules/c_InterestingFilesModule/README.txt
index 9201ca2ec0dc647f57fa20e6c76fa50eb903d166..1ee9933a4182e832897d6848765289d818404552 100644
--- a/framework/modules/c_InterestingFilesModule/README.txt
+++ b/framework/modules/c_InterestingFilesModule/README.txt
@@ -36,7 +36,7 @@ The configuration file is an XML document that defines interesting
 file sets in terms of search criteria.  Here is a sample: 
 
 <?xml version="1.0" encoding="utf-8"?>
-<INTERESTING_FILES>
+<INTERESTING_FILES ignoreKnown="0">
     <INTERESTING_FILE_SET name="HTMLFilesType" description="Files with extension .htm*">
         <EXTENSION typeFilter="file">.htm*</EXTENSION>
     </INTERESTING_FILE_SET>
@@ -97,7 +97,20 @@ search named "SuspiciousFiles" will find files and directories that end in
 attributes. Matches with this filter must contain the specified string as
 a sub-string of the file or directory path.
 
+Known files (e.g. files in the NSRL) can be ignored by providing the 
+'ignoreKnown' attribute either on the top level 'INTERESTING_FILES' element
+or on one or more 'INTERESTING_FILE_SET' elements.
+The following valid values for the 'ignoreKnown' attribute are based on the
+TskImgDB::KNOWN_STATUS enumeration in TskImgDB.h.
 
+  0 - All known files (both good and bad)
+  1 - Known good files
+  2 - Known bad (or notable) files
+  3 - Unknown files
+
+The ability to ignore known files depends on the existence of a hash database
+along with hash calculation and lookup modules.
+  
 RESULTS
 
 The result of the lookup is written to the blackboard as an artifact. 
diff --git a/framework/tsk/framework/extraction/TskCarvePrepSectorConcat.cpp b/framework/tsk/framework/extraction/TskCarvePrepSectorConcat.cpp
index 1771d8a824e8bba3b2d5d53b523ef79493b00d99..471854e959c1f11ee551147ff950b91601bfce5b 100644
--- a/framework/tsk/framework/extraction/TskCarvePrepSectorConcat.cpp
+++ b/framework/tsk/framework/extraction/TskCarvePrepSectorConcat.cpp
@@ -40,7 +40,8 @@
 namespace
 {
     const size_t SECTOR_SIZE = 512;
-    const size_t DEFAULT_SECTORS_PER_READ = 32; 
+    const size_t DEFAULT_SECTORS_PER_READ = 32;
+    static const char zeroBuffer[DEFAULT_SECTORS_PER_READ * SECTOR_SIZE] = { 0 };
 }
 
 TskCarvePrepSectorConcat::TskCarvePrepSectorConcat()
@@ -161,6 +162,8 @@ void TskCarvePrepSectorConcat::createUnallocSectorsImgFiles(const std::string &o
         int unallocSectorsImgId = 0;
         std::ofstream outfile;
         uint64_t currentFileOffset = 0; // In bytes
+        Poco::File currentFile;
+
         do 
         {
             // Keep track of the starting offsets in the output file (in bytes) and in the image (in sectors) of the sector run or part of a sector run 
@@ -194,17 +197,7 @@ void TskCarvePrepSectorConcat::createUnallocSectorsImgFiles(const std::string &o
                         startingImageOffset += (currentFileOffset - startingFileOffset) / 512;
                     }
 
-                    // Close the current output file.
-                    if (unallocSectorsImgId) 
-                    {
-                        outfile.close();
-                    }
-
-                    // Schedule the current output file for carving. Note that derived classes can change this behavior by overriding onUnallocSectorsImgFileCreated.
-                    if (currentFileOffset > 0) 
-                    {
-                        onUnallocSectorsImgFileCreated(unallocSectorsImgId); 
-                    }
+                    closeAndSchedule(unallocSectorsImgId, currentFile, outfile);
 
                     // Get the next output file number. 
                     if (imgDB.addUnallocImg(unallocSectorsImgId) == -1) 
@@ -219,6 +212,7 @@ void TskCarvePrepSectorConcat::createUnallocSectorsImgFiles(const std::string &o
                     
                     // Create an output file in the subdirectory.
                     path << Poco::Path::separator() << outputFileName.c_str();
+                    currentFile = path.str();
                     outfile.open(path.str().c_str(), std::ios_base::out|std::ios_base::binary);
                     if (outfile.fail())
                     {
@@ -243,6 +237,16 @@ void TskCarvePrepSectorConcat::createUnallocSectorsImgFiles(const std::string &o
                     break;
                 }
 
+                // If we are at the start of a new output file and the chunk we've just read
+                // contains nothing but zeros there is no need to write it to the file.
+                // This allows us skip carving for potentially large areas that contain nothing.
+                if (currentFileOffset == 0 && sectorBuffer[0] == 0 && !memcmp(sectorBuffer, zeroBuffer, sectorsRead * SECTOR_SIZE))
+                {
+                    sectorRunOffset += sectorsRead;
+                    startingImageOffset += sectorsRead;
+                    continue;
+                }
+
                 // Write the chunk of sectors to the output file.
                 outfile.write(sectorBuffer, sectorsRead * 512);
                 if (outfile.bad())
@@ -271,17 +275,7 @@ void TskCarvePrepSectorConcat::createUnallocSectorsImgFiles(const std::string &o
         }
         while(sectorRuns.next() != -1);
 
-        // Close the final output file.
-        if (unallocSectorsImgId) 
-        {
-            outfile.close();
-        }
-
-        // Schedule the final output file.
-        if (currentFileOffset > 0)
-        {
-            onUnallocSectorsImgFileCreated(unallocSectorsImgId);
-        }
+        closeAndSchedule(unallocSectorsImgId, currentFile, outfile);
 
         if (sectorBuffer != NULL)
         {
@@ -334,3 +328,22 @@ void TskCarvePrepSectorConcat::mapFileToImage(int unallocSectorsImgId, std::ofst
         throw TskException(msg.str());
     }
 }
+
+void TskCarvePrepSectorConcat::closeAndSchedule(const int unallocSectorsImgId, Poco::File& outFile, std::ofstream& outFileStream) const
+{
+    if (unallocSectorsImgId == 0)
+        return;
+
+    outFileStream.close();
+
+    // If this is a zero length file we remove it and skip carving.
+    if (outFile.getSize() == 0)
+    {
+        outFile.remove();
+        TskServices::Instance().getImgDB().setUnallocImgStatus(unallocSectorsImgId, TskImgDB::IMGDB_UNALLOC_IMG_STATUS_CARVED_NOT_NEEDED);
+    }
+    else
+    {
+        onUnallocSectorsImgFileCreated(unallocSectorsImgId);
+    }
+}
\ No newline at end of file
diff --git a/framework/tsk/framework/extraction/TskCarvePrepSectorConcat.h b/framework/tsk/framework/extraction/TskCarvePrepSectorConcat.h
index ff3a03350a9fdcd4409b540773c7a1160a33e65f..c7cf67c1a71b5c48b38df63088884f24874d1353 100644
--- a/framework/tsk/framework/extraction/TskCarvePrepSectorConcat.h
+++ b/framework/tsk/framework/extraction/TskCarvePrepSectorConcat.h
@@ -19,6 +19,9 @@
 // TSK Framework includes
 #include "CarvePrep.h"
 
+// Poco includes
+#include "Poco/File.h"
+
 // C/C++ library includes
 #include <string>
 
@@ -131,6 +134,15 @@ class TSK_FRAMEWORK_API TskCarvePrepSectorConcat : public CarvePrep
      *  @return Throws TskException on error.
      */
     void mapFileToImage(int unallocSectorsImgId, std::ofstream & outfile, uint64_t startingFileOffset, uint64_t endingFileOffset, int volumeID, uint64_t startingImageOffset) const;
+
+    /**
+     * Close the unallocated sectors image file and schedule for carving
+     * if necessary.
+     * Carving will not be necessary if it is a zero length file, in which 
+     * case the file will be deleted and the unalloc image status record
+     * will be set to carving not needed.
+     */
+    void closeAndSchedule(const int unallocSectorsImgId, Poco::File& outFile, std::ofstream& outFileStream) const;
 };
 
 #endif
diff --git a/framework/tsk/framework/services/TskImgDBPostgreSQL.cpp b/framework/tsk/framework/services/TskImgDBPostgreSQL.cpp
index ba2f217e74bf55a6c5d3268d78facef4aaff36d7..536ddef64a6a1a13f74531a0dd66ab293b92e5e6 100755
--- a/framework/tsk/framework/services/TskImgDBPostgreSQL.cpp
+++ b/framework/tsk/framework/services/TskImgDBPostgreSQL.cpp
@@ -157,11 +157,11 @@ int TskImgDBPostgreSQL::initialize()
         return 1;
     }
 
-    if (initializePreparedStatements())
-    {
-        // Error message will have been logged by initializePreparedStatements()
-        return 1;
-    }
+    //if (initializePreparedStatements())
+    //{
+    //    // Error message will have been logged by initializePreparedStatements()
+    //    return 1;
+    //}
 
     addToolInfo("DbSchema", IMGDB_SCHEMA_VERSION);
     LOGINFO(L"ImgDB Created.");
@@ -273,7 +273,7 @@ int TskImgDBPostgreSQL::open()
 
         std::stringstream dbConnectionString;
         dbConnectionString << "host='" << db_host_ip << "' port='" << db_port
-            << "' dbname='" << m_dbName << "' user='" << name << "'";
+            << "' dbname='" << Poco::replace(m_dbName, "'", "\\'") << "' user='" << name << "'";
 
         m_dbConnection = new pqxx::connection(dbConnectionString.str());
     }
@@ -653,24 +653,35 @@ int TskImgDBPostgreSQL::addFsFileInfo(int fileSystemID, const TSK_FS_FILE *fileS
     try
     {
         // We don't provide file_id to the prepared function because it uses DEFAULT for that.
-        stmt << "EXECUTE addFsFileInfoPlan ("
-            << IMGDB_FILES_TYPE_FS << ", "
-            << IMGDB_FILES_STATUS_READY_FOR_ANALYSIS << ", "
-            << m_dbConnection->quote(fileName) << ", "
-            << parFileId << ", "
-            << fileSystemFile->name->type << ", "
-            << meta_type << ", "
-            << fileSystemFile->name->flags << ", "
-            << meta_flags << ", "
-            << size << ", "
-            << crtime << ", "
-            << ctime << ", "
-            << atime << ", "
-            << mtime << ", "
-            << meta_mode << ", "
-            << gid << ", "
-            << uid
-            << ", E" << m_dbConnection->quote(fullpath) << ")";
+        stmt << "INSERT INTO files (file_id, type_id, status, name, par_file_id, dir_type, meta_type, dir_flags, meta_flags, size, crtime, ctime, atime, mtime, mode, gid, uid, full_path) VALUES ("
+            << "DEFAULT, " << IMGDB_FILES_TYPE_FS << ", " << IMGDB_FILES_STATUS_READY_FOR_ANALYSIS << ", " << m_dbConnection->quote(fileName) << ", "
+            << parFileId << ", " << fileSystemFile->name->type << ", " << meta_type << ", "
+            << fileSystemFile->name->flags << ", " << meta_flags << ", " << size << ", " << crtime << ", " << ctime << ", " << atime << ", "
+            << mtime << ", " << meta_mode << ", " << gid << ", " << uid << ", E" << m_dbConnection->quote(fullpath) << ")"
+            << " RETURNING file_id";
+
+        // Commenting out to see if the addition of prepared statements is
+        // the cause of the frequent PostgreSQL server crashes we've seen
+        // recently.
+
+        //stmt << "EXECUTE addFsFileInfoPlan ("
+        //    << IMGDB_FILES_TYPE_FS << ", "
+        //    << IMGDB_FILES_STATUS_READY_FOR_ANALYSIS << ", "
+        //    << m_dbConnection->quote(fileName) << ", "
+        //    << parFileId << ", "
+        //    << fileSystemFile->name->type << ", "
+        //    << meta_type << ", "
+        //    << fileSystemFile->name->flags << ", "
+        //    << meta_flags << ", "
+        //    << size << ", "
+        //    << crtime << ", "
+        //    << ctime << ", "
+        //    << atime << ", "
+        //    << mtime << ", "
+        //    << meta_mode << ", "
+        //    << gid << ", "
+        //    << uid
+        //    << ", E" << m_dbConnection->quote(fullpath) << ")";
 
         result R = executeStatement(stmt.str());
         
@@ -1367,16 +1378,28 @@ int TskImgDBPostgreSQL::addCarvedFileInfo(int vol_id, const char *name, uint64_t
 
     stringstream stmt;
 
-    stmt << "EXECUTE addCarvedFileInfoPlan ("
-        << IMGDB_FILES_TYPE_CARVED << ", "
-        << IMGDB_FILES_STATUS_CREATED << ", "
-        << m_dbConnection->quote(utf8Name) << ", "
-        << TSK_FS_NAME_TYPE_REG << ", "
-        << TSK_FS_META_TYPE_REG << ", "
-        << TSK_FS_NAME_FLAG_UNALLOC << ", "
-        << TSK_FS_META_FLAG_UNALLOC << ", "
-        << size << ","
-        << m_dbConnection->quote(utf8Name) << ")";
+    // Commenting out to see if the addition of prepared statements is
+    // the cause of the frequent PostgreSQL server crashes we've seen
+    // recently.
+
+    //stmt << "EXECUTE addCarvedFileInfoPlan ("
+    //    << IMGDB_FILES_TYPE_CARVED << ", "
+    //    << IMGDB_FILES_STATUS_CREATED << ", "
+    //    << m_dbConnection->quote(utf8Name) << ", "
+    //    << TSK_FS_NAME_TYPE_REG << ", "
+    //    << TSK_FS_META_TYPE_REG << ", "
+    //    << TSK_FS_NAME_FLAG_UNALLOC << ", "
+    //    << TSK_FS_META_FLAG_UNALLOC << ", "
+    //    << size << ","
+    //    << m_dbConnection->quote(utf8Name) << ")";
+
+    stmt << "INSERT INTO files (file_id, type_id, name, par_file_id, dir_type, meta_type,"
+        "dir_flags, meta_flags, size, ctime, crtime, atime, mtime, mode, uid, gid, status, full_path) "
+        "VALUES (DEFAULT, " << IMGDB_FILES_TYPE_CARVED << ", " << m_dbConnection->quote(utf8Name)
+        << ", NULL, " <<  TSK_FS_NAME_TYPE_REG << ", " <<  TSK_FS_META_TYPE_REG << ", "
+        << TSK_FS_NAME_FLAG_UNALLOC << ", " << TSK_FS_META_FLAG_UNALLOC << ", "
+        << size << ", 0, 0, 0, 0, NULL, NULL, NULL, " << IMGDB_FILES_STATUS_CREATED << "," << m_dbConnection->quote(utf8Name) << ")"
+        << " RETURNING file_id";
 
     try
     {
@@ -1467,19 +1490,28 @@ int TskImgDBPostgreSQL::addDerivedFileInfo(const std::string& name, const uint64
 
     std::stringstream stmt;
 
-    stmt << "EXECUTE addDerivedFileInfoPlan ("
-        << IMGDB_FILES_TYPE_DERIVED << ", "
-        << IMGDB_FILES_STATUS_CREATED << ", "
-        << m_dbConnection->quote(&cleanName[0]) << ", " 
-        << parentId << ", "
-        << dirType << ", "
-        << metaType << ", "
-        << size << ", "
-        << crtime << ", "
-        << ctime << ", "
-        << atime << ", "
-        << mtime << ", "
-        << m_dbConnection->quote(&cleanPath[0]) << ")";
+    // Commenting out to see if the addition of prepared statements is
+    // the cause of the frequent PostgreSQL server crashes we've seen
+    // recently.
+
+    //stmt << "EXECUTE addDerivedFileInfoPlan ("
+    //    << IMGDB_FILES_TYPE_DERIVED << ", "
+    //    << IMGDB_FILES_STATUS_CREATED << ", "
+    //    << m_dbConnection->quote(&cleanName[0]) << ", " 
+    //    << parentId << ", "
+    //    << dirType << ", "
+    //    << metaType << ", "
+    //    << size << ", "
+    //    << crtime << ", "
+    //    << ctime << ", "
+    //    << atime << ", "
+    //    << mtime << ", "
+    //    << m_dbConnection->quote(&cleanPath[0]) << ")";
+
+    stmt << "INSERT INTO files (file_id, type_id, name, par_file_id, dir_type, meta_type, size, ctime, crtime, atime, mtime, status, full_path) "
+        "VALUES (DEFAULT, " << IMGDB_FILES_TYPE_DERIVED << ", " << m_dbConnection->quote(&cleanName[0]) << ", " << parentId << ", " << dirType << ", " << metaType << ", " << size
+        << ", " << ctime << ", " << crtime << ", " << atime << ", " << mtime << ", " << IMGDB_FILES_STATUS_CREATED << ", E" << m_dbConnection->quote(&cleanPath[0]) << ")"
+        << " RETURNING file_id";
 
     try
     {
diff --git a/m4/ac_prog_java.m4 b/m4/ac_prog_java.m4
new file mode 100644
index 0000000000000000000000000000000000000000..1ba1688702ae9dbe97edfe5cc40a9412d24df64b
--- /dev/null
+++ b/m4/ac_prog_java.m4
@@ -0,0 +1,83 @@
+dnl @synopsis AC_PROG_JAVA
+dnl
+dnl Here is a summary of the main macros:
+dnl
+dnl AC_PROG_JAVAC: finds a Java compiler.
+dnl
+dnl AC_PROG_JAVA: finds a Java virtual machine.
+dnl
+dnl AC_CHECK_CLASS: finds if we have the given class (beware of
+dnl CLASSPATH!).
+dnl
+dnl AC_CHECK_RQRD_CLASS: finds if we have the given class and stops
+dnl otherwise.
+dnl
+dnl AC_TRY_COMPILE_JAVA: attempt to compile user given source.
+dnl
+dnl AC_TRY_RUN_JAVA: attempt to compile and run user given source.
+dnl
+dnl AC_JAVA_OPTIONS: adds Java configure options.
+dnl
+dnl AC_PROG_JAVA tests an existing Java virtual machine. It uses the
+dnl environment variable JAVA then tests in sequence various common
+dnl Java virtual machines. For political reasons, it starts with the
+dnl free ones. You *must* call [AC_PROG_JAVAC] before.
+dnl
+dnl If you want to force a specific VM:
+dnl
+dnl - at the configure.in level, set JAVA=yourvm before calling
+dnl AC_PROG_JAVA
+dnl
+dnl   (but after AC_INIT)
+dnl
+dnl - at the configure level, setenv JAVA
+dnl
+dnl You can use the JAVA variable in your Makefile.in, with @JAVA@.
+dnl
+dnl *Warning*: its success or failure can depend on a proper setting of
+dnl the CLASSPATH env. variable.
+dnl
+dnl TODO: allow to exclude virtual machines (rationale: most Java
+dnl programs cannot run with some VM like kaffe).
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java
+dnl programs. It is VERY IMPORTANT that you download the whole set,
+dnl some macros depend on other. Unfortunately, the autoconf archive
+dnl does not support the concept of set of macros, so I had to break it
+dnl for submission.
+dnl
+dnl A Web page, with a link to the latest CVS snapshot is at
+dnl <http://www.internatif.org/bortzmeyer/autoconf-Java/>.
+dnl
+dnl This is a sample configure.in Process this file with autoconf to
+dnl produce a configure script.
+dnl
+dnl    AC_INIT(UnTag.java)
+dnl
+dnl    dnl Checks for programs.
+dnl    AC_CHECK_CLASSPATH
+dnl    AC_PROG_JAVAC
+dnl    AC_PROG_JAVA
+dnl
+dnl    dnl Checks for classes
+dnl    AC_CHECK_RQRD_CLASS(org.xml.sax.Parser)
+dnl    AC_CHECK_RQRD_CLASS(com.jclark.xml.sax.Driver)
+dnl
+dnl    AC_OUTPUT(Makefile)
+dnl
+dnl @category Java
+dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
+dnl @version 2000-07-19
+dnl @license GPLWithACException
+
+AC_DEFUN([AC_PROG_JAVA],[
+AC_REQUIRE([AC_EXEEXT])dnl
+if test x$JAVAPREFIX = x; then
+	test x$JAVA = x && AC_CHECK_PROGS(JAVA, kaffe$EXEEXT java$EXEEXT)
+else
+	test x$JAVA = x && AC_CHECK_PROGS(JAVA, kaffe$EXEEXT java$EXEEXT, $JAVAPREFIX)
+fi
+test x$JAVA = x && AC_MSG_WARN([no acceptable Java virtual machine found in \$PATH])
+AC_PROG_JAVA_WORKS
+AC_PROVIDE([$0])dnl
+])
diff --git a/m4/ac_prog_java_works.m4 b/m4/ac_prog_java_works.m4
new file mode 100644
index 0000000000000000000000000000000000000000..cc71eb2866f39219183436a4814ac7ab9bf11051
--- /dev/null
+++ b/m4/ac_prog_java_works.m4
@@ -0,0 +1,101 @@
+dnl @synopsis AC_PROG_JAVA_WORKS
+dnl
+dnl Internal use ONLY.
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java
+dnl programs. It is VERY IMPORTANT that you download the whole set,
+dnl some macros depend on other. Unfortunately, the autoconf archive
+dnl does not support the concept of set of macros, so I had to break it
+dnl for submission. The general documentation, as well as the sample
+dnl configure.in, is included in the AC_PROG_JAVA macro.
+dnl
+dnl @category Java
+dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
+dnl @version 2000-07-19
+dnl @license GPLWithACException
+
+AC_DEFUN([AC_PROG_JAVA_WORKS], [
+AC_CHECK_PROG(uudecode, uudecode$EXEEXT, yes)
+if test x$JAVA != x; then
+if test x$uudecode = xyes; then
+AC_CACHE_CHECK([if uudecode can decode base 64 file], ac_cv_prog_uudecode_base64, [
+dnl /**
+dnl  * Test.java: used to test if java compiler works.
+dnl  */
+dnl public class Test
+dnl {
+dnl
+dnl public static void
+dnl main( String[] argv )
+dnl {
+dnl     System.exit (0);
+dnl }
+dnl
+dnl }
+cat << \EOF > Test.uue
+begin-base64 644 Test.class
+yv66vgADAC0AFQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE
+bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51
+bWJlclRhYmxlDAAKAAsBAARleGl0AQAEKEkpVgoADQAJBwAOAQAQamF2YS9s
+YW5nL1N5c3RlbQEABjxpbml0PgEAAygpVgwADwAQCgADABEBAApTb3VyY2VG
+aWxlAQAJVGVzdC5qYXZhACEAAQADAAAAAAACAAkABQAGAAEABwAAACEAAQAB
+AAAABQO4AAyxAAAAAQAIAAAACgACAAAACgAEAAsAAQAPABAAAQAHAAAAIQAB
+AAEAAAAFKrcAErEAAAABAAgAAAAKAAIAAAAEAAQABAABABMAAAACABQ=
+====
+EOF
+if uudecode$EXEEXT Test.uue; then
+	ac_cv_prog_uudecode_base64=yes
+else
+	echo "configure: __oline__: uudecode had trouble decoding base	64 file 'Test.uue'" >&AC_FD_CC
+	echo "configure: failed file was:" >&AC_FD_CC
+	cat Test.uue >&AC_FD_CC
+	ac_cv_prog_uudecode_base64=no
+fi
+rm -f Test.uue])
+fi
+if test x$ac_cv_prog_uudecode_base64 != xyes; then
+	rm -f Test.class
+	AC_MSG_WARN([I have to compile Test.class from scratch])
+	if test x$ac_cv_prog_javac_works = xno; then
+		AC_MSG_ERROR([Cannot compile java source. $JAVAC does not work properly])
+	fi
+	if test x$ac_cv_prog_javac_works = x; then
+		AC_PROG_JAVAC
+	fi
+fi
+AC_CACHE_CHECK(if $JAVA works, ac_cv_prog_java_works, [
+JAVA_TEST=Test.java
+CLASS_TEST=Test.class
+TEST=Test
+changequote(, )dnl
+cat << \EOF > $JAVA_TEST
+/* [#]line __oline__ "configure" */
+public class
+Test {
+public static void main (String args[]) {
+	System.exit(0);
+} }
+EOF
+changequote([, ])dnl
+if test x$ac_cv_prog_uudecode_base64 != xyes; then
+	if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) && test -s $CLASS_TEST; then
+		:
+	else
+		echo "configure: failed program was:" >&AC_FD_CC
+		cat $JAVA_TEST >&AC_FD_CC
+		AC_MSG_ERROR(The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?))
+	fi
+fi
+																									       if AC_TRY_COMMAND($JAVA $JAVAFLAGS $TEST) >/dev/null 2>&1; then
+	ac_cv_prog_java_works=yes
+else
+	echo "configure: failed program was:" >&AC_FD_CC
+	cat $JAVA_TEST >&AC_FD_CC
+	AC_MSG_ERROR(The Java VM $JAVA failed (see config.log, check the CLASSPATH?))
+fi
+rm -fr $JAVA_TEST $CLASS_TEST Test.uue])
+AC_PROVIDE([$0])dnl
+fi
+]
+)
+
diff --git a/man/img_cat.1 b/man/img_cat.1
index 06f348bc7e80959f314c9de64b553d286bbf93a9..e0fdf92e3e85fdfc53fae0cfef7705c6ae444bc1 100644
--- a/man/img_cat.1
+++ b/man/img_cat.1
@@ -2,7 +2,7 @@
 .SH NAME
 img_cat \- Output contents of an image file.
 .SH SYNOPSIS
-.B img_cat [-i imgtype] [-b dev_sector_size] [-b start_sector] [-e stop_sector] [-vV] 
+.B img_cat [-i imgtype] [-b dev_sector_size] [-s start_sector] [-e stop_sector] [-vV] 
 .I image [images] 
 .SH DESCRIPTION
 .B img_cat
diff --git a/tools/fiwalk/src/fiwalk.cpp b/tools/fiwalk/src/fiwalk.cpp
index 8bfba32f36c5a322d8dc74aa2c78b62557a23d9f..e32c55aa3cd33994ae9567e981cca16dc51295be 100644
--- a/tools/fiwalk/src/fiwalk.cpp
+++ b/tools/fiwalk/src/fiwalk.cpp
@@ -664,13 +664,6 @@ int main(int argc, char * const *argv1)
 	fprintf(stderr,"ERROR: fiwalk was compiled without AFF support.\n");
 	exit(0);
 #else
-#if 0
-	if((tsk_img_type_supported() & TSK_IMG_TYPE_AFF_AFF)==0){
-	    fprintf(stderr,"ERROR: fiwalk was compiled with AFF support but the TSK library is not.\n");
-	    fprintf(stderr,"tsk_img_type_supported=0x%x\n",tsk_img_type_supported());
-	    exit(0);
-	}
-#endif
 #endif
     }
 
diff --git a/tsk/auto/auto_db.cpp b/tsk/auto/auto_db.cpp
index 37190621f3e335155071d2f228bca0812bebee1a..e87d17891dd9128584b9db890d66bc02dd338b56 100644
--- a/tsk/auto/auto_db.cpp
+++ b/tsk/auto/auto_db.cpp
@@ -193,19 +193,20 @@ uint8_t
 uint8_t
 TskAutoDb::addImageDetails(const char *const img_ptrs[], int a_num)
 {
-    string md5 = "";
-#if HAVE_LIBEWF
-    if (m_img_info->itype == TSK_IMG_TYPE_EWF_EWF) {
+//    string md5 = "";
+//#if HAVE_LIBEWF
+//    if (m_img_info->itype == TSK_IMG_TYPE_EWF_EWF) {
         // @@@ This shoudl really probably be inside of a tsk_img_ method
-        IMG_EWF_INFO *ewf_info = (IMG_EWF_INFO *)m_img_info;
-        if (ewf_info->md5hash_isset) {
-            md5 = ewf_info->md5hash;
-        }
-    }
-#endif
+//        IMG_EWF_INFO *ewf_info = (IMG_EWF_INFO *)m_img_info;
+//        if (ewf_info->md5hash_isset) {
+//            md5 = ewf_info->md5hash;
+//        }
+//    }
+//#endif
 
     if (m_db->addImageInfo(m_img_info->itype, m_img_info->sector_size,
-            m_curImgId, m_curImgTZone, m_img_info->size, md5)) {
+ //           m_curImgId, m_curImgTZone, m_img_info->size, md5)) {
+            m_curImgId, m_curImgTZone)) { 
         return 1;
     }
 
diff --git a/tsk/auto/db_sqlite.cpp b/tsk/auto/db_sqlite.cpp
index 0fefa672b053051ba72416e0065e23004d7a9741..3a53d32f7ffb83cc21adde0e007976e05bf83a34 100755
--- a/tsk/auto/db_sqlite.cpp
+++ b/tsk/auto/db_sqlite.cpp
@@ -25,7 +25,6 @@ using std::stringstream;
 using std::sort;
 using std::for_each;
 
-
 #define TSK_SCHEMA_VER 4
 
 /**
@@ -238,7 +237,9 @@ int
             "Error creating tsk_objects table: %s\n")
         ||
         attempt_exec
-        ("CREATE TABLE tsk_image_info (obj_id INTEGER PRIMARY KEY, type INTEGER, ssize INTEGER, tzone TEXT, size INTEGER, md5 TEXT);",
+//        ("CREATE TABLE tsk_image_info (obj_id INTEGER PRIMARY KEY, type INTEGER, ssize INTEGER, tzone TEXT, size INTEGER, md5 TEXT);",
+
+        ("CREATE TABLE tsk_image_info (obj_id INTEGER PRIMARY KEY, type INTEGER, ssize INTEGER, tzone TEXT);",
             "Error creating tsk_image_info table: %s\n")
         ||
         attempt_exec
@@ -433,9 +434,14 @@ int
 
     objId = sqlite3_last_insert_rowid(m_db);
 
+//    snprintf(stmt, 1024,
+//        "INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5) VALUES (%lld, %d, %d, '%s', %"PRIuOFF", '%s');",
+//        objId, type, ssize, timezone.c_str(), size, md5.c_str());
+    
     snprintf(stmt, 1024,
-        "INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5) VALUES (%lld, %d, %d, '%s', %"PRIuOFF", '%s');",
-        objId, type, ssize, timezone.c_str(), size, md5.c_str());
+        "INSERT INTO tsk_image_info (obj_id, type, ssize, tzone) VALUES (%lld, %d, %d, '%s');",
+        objId, type, ssize, timezone.c_str());
+
     return attempt_exec(stmt,
         "Error adding data to tsk_image_info table: %s\n");
 }
diff --git a/tsk/fs/tsk_yaffs.h b/tsk/fs/tsk_yaffs.h
index bd29dd220a968632cb0a30cc824a57423baa9582..93ccc1bceb0386eae2fbb7eaab4035c7916a1e42 100644
--- a/tsk/fs/tsk_yaffs.h
+++ b/tsk/fs/tsk_yaffs.h
@@ -34,6 +34,30 @@ extern "C" {
 
 #define YAFFS_DEFAULT_MAX_TEST_BLOCKS   400  // Maximum number of blocks to test looking for Yaffs2 spare under auto-detect
 
+#define YAFFS_HELP_MESSAGE   "See http://wiki.sleuthkit.org/index.php?title=YAFFS2 for help on Yaffs2 configuration"
+
+/*
+ * Yaffs config file constants and return values
+ */
+#ifdef TSK_WIN32
+#define YAFFS_CONFIG_FILE_SUFFIX          L"-yaffs2.config"
+#else
+#define YAFFS_CONFIG_FILE_SUFFIX          "-yaffs2.config"
+#endif
+
+#define YAFFS_CONFIG_SEQ_NUM_STR          "spare_seq_num_offset"
+#define YAFFS_CONFIG_OBJ_ID_STR           "spare_obj_id_offset"
+#define YAFFS_CONFIG_CHUNK_ID_STR         "spare_chunk_id_offset"
+#define YAFFS_CONFIG_PAGE_SIZE_STR        "flash_page_size"
+#define YAFFS_CONFIG_SPARE_SIZE_STR       "flash_spare_size"
+#define YAFFS_CONFIG_CHUNKS_PER_BLOCK_STR "flash_chunks_per_block"
+
+typedef enum {
+    YAFFS_CONFIG_OK,
+    YAFFS_CONFIG_FILE_NOT_FOUND,
+    YAFFS_CONFIG_ERROR
+} YAFFS_CONFIG_STATUS;
+
 /*
 ** Yaffs Object Flags
 */
diff --git a/tsk/fs/yaffs.cpp b/tsk/fs/yaffs.cpp
index fdb61921f916b2dba26fce6990ea365bf5ddbfcd..0984cabee43e74913ce46eda69469afdedc3da74 100644
--- a/tsk/fs/yaffs.cpp
+++ b/tsk/fs/yaffs.cpp
@@ -28,6 +28,10 @@ v** Copyright (c) 2002-2003 Brian Carrier, @stake Inc.  All rights reserved
 --*/
 
 #include <vector>
+#include <map>
+#include <algorithm>
+#include <string>
+#include <set>
 
 #include "tsk_fs_i.h"
 #include "tsk_yaffs.h"
@@ -611,34 +615,44 @@ static void
 static void
     yaffscache_objects_free(YAFFSFS_INFO *yfs)
 {
-    YaffsCacheObject *obj = yfs->cache_objects;
-    while(obj != NULL) {
-        YaffsCacheObject *to_free = obj;
+    if((yfs != NULL) && (yfs->cache_objects != NULL)){
+        YaffsCacheObject *obj = yfs->cache_objects;
+        while(obj != NULL) {
+            YaffsCacheObject *to_free = obj;
+
+            YaffsCacheVersion *ver = obj->yco_latest;
+            while(ver != NULL) {
+                YaffsCacheVersion *v_to_free = ver;
+                ver = ver->ycv_prior;
+                free(v_to_free);
+            }
 
-        YaffsCacheVersion *ver = obj->yco_latest;
-        while(ver != NULL) {
-            YaffsCacheVersion *v_to_free = ver;
-            ver = ver->ycv_prior;
-            free(v_to_free);
+            obj = obj->yco_next;
+            free(to_free);
         }
-
-        obj = obj->yco_next;
-        free(to_free);
     }
 }
 
 static void
     yaffscache_chunks_free(YAFFSFS_INFO *yfs)
 {
-    std::map<unsigned int,YaffsCacheChunkGroup>::iterator iter;
-    for( iter = yfs->chunkMap->begin(); iter != yfs->chunkMap->end(); ++iter ) {
-        YaffsCacheChunk *chunk = yfs->chunkMap->operator[](iter->first).cache_chunks_head;
-        while(chunk != NULL) {
-            YaffsCacheChunk *to_free = chunk;
-            chunk = chunk->ycc_next;
-            free(to_free);
+    if((yfs != NULL) && (yfs->chunkMap != NULL)){
+        // Free the YaffsCacheChunks in each ChunkGroup
+        std::map<unsigned int,YaffsCacheChunkGroup>::iterator iter;
+        for( iter = yfs->chunkMap->begin(); iter != yfs->chunkMap->end(); ++iter ) {
+            YaffsCacheChunk *chunk = yfs->chunkMap->operator[](iter->first).cache_chunks_head;
+            while(chunk != NULL) {
+                YaffsCacheChunk *to_free = chunk;
+                chunk = chunk->ycc_next;
+                free(to_free);
+            }
         }
+
+        // Free the map
+        yfs->chunkMap->clear();
+        delete yfs->chunkMap;
     }
+
 }
 
 
@@ -649,6 +663,212 @@ static void
 *
 */
 
+/* Function to parse config file
+ *
+ * @param img_info Image info for this image
+ * @param map<string, int> Stores values from config file indexed on parameter name
+ * @returns YAFFS_CONFIG_STATUS One of 	YAFFS_CONFIG_OK, YAFFS_CONFIG_FILE_NOT_FOUND, or YAFFS_CONFIG_ERROR
+ */
+static YAFFS_CONFIG_STATUS
+yaffs_load_config_file(TSK_IMG_INFO * a_img_info, std::map<std::string, std::string> & results){
+    const TSK_TCHAR ** image_names;
+    int num_imgs;
+    size_t config_file_name_len;
+    TSK_TCHAR * config_file_name;
+    FILE* config_file;
+    char buf[1001];
+
+    // Get the image name(s)
+    image_names = tsk_img_get_names(a_img_info, &num_imgs);
+    if(num_imgs < 1){
+        return YAFFS_CONFIG_ERROR;
+    }
+
+    // Construct the name of the config file from the first image name
+    config_file_name_len = TSTRLEN(image_names[0]);
+    config_file_name_len += TSTRLEN(YAFFS_CONFIG_FILE_SUFFIX);
+    config_file_name = (TSK_TCHAR *) tsk_malloc(sizeof(TSK_TCHAR) * (config_file_name_len + 1));
+
+    TSTRNCPY(config_file_name, image_names[0], TSTRLEN(image_names[0]) + 1);
+    TSTRNCAT(config_file_name, YAFFS_CONFIG_FILE_SUFFIX, TSTRLEN(YAFFS_CONFIG_FILE_SUFFIX) + 1);
+
+#ifdef TSK_WIN32
+    HANDLE hWin;
+
+    if ((hWin = CreateFile(config_file_name, GENERIC_READ,
+            FILE_SHARE_READ, 0, OPEN_EXISTING, 0,
+            0)) == INVALID_HANDLE_VALUE) {
+
+        // For the moment, assume that the file just doesn't exist, which isn't an error
+        free(config_file_name);
+        return YAFFS_CONFIG_FILE_NOT_FOUND;
+    }
+    config_file = _fdopen(_open_osfhandle((intptr_t) hWin, _O_RDONLY), "r");
+    if (config_file == NULL) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_FS);
+        tsk_error_set_errstr(
+                    "yaffs_load_config: Error converting Windows handle to C handle");
+        free(config_file_name);
+        CloseHandle(hWin);
+        return YAFFS_CONFIG_ERROR;
+    }
+#else
+    if (NULL == (config_file = fopen(config_file_name, "r"))) {
+        free(config_file_name);
+        return YAFFS_CONFIG_FILE_NOT_FOUND;
+    }
+#endif
+
+    while(fgets(buf, 1000, config_file) != NULL){
+
+        // Is it a comment?
+        if((buf[0] == '#') || (buf[0] == ';')){
+            continue;
+        }
+
+        // Is there a '=' ?
+        if(strchr(buf, '=') == NULL){
+            continue;
+        }
+
+        // Copy to strings while removing whitespace and converting to lower case
+        std::string paramName("");
+        std::string paramVal("");
+        
+        const char * paramNamePtr = strtok(buf, "=");
+        while(*paramNamePtr != '\0'){
+            if(! isspace((char)(*paramNamePtr))){
+                paramName += tolower((char)(*paramNamePtr));
+            }
+            paramNamePtr++;
+        }
+    
+        const char * paramValPtr = strtok(NULL, "=");
+        while(*paramValPtr != '\0'){
+            if(! isspace(*paramValPtr)){
+                paramVal += tolower((char)(*paramValPtr));
+            }
+            paramValPtr++;
+        }
+        
+        // Make sure this parameter is not already in the map
+        if(results.find(paramName) != results.end()){
+            // Duplicate parameter - return an error
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_FS);
+            tsk_error_set_errstr(
+                        "yaffs_load_config: Duplicate parameter name in config file (\"%s\"). %s", paramName.c_str(), YAFFS_HELP_MESSAGE);
+            fclose(config_file);
+            free(config_file_name);
+            return YAFFS_CONFIG_ERROR;
+        }
+
+        // Add this entry to the map
+        results[paramName] = paramVal;
+    }
+
+    fclose(config_file);
+    free(config_file_name);
+    return YAFFS_CONFIG_OK;
+}
+
+/*
+ * Helper function for yaffs_validate_config
+ * Tests that a string consists only of digits and has at least one digit
+ * (Can modify later if we want negative fields to be valid)
+ *
+ * @param numStr String to test
+ * @returns 1 on error, 0 on success
+ */
+static int
+yaffs_validate_integer_field(std::string numStr){
+    unsigned int i;
+
+    // Test if empty
+    if(numStr.length() == 0){
+        return 1;
+    }
+
+    // Test each character
+    for(i = 0;i < numStr.length();i++){
+        if(! isdigit(numStr[i])){
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Function to validate the contents of the config file
+ * Currently testing:
+ *  All YAFFS_CONFIG fields should be integers (if they exist)
+ *  Either need all three of YAFFS_CONFIG_SEQ_NUM_STR, YAFFS_CONFIG_OBJ_ID_STR, YAFFS_CONFIG_CHUNK_ID_STR
+ *   or none of them
+ *
+ * @param paramMap Holds mapping of parameter name to parameter value
+ * @returns 1 on error (invalid parameters), 0 on success
+ */
+static int
+yaffs_validate_config_file(std::map<std::string, std::string> & paramMap){
+    int offset_field_count;
+
+    // Make a list of all fields to test
+    std::set<std::string> integerParams;
+    integerParams.insert(YAFFS_CONFIG_SEQ_NUM_STR);
+    integerParams.insert(YAFFS_CONFIG_OBJ_ID_STR);
+    integerParams.insert(YAFFS_CONFIG_CHUNK_ID_STR);
+    integerParams.insert(YAFFS_CONFIG_PAGE_SIZE_STR);
+    integerParams.insert(YAFFS_CONFIG_SPARE_SIZE_STR);
+    integerParams.insert(YAFFS_CONFIG_CHUNKS_PER_BLOCK_STR);
+
+    // If the parameter is set, verify that the value is an int
+    for(std::set<std::string>::iterator it = integerParams.begin();it != integerParams.end();it++){
+        if((paramMap.find(*it) != paramMap.end()) && 
+            (0 != yaffs_validate_integer_field(paramMap[*it]))){
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_FS);
+            tsk_error_set_errstr(
+                        "yaffs_validate_config_file: Empty or non-integer value for Yaffs2 parameter \"%s\". %s", (*it).c_str(), YAFFS_HELP_MESSAGE);
+            return 1;
+        }
+    }
+
+    // Check that we have all three spare offset fields, or none of the three
+    offset_field_count = 0;
+    if(paramMap.find(YAFFS_CONFIG_SEQ_NUM_STR) != paramMap.end()){
+        offset_field_count++;
+    }
+    if(paramMap.find(YAFFS_CONFIG_OBJ_ID_STR) != paramMap.end()){
+        offset_field_count++;
+    }
+    if(paramMap.find(YAFFS_CONFIG_CHUNK_ID_STR) != paramMap.end()){
+        offset_field_count++;
+    }
+
+    if(! ((offset_field_count == 0) || (offset_field_count == 3))){
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_FS);
+            tsk_error_set_errstr(
+                        "yaffs_validate_config_file: Require either all three spare offset fields or none. %s", YAFFS_HELP_MESSAGE);
+            return 1;
+    }
+
+    // Make sure there aren't any unexpected fields present
+    for(std::map<std::string, std::string>::iterator it = paramMap.begin(); it != paramMap.end();it++){
+        if(integerParams.find(it->first) == integerParams.end()){
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_FS);
+            tsk_error_set_errstr(
+                        "yaffs_validate_config_file: Found unexpected field in config file (\"%s\"). %s", it->first.c_str(), YAFFS_HELP_MESSAGE);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
 /*
 * Function to attempt to determine the layout of the yaffs spare area.
 * Results of the analysis (if the format could be determined) will be stored
@@ -666,6 +886,8 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
     unsigned int chunksToTest = 10;  // Number of chunks to test in each block 
     unsigned int minChunksRead = 10; // Minimum number of chunks we require to run the test (we might not get the full number we want to test for a very small file)
 
+    unsigned int chunkSize = yfs->page_size + yfs->spare_size;
+    unsigned int blockSize = yfs->chunks_per_block * chunkSize;
 
     TSK_FS_INFO *fs = &(yfs->fs_info);
     unsigned int cnt;
@@ -677,6 +899,7 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
     unsigned int currentOffset;
 
     unsigned char * allSpares;
+    unsigned int allSparesLength;
     TSK_OFF_T offset;
     TSK_OFF_T maxBlocks;
 
@@ -696,19 +919,23 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
     int thisChunkBase;
     int lastChunkBase;
 
-    if ((spareBuffer = (unsigned char*) tsk_malloc(yfs->spare_size)) == NULL) {
+    // The spare area needs to be at least 16 bytes to run the test
+    if(yfs->spare_size < 16){
+        if(tsk_verbose && (! yfs->autoDetect)){
+            tsk_fprintf(stderr,
+                "yaffs_initialize_spare_format failed - given spare size (%d) is not large enough to contain needed fields\n", yfs->spare_size);
+        }
         return TSK_ERR;
     }
 
-    if ((allSpares = (unsigned char*) tsk_malloc(yfs->spare_size * blocksToTest * chunksToTest)) == NULL) {
-        free(spareBuffer);
+    if ((spareBuffer = (unsigned char*) tsk_malloc(yfs->spare_size)) == NULL) {
         return TSK_ERR;
     }
 
-    // Initialize the array containing the spares so that uninitialized entries won't cause failure if we don't have enough
-    // data to fill it.
-    for(i = 0;i < yfs->spare_size * blocksToTest * chunksToTest;i++){
-        allSpares[i] = 0x01;
+    allSparesLength = yfs->spare_size * blocksToTest * chunksToTest;
+    if ((allSpares = (unsigned char*) tsk_malloc(allSparesLength)) == NULL) {
+        free(spareBuffer);
+        return TSK_ERR;
     }
 
     // Initialize the pointers to one of the configurations we've seen (thought these defaults should not get used)
@@ -727,7 +954,7 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
     //  observed exception.
 
     // Calculate the number of blocks in the image
-    maxBlocks = yfs->fs_info.img_info->size / (yfs->chunks_per_block * (yfs->page_size + yfs->spare_size));
+    maxBlocks = yfs->fs_info.img_info->size / (yfs->chunks_per_block * chunkSize);
 
     // If maxBlocksToTest = 0 (unlimited), set it to the total number of blocks
     // Also reduce the number of blocks to test if it is larger than the total number of blocks
@@ -740,7 +967,7 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
     for(TSK_OFF_T blockIndex = 0;blockIndex < maxBlocksToTest;blockIndex++){
 
         // Read the last spare area that we want to test first
-        offset = (TSK_OFF_T)blockIndex * yfs->chunks_per_block * (yfs->page_size + yfs->spare_size) + (chunksToTest - 1) * (yfs->page_size + yfs->spare_size) + yfs->page_size;
+        offset = (TSK_OFF_T)blockIndex * blockSize + (chunksToTest - 1) * chunkSize + yfs->page_size;
         cnt = tsk_img_read(fs->img_info, offset, (char *) spareBuffer,
             yfs->spare_size);
         if (cnt == -1 || cnt < yfs->spare_size) {
@@ -774,7 +1001,7 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
 
         // Copy all earlier spare areas in the block
         for(chunkIndex = 0;chunkIndex < chunksToTest - 1;chunkIndex++){
-            offset = blockIndex * yfs->chunks_per_block * (yfs->page_size + yfs->spare_size) + chunkIndex * (yfs->page_size + yfs->spare_size) + yfs->page_size;
+            offset = blockIndex * blockSize + chunkIndex * chunkSize + yfs->page_size;
             cnt = tsk_img_read(fs->img_info, offset, (char *) spareBuffer,
                 yfs->spare_size);
             if (cnt == -1 || cnt < yfs->spare_size) {
@@ -817,7 +1044,7 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
 
     // Print out the collected spare areas if we're in verbose mode
     if(tsk_verbose && (! yfs->autoDetect)){
-        for(blockIndex = 0;blockIndex < blocksToTest;blockIndex++){
+        for(blockIndex = 0;blockIndex < nBlocksTested;blockIndex++){
             for(chunkIndex = 0;chunkIndex < chunksToTest;chunkIndex++){
                 for(i = 0;i < yfs->spare_size;i++){
                     fprintf(stderr, "%02x", allSpares[blockIndex * yfs->spare_size * chunksToTest + chunkIndex * yfs->spare_size + i]);
@@ -828,9 +1055,9 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
     }
 
     // Test all indices into the spare area (that leave enough space for all 16 bytes)
-    for(currentOffset = 0;currentOffset < yfs->spare_size - 16;currentOffset++){
+    for(currentOffset = 0;currentOffset <= yfs->spare_size - 16;currentOffset++){
         goodOffset = 1;
-        for(blockIndex = 0;blockIndex < blocksToTest;blockIndex++){
+        for(blockIndex = 0;blockIndex < nBlocksTested;blockIndex++){
             for(chunkIndex = 1;chunkIndex < chunksToTest;chunkIndex++){
 
                 lastChunkBase = blockIndex * yfs->spare_size * chunksToTest + (chunkIndex - 1) * yfs->spare_size;
@@ -901,7 +1128,7 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
                         break;
                     }
                 }
-                if(allSameByte && (allSpares[thisChunkBase + currentOffset] != 0x01)){ // allSpares was initialized with all 0x01 - there might be lines of it left
+                if(allSameByte){
                     if(tsk_verbose && (! yfs->autoDetect)){
                         tsk_fprintf(stderr,
                             "yaffs_initialize_spare_format: Elimimating offset %d - all repeated bytes\n", 
@@ -937,7 +1164,7 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
 
             // We probably don't want the first byte to always be 0xff
             int firstByteFF = 1;
-            for(blockIndex = 0;blockIndex < blocksToTest;blockIndex++){
+            for(blockIndex = 0;blockIndex < nBlocksTested;blockIndex++){
                 for(chunkIndex = 1;chunkIndex < chunksToTest;chunkIndex++){
                     if(allSpares[blockIndex * yfs->spare_size * chunksToTest + chunkIndex * yfs->spare_size + currentOffset] != 0xff){
                         firstByteFF = 0;
@@ -993,6 +1220,8 @@ yaffs_initialize_spare_format(YAFFSFS_INFO * yfs, TSK_OFF_T maxBlocksToTest){
             tsk_fprintf(stderr,
                 "yaffs_initialize_spare_format: Final offsets: %d (sequence number), %d (object id), %d (chunk id), %d (n bytes)\n",
                 bestOffset, bestOffset+4, bestOffset+8, bestOffset+12);
+            tsk_fprintf(stderr,
+                "If these do not seem valid: %s\n", YAFFS_HELP_MESSAGE);
         }
         return TSK_OK;
     }
@@ -1079,11 +1308,18 @@ static uint8_t
     uint32_t object_id;
     uint32_t chunk_id;
 
+    // Should have checked this by now, but just in case
+    if((yfs->spare_seq_offset + 4 > yfs->spare_size) ||
+        (yfs->spare_obj_id_offset + 4 > yfs->spare_size) ||
+        (yfs->spare_chunk_id_offset + 4 > yfs->spare_size)){
+            return 1;
+    }
+
     if ((spr = (unsigned char*) tsk_malloc(yfs->spare_size)) == NULL) {
         return 1;
     }
 
-    if (yfs->spare_size < 46) {
+    if (yfs->spare_size < 46) { // Why is this 46?
         tsk_error_reset();
         tsk_error_set_errno(TSK_ERR_FS_ARG);
         tsk_error_set_errstr("yaffsfs_read_spare: spare size is too small");
@@ -1528,7 +1764,6 @@ static uint8_t
     uint8_t type;
     char *real_name;
 
-
     if (a_fs_file == NULL) {
         tsk_error_set_errno(TSK_ERR_FS_ARG);
         tsk_error_set_errstr("yaffsfs_inode_lookup: fs_file is NULL");
@@ -1569,6 +1804,10 @@ static uint8_t
         return 1;
     }
 
+    if(version->ycv_header_chunk == NULL){
+        return 1;
+    }
+
     if (yaffsfs_read_chunk(yfs, &header, &spare, version->ycv_header_chunk->ycc_offset) != TSK_OK) {
         if (tsk_verbose)
             tsk_fprintf(stderr, "yaffs_inode_lookup: yaffsfs_read_chunk failed!\n");
@@ -2218,17 +2457,18 @@ static uint8_t
 static void
     yaffsfs_close(TSK_FS_INFO *fs)
 {
-    YAFFSFS_INFO *yfs = (YAFFSFS_INFO *)fs;
+    if(fs != NULL){
+        YAFFSFS_INFO *yfs = (YAFFSFS_INFO *)fs;
 
-    fs->tag = 0;
+        fs->tag = 0;
 
-    // TODO: Walk and free the cache structures
-    yaffscache_objects_free(yfs);
-    yaffscache_chunks_free(yfs);
+        // Walk and free the cache structures
+        yaffscache_objects_free(yfs);
+        yaffscache_chunks_free(yfs);
 
-    //tsk_deinit_lock(&yaffsfs->lock);
-
-    tsk_fs_free(fs);
+        //tsk_deinit_lock(&yaffsfs->lock);
+        tsk_fs_free(fs);
+	}
 }
 
 typedef struct _dir_open_cb_args {
@@ -2384,6 +2624,7 @@ static TSK_RETVAL_ENUM
         return TSK_ERR;
     }
 
+
     if ((fs_dir->fs_file = 
         tsk_fs_file_open_meta(a_fs, NULL, a_addr)) == NULL) {
             tsk_error_errstr2_concat(" - yaffs_dir_open_meta");
@@ -2661,12 +2902,14 @@ TSK_FS_INFO *
     yaffs2_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset,
     TSK_FS_TYPE_ENUM ftype, uint8_t test)
 {
-    YAFFSFS_INFO *yaffsfs;
-    TSK_FS_INFO *fs;
+    YAFFSFS_INFO *yaffsfs = NULL;
+    TSK_FS_INFO *fs = NULL;
     const unsigned int psize = img_info->page_size;
     const unsigned int ssize = img_info->spare_size;
     YaffsHeader * first_header = NULL;
     TSK_FS_DIR *test_dir;
+    std::map<std::string, std::string> configParams;
+    YAFFS_CONFIG_STATUS config_file_status;
 
     // clean up any error messages that are lying around
     tsk_error_reset();
@@ -2680,13 +2923,47 @@ TSK_FS_INFO *
 
     if ((yaffsfs = (YAFFSFS_INFO *) tsk_fs_malloc(sizeof(YAFFSFS_INFO))) == NULL)
         return NULL;
+    yaffsfs->cache_objects = NULL;
+    yaffsfs->chunkMap = NULL;
+
+    // Read config file (if it exists)
+    config_file_status = yaffs_load_config_file(img_info, configParams);
+    if(config_file_status == YAFFS_CONFIG_ERROR){
+        // tsk_error was set by yaffs_load_config
+        goto on_error;
+    }
+    else if(config_file_status == YAFFS_CONFIG_OK){
+        // Validate the input
+        // If it fails validation, return (tsk_error will be set up already)
+        if(1 == yaffs_validate_config_file(configParams)){
+            goto on_error;
+        }
+    }
+
+    // If we read these fields from the config file, use those values. Otherwise use the defaults
+    if(configParams.find(YAFFS_CONFIG_PAGE_SIZE_STR) != configParams.end()){
+        yaffsfs->page_size = atoi(configParams[YAFFS_CONFIG_PAGE_SIZE_STR].c_str());
+    }
+    else{
+        yaffsfs->page_size = psize == 0 ? YAFFS_DEFAULT_PAGE_SIZE : psize;
+    }
+
+    if(configParams.find(YAFFS_CONFIG_SPARE_SIZE_STR) != configParams.end()){
+        yaffsfs->spare_size = atoi(configParams[YAFFS_CONFIG_SPARE_SIZE_STR].c_str());
+    }
+    else{
+        yaffsfs->spare_size = ssize == 0 ? YAFFS_DEFAULT_SPARE_SIZE : ssize;
+    }
+
+    if(configParams.find(YAFFS_CONFIG_CHUNKS_PER_BLOCK_STR) != configParams.end()){
+        yaffsfs->chunks_per_block = atoi(configParams[YAFFS_CONFIG_CHUNKS_PER_BLOCK_STR].c_str());
+    }
+    else{
+        yaffsfs->chunks_per_block = 64;
+    }
 
-    yaffsfs->page_size = psize == 0 ? YAFFS_DEFAULT_PAGE_SIZE : psize;
-    yaffsfs->spare_size = ssize == 0 ? YAFFS_DEFAULT_SPARE_SIZE : ssize;
-    yaffsfs->chunks_per_block = 64;
     // TODO: Why are 2 different memory allocation methods used in the same code?
     // This makes things unnecessary complex.
-    yaffsfs->chunkMap = new std::map<uint32_t, YaffsCacheChunkGroup>;
     yaffsfs->max_obj_id = 1;
     yaffsfs->max_version = 0;
 
@@ -2708,23 +2985,45 @@ TSK_FS_INFO *
     fs->endian = TSK_LIT_ENDIAN;
 
     // Determine the layout of the spare area
+    // If it was specified in the config file, use those values. Otherwise do the auto-detection
+    if(configParams.find(YAFFS_CONFIG_SEQ_NUM_STR) != configParams.end()){
+        // In the validation step, we ensured that if one of the offsets was set, we have all of them
+        yaffsfs->spare_seq_offset = atoi(configParams[YAFFS_CONFIG_SEQ_NUM_STR].c_str());
+        yaffsfs->spare_obj_id_offset = atoi(configParams[YAFFS_CONFIG_OBJ_ID_STR].c_str());
+        yaffsfs->spare_chunk_id_offset = atoi(configParams[YAFFS_CONFIG_CHUNK_ID_STR].c_str());
+
+        // Check that the offsets are valid for the given spare area size (fields are 4 bytes long)
+        if((yaffsfs->spare_seq_offset + 4 > yaffsfs->spare_size) ||
+            (yaffsfs->spare_obj_id_offset + 4 > yaffsfs->spare_size) ||
+            (yaffsfs->spare_chunk_id_offset + 4 > yaffsfs->spare_size)){
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_FS);
+            tsk_error_set_errstr("yaffs2_open: Offset(s) in config file too large for spare area (size %d). %s", yaffsfs->spare_size, YAFFS_HELP_MESSAGE);
+            goto on_error;
+        }
 
-    // Decide how many blocks to test. If we're not doing auto-detection, set to zero (no limit)
-    unsigned int maxBlocksToTest;
-    if(yaffsfs->autoDetect){
-        maxBlocksToTest = YAFFS_DEFAULT_MAX_TEST_BLOCKS;
+
+        // nBytes isn't currently used, so just set to zero
+        yaffsfs->spare_nbytes_offset = 0;
     }
     else{
-        maxBlocksToTest = 0;
-    }
+        // Decide how many blocks to test. If we're not doing auto-detection, set to zero (no limit)
+        unsigned int maxBlocksToTest;
+        if(yaffsfs->autoDetect){
+            maxBlocksToTest = YAFFS_DEFAULT_MAX_TEST_BLOCKS;
+        }
+        else{
+            maxBlocksToTest = 0;
+        }
 
-    if(yaffs_initialize_spare_format(yaffsfs, maxBlocksToTest) != TSK_OK){
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
-        tsk_error_set_errstr("not a YAFFS file system (bad spare format)");
-        if (tsk_verbose)
-            fprintf(stderr, "yaffsfs_open: could not find valid spare area format\n");
-        goto on_error;
+        if(yaffs_initialize_spare_format(yaffsfs, maxBlocksToTest) != TSK_OK){
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_FS_MAGIC);
+            tsk_error_set_errstr("not a YAFFS file system (bad spare format). %s", YAFFS_HELP_MESSAGE);
+            if (tsk_verbose)
+                fprintf(stderr, "yaffsfs_open: could not find valid spare area format\n%s\n", YAFFS_HELP_MESSAGE);
+            goto on_error;
+        }
     }
 
     /*
@@ -2736,9 +3035,9 @@ TSK_FS_INFO *
     if (yaffsfs_read_header(yaffsfs, &first_header, 0)) {
         tsk_error_reset();
         tsk_error_set_errno(TSK_ERR_FS_MAGIC);
-        tsk_error_set_errstr("not a YAFFS file system (first record)");
+        tsk_error_set_errstr("not a YAFFS file system (first record). %s", YAFFS_HELP_MESSAGE);
         if (tsk_verbose)
-            fprintf(stderr, "yaffsfs_open: invalid first record\n");
+            fprintf(stderr, "yaffsfs_open: invalid first record\n%s\n", YAFFS_HELP_MESSAGE);
         goto on_error;
     }
     free(first_header);
@@ -2798,44 +3097,34 @@ TSK_FS_INFO *
     *       cache is shared among threads.
     */
     //tsk_init_lock(&yaffsfs->lock);
-    yaffsfs->cache_objects = NULL;
+    yaffsfs->chunkMap = new std::map<uint32_t, YaffsCacheChunkGroup>;
     yaffsfs_cache_fs(yaffsfs);
 
     if (tsk_verbose) {
         fprintf(stderr, "yaffsfs_open: done building cache!\n");
         //yaffscache_objects_dump(yaffsfs, stderr);
     }
-    fflush(stderr);
 
     // Update the number of inums now that we've read in the file system
     fs->inum_count = fs->last_inum - 1;
 
     test_dir = tsk_fs_dir_open_meta(fs, fs->root_inum);
     if (test_dir == NULL) {
-        yaffsfs_close(fs);
-
         tsk_error_reset();
         tsk_error_set_errno(TSK_ERR_FS_MAGIC);
-        tsk_error_set_errstr("not a YAFFS file system (no root directory)");
+        tsk_error_set_errstr("not a YAFFS file system (no root directory). %s", YAFFS_HELP_MESSAGE);
         if (tsk_verbose)
-            fprintf(stderr, "yaffsfs_open: invalid file system\n");
-        return NULL;
+            fprintf(stderr, "yaffsfs_open: invalid file system\n%s\n", YAFFS_HELP_MESSAGE);
+        goto on_error;
     }
     tsk_fs_dir_close(test_dir);
 
     return fs;
 
 on_error:
-    // Make sure to free yaffsfs here otherwise it will leak
-    if( yaffsfs != NULL ) {
-        // TODO: where is chunkMap freed in normal operations?
-        if( yaffsfs->chunkMap != NULL ) {
-            yaffsfs->chunkMap->clear();
+    // yaffsfs_close frees all the cache objects
+    yaffsfs_close(fs);
 
-            delete yaffsfs->chunkMap;
-        }
-        free( yaffsfs );
-    }
     return NULL;
 }