From e9230d187de2c4f15c642bc2b663ca2016c57339 Mon Sep 17 00:00:00 2001
From: Richard Cordovano <rcordovano@basistech.com>
Date: Wed, 8 Jan 2014 11:08:01 -0500
Subject: [PATCH] Commit interim hash db work

---
 bindings/java/jni/dataModel_SleuthkitJNI.cpp | 306 +++++++++++--------
 bindings/java/jni/dataModel_SleuthkitJNI.h   |  13 +-
 tsk/hashdb/sqlite.cpp                        |  76 ++---
 tsk/hashdb/tsk_hashdb.cpp                    |  52 +++-
 tsk/hashdb/tsk_hashdb.h                      |  16 +-
 win32/tsk-win.sln                            |  18 +-
 6 files changed, 291 insertions(+), 190 deletions(-)

diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.cpp b/bindings/java/jni/dataModel_SleuthkitJNI.cpp
index c62b8a6ac..c27df257f 100644
--- a/bindings/java/jni/dataModel_SleuthkitJNI.cpp
+++ b/bindings/java/jni/dataModel_SleuthkitJNI.cpp
@@ -255,7 +255,7 @@ JNIEXPORT void JNICALL
     return;
 }
 
-/*
+/**
  * Opens a hash database to use for hash lookups.
  * @param env Pointer to Java environment from which this method was called
  * @param obj The Java object from which this method was called
@@ -281,7 +281,7 @@ JNIEXPORT jint JNICALL
     return hashDbs.size();
 }
 
-/*
+/**
  * Creates a new hash database.
  * @param env Pointer to Java environment from which this method was called
  * @param obj The Java object from which this method was called
@@ -311,7 +311,7 @@ JNIEXPORT jint JNICALL
     return hashDbs.size();
 }
 
-/*
+/**
  * Adds data to a hash database.
  * @param env Pointer to Java environment from which this method was called.
  * @param obj The Java object from which this method was called
@@ -377,7 +377,7 @@ JNIEXPORT jint JNICALL
     return 0;
 }
 
-/*
+/**
  * Queries whether or not a hash database accepts updates.
  * @param env Pointer to Java environment from which this method was called.
  * @param obj The Java object from which this method was called
@@ -402,7 +402,7 @@ JNIEXPORT jboolean JNICALL
     return (jboolean)(db->updateable == 1);
 }
 
-/*
+/**
  * Queries whether or not a hash database can be indexed.
  * @param env Pointer to Java environment from which this method was called.
  * @param obj The Java object from which this method was called
@@ -426,43 +426,103 @@ JNIEXPORT jboolean JNICALL
 
     return (jboolean)(db->uses_external_indexes == 1);
 }
-    
+ 
+// RJCTODO: Need to restore declaration in header file. Need to update Autopsy for receiving NULL.
+// RJCTODO: Finish comment
+/**
+ * @param env Pointer to Java environment from which this method was called.
+ * @param obj The Java object from which this method was called
+ * @param dbHandle A handle for the hash database
+ * @return Path to the hash database, 
+ */
+JNIEXPORT jstring JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbPathNat(JNIEnv * env,
+    jclass obj, jint dbHandle)
+{
+    char cpath[1024]; // RJCTODO: Are these big enough? malloc some space instead?
+
+    if((size_t)dbHandle > hashDbs.size()) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return NULL;
+    }
+
+    TSK_HDB_INFO *db = hashDbs.at(dbHandle-1);
+    if (db == NULL) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return NULL;
+    }
+
+    jstring jpath = NULL;
+    const TSK_TCHAR *db_path = tsk_hdb_get_path(db);
+    if (NULL != db_path) {
+        snprintf(cpath, 1024, "%" PRIttocTSK, db_path);
+        jpath = env->NewStringUTF(cpath);
+    }
+    return jpath;
+}
+
+// RJCTODO: Fix comment.
 /*
- * Get path.
+ * Get path of external index.
  * @param env pointer to java environment this was called from
  * @param obj the java object this was called from
  * @param dbHandle Which DB.
  * @return path
  */
 JNIEXPORT jstring JNICALL
-    Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbPathNat(JNIEnv * env,
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIndexPathNat(JNIEnv * env,
     jclass obj, jint dbHandle)
 {
     char cpath[1024];
-    char *none = "None";   //on error or if no name is available // RJCTODO: Go back to using null if possible...or empty string
 
     if((size_t)dbHandle > hashDbs.size()) {
         setThrowTskCoreError(env, "Invalid database handle");
-        return env->NewStringUTF(none);
+        return NULL;
     }
 
     TSK_HDB_INFO *db = hashDbs.at(dbHandle-1);
     if (db == NULL) {
         setThrowTskCoreError(env, "Invalid database handle");
-        return env->NewStringUTF(none);
+        return NULL;
     }
 
-    if((db->db_fname != NULL)) {
-        snprintf(cpath, 1024, "%" PRIttocTSK, db->db_fname);
-        jstring jname = env->NewStringUTF(cpath);
-        return jname;
-    } 
-    else {
-        return env->NewStringUTF(none);
+    jstring jpath = NULL;
+    const TSK_TCHAR *db_path = tsk_hdb_get_idx_path(db);
+    if (NULL != db_path) {
+        snprintf(cpath, 1024, "%" PRIttocTSK, db_path);
+        jpath = env->NewStringUTF(cpath);
     }
+    return jpath;
 }
 
-/*
+// RJCTODO: Fix comment.
+/**
+ * Test for index only (no original Db file) legacy (IDX format).
+ * @param env pointer to java environment this was called from
+ * @param obj the java object this was called from
+ * @param dbHandle Which DB.
+ * @return true if index only AND is legacy
+ */
+JNIEXPORT jboolean JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIsIdxOnlyNat(JNIEnv * env,
+    jclass obj, jint dbHandle)
+{
+    if((size_t)dbHandle > hashDbs.size()) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return (jboolean)false;
+    }
+
+    TSK_HDB_INFO *db = hashDbs.at(dbHandle-1);
+    if (db == NULL) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return (jboolean)false;
+    }
+
+    return (jboolean)(db->db_type == TSK_HDB_DBTYPE_IDXONLY_ID);
+}
+
+// RJCTODO: Fix comment.
+/**
  * Get the name of the database pointed to by path
  * @param env pointer to java environment this was called from
  * @param obj the java object this was called from
@@ -471,25 +531,30 @@ JNIEXPORT jstring JNICALL
 JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbGetName
   (JNIEnv * env, jclass obj, jint dbHandle)
 {
-    // RJCTODO: Decide the fate of this
-    //if((size_t) dbHandle > hashDbs.size()) {
-    //    setThrowTskCoreError(env, "Invalid database handle");
-    //    return env->NewStringUTF("-1");
-    //} else {
-    //    TSK_HDB_INFO * temp = hashDbs.at(dbHandle-1);
-    //    if (temp == NULL) {
-    //        setThrowTskCoreError(env, "Error: database object is null");
-    //        return env->NewStringUTF("-1");
-    //    }
-
-
-    //    jstring jname = env->NewStringUTF(temp->db_name);
-    //    return jname;
-    //}
-    return env->NewStringUTF("-1");
+    char c_name[1024];
+
+    if((size_t)dbHandle > hashDbs.size()) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return NULL;
+    }
+
+    TSK_HDB_INFO *db = hashDbs.at(dbHandle-1);
+    if (db == NULL) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return NULL;
+    }
+
+    jstring j_name = NULL;
+    const TSK_TCHAR *db_name = tsk_hdb_get_name(db);
+    if (NULL != db_name) {
+        snprintf(c_name, 1024, "%" PRIttocTSK, db_name);
+        j_name = env->NewStringUTF(c_name);
+    }
+    return j_name;
 }
 
-/*
+// RJCTODO: Fix comment.
+/**
  * Close all hash dbs and destroy associated memory structures.
  * And it resets the handle counting.
  * @param env pointer to java environment this was called from
@@ -509,7 +574,8 @@ JNIEXPORT void JNICALL
     hashDbs.clear();
 }
 
-/*
+// RJCTODO: Fix comment.
+/**
  * Close a hash db and destroy associated memory structures.
  * Existing handles are not affected.
  * @param env pointer to java environment this was called from
@@ -538,7 +604,8 @@ JNIEXPORT void JNICALL
     hashDbs.at(dbHandle-1) = NULL;
 }
 
-/*
+// RJCTODO: Fix comment.
+/**
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
  * Method:    hashDbLookup
  * Signature: (Ljava/lang/String;)I
@@ -581,75 +648,73 @@ JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbLooku
  */
 JNIEXPORT jobject JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbLookupVerbose
 (JNIEnv * env, jclass obj, jstring hash, jint dbHandle) {
-    
-    // RJCTODO: This is the troubling stuff that needs to be enhanced with
-    // a query to determine if verbose lookup is supported; there then needs
-    // to be a function ptr in the TSKDHB_INFO to handle this;
-    // need to check to see how Sam's new code is handling this for the sake of integration
+    if((size_t)dbHandle > hashDbs.size()) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return (jboolean)false;
+    }
+
+    TSK_HDB_INFO *db = hashDbs.at(dbHandle-1);
+    if (db == NULL) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return (jboolean)false;
+    }
+
+
+    if (tsk_hdb_has_verbose_lookup(db) == 0) {
+        setThrowTskCoreError(env, "Invalid database operation, verbose lookup not supported");
+        return (jboolean)false;
+    }
+
+    // RJCTODO: need to check to see how Sam's new code is handling this for the sake of integration
     // (or is there code in this code base in AbstractAbstractFileNode?)
     
     jobject object = NULL;
-    SQliteHashStruct * hdata = NULL;
-
-    //if((size_t) dbHandle > hashDbs.size()) {
-    //    setThrowTskCoreError(env, "Invalid database handle");
-    //    return NULL;
-    //}
-
-    //jboolean isCopy;
-    //const char *inputHash = (const char *) env->GetStringUTFChars(hash, &isCopy);
-
-    //TSK_HDB_INFO * db = hashDbs.at(dbHandle-1);
-    //if (db != NULL) {
-    //    // tsk_hdb_lookup_str will also make sure the index struct is setup
-    //    int64_t hashId = tsk_hdb_lookup_str_id(db, inputHash);
-
-    //    if ((hashId > 0) && (db->idx_info->getAllData != NULL)) {
-    //        // Find the data associated with this hash
-    //        hdata = (SQliteHashStruct *)(db->idx_info->getAllData(db, hashId));
-
-    //        // Build the Java version of the HashInfo object
-    //        jclass clazz;
-    //        clazz = env->FindClass("org/sleuthkit/datamodel/HashInfo");
-    //        // get methods
-    //        jmethodID ctor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
-    //        jmethodID addName = env->GetMethodID(clazz, "addName", "(Ljava/lang/String;)V");
-    //        jmethodID addComment = env->GetMethodID(clazz, "addComment", "(Ljava/lang/String;)V");
-
-    //        //convert hashes
-    //        const char *md5 = hdata->hashMd5.c_str();
-    //        jstring md5j = env->NewStringUTF(md5);
-    //        
-    //        const char *sha1 = hdata->hashSha1.c_str();
-    //        jstring sha1j = env->NewStringUTF(sha1);
-    //        
-    //        const char *sha256 = hdata->hashSha2_256.c_str();
-    //        jstring sha256j = env->NewStringUTF(sha256);
-
-    //        // make the object
-    //        object = env->NewObject(clazz, ctor, md5j, sha1j, sha256j);
-
-    //        // finish populating the object
-    //        std::vector<std::string>::iterator name_it = hdata->names.begin();
-    //        for (; name_it != hdata->names.end(); ++name_it) {
-    //            const char *name = name_it->c_str();
-    //            jstring namej = env->NewStringUTF(name);
-    //            env->CallVoidMethod(object, addName, namej);
-    //        }
-
-    //        std::vector<std::string>::iterator comment_it = hdata->comments.begin();
-    //        for (; comment_it != hdata->comments.end(); ++comment_it) {
-    //            const char *comment = comment_it->c_str();
-    //            jstring commentj = env->NewStringUTF(comment);
-    //            env->CallVoidMethod(object, addComment, commentj);
-    //        }
-
-    //    }
-    //}
-
-    //// Cleanup
-    //env->ReleaseStringUTFChars(hash, (const char *) inputHash);
-    //delete hdata;
+    //SQliteHashStruct * hdata = NULL;
+
+    jboolean isCopy;
+    const char *inputHash = (const char *) env->GetStringUTFChars(hash, &isCopy);
+
+    TskHashLookupResult *result = (TskHashLookupResult*)tsk_hdb_lookup_verbose_str(db, inputHash);
+
+    // RJCTODO: Looks like a better name...
+    // Build the Java version of the HashInfo object
+    jclass clazz;
+    clazz = env->FindClass("org/sleuthkit/datamodel/HashInfo");
+    jmethodID ctor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+    jmethodID addName = env->GetMethodID(clazz, "addName", "(Ljava/lang/String;)V");
+    jmethodID addComment = env->GetMethodID(clazz, "addComment", "(Ljava/lang/String;)V");
+
+    //convert hashes
+    const char *md5 = result->hashMd5.c_str();
+    jstring md5j = env->NewStringUTF(md5);
+            
+    const char *sha1 = result->hashSha1.c_str();
+    jstring sha1j = env->NewStringUTF(sha1);
+            
+    const char *sha256 = result->hashSha2_256.c_str();
+    jstring sha256j = env->NewStringUTF(sha256);
+
+    // make the object
+    object = env->NewObject(clazz, ctor, md5j, sha1j, sha256j);
+
+    // finish populating the object
+    std::vector<std::string>::iterator name_it = result->names.begin();
+    for (; name_it != result->names.end(); ++name_it) {
+        const char *name = name_it->c_str();
+        jstring namej = env->NewStringUTF(name);
+        env->CallVoidMethod(object, addName, namej);
+    }
+
+    std::vector<std::string>::iterator comment_it = result->comments.begin();
+    for (; comment_it != result->comments.end(); ++comment_it) {
+        const char *comment = comment_it->c_str();
+        jstring commentj = env->NewStringUTF(comment);
+        env->CallVoidMethod(object, addComment, commentj);
+    }
+
+    // Cleanup
+    env->ReleaseStringUTFChars(hash, (const char *) inputHash);
+    delete result; // RJCTODO: Should this be a free?
 
     return object;
 }
@@ -1586,7 +1651,7 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbCreateIndexNat (JNIEnv * env,
         return;
     }
 
-    if (!db->uses_external_index) {
+    if (!db->uses_external_indexes) {
         setThrowTskCoreError(env, "Database does not have an external index");
         return;
     }
@@ -1607,38 +1672,9 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbCreateIndexNat (JNIEnv * env,
         TSNPRINTF(idx_type, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_NSRL_MD5_STR);
     }
   
-    if (tsk_hdb_makeindex(db, idx_type) != 0) {
+    if (tsk_hdb_make_index(db, idx_type) != 0) {
         setThrowTskCoreError(env);
     }
-
-    // RJCTODO: Remove this
-    //// [Re]create the hash information and file
-    //uint8_t err = tsk_hdb_regenerate_index(db, dbType, (overwrite ? 1 : 0));
-
-    //// Make an error message
-    //if (err > 0) {
-    //    char c_db_type[32];
-    //    snprintf(c_db_type, 32, "%" PRIttocTSK, dbType);
-    //    std::string dbTypeStr(c_db_type);
-
-    //    std::string msg("Error: index regeneration (db_type = " + dbTypeStr + "): ");
-    //    switch (err) {
-    //        case 1: 
-    //            msg += "delete old failed.";
-    //        break;
-    //        case 2: 
-    //            msg += "delete old (2nd pass) failed.";
-    //        break;
-    //        case 3: 
-    //            msg += "tsk_hdb_makeindex failed.";
-    //        break;
-    //    }
-    //    setThrowTskCoreError(env, msg.c_str());
-    //    return;
-    //}
-
-    //// success
-    //return;
 }
 
 /*
diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.h b/bindings/java/jni/dataModel_SleuthkitJNI.h
index 10eb640b4..32544c35a 100644
--- a/bindings/java/jni/dataModel_SleuthkitJNI.h
+++ b/bindings/java/jni/dataModel_SleuthkitJNI.h
@@ -96,11 +96,11 @@ JNIEXPORT jboolean JNICALL
 
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
- * Method:    hashDbUsesExternalIndexesNat
+ * Method:    hashDbIsReindexableNat
  * Signature: 
  */
 JNIEXPORT jboolean JNICALL
-    Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbUsesExternalIndexesNat(JNIEnv * env,
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIsReindexableNat(JNIEnv * env,
     jclass obj, jint dbHandle);
 
 /*
@@ -112,6 +112,15 @@ JNIEXPORT jstring JNICALL
     Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbPathNat(JNIEnv * env,
     jclass obj, jint dbHandle);
 
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    hashDbIndexPathNat
+ * Signature: 
+ */
+JNIEXPORT jstring JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIndexPathNat(JNIEnv * env,
+    jclass obj, jint dbHandle);
+
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
  * Method:    hashDbGetName
diff --git a/tsk/hashdb/sqlite.cpp b/tsk/hashdb/sqlite.cpp
index 1e1ba0ffc..c8e87d6c7 100644
--- a/tsk/hashdb/sqlite.cpp
+++ b/tsk/hashdb/sqlite.cpp
@@ -21,6 +21,9 @@
 
 static const int chunkSize = 1024 * 1024;
 static sqlite3_stmt *m_stmt = NULL; // RJCTODO: Get rid of the m_
+
+
+
 static bool need_SQL_index = false; // RJCTODO: Get rid of this
 static const char hex[] = "0123456789abcdef";
 uint8_t sqlite_v1_addentry_bin(TSK_HDB_INFO * hdb_info, uint8_t* hvalue, int hlen, TSK_OFF_T offset);
@@ -306,45 +309,50 @@ sqlite_hdb_add(TSK_HDB_INFO * hdb_info, const char * filename, const char * md5,
 //}
 
 /**
- * This function is a no-op for SQLite hash database. The index is "internal" to the RDBMS.
  * @return 1 on error and 0 on success
  */
-//uint8_t
-//sqlite_v1_addentry_bin(TSK_HDB_INFO * hdb_info, uint8_t* hvalue, int hlen,
-//                    TSK_OFF_T offset)
-//{
-// RJCTODO: This needs to go into a separate add to hash database function, as opposed to an add to index function
- //   if (attempt(sqlite3_bind_blob(m_stmt, 1, hvalue, hlen, SQLITE_TRANSIENT),
-	//	SQLITE_OK,
-	//	"Error binding binary blob: %s\n",
-	//	hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite) ||
-	//	attempt(sqlite3_bind_int64(m_stmt, 2, offset),
-	//	SQLITE_OK,
-	//	"Error binding entry offset: %s\n",
-	//	hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite) ) {
- //       return 1;
- //   }
+uint8_t
+sqlite_hdb_add_hash(TSK_HDB_INFO * hdb_info_base, const char *filename, 
+    const char *md5, const char *sha1, const char *sha256, const char *comment)
+{
+    TSK_SQLITE_HDB_INFO *hdb_info = (TSK_SQLITE_HDB_INFO*)hdb_info_base;
 
- //   // Don't report error on constraint -- we just will silently not add that duplicate hash
-	//int r = sqlite3_step(m_stmt);
- //   if ((r != SQLITE_DONE) && (r != SQLITE_CONSTRAINT) ) {
-	//	tsk_error_reset();
-	//	tsk_error_set_errno(TSK_ERR_AUTO_DB);
-	//	tsk_error_set_errstr("Error stepping: %s\n", sqlite3_errmsg( hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite), r);
- //       return 1;
- //   }
+    // RJCTODO: hash_len funk
+    if (attempt(sqlite3_bind_blob(m_stmt, 1, md5, hdb_info_base->hash_len, SQLITE_TRANSIENT),
+		SQLITE_OK,
+		"Error binding binary blob: %s\n",
+        hdb_info->db)) {
+        return 1;
+    }
 
-	//r = sqlite3_reset(m_stmt);
- //   if ((r != SQLITE_OK) && (r != SQLITE_CONSTRAINT) ) {
-	//	tsk_error_reset();
-	//	tsk_error_set_errno(TSK_ERR_AUTO_DB);
-	//	tsk_error_set_errstr("Error resetting: %s\n", sqlite3_errmsg( hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite), r);
- //       return 1;
- //   }
+    uint64_t row_id = 0;
+    // RJCTODO: Need to do a query here, to get an id
 
- //   return 0;
-//    return 0;
-//}
+    // RJCTODO: If no id found, add and get id
+    // Don't report error on constraint -- we just will silently not add that duplicate hash
+	    int r = sqlite3_step(m_stmt);
+        if ((r != SQLITE_DONE) && (r != SQLITE_CONSTRAINT) ) {
+		    tsk_error_reset();
+		    tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		    tsk_error_set_errstr("Error stepping: %s\n", sqlite3_errmsg(hdb_info->db), r);
+            return 1;
+        }
+
+        // RJCTODO: I guess this is needed, not done in other TSK/Autopsy code?
+	    r = sqlite3_reset(m_stmt);
+        if ((r != SQLITE_OK) && (r != SQLITE_CONSTRAINT) ) {
+		    tsk_error_reset();
+		    tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		    tsk_error_set_errstr("Error resetting: %s\n", sqlite3_errmsg(hdb_info->db), r);
+            return 1;
+        }
+        row_id = sqlite3_last_insert_rowid(hdb_info->db);
+
+
+    // RJCTODO: Insert 
+
+    return 0;
+}
 
 /**
  * This function is a no-op for SQLite hash database. The index is "internal" to the RDBMS.
diff --git a/tsk/hashdb/tsk_hashdb.cpp b/tsk/hashdb/tsk_hashdb.cpp
index 0d90ac46f..398926578 100644
--- a/tsk/hashdb/tsk_hashdb.cpp
+++ b/tsk/hashdb/tsk_hashdb.cpp
@@ -241,6 +241,45 @@ tsk_hdb_open(TSK_TCHAR *file_path, TSK_HDB_OPEN_ENUM flags)
     return hdb_info;
 }
 
+const TSK_TCHAR *tsk_hdb_get_path(TSK_HDB_INFO * hdb_info)
+{
+    assert(hdb_info);
+    if (!hdb_info) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr("tsk_hdb_get_path: NULL hdb_info");
+        return 0;
+    }
+
+    return hdb_info->get_db_path(hdb_info);
+}
+
+const TSK_TCHAR *tsk_hdb_get_name(TSK_HDB_INFO * hdb_info)
+{
+    assert(hdb_info);
+    if (!hdb_info) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr("tsk_hdb_get_path: NULL hdb_info");
+        return 0;
+    }
+
+    return hdb_info->get_db_name(hdb_info);
+}
+
+const TSK_TCHAR *tsk_hdb_get_idx_path(TSK_HDB_INFO * hdb_info)
+{
+    assert(hdb_info);
+    if (!hdb_info) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr("tsk_hdb_get_path: NULL hdb_info");
+        return 0;
+    }
+
+    return hdb_info->get_index_path(hdb_info);
+}
+
 /**
  * \ingroup hashdblib
  * Determine if the open hash database has an index.
@@ -465,14 +504,23 @@ tsk_hdb_lookup_bin(TSK_HDB_INFO * hdb_info, uint8_t * hash, uint8_t len,
 }
 
 uint8_t 
-tsk_hdb_has_verbose_lookup()
+tsk_hdb_has_verbose_lookup(TSK_HDB_INFO *hdb_info)
 {
+    assert(hdb_info);
+    if (!hdb_info) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr("tsk_hdb_has_verbose_lookup: NULL hdb_info");
+        return 0;
+    }
+
+    return hdb_info->has_verbose_lookup(hdb_info);
 }
  
 void *
 tsk_hdb_lookup_verbose_str(TSK_HDB_INFO *hdb_info, const char *hash)
 {
-    if (hdb_info->has_verbose_lookup()) {
+    if (hdb_info->has_verbose_lookup(hdb_info)) {
         return hdb_info->lookup_verbose_str(hdb_info, hash);
     }
     else {
diff --git a/tsk/hashdb/tsk_hashdb.h b/tsk/hashdb/tsk_hashdb.h
index 4da6cedab..dc9cdd3f9 100644
--- a/tsk/hashdb/tsk_hashdb.h
+++ b/tsk/hashdb/tsk_hashdb.h
@@ -125,15 +125,18 @@ extern "C" {
         TSK_HDB_DBTYPE_ENUM db_type;  ///< Type of database
         TSK_HDB_HTYPE_ENUM hash_type; ///< Type of hash used in index 
         uint16_t hash_len;            ///< Length of hash 
-        uint8_t updateable;           ///< Allow new entries to be added? // RJCTODO: Could be done by dbtype, as is also true for 
-        uint8_t uses_external_indexes; // RJCTODO: Is this a good idea?           
+        uint8_t updateable;           ///< Allow new entries to be added? // RJCTODO: Could become function
+        uint8_t uses_external_indexes; // RJCTODO: Could become function           
         tsk_lock_t lock;              ///< Lock for lazy loading and idx_lbuf
+        const TSK_TCHAR*(*get_db_path)(TSK_HDB_INFO *);
+        const TSK_TCHAR*(*get_db_name)(TSK_HDB_INFO *);
         uint8_t(*has_index)(TSK_HDB_INFO *, TSK_HDB_HTYPE_ENUM);
         uint8_t(*make_index)(TSK_HDB_INFO *, TSK_TCHAR *);     ///< \internal Database-specific function to make index 
         uint8_t(*open_index)(TSK_HDB_INFO *, TSK_HDB_HTYPE_ENUM);
+        const TSK_TCHAR*(*get_index_path)(TSK_HDB_INFO *);
         int8_t(*lookup_str)(TSK_HDB_INFO *, const char *, TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *);
         int8_t(*lookup_raw)(TSK_HDB_INFO *, uint8_t *, uint8_t, TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *);
-        uint8_t(*has_verbose_lookup)();
+        uint8_t(*has_verbose_lookup)(TSK_HDB_INFO *);
         void*(*lookup_verbose_str)(TSK_HDB_INFO *, const char *);
         uint8_t(*add_comment)(TSK_HDB_INFO *, char *, int64_t); // RJCTODO: Can probably go away
         uint8_t(*add_filename)(TSK_HDB_INFO *, char *, int64_t); // RJCTODO: Can probably go away
@@ -173,15 +176,18 @@ extern "C" {
     /* Functions */
     extern uint8_t tsk_hdb_create(TSK_TCHAR *);
     extern TSK_HDB_INFO *tsk_hdb_open(TSK_TCHAR *, TSK_HDB_OPEN_ENUM);
+    extern const TSK_TCHAR *tsk_hdb_get_path(TSK_HDB_INFO * hdb_info);
+    extern const TSK_TCHAR *tsk_hdb_get_name(TSK_HDB_INFO * hdb_info);
     extern uint8_t tsk_hdb_has_idx(TSK_HDB_INFO * hdb_info, TSK_HDB_HTYPE_ENUM htype);
     extern uint8_t tsk_hdb_is_idx_only(TSK_HDB_INFO *);
     extern uint8_t tsk_hdb_make_index(TSK_HDB_INFO *, TSK_TCHAR *);
+    extern const TSK_TCHAR *tsk_hdb_get_idx_path(TSK_HDB_INFO * hdb_info);
     extern int8_t tsk_hdb_lookup_str(TSK_HDB_INFO *, const char *,
         TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *);
     extern int8_t tsk_hdb_lookup_bin(TSK_HDB_INFO *, uint8_t *, uint8_t, 
         TSK_HDB_FLAG_ENUM,  TSK_HDB_LOOKUP_FN, void *);
-    extern uint8_t tsk_hdb_has_verbose_lookup();
-    extern void *tsk_hdb_lookup_verbose(TSK_HDB_INFO *, const char *);
+    extern uint8_t tsk_hdb_has_verbose_lookup(TSK_HDB_INFO *);
+    extern void *tsk_hdb_lookup_verbose_str(TSK_HDB_INFO *, const char *);
     extern int8_t tsk_hdb_add_hash(TSK_HDB_INFO *, const char*, const char*, 
         const char*, const char*, const char*);
     extern void tsk_hdb_close(TSK_HDB_INFO * hdb_info);
diff --git a/win32/tsk-win.sln b/win32/tsk-win.sln
index bec973555..dcfa33374 100644
--- a/win32/tsk-win.sln
+++ b/win32/tsk-win.sln
@@ -397,28 +397,22 @@ Global
 		{11A8927C-F971-4104-A286-5DC11C25E2EC}.Release|x64.Build.0 = Release|x64
 		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Debug_NoLibs|Win32.ActiveCfg = Debug_NoLibs|Win32
 		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Debug_NoLibs|Win32.Build.0 = Debug_NoLibs|Win32
-		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Debug_NoLibs|x64.ActiveCfg = Debug_NoLibs|x64
-		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Debug_NoLibs|x64.Build.0 = Debug_NoLibs|x64
+		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Debug_NoLibs|x64.ActiveCfg = Debug_NoLibs|Win32
 		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Debug|Win32.ActiveCfg = Debug|Win32
 		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Debug|Win32.Build.0 = Debug|Win32
-		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Debug|x64.ActiveCfg = Debug|x64
-		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Debug|x64.Build.0 = Debug|x64
+		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Debug|x64.ActiveCfg = Debug|Win32
 		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Release|Win32.ActiveCfg = Release|Win32
 		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Release|Win32.Build.0 = Release|Win32
-		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Release|x64.ActiveCfg = Release|x64
-		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Release|x64.Build.0 = Release|x64
+		{62D88133-09F6-4E13-B39F-36FCEFBE4FAF}.Release|x64.ActiveCfg = Release|Win32
 		{76EFC06C-1F64-4478-ABE8-79832716B393}.Debug_NoLibs|Win32.ActiveCfg = Debug_NoLibs|Win32
 		{76EFC06C-1F64-4478-ABE8-79832716B393}.Debug_NoLibs|Win32.Build.0 = Debug_NoLibs|Win32
-		{76EFC06C-1F64-4478-ABE8-79832716B393}.Debug_NoLibs|x64.ActiveCfg = Debug_NoLibs|x64
-		{76EFC06C-1F64-4478-ABE8-79832716B393}.Debug_NoLibs|x64.Build.0 = Debug_NoLibs|x64
+		{76EFC06C-1F64-4478-ABE8-79832716B393}.Debug_NoLibs|x64.ActiveCfg = Debug_NoLibs|Win32
 		{76EFC06C-1F64-4478-ABE8-79832716B393}.Debug|Win32.ActiveCfg = Debug|Win32
 		{76EFC06C-1F64-4478-ABE8-79832716B393}.Debug|Win32.Build.0 = Debug|Win32
-		{76EFC06C-1F64-4478-ABE8-79832716B393}.Debug|x64.ActiveCfg = Debug|x64
-		{76EFC06C-1F64-4478-ABE8-79832716B393}.Debug|x64.Build.0 = Debug|x64
+		{76EFC06C-1F64-4478-ABE8-79832716B393}.Debug|x64.ActiveCfg = Debug|Win32
 		{76EFC06C-1F64-4478-ABE8-79832716B393}.Release|Win32.ActiveCfg = Release|Win32
 		{76EFC06C-1F64-4478-ABE8-79832716B393}.Release|Win32.Build.0 = Release|Win32
-		{76EFC06C-1F64-4478-ABE8-79832716B393}.Release|x64.ActiveCfg = Release|x64
-		{76EFC06C-1F64-4478-ABE8-79832716B393}.Release|x64.Build.0 = Release|x64
+		{76EFC06C-1F64-4478-ABE8-79832716B393}.Release|x64.ActiveCfg = Release|Win32
 		{E4A40368-152D-4D54-9E2E-4B140212F98F}.Debug_NoLibs|Win32.ActiveCfg = Debug_NoLibs|Win32
 		{E4A40368-152D-4D54-9E2E-4B140212F98F}.Debug_NoLibs|Win32.Build.0 = Debug_NoLibs|Win32
 		{E4A40368-152D-4D54-9E2E-4B140212F98F}.Debug_NoLibs|x64.ActiveCfg = Debug_NoLibs|x64
-- 
GitLab