From 0c17063163fb8ea15a1b221be19f1fd27f51074b Mon Sep 17 00:00:00 2001
From: apriestman <apriestman@basistech.com>
Date: Fri, 6 Mar 2020 12:41:47 -0500
Subject: [PATCH] Added unallocated pool blocks

---
 bindings/java/jni/auto_db_java.cpp            | 161 +++++++++++++++++-
 bindings/java/jni/auto_db_java.h              |   8 +
 .../org/sleuthkit/datamodel/JniDbHelper.java  |   1 -
 .../sleuthkit/datamodel/SleuthkitCase.java    |   2 +-
 4 files changed, 162 insertions(+), 10 deletions(-)

diff --git a/bindings/java/jni/auto_db_java.cpp b/bindings/java/jni/auto_db_java.cpp
index 92da611ea..d58f323ab 100644
--- a/bindings/java/jni/auto_db_java.cpp
+++ b/bindings/java/jni/auto_db_java.cpp
@@ -1097,8 +1097,6 @@ TskAutoDbJava::findParObjId(const TSK_FS_FILE* fs_file, const char* parentPath,
         return -1;
     }
 
-    int64_t parObjId;
-
     if (m_getParentIdMethodID == NULL) {
         printf("#### Yikes m_addFileSystemMethodID is null...\n");
         return TSK_ERR;
@@ -1117,7 +1115,64 @@ TskAutoDbJava::findParObjId(const TSK_FS_FILE* fs_file, const char* parentPath,
         return -1;
     }
 
-    return parObjId;
+    return objId;
+}
+
+/**
+* Adds a fake volume that will hold the unallocated blocks for the pool.
+*
+* @param vol_index The index for the new volume (should be one higher than the number of pool volumes)
+* @param parObjId  The object ID of the parent volume system
+* @param objId     Will be set to the object ID of the new volume
+*
+* @returns TSK_ERR on error, TSK_OK on success
+*/
+TSK_RETVAL_ENUM
+TskAutoDbJava::addUnallocatedPoolVolume(int vol_index, int64_t parObjId, int64_t& objId)
+{
+
+    printf("addUnallocatedPoolVolume\n");
+    fflush(stdout);
+
+    if (m_addVolumeMethodID == NULL) {
+        printf("#### Yikes m_addVolumeMethodID is null...\n");
+        return TSK_ERR;
+    }
+
+    char *desc = "Unallocated Blocks";
+    jstring descj = m_jniEnv->NewStringUTF(desc); // TODO free?
+
+    jlong objIdj = m_jniEnv->CallLongMethod(m_javaDbObj, m_addVolumeMethodID,
+        parObjId, vol_index, 0, 0,
+        descj, 0);
+    objId = (int64_t)objIdj;
+    printf("New unalloc pool volume object ID: %lld\n", objId);
+    fflush(stdout);
+
+    if (objId < 0) {
+        return TSK_ERR;
+    }
+    /*
+    char stmt[1024];
+
+    if (addObject(TSK_DB_OBJECT_TYPE_VOL, parObjId, objId))
+        return 1;
+
+    char *desc = "Unallocated Blocks";
+    char *desc_sql = PQescapeLiteral(conn, desc, strlen(desc));
+
+    snprintf(stmt, 1024,
+        "INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags)"
+        "VALUES (%lld, %" PRIuPNUM ",%d, %d, %s, %d)",
+        objId, vol_index, 0, 0, desc_sql, 0);
+
+    if (attempt_exec(stmt, "Error adding data to tsk_vs_parts table: %s\n")) {
+        PQfreemem(desc_sql);
+        return TSK_ERR;
+    }
+
+    PQfreemem(desc_sql);*/
+    return TSK_OK;
 }
 
 
@@ -1347,6 +1402,8 @@ TskAutoDbJava::filterPool(const TSK_POOL_INFO * pool_info)
             registerError();
             return TSK_FILTER_STOP;
         }
+        // Save the parent obj ID for the pool
+        m_poolOffsetToParentId[pool_info->img_offset] = m_curVolId;
     }
     else {
         // pool doesn't live in a volume, use image as parent
@@ -1354,13 +1411,86 @@ TskAutoDbJava::filterPool(const TSK_POOL_INFO * pool_info)
             registerError();
             return TSK_FILTER_STOP;
         }
+        // Save the parent obj ID for the pool
+        m_poolOffsetToParentId[pool_info->img_offset] = m_curImgId;
     }
 
-    
+    // Store the volume system object ID for later use
+    m_poolOffsetToVsId[pool_info->img_offset] = m_curPoolVs;
 
     return TSK_FILTER_CONT;
 }
 
+/**
+* Adds unallocated pool blocks to a new volume.
+*
+* @param numPool Will be updated with the number of pools processed
+*
+* @return Returns 0 for success, 1 for failure
+*/
+TSK_RETVAL_ENUM
+TskAutoDbJava::addUnallocatedPoolBlocksToDb(size_t & numPool) {
+
+    for (int i = 0; i < m_poolInfos.size(); i++) {
+        const TSK_POOL_INFO * pool_info = m_poolInfos[i];
+        if (m_poolOffsetToVsId.find(pool_info->img_offset) == m_poolOffsetToVsId.end()) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_AUTO_DB);
+            tsk_error_set_errstr("Error addUnallocatedPoolBlocksToDb() - could not find volume system object ID for pool at offset %lld", pool_info->img_offset);
+            return TSK_ERR;
+        }
+        int64_t curPoolVs = m_poolOffsetToVsId[pool_info->img_offset];
+
+        /* Make sure  the pool_info is still allocated */
+        if (pool_info->tag != TSK_POOL_INFO_TAG) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_AUTO_DB);
+            tsk_error_set_errstr("Error addUnallocatedPoolBlocksToDb() - pool_info is not allocated");
+            return TSK_ERR;
+        }
+
+        /* Only APFS pools are currently supported */
+        if (pool_info->ctype != TSK_POOL_TYPE_APFS) {
+            continue;
+        }
+
+        /* Increment the count of pools found */
+        numPool++;
+
+        /* Create the volume */
+        int64_t unallocVolObjId;
+        if (TSK_ERR == addUnallocatedPoolVolume(pool_info->num_vols, curPoolVs, unallocVolObjId)) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_AUTO_DB);
+            tsk_error_set_errstr("Error addUnallocatedPoolBlocksToDb() - error createing unallocated space pool volume");
+            return TSK_ERR;
+        }
+
+        /* Create the unallocated space files */
+        TSK_FS_ATTR_RUN * unalloc_runs = tsk_pool_unallocated_runs(pool_info);
+        TSK_FS_ATTR_RUN * current_run = unalloc_runs;
+        vector<TSK_DB_FILE_LAYOUT_RANGE> ranges;
+        while (current_run != NULL) {
+
+            TSK_DB_FILE_LAYOUT_RANGE tempRange(current_run->addr * pool_info->block_size, current_run->len * pool_info->block_size, 0);
+
+            ranges.push_back(tempRange);
+            int64_t fileObjId = 0;
+            if (TSK_ERR == addUnallocBlockFile(unallocVolObjId, NULL, current_run->len * pool_info->block_size, ranges, fileObjId, m_curImgId)) {
+                registerError();
+                tsk_fs_attr_run_free(unalloc_runs);
+                return TSK_ERR;
+            }
+
+            current_run = current_run->next;
+            ranges.clear();
+        }
+        tsk_fs_attr_run_free(unalloc_runs);
+    }
+
+    return TSK_OK;
+}
+
 TSK_FILTER_ENUM
 TskAutoDbJava::filterPoolVol(const TSK_POOL_VOLUME_INFO * pool_vol)
 {
@@ -1819,7 +1949,7 @@ TSK_WALK_RET_ENUM TskAutoDbJava::fsWalkUnallocBlocksCb(const TSK_FS_BLOCK *a_blo
 */
 TSK_RETVAL_ENUM TskAutoDbJava::addFsInfoUnalloc(const TSK_DB_FS_INFO & dbFsInfo) {
 
-    // Unalloc space is not yet implemented for APFS
+    // Unalloc space is handled separately for APFS
     if (dbFsInfo.fType == TSK_FS_TYPE_APFS) {
         return TSK_OK;
     }
@@ -1890,18 +2020,20 @@ TSK_RETVAL_ENUM TskAutoDbJava::addUnallocSpaceToDb() {
 
     size_t numVsP = 0;
     size_t numFs = 0;
+    size_t numPool = 0;
 
     TSK_RETVAL_ENUM retFsSpace = addUnallocFsSpaceToDb(numFs);
     TSK_RETVAL_ENUM retVsSpace = addUnallocVsSpaceToDb(numVsP);
+    TSK_RETVAL_ENUM retPoolSpace = addUnallocatedPoolBlocksToDb(numPool);
 
-    //handle case when no fs and no vs partitions
+    //handle case when no fs and no vs partitions and no pools
     TSK_RETVAL_ENUM retImgFile = TSK_OK;
-    if (numVsP == 0 && numFs == 0) {
+    if (numVsP == 0 && numFs == 0 && numPool == 0) {
         retImgFile = addUnallocImageSpaceToDb();
     }
     
     
-    if (retFsSpace == TSK_ERR || retVsSpace == TSK_ERR || retImgFile == TSK_ERR)
+    if (retFsSpace == TSK_ERR || retVsSpace == TSK_ERR || retPoolSpace == TSK_ERR || retImgFile == TSK_ERR)
         return TSK_ERR;
     else
         return TSK_OK;
@@ -1986,6 +2118,19 @@ TSK_RETVAL_ENUM TskAutoDbJava::addUnallocVsSpaceToDb(size_t & numVsP) {
                 //skip processing this vspart
                 continue;
             }
+
+            // Check if the volume contains a pool
+            bool hasPool = false;
+            for (std::map<int64_t, int64_t>::iterator iter = m_poolOffsetToParentId.begin(); iter != m_poolOffsetToParentId.end(); ++iter) {
+                if (iter->second == vsPart.objId) {
+                    hasPool = true;
+                }
+            }
+            if (hasPool) {
+                // Skip processing this vspart
+                continue;
+            }
+
         } //end checking vspart flags
 
         //get sector size and image offset from parent vs info
diff --git a/bindings/java/jni/auto_db_java.h b/bindings/java/jni/auto_db_java.h
index 7657219e1..d981e88cc 100644
--- a/bindings/java/jni/auto_db_java.h
+++ b/bindings/java/jni/auto_db_java.h
@@ -140,6 +140,12 @@ class TskAutoDbJava :public TskAuto {
     bool m_foundStructure;  ///< Set to true when we find either a volume or file system
     bool m_attributeAdded; ///< Set to true when an attribute was added by processAttributes
 
+    // These are used to write unallocated blocks for pools at the end of the add image
+    // process. We can't load the pool_info objects directly from the database so we will
+    // store info about them here.
+    std::map<int64_t, int64_t> m_poolOffsetToParentId;
+    std::map<int64_t, int64_t> m_poolOffsetToVsId;
+
     // Used to look up object IDs for files
     #define MAX_PATH_LENGTH_JAVA_DB_LOOKUP 2048
     char parent_name[MAX_PATH_LENGTH_JAVA_DB_LOOKUP];
@@ -200,6 +206,7 @@ class TskAutoDbJava :public TskAuto {
     virtual TSK_RETVAL_ENUM processAttribute(TSK_FS_FILE *,
         const TSK_FS_ATTR * fs_attr, const char *path);
 
+    TSK_RETVAL_ENUM addUnallocatedPoolBlocksToDb(size_t & numPool);
     static TSK_WALK_RET_ENUM fsWalkUnallocBlocksCb(const TSK_FS_BLOCK *a_block, void *a_ptr);
     TSK_RETVAL_ENUM addFsInfoUnalloc(const TSK_DB_FS_INFO & dbFsInfo);
     TSK_RETVAL_ENUM addUnallocFsSpaceToDb(size_t & numFs);
@@ -236,6 +243,7 @@ class TskAutoDbJava :public TskAuto {
         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);
+    TSK_RETVAL_ENUM addUnallocatedPoolVolume(int vol_index, int64_t parObjId, int64_t& objId);
 
 };
 
diff --git a/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java b/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java
index 29913c361..65719eaea 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java
@@ -219,5 +219,4 @@ long addUnallocFsBlockFilesParent(long fsObjId, String name) {
 			return -1;
 		}
 	}
-	
 }
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
index a8e66aa4b..ef8488d71 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
@@ -6000,7 +6000,7 @@ public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS
 			preparedStatement.clearParameters();
 			preparedStatement.setLong(1, newObjId);
 			preparedStatement.setLong(2, imgOffset);
-			preparedStatement.setShort(3, (short) type.getValue());
+			preparedStatement.setInt(3, type.getValue());
 			preparedStatement.setLong(4, blockSize);
 			preparedStatement.setLong(5, blockCount);
 			preparedStatement.setLong(6, rootInum);
-- 
GitLab