From d396fef3c72c158766c8d731e5d9f974cc048a2c Mon Sep 17 00:00:00 2001
From: apriestman <apriestman@basistech.com>
Date: Wed, 4 Mar 2020 14:25:52 -0500
Subject: [PATCH] Added unallocated space

---
 bindings/java/jni/auto_db_java.cpp            | 351 +++++++++++++++---
 bindings/java/jni/auto_db_java.h              |  33 +-
 .../org/sleuthkit/datamodel/JniDbHelper.java  | 102 +++--
 .../sleuthkit/datamodel/SleuthkitCase.java    | 121 ++++--
 4 files changed, 492 insertions(+), 115 deletions(-)

diff --git a/bindings/java/jni/auto_db_java.cpp b/bindings/java/jni/auto_db_java.cpp
index c290733f2..c8ea89b22 100644
--- a/bindings/java/jni/auto_db_java.cpp
+++ b/bindings/java/jni/auto_db_java.cpp
@@ -127,7 +127,6 @@ TskAutoDbJava::initializeJni(JNIEnv * jniEnv, jobject jobj) {
         return TSK_ERR;
     }
 
-    //(JJLjava/lang/String;Ljava/lang/String;)J
     m_getParentIdMethodID = m_jniEnv->GetMethodID(m_callbackClass, "findParentObjId", "(JJLjava/lang/String;Ljava/lang/String;)J");
     if (m_getParentIdMethodID == NULL) {
         printf("#### Error loading m_getParentIdMethodID\n");
@@ -135,6 +134,27 @@ TskAutoDbJava::initializeJni(JNIEnv * jniEnv, jobject jobj) {
         return TSK_ERR;
     }
 
+    m_addUnallocParentMethodID = m_jniEnv->GetMethodID(m_callbackClass, "addUnallocFsBlockFilesParent", "(JLjava/lang/String;)J");
+    if (m_addUnallocParentMethodID == NULL) {
+        printf("#### Error loading m_addUnallocParentMethodID\n");
+        fflush(stdout);
+        return TSK_ERR;
+    }
+
+    m_addLayoutFileMethodID = m_jniEnv->GetMethodID(m_callbackClass, "addLayoutFile", "(JJJILjava/lang/String;J)J");
+    if (m_addLayoutFileMethodID == NULL) {
+        printf("#### Error loading m_addLayoutFileMethodID\n");
+        fflush(stdout);
+        return TSK_ERR;
+    }
+    
+    m_addLayoutFileRangeMethodID = m_jniEnv->GetMethodID(m_callbackClass, "addLayoutFileRange", "(JJJJ)J");
+    if (m_addLayoutFileRangeMethodID == NULL) {
+        printf("#### Error loading m_addLayoutFileRangeMethodID\n");
+        fflush(stdout);
+        return TSK_ERR;
+    }
+
     printf("\n#### Yay found method IDs!\n");
     fflush(stdout);
     return TSK_OK;
@@ -144,7 +164,37 @@ TskAutoDbJava::initializeJni(JNIEnv * jniEnv, jobject jobj) {
 ////////////////////////////////////////////////////////////////////////////
 
 
+void 
+TskAutoDbJava::saveObjectInfo(uint64_t objId, uint64_t parObjId, TSK_DB_OBJECT_TYPE_ENUM type) {
+    TSK_DB_OBJECT objectInfo;
+    objectInfo.objId = objId;
+    objectInfo.parObjId = parObjId;
+    objectInfo.type = type;
+    m_savedObjects.push_back(objectInfo);
+}
 
+TSK_RETVAL_ENUM 
+TskAutoDbJava::getObjectInfo(uint64_t objId, TSK_DB_OBJECT** obj_info) {
+    printf("In getObjectInfo for obj id %lld\n", objId);
+    fflush(stdout);
+    for (vector<TSK_DB_OBJECT>::iterator itObjs = m_savedObjects.begin();
+            itObjs != m_savedObjects.end(); ++itObjs) {
+        TSK_DB_OBJECT* tskDbObj = &(*itObjs);
+        if (tskDbObj->objId == objId) {
+            printf("  Found it = tskDbObj = 0x%x\n", tskDbObj);
+            fflush(stdout);
+            *obj_info = tskDbObj;
+            printf("  Returning from getObjectInfo - obj_info = 0x%x\n", *obj_info);
+            fflush(stdout);
+            return TSK_OK;
+        }
+    }
+
+    // Object not found
+    printf("\n#### OH NO!!!!! Couldn't find object with id %lld\n", objId);
+    fflush(stdout);
+    return TSK_ERR;
+}
 
 TSK_RETVAL_ENUM
 TskAutoDbJava::addImageInfo(int type, TSK_OFF_T ssize, int64_t & objId, const string & timezone, TSK_OFF_T size, const string &md5,
@@ -189,6 +239,8 @@ TskAutoDbJava::addImageInfo(int type, TSK_OFF_T ssize, int64_t & objId, const st
     if (objId < 0) {
         return TSK_ERR;
     }
+
+    saveObjectInfo(objId, 0, TSK_DB_OBJECT_TYPE_IMG);
     return TSK_OK;
 }
 
@@ -238,6 +290,16 @@ TskAutoDbJava::addVsInfo(const TSK_VS_INFO* vs_info, int64_t parObjId, int64_t&
     if (objId < 0) {
         return TSK_ERR;
     }
+
+    // Save the vs info to use for unallocated blocks later
+    TSK_DB_VS_INFO vs_db;
+    vs_db.objId = objId;
+    vs_db.offset = vs_info->offset;
+    vs_db.vstype = vs_info->vstype;
+    vs_db.block_size = vs_info->block_size;
+    m_savedVsInfo.push_back(vs_db);
+
+    saveObjectInfo(objId, parObjId, TSK_DB_OBJECT_TYPE_VS);
     return TSK_OK;
 }
 
@@ -251,12 +313,13 @@ TskAutoDbJava::addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId
     jlong poolObjIdj = m_jniEnv->CallLongMethod(m_javaDbObj, m_addPoolMethodID,
         parObjId, pool_info->ctype);
     long poolObjId = (int64_t)poolObjIdj;
-    printf("New pool object ID: %lld\n", objId);
+    printf("New pool object ID: %lld\n", poolObjId);
     fflush(stdout);
 
     if (poolObjId < 0) {
         return TSK_ERR;
     }
+    saveObjectInfo(poolObjId, parObjId, TSK_DB_OBJECT_TYPE_POOL);
 
     // "INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (%" PRId64 ", %d,%" PRIuDADDR ",%d)", 
     // objId, TSK_VS_TYPE_APFS, pool_info->img_offset, pool_info->block_size); // TODO - offset
@@ -271,6 +334,15 @@ TskAutoDbJava::addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId
     printf("New pool volume system object ID: %lld\n", objId);
     fflush(stdout);
 
+    // Save the vs info to use for unallocated blocks later - TODO do we need this?
+    //TSK_DB_VS_INFO vs_db;
+    //vs_db.objId = objId;
+    //vs_db.offset = pool_info->img_offset;
+    //vs_db.vstype = TSK_VS_TYPE_APFS;
+    //vs_db.block_size = (uint64_t)pool_info->block_size;
+    //m_savedVsInfo.push_back(vs_db);
+
+    saveObjectInfo(objId, poolObjId, TSK_DB_OBJECT_TYPE_VS);
     return TSK_OK;
 }
 
@@ -298,6 +370,8 @@ TskAutoDbJava::addPoolVolumeInfo(const TSK_POOL_VOLUME_INFO* pool_vol,
     if (objId < 0) {
         return TSK_ERR;
     }
+
+    saveObjectInfo(objId, parObjId, TSK_DB_OBJECT_TYPE_VOL);
     return TSK_OK;
 }
 
@@ -324,6 +398,18 @@ TskAutoDbJava::addVolumeInfo(const TSK_VS_PART_INFO* vs_part,
     if (objId < 0) {
         return TSK_ERR;
     }
+
+    // Save the volume info for creating unallocated blocks later
+    TSK_DB_VS_PART_INFO vs_part_db;
+    vs_part_db.objId = objId;
+    vs_part_db.addr = vs_part->addr;
+    vs_part_db.start = vs_part->start;
+    vs_part_db.len = vs_part->len;
+    strncpy(vs_part_db.desc, vs_part->desc, TSK_MAX_DB_VS_PART_INFO_DESC_LEN - 1);
+    vs_part_db.flags = vs_part->flags;
+    m_savedVsPartInfo.push_back(vs_part_db);
+
+    saveObjectInfo(objId, parObjId, TSK_DB_OBJECT_TYPE_VOL);
     return TSK_OK;
 }
 
@@ -349,6 +435,19 @@ TskAutoDbJava::addFsInfo(const TSK_FS_INFO* fs_info, int64_t parObjId,
         return TSK_ERR;
     }
 
+    // Save the file system info for created unallocated blocks later
+    TSK_DB_FS_INFO fs_info_db;
+    fs_info_db.objId = objId;
+    fs_info_db.imgOffset = fs_info->offset;
+    fs_info_db.fType = fs_info->ftype;
+    fs_info_db.block_size = fs_info->block_size;
+    fs_info_db.block_count = fs_info->block_count;
+    fs_info_db.root_inum = fs_info->root_inum;
+    fs_info_db.first_inum = fs_info->first_inum;
+    fs_info_db.last_inum = fs_info->last_inum;
+    m_savedFsInfo.push_back(fs_info_db);
+
+    saveObjectInfo(objId, parObjId, TSK_DB_OBJECT_TYPE_FS);
     return TSK_OK;
 }
 
@@ -671,17 +770,136 @@ if (!TSK_FS_ISDOT(name))
     return TSK_OK;
 }
 
+//internal function object to check for range overlap
+typedef struct _checkFileLayoutRangeOverlap {
+    const vector<TSK_DB_FILE_LAYOUT_RANGE> & ranges;
+    bool hasOverlap;
+
+    explicit _checkFileLayoutRangeOverlap(const vector<TSK_DB_FILE_LAYOUT_RANGE> & ranges)
+        : ranges(ranges), hasOverlap(false) {}
+
+    bool getHasOverlap() const { return hasOverlap; }
+    void operator() (const TSK_DB_FILE_LAYOUT_RANGE & range) {
+        if (hasOverlap)
+            return; //no need to check other
+
+        uint64_t start = range.byteStart;
+        uint64_t end = start + range.byteLen;
+
+        vector<TSK_DB_FILE_LAYOUT_RANGE>::const_iterator it;
+        for (it = ranges.begin(); it != ranges.end(); ++it) {
+            const TSK_DB_FILE_LAYOUT_RANGE * otherRange = &(*it);
+            if (&range == otherRange)
+                continue; //skip, it's the same range
+            uint64_t otherStart = otherRange->byteStart;
+            uint64_t otherEnd = otherStart + otherRange->byteLen;
+            if (start <= otherEnd && end >= otherStart) {
+                hasOverlap = true;
+                break;
+            }
+        }
+    }
+
+} checkFileLayoutRangeOverlap;
+
 TSK_RETVAL_ENUM
-addFileWithLayoutRange(const TSK_DB_FILES_TYPE_ENUM dbFileType, const int64_t parentObjId,
+TskAutoDbJava::addFileWithLayoutRange(const TSK_DB_FILES_TYPE_ENUM dbFileType, const int64_t parentObjId,
     const int64_t fsObjId, const uint64_t size,
     vector<TSK_DB_FILE_LAYOUT_RANGE>& ranges, int64_t& objId,
     int64_t dataSourceObjId) {
     printf("addFileWithLayoutRange\n");
+
+    const size_t numRanges = ranges.size();
+
+    if (numRanges < 1) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_AUTO_DB);
+        tsk_error_set_errstr("Error addFileWithLayoutRange() - no ranges present");
+        return TSK_ERR;
+    }
+
+    stringstream fileNameSs;
+    switch (dbFileType) {
+    case TSK_DB_FILES_TYPE_UNALLOC_BLOCKS:
+        fileNameSs << "Unalloc";
+        break;
+
+    case TSK_DB_FILES_TYPE_UNUSED_BLOCKS:
+        fileNameSs << "Unused";
+        break;
+
+    case TSK_DB_FILES_TYPE_CARVED:
+        fileNameSs << "Carved";
+        break;
+    default:
+        stringstream sserr;
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_AUTO_DB);
+        sserr << "Error addFileWithLayoutRange() - unsupported file type for file layout range: ";
+        sserr << (int)dbFileType;
+        tsk_error_set_errstr("%s", sserr.str().c_str());
+        return TSK_ERR;
+    }
+
+    //ensure layout ranges are sorted (to generate file name and to be inserted in sequence order)
+    sort(ranges.begin(), ranges.end());
+
+    //dome some checking
+    //ensure there is no overlap and each range has unique byte range
+    const checkFileLayoutRangeOverlap & overlapRes =
+        for_each(ranges.begin(), ranges.end(), checkFileLayoutRangeOverlap(ranges));
+    if (overlapRes.getHasOverlap()) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_AUTO_DB);
+        tsk_error_set_errstr("Error addFileWithLayoutRange() - overlap detected between ranges");
+        return TSK_ERR;
+    }
+
+    //construct filename with parent obj id, start byte of first range, end byte of last range
+    fileNameSs << "_" << parentObjId << "_" << ranges[0].byteStart;
+    fileNameSs << "_" << (ranges[numRanges - 1].byteStart + ranges[numRanges - 1].byteLen);
+
+    //insert into tsk files and tsk objects
+
+    //m_addLayoutFileMethodID
+    printf("Calling addLayoutFile in Java\n");
+    fflush(stdout);
+
+    if (m_addLayoutFileMethodID == NULL) {
+        printf("#### Yikes m_addLayoutFileMethodID is null...\n");
+        return TSK_ERR;
+    }
+
+    jstring namej = m_jniEnv->NewStringUTF(fileNameSs.str().c_str()); // TODO free?
+
+    jlong objIdj = m_jniEnv->CallLongMethod(m_javaDbObj, m_addLayoutFileMethodID,
+        parentObjId, fsObjId, dataSourceObjId, dbFileType, namej, size);
+    objId = (int64_t)objIdj;
+    printf("New layout file object ID: %lld\n", objId);
+    fflush(stdout);
+    if (objId < 0) {
+        printf("#### Oh no layout file ID is invalid");
+        fflush(stdout);
+        return TSK_ERR;
+    }
+
+    //fill in fileObjId and insert ranges
+    printf("Adding layout file ranges for file ID: %lld\n", objId);
+    for (vector<TSK_DB_FILE_LAYOUT_RANGE>::iterator it = ranges.begin();
+        it != ranges.end(); ++it) {
+        TSK_DB_FILE_LAYOUT_RANGE & range = *it;
+        range.fileObjId = objId;
+        if (-1 == m_jniEnv->CallLongMethod(m_javaDbObj, m_addLayoutFileRangeMethodID,
+            objId, range.byteStart, range.byteLen, range.sequence)) {
+            return TSK_ERR;
+        }
+    }
+
     return TSK_OK;
 }
 
 TSK_RETVAL_ENUM
-addUnallocBlockFile(const int64_t parentObjId, const int64_t fsObjId, const uint64_t size,
+TskAutoDbJava::addUnallocBlockFile(const int64_t parentObjId, const int64_t fsObjId, const uint64_t size,
     vector<TSK_DB_FILE_LAYOUT_RANGE>& ranges, int64_t& objId,
     int64_t dataSourceObjId) {
     printf("addUnallocBlockFile\n");
@@ -690,7 +908,7 @@ addUnallocBlockFile(const int64_t parentObjId, const int64_t fsObjId, const uint
 }
 
 TSK_RETVAL_ENUM
-addUnusedBlockFile(const int64_t parentObjId, const int64_t fsObjId, const uint64_t size,
+TskAutoDbJava::addUnusedBlockFile(const int64_t parentObjId, const int64_t fsObjId, const uint64_t size,
     vector<TSK_DB_FILE_LAYOUT_RANGE>& ranges, int64_t& objId,
     int64_t dataSourceObjId) {
     printf("addUnusedBlockFile\n");
@@ -703,7 +921,24 @@ addUnusedBlockFile(const int64_t parentObjId, const int64_t fsObjId, const uint6
 TSK_RETVAL_ENUM
 TskAutoDbJava::addUnallocFsBlockFilesParent(const int64_t fsObjId, int64_t& objId,
     int64_t dataSourceObjId) {
-    printf("addUnallocFsBlockfilesParent\n");
+
+    if (m_addUnallocParentMethodID == NULL) {
+        printf("#### Yikes m_addUnallocParentMethodID is null...\n");
+        return TSK_ERR;
+    }
+
+    const char * const unallocDirName = "$Unalloc";
+    jstring namej = m_jniEnv->NewStringUTF(unallocDirName); // TODO free?
+
+    jlong objIdj = m_jniEnv->CallLongMethod(m_javaDbObj, m_addUnallocParentMethodID,
+        fsObjId, namej);
+    objId = (int64_t)objIdj;
+    printf("#### New unalloc dir object ID: %lld\n", objId);
+    fflush(stdout);
+
+    if (objId < 0) {
+        return TSK_ERR;
+    }
     return TSK_OK;
 }
 
@@ -1555,8 +1790,9 @@ TSK_WALK_RET_ENUM TskAutoDbJava::fsWalkUnallocBlocksCb(const TSK_FS_BLOCK *a_blo
     // at this point we are either chunking and have reached the chunk limit
     // or we're not chunking. Either way we now add what we've got to the DB
     int64_t fileObjId = 0;
-    if (-1 == addUnallocBlockFile(unallocBlockWlkTrack->tskAutoDbJava.m_curUnallocDirId,
-        unallocBlockWlkTrack->fsObjId, unallocBlockWlkTrack->size, unallocBlockWlkTrack->ranges, fileObjId, unallocBlockWlkTrack->tskAutoDbJava.m_curImgId) == TSK_ERR) {
+    TskAutoDbJava & tskAutoDbJava = unallocBlockWlkTrack->tskAutoDbJava;
+    if (-1 == tskAutoDbJava.addUnallocBlockFile(tskAutoDbJava.m_curUnallocDirId,
+        unallocBlockWlkTrack->fsObjId, unallocBlockWlkTrack->size, unallocBlockWlkTrack->ranges, fileObjId, tskAutoDbJava.m_curImgId) == TSK_ERR) {
             // @@@ Handle error -> Don't have access to registerError() though...
     }
 
@@ -1678,26 +1914,17 @@ TSK_RETVAL_ENUM TskAutoDbJava::addUnallocSpaceToDb() {
 */
 TSK_RETVAL_ENUM TskAutoDbJava::addUnallocFsSpaceToDb(size_t & numFs) {
 
-    vector<TSK_DB_FS_INFO> fsInfos;
-
     if(m_stopAllProcessing) {
         return TSK_OK;
     }
 
+    //m_savedFsInfo
+    printf("In addUnallocFsSpaceToDb!!!! Have %d file systems\n", m_savedFsInfo.size()); // TODO TODO
+    fflush(stdout);
 
-    printf("SKIPPING addUnallocFsSpaceToDb!!!!\n"); // TODO TODO
-/*
-    uint16_t ret = m_db->getFsInfos(m_curImgId, fsInfos);
-    if (ret) {
-        tsk_error_set_errstr2("addUnallocFsSpaceToDb: error getting fs infos from db");
-        registerError();
-        return TSK_ERR;
-    }
-
-    numFs = fsInfos.size();
-
+    numFs = m_savedFsInfo.size();
     TSK_RETVAL_ENUM allFsProcessRet = TSK_OK;
-    for (vector<TSK_DB_FS_INFO>::iterator it = fsInfos.begin(); it!= fsInfos.end(); ++it) {
+    for (vector<TSK_DB_FS_INFO>::iterator it = m_savedFsInfo.begin(); it!= m_savedFsInfo.end(); ++it) {
         if (m_stopAllProcessing) {
             break;
         }
@@ -1707,7 +1934,7 @@ TSK_RETVAL_ENUM TskAutoDbJava::addUnallocFsSpaceToDb(size_t & numFs) {
 
     //TODO set parent_path for newly created virt dir/file hierarchy for consistency
 
-    return allFsProcessRet;*/
+    return allFsProcessRet;
     return TSK_OK;
 }
 
@@ -1718,45 +1945,29 @@ TSK_RETVAL_ENUM TskAutoDbJava::addUnallocFsSpaceToDb(size_t & numFs) {
 */
 TSK_RETVAL_ENUM TskAutoDbJava::addUnallocVsSpaceToDb(size_t & numVsP) {
 
-    vector<TSK_DB_VS_PART_INFO> vsPartInfos;
-
-
-    printf("SKIPPING addUnallocVsSpaceToDb!!!!\n"); // TODO TODO
-    /*
-    TSK_RETVAL_ENUM retVsPartInfos = m_db->getVsPartInfos(m_curImgId, vsPartInfos);
-    if (retVsPartInfos == TSK_ERR) {
-        tsk_error_set_errstr2("addUnallocVsSpaceToDb: error getting vs part infos from db");
-        registerError();
-        return TSK_ERR;
-    }
-    numVsP = vsPartInfos.size();
+    printf("\n#### addUnallocVsSpaceToDb!!!! Have %d volumes\n", m_savedVsPartInfo.size());
+    numVsP = m_savedVsPartInfo.size();
 
     //get fs infos to see if this vspart has fs
-    vector<TSK_DB_FS_INFO> fsInfos;
-    uint16_t retFsInfos = m_db->getFsInfos(m_curImgId, fsInfos);
-    if (retFsInfos) {
-        tsk_error_set_errstr2("addUnallocVsSpaceToDb: error getting fs infos from db");
-        registerError();
-        return TSK_ERR;
-    }
-
-    for (vector<TSK_DB_VS_PART_INFO>::const_iterator it = vsPartInfos.begin();
-            it != vsPartInfos.end(); ++it) {
+    for (vector<TSK_DB_VS_PART_INFO>::const_iterator it = m_savedVsPartInfo.begin();
+            it != m_savedVsPartInfo.end(); ++it) {
         if (m_stopAllProcessing) {
             break;
         }
         const TSK_DB_VS_PART_INFO &vsPart = *it;
+        printf("Looking at volume with obj ID %lld\n", vsPart.objId);
+        fflush(stdout);
 
         //interested in unalloc, meta, or alloc and no fs
         if ( (vsPart.flags & (TSK_VS_PART_FLAG_UNALLOC | TSK_VS_PART_FLAG_META)) == 0 ) {
             //check if vspart has no fs
             bool hasFs = false;
-            for (vector<TSK_DB_FS_INFO>::const_iterator itFs = fsInfos.begin();
-               itFs != fsInfos.end(); ++itFs) {
+            for (vector<TSK_DB_FS_INFO>::const_iterator itFs = m_savedFsInfo.begin();
+               itFs != m_savedFsInfo.end(); ++itFs) {
                const TSK_DB_FS_INFO & fsInfo = *itFs;
 
-               TSK_DB_OBJECT fsObjInfo;
-               if (m_db->getObjectInfo(fsInfo.objId, fsObjInfo) == TSK_ERR ) {
+               TSK_DB_OBJECT* fsObjInfo = NULL;
+               if (getObjectInfo(fsInfo.objId, &fsObjInfo) == TSK_ERR ) {
                    stringstream errss;
                    errss << "addUnallocVsSpaceToDb: error getting object info for fs from db, objId: " << fsInfo.objId;
                    tsk_error_set_errstr2("%s", errss.str().c_str());
@@ -1764,7 +1975,7 @@ TSK_RETVAL_ENUM TskAutoDbJava::addUnallocVsSpaceToDb(size_t & numVsP) {
                    return TSK_ERR;
                }
 
-               if (fsObjInfo.parObjId == vsPart.objId) {
+               if (fsObjInfo->parObjId == vsPart.objId) {
                    hasFs = true;
                    break;
                }
@@ -1779,36 +1990,58 @@ TSK_RETVAL_ENUM TskAutoDbJava::addUnallocVsSpaceToDb(size_t & numVsP) {
         //get sector size and image offset from parent vs info
 
         //get parent id of this vs part
-        TSK_DB_OBJECT vsPartObj;     
-        if (m_db->getObjectInfo(vsPart.objId, vsPartObj) == TSK_ERR) {
+        printf("Trying to get parent ID of volume...\n");
+        printf("Loading vsPartObj\n");
+        fflush(stdout);
+        TSK_DB_OBJECT* vsPartObj = NULL;     
+        if (getObjectInfo(vsPart.objId, &vsPartObj) == TSK_ERR) {
             stringstream errss;
             errss << "addUnallocVsSpaceToDb: error getting object info for vs part from db, objId: " << vsPart.objId;
             tsk_error_set_errstr2("%s", errss.str().c_str());
             registerError();
             return TSK_ERR;
         }
+        if (vsPartObj == NULL) {
+            printf("ARGH vsPartObj is null\n");
+            return TSK_ERR;
+        }
+
+        printf("Loading vsInfo\n");
+        fflush(stdout);
+        TSK_DB_VS_INFO* vsInfo = NULL;
+        for (vector<TSK_DB_VS_INFO>::iterator itVs = m_savedVsInfo.begin();
+                itVs != m_savedVsInfo.end(); ++itVs) {
+            TSK_DB_VS_INFO* temp_vs_info = &(*itVs);
+            printf("Looking at vs with obj ID %lld\n", temp_vs_info->objId);
+            if (temp_vs_info->objId == vsPartObj->parObjId) {
+                vsInfo = temp_vs_info;
+            }
+        }
 
-        TSK_DB_VS_INFO vsInfo;
-        if (m_db->getVsInfo(vsPartObj.parObjId, vsInfo) ) {
+        printf("Checking if vsInfo is null\n");
+        fflush(stdout);
+        if (vsInfo == NULL ) {
             stringstream errss;
-            errss << "addUnallocVsSpaceToDb: error getting volume system info from db, objId: " << vsPartObj.parObjId;
+            errss << "addUnallocVsSpaceToDb: error getting volume system info from db, objId: " << vsPartObj->parObjId;
             tsk_error_set_errstr2("%s", errss.str().c_str());
             registerError();
             return TSK_ERR;
         }
 
         //create an unalloc file with unalloc part, with vs part as parent
+        printf("About to call addUnallocBlockFile");
+        fflush(stdout);
         vector<TSK_DB_FILE_LAYOUT_RANGE> ranges;
-        const uint64_t byteStart = vsInfo.offset + vsInfo.block_size * vsPart.start;
-        const uint64_t byteLen = vsInfo.block_size * vsPart.len; 
+        const uint64_t byteStart = vsInfo->offset + vsInfo->block_size * vsPart.start;
+        const uint64_t byteLen = vsInfo->block_size * vsPart.len; 
         TSK_DB_FILE_LAYOUT_RANGE tempRange(byteStart, byteLen, 0);
         ranges.push_back(tempRange);
         int64_t fileObjId = 0;
-        if (m_db->addUnallocBlockFile(vsPart.objId, 0, tempRange.byteLen, ranges, fileObjId, m_curImgId) == TSK_ERR) {
+        if (addUnallocBlockFile(vsPart.objId, 0, tempRange.byteLen, ranges, fileObjId, m_curImgId) == TSK_ERR) {
             registerError();
             return TSK_ERR;
         }
-    }*/
+    }
 
     return TSK_OK;
 }
diff --git a/bindings/java/jni/auto_db_java.h b/bindings/java/jni/auto_db_java.h
index b8049de22..7657219e1 100644
--- a/bindings/java/jni/auto_db_java.h
+++ b/bindings/java/jni/auto_db_java.h
@@ -162,7 +162,16 @@ class TskAutoDbJava :public TskAuto {
     jmethodID m_addFileSystemMethodID = NULL;
     jmethodID m_addFileMethodID = NULL;
     jmethodID m_getParentIdMethodID = NULL;
+    jmethodID m_addUnallocParentMethodID = NULL;
+    jmethodID m_addLayoutFileMethodID = NULL;
+    jmethodID m_addLayoutFileRangeMethodID = NULL;
 
+    vector<TSK_DB_FS_INFO> m_savedFsInfo;
+    vector<TSK_DB_VS_INFO> m_savedVsInfo;
+    vector<TSK_DB_VS_PART_INFO> m_savedVsPartInfo;
+    vector<TSK_DB_OBJECT> m_savedObjects;
+    void saveObjectInfo(uint64_t objId, uint64_t parObjId, TSK_DB_OBJECT_TYPE_ENUM type);
+    TSK_RETVAL_ENUM getObjectInfo(uint64_t objId, TSK_DB_OBJECT** obj_info);
 
     // prevent copying until we add proper logic to handle it
     TskAutoDbJava(const TskAutoDbJava&);
@@ -170,9 +179,9 @@ class TskAutoDbJava :public TskAuto {
 
     //internal structure to keep track of temp. unalloc block range
     typedef struct _UNALLOC_BLOCK_WLK_TRACK {
-        _UNALLOC_BLOCK_WLK_TRACK(const TskAutoDbJava & tskAutoDbJava, const TSK_FS_INFO & fsInfo, const int64_t fsObjId, int64_t minChunkSize, int64_t maxChunkSize)
+        _UNALLOC_BLOCK_WLK_TRACK(TskAutoDbJava & tskAutoDbJava, const TSK_FS_INFO & fsInfo, const int64_t fsObjId, int64_t minChunkSize, int64_t maxChunkSize)
             : tskAutoDbJava(tskAutoDbJava),fsInfo(fsInfo),fsObjId(fsObjId),curRangeStart(0), minChunkSize(minChunkSize), maxChunkSize(maxChunkSize), prevBlock(0), isStart(true), nextSequenceNo(0) {}
-        const TskAutoDbJava & tskAutoDbJava;
+        TskAutoDbJava & tskAutoDbJava;
         const TSK_FS_INFO & fsInfo;
         const int64_t fsObjId;
         vector<TSK_DB_FILE_LAYOUT_RANGE> ranges;																																										
@@ -216,16 +225,16 @@ class TskAutoDbJava :public TskAuto {
         const unsigned char*const md5, const TSK_DB_FILES_KNOWN_ENUM known,
         int64_t fsObjId, int64_t parObjId,
         int64_t& objId, int64_t dataSourceObjId);
-    //TSK_RETVAL_ENUM addFileWithLayoutRange(const TSK_DB_FILES_TYPE_ENUM dbFileType, const int64_t parentObjId,
-    //    const int64_t fsObjId, const uint64_t size,
-    //    vector<TSK_DB_FILE_LAYOUT_RANGE>& ranges, int64_t& objId,
-    //    int64_t dataSourceObjId);
-    //TSK_RETVAL_ENUM addUnallocBlockFile(const int64_t parentObjId, const int64_t fsObjId, const uint64_t size,
-    //    vector<TSK_DB_FILE_LAYOUT_RANGE>& ranges, int64_t& objId,
-    //    int64_t dataSourceObjId);
-    //TSK_RETVAL_ENUM addUnusedBlockFile(const int64_t parentObjId, const int64_t fsObjId, const uint64_t size,
-    //    vector<TSK_DB_FILE_LAYOUT_RANGE>& ranges, int64_t& objId,
-    //    int64_t dataSourceObjId);
+    TSK_RETVAL_ENUM addFileWithLayoutRange(const TSK_DB_FILES_TYPE_ENUM dbFileType, const int64_t parentObjId,
+        const int64_t fsObjId, const uint64_t size,
+        vector<TSK_DB_FILE_LAYOUT_RANGE>& ranges, int64_t& objId,
+        int64_t dataSourceObjId);
+    TSK_RETVAL_ENUM addUnallocBlockFile(const int64_t parentObjId, const int64_t fsObjId, const uint64_t size,
+        vector<TSK_DB_FILE_LAYOUT_RANGE>& ranges, int64_t& objId,
+        int64_t dataSourceObjId);
+    TSK_RETVAL_ENUM addUnusedBlockFile(const int64_t parentObjId, const int64_t fsObjId, const uint64_t size,
+        vector<TSK_DB_FILE_LAYOUT_RANGE>& ranges, int64_t& objId,
+        int64_t dataSourceObjId);
     TSK_RETVAL_ENUM addUnallocFsBlockFilesParent(const int64_t fsObjId, int64_t& objId, int64_t dataSourceObjId);
 
 };
diff --git a/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java b/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java
index f5589f939..29913c361 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java
@@ -5,6 +5,8 @@
  */
 package org.sleuthkit.datamodel;
 
+import java.util.HashMap;
+import java.util.Map;
 import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
 
 /**
@@ -12,8 +14,10 @@
  */
 class JniDbHelper {
 	
-	SleuthkitCase caseDb;
-	CaseDbTransaction trans;
+	private SleuthkitCase caseDb;
+	private CaseDbTransaction trans;
+	
+	private Map<Long, Long> fsIdToRootDir = new HashMap<>();
 	
 	JniDbHelper(SleuthkitCase caseDb) {
 		this.caseDb = caseDb;
@@ -91,7 +95,7 @@ long addVolume(long parentObjId, long addr, long start, long length, String desc
 			return -1;
 		}
 	}
-	// TskData.TSK_POOL_TYPE_ENUM
+
 	long addPool(long parentObjId, int poolType) {
 		try {
 			Pool pool = caseDb.addPool(parentObjId, TskData.TSK_POOL_TYPE_ENUM.valueOf(poolType), trans);
@@ -106,7 +110,7 @@ long addFileSystem(long parentObjId, long imgOffset, int fsType, long blockSize,
 			long rootInum, long firstInum, long lastInum) {
 		try {
 			FileSystem fs = caseDb.addFileSystem(parentObjId, imgOffset, TskData.TSK_FS_TYPE_ENUM.valueOf(fsType), blockSize, blockCount,
-					rootInum, firstInum, lastInum, "", trans);
+					rootInum, firstInum, lastInum, null, trans);
 			return fs.getId();
 		} catch (TskCoreException ex) {
 			ex.printStackTrace();
@@ -114,27 +118,18 @@ long addFileSystem(long parentObjId, long imgOffset, int fsType, long blockSize,
 		}
 	}
 
-	// fs_obj_id, obj_id, data_source_obj_id, type, 
-	// attr_type, attr_id, 
-	// name, 
-	// meta_addr, meta_seq, 
-	// dir_type, 
-	// meta_type, dir_flags, meta_flags, 
-	// size, crtime, ctime, atime, mtime, mode, gid, uid, md5, known, parent_path, extension)"
 	long addFile(long parentObjId, 
         long fsObjId, long dataSourceObjId,
-        int fsType, // TSK_DB_FILES_TYPE_FS,
+        int fsType,
         int attrType, int attrId, String name,
         long metaAddr, long metaSeq,
         int dirType, int metaType, int dirFlags, int metaFlags,
         long size,
         long crtime, long ctime, long atime, long mtime,
         int meta_mode, int gid, int uid, /// md5TextPtr, known,
-        String escaped_path, String extension
-	
-	) {
+        String escaped_path, String extension) {
 		try {
-			return caseDb.addFileSystemFileJNI(parentObjId, 
+			long objId = caseDb.addFileSystemFileJNI(parentObjId, 
 				fsObjId, dataSourceObjId,
 				fsType,
 				attrType, attrId, name,
@@ -142,18 +137,83 @@ long addFile(long parentObjId,
 				dirType, metaType, dirFlags, metaFlags,
 				size,
 				crtime, ctime, atime, mtime,
-				meta_mode, gid, uid, /// md5TextPtr, known,
-				"", TskData.FileKnown.UNKNOWN,
-				escaped_path, extension, trans);
+				meta_mode, gid, uid,
+				null, TskData.FileKnown.UNKNOWN,
+				escaped_path, extension, 
+				false, trans);
+			
+			if (parentObjId == fsObjId) {
+				fsIdToRootDir.put(fsObjId, objId);
+			}
+			return objId;
+		} catch (TskCoreException ex) {
+			ex.printStackTrace();
+			return -1;
+		}
+	}
+	
+	long addLayoutFile(long parentObjId, 
+        long fsObjId, long dataSourceObjId,
+        int fileType,
+		String name, long size) {
+		try {
+			// The file system may be null for layout files
+			Long fsObjIdForDb = fsObjId;
+			if (fsObjId == 0) {
+				fsObjIdForDb = null;
+			}
+			
+			System.out.println("@@@ addLayoutFile: parentObjId: " + parentObjId + ", fsObjId: " + fsObjId + ", dsObjId: " + dataSourceObjId);
+			long objId = caseDb.addFileSystemFileJNI(parentObjId, 
+				fsObjIdForDb, dataSourceObjId,
+				fileType,
+				null, null, name,
+				null, null,
+				TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue(), 
+				TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue(), 
+				TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue(), 
+				TskData.TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(),
+				size,
+				null, null, null, null,
+				null, null, null,
+				null, TskData.FileKnown.UNKNOWN,
+				null, null, 
+				true, trans);
+			return objId;
+		} catch (TskCoreException ex) {
+			System.out.println("\n@@@ Error in addLayoutFile");
+			ex.printStackTrace();
+			return -1;
+		}
+	}	
+	
+	long addLayoutFileRange(long objId, long byteStart, long byteLen, long seq) {
+		try {
+			caseDb.addLayoutFileRangeJNI(objId, byteStart, byteLen, seq, trans);
+			return 0;
+		} catch (TskCoreException ex) {
+			ex.printStackTrace();
+			return -1;
+		}
+	}
+	
+	long findParentObjId(long metaAddr, long fsObjId, String path, String name) {
+		try {
+			return caseDb.findParentObjIdJNI(metaAddr, fsObjId, path, name, trans);
 		} catch (TskCoreException ex) {
 			ex.printStackTrace();
 			return -1;
 		}
 	}
 	
-	long findParentObjId(long metaAddr, long fsobjId, String path, String name) {
+	long addUnallocFsBlockFilesParent(long fsObjId, String name) {
 		try {
-			return caseDb.findParentObjIdJNI(metaAddr, fsobjId, path, name, trans);
+			if (! fsIdToRootDir.containsKey(fsObjId)) {
+				System.out.println("Argh no fs id...");
+				return -1;
+			}
+			VirtualDirectory dir = caseDb.addVirtualDirectory(fsIdToRootDir.get(fsObjId), name, trans);
+			return dir.getId();
 		} catch (TskCoreException ex) {
 			ex.printStackTrace();
 			return -1;
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
index 8e070c0c3..0c58e52af 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
@@ -11002,14 +11002,15 @@ long addImageJNI(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size,
 			preparedStatement.setString(6, md5);
 			preparedStatement.setString(7, sha1);
 			preparedStatement.setString(8, sha256);
-			preparedStatement.setString(9, "");
+			preparedStatement.setString(9, null);
 			connection.executeUpdate(preparedStatement);
 
 			// Add a row to data_source_info
-			preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO);
+			preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO_WITH_ACQ_DETAIL);
 			preparedStatement.setLong(1, newObjId);
 			preparedStatement.setString(2, deviceId);
 			preparedStatement.setString(3, timezone);
+			preparedStatement.setString(4, "");
 			connection.executeUpdate(preparedStatement);
 
 			return newObjId;
@@ -11064,16 +11065,17 @@ long findParentObjIdJNI(long metaAddr, long fsObjId, String path, String name, C
 	}
 	
 	long addFileSystemFileJNI(long parentObjId, 
-			long fsObjId, long dataSourceObjId,
+			Long fsObjId, long dataSourceObjId,
 			int fsType,
-			int attrType, int attrId, String name,
-			long metaAddr, long metaSeq,
+			Integer attrType, Integer attrId, String name,
+			Long metaAddr, Long metaSeq,
 			int dirType, int metaType, int dirFlags, int metaFlags,
 			long size,
-			long crtime, long ctime, long atime, long mtime,
-			int meta_mode, int gid, int uid,
+			Long crtime, Long ctime, Long atime, Long mtime,
+			Integer meta_mode, Integer gid, Integer uid,
 			String md5, TskData.FileKnown known,
-			String escaped_path, String extension, CaseDbTransaction transaction) throws TskCoreException {
+			String escaped_path, String extension, 
+			boolean hasLayout, CaseDbTransaction transaction) throws TskCoreException {
 
 		Statement queryStatement = null;
 		try {
@@ -11089,34 +11091,88 @@ long addFileSystemFileJNI(long parentObjId,
 			//                        mode, gid, uid, md5, known, parent_path, extension)
 			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE_All_FIELDS);
 			statement.clearParameters();
-			statement.setLong(1, fsObjId);					// fs_obj_id
+			if (fsObjId != null) {
+				statement.setLong(1, fsObjId);					// fs_obj_id
+			} else {
+				statement.setNull(1, java.sql.Types.BIGINT);
+			}
 			statement.setLong(2, objectId);					// obj_id 
 			statement.setLong(3, dataSourceObjId);			// data_source_obj_id 
 			statement.setShort(4, (short)fsType);	        // type
-			statement.setShort(5, (short)attrType);		    // attr_type
-			statement.setInt(6, attrId);					// attr_id
+			if (attrType != null) {
+				statement.setShort(5, attrType.shortValue());  // attr_type
+			} else {
+				statement.setNull(5, java.sql.Types.SMALLINT);
+			}
+			if (attrId != null) {
+				statement.setInt(6, attrId);				// attr_id
+			} else {
+				statement.setNull(6, java.sql.Types.INTEGER);
+			}
 			statement.setString(7, name);					// name
-			statement.setLong(8, metaAddr);					// meta_addr
-			statement.setInt(9, (int)metaSeq);				// meta_seq
+			if (metaAddr != null) {
+				statement.setLong(8, metaAddr);				// meta_addr
+			} else {
+				statement.setNull(8, java.sql.Types.BIGINT);
+			}
+			if (metaSeq != null) {
+				statement.setInt(9, metaSeq.intValue());	// meta_seq
+			} else {
+				statement.setNull(9, java.sql.Types.INTEGER);
+			}
 			statement.setShort(10, (short)dirType);			// dir_type
 			statement.setShort(11, (short)metaType);		// meta_type
 			statement.setShort(12, (short)dirFlags);		// dir_flags
 			statement.setShort(13, (short)metaFlags);		// meta_flags
 			statement.setLong(14, size < 0 ? 0 : size);     // size
-			statement.setLong(15, ctime);                   // ctime
-			statement.setLong(16, crtime);                  // crtime
-			statement.setLong(17, atime);                   // atime
-			statement.setLong(18, mtime);                   // mtime
-			statement.setInt(19, meta_mode);                // mode
-			statement.setInt(20, gid);                      // gid
-			statement.setInt(21, uid);                      // uid
+			if (ctime != null) {
+				statement.setLong(15, ctime);               // ctime
+			} else {
+				statement.setNull(15, java.sql.Types.BIGINT);
+			}
+			if (crtime != null) {
+				statement.setLong(16, crtime);              // crtime
+			} else {
+				statement.setNull(16, java.sql.Types.BIGINT);
+			}
+			if (atime != null) {
+				statement.setLong(17, atime);               // atime
+			} else {
+				statement.setNull(17, java.sql.Types.BIGINT);
+			}
+			if (mtime != null) {
+				statement.setLong(18, mtime);               // mtime
+			} else {
+				statement.setNull(18, java.sql.Types.BIGINT);
+			}
+			if (meta_mode != null) {
+				statement.setLong(19, meta_mode);               // mode
+			} else {
+				statement.setNull(19, java.sql.Types.BIGINT);
+			}
+			if (gid != null) {
+				statement.setLong(20, gid);               // gid
+			} else {
+				statement.setNull(20, java.sql.Types.BIGINT);
+			}
+			if (uid != null) {
+				statement.setLong(21, uid);               // uid
+			} else {
+				statement.setNull(21, java.sql.Types.BIGINT);
+			}
 			statement.setString(22, md5);                   // md5
 			statement.setInt(23, known.getFileKnownValue());// known
 			statement.setString(24, escaped_path);          // parent_path
 			statement.setString(25, extension);             // extension
+			if (hasLayout) {
+				statement.setInt(26, 1);                    // has_layout
+			} else {
+				statement.setNull(26, java.sql.Types.INTEGER);
+			}
 			connection.executeUpdate(statement);
 
-			if (TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() != fsType
+			if (! hasLayout
+					&& TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() != fsType
 					&& (!name.equals(".")) && (!name.equals(".."))) {
 				TimelineManager timelineManager = getTimelineManager();
 				DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, name, 
@@ -11136,6 +11192,24 @@ long addFileSystemFileJNI(long parentObjId,
 			closeStatement(queryStatement);
 		}
 	}
+	
+	void addLayoutFileRangeJNI(long objId, long byteStart, long byteLen, 
+			long seq, CaseDbTransaction transaction) throws TskCoreException {
+		try {
+			transaction.acquireSingleUserCaseWriteLock();
+			CaseDbConnection connection = transaction.getConnection();
+			
+			PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE);
+			prepStmt.clearParameters();
+			prepStmt.setLong(1, objId); 
+			prepStmt.setLong(2, byteStart);
+			prepStmt.setLong(3, byteLen);
+			prepStmt.setLong(4, seq);
+			connection.executeUpdate(prepStmt);
+		} catch (SQLException ex) {
+			throw new TskCoreException("Error adding layout range to file with obj ID " + objId, ex);
+		}
+	}
 
 	/**
 	 * Stores a pair of object ID and its type
@@ -11232,8 +11306,8 @@ private enum PREPARED_STATEMENT {
 				+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS
 		INSERT_FILE_SYSTEM_FILE("INSERT INTO tsk_files(obj_id, fs_obj_id, data_source_obj_id, attr_type, attr_id, name, meta_addr, meta_seq, type, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, extension)"
 				+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
-		INSERT_FILE_SYSTEM_FILE_All_FIELDS("INSERT INTO tsk_files (fs_obj_id, obj_id, data_source_obj_id, type, attr_type, attr_id, name, meta_addr, meta_seq, dir_type, meta_type, dir_flags, meta_flags, size, crtime, ctime, atime, mtime, mode, gid, uid, md5, known, parent_path, extension)"
-				+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
+		INSERT_FILE_SYSTEM_FILE_All_FIELDS("INSERT INTO tsk_files (fs_obj_id, obj_id, data_source_obj_id, type, attr_type, attr_id, name, meta_addr, meta_seq, dir_type, meta_type, dir_flags, meta_flags, size, crtime, ctime, atime, mtime, mode, gid, uid, md5, known, parent_path, extension, has_layout)"
+				+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS
 		UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?,  meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ?  "
 				+ "WHERE obj_id = ?"), //NON-NLS
 		INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS
@@ -11346,6 +11420,7 @@ private enum PREPARED_STATEMENT {
 		INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)"
 				+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
 		INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone) VALUES (?, ?, ?)"),
+		INSERT_DATA_SOURCE_INFO_WITH_ACQ_DETAIL("INSERT INTO data_source_info (obj_id, device_id, time_zone, acquisition_details) VALUES (?, ?, ?, ?)"),
 		INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"),
 		INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"),
 		INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"),
-- 
GitLab