From 17c85aec2863bae32b07124025716499693cf27a Mon Sep 17 00:00:00 2001
From: Ann Priestman <apriestman@basistech.com>
Date: Mon, 11 Nov 2019 15:32:02 -0500
Subject: [PATCH] Pass in pool img info from Autopsy

---
 bindings/java/jni/dataModel_SleuthkitJNI.cpp  | 114 ++++++++++++++----
 bindings/java/jni/dataModel_SleuthkitJNI.h    |  28 ++++-
 .../src/org/sleuthkit/datamodel/Pool.java     |  17 ++-
 .../sleuthkit/datamodel/SleuthkitCase.java    |   2 +-
 .../org/sleuthkit/datamodel/SleuthkitJNI.java |  79 ++++++++++--
 tsk/auto/db_sqlite.cpp                        |   6 +-
 tsk/pool/apfs_pool_compat.cpp                 |  18 +--
 tsk/pool/pool_compat.hpp                      |   1 +
 tsk/pool/tsk_pool.h                           |   1 +
 tsk/pool/tsk_pool.hpp                         |   6 +
 10 files changed, 216 insertions(+), 56 deletions(-)

diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.cpp b/bindings/java/jni/dataModel_SleuthkitJNI.cpp
index a3561d990..52eaaf4d0 100644
--- a/bindings/java/jni/dataModel_SleuthkitJNI.cpp
+++ b/bindings/java/jni/dataModel_SleuthkitJNI.cpp
@@ -1445,7 +1445,8 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_openPoolNat(JNIEnv * env,
     printf("  Casted img_info\n");
 
     // TODO - use pool type
-    const TSK_POOL_INFO *pool = tsk_pool_open_img_sing(img_info, offset * img_info->sector_size, TSK_POOL_TYPE_DETECT);
+    //const TSK_POOL_INFO *pool = tsk_pool_open_img_sing(img_info, offset * img_info->sector_size, TSK_POOL_TYPE_DETECT);
+    const TSK_POOL_INFO *pool = tsk_pool_open_img_sing(img_info, offset, TSK_POOL_TYPE_DETECT);
     if (pool == NULL) {
         printf("  Failed to load pool\n");
         tsk_error_print(stderr);
@@ -1458,6 +1459,7 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_openPoolNat(JNIEnv * env,
 }
 
 /*
+TODO UPDATe
 * Open file system with the given offset
 * @return the created TSK_FS_INFO pointer
 * @param env pointer to java environment this was called from
@@ -1465,39 +1467,27 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_openPoolNat(JNIEnv * env,
 * @param a_img_info the pointer to the parent img object
 * @param fs_offset the offset in bytes to the file system
 */
-JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_openFsPoolNat
-(JNIEnv * env, jclass obj, jlong a_img_info, jlong fs_offset, jlong a_pool_info, jlong pool_block) {
-    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
-    if (img_info == 0) {
-        //exception already set
-        return 0;
-    }
+JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getImgInfoNat
+(JNIEnv * env, jclass obj, jlong a_pool_info, jlong pool_block) {
 
-    printf("@@@ openFsPoolNat - trying to cast pool with address 0x%x\n", a_pool_info);
+
+    printf("@@@ openGetImgInfoNat - trying to cast pool with address 0x%x\n", a_pool_info);
     TSK_POOL_INFO *pool_info = castPoolInfo(env, a_pool_info);
     if (pool_info == 0) {
-        printf("@@@ openFsPoolNat - Invalid cast to pool???\n");
+        printf("@@@ openGetImgInfoNat - Invalid cast to pool???\n");
         fflush(stdout);
         //exception already set
         return 0;
     }
 
-    TSK_FS_INFO *fs_info;
-    printf("Java_org_sleuthkit_datamodel_SleuthkitJNI_openFsPoolNat - pool_block = %lld\n", pool_block);
+    printf("Java_org_sleuthkit_datamodel_SleuthkitJNI_openGetImgInfoNat - pool_block = %lld\n", pool_block);
     fflush(stdout);
-    printf("  Ok have a pool\n");
 
     printf("  Making new img_info\n");
     fflush(stdout);
-    img_info = pool_info->get_img_info(pool_info, pool_block);
+    TSK_IMG_INFO *img_info = pool_info->get_img_info(pool_info, pool_block);
 
-    fs_info =
-        tsk_fs_open_img(img_info, (TSK_OFF_T)fs_offset,
-            TSK_FS_TYPE_DETECT);
-    if (fs_info == NULL) {
-        setThrowTskCoreError(env, tsk_error_get());
-    }
-    return (jlong)fs_info;
+    return (jlong)img_info;
 }
 
 /*
@@ -1679,6 +1669,70 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_readImgNat(JNIEnv * env,
     return (jint)copiedbytes;
 }
 
+/*
+TODO UPDATE
+* Read bytes from the given volume system
+* @return number of bytes read from the volume system, -1 on error
+* @param env pointer to java environment this was called from
+* @param obj the java object this was called from
+* @param a_vs_info the pointer to the volume system object
+* @param offset the offset in bytes to start at
+* @param len number of bytes to read
+*/
+JNIEXPORT jint JNICALL
+Java_org_sleuthkit_datamodel_SleuthkitJNI_readPoolNat(JNIEnv * env,
+    jclass obj, jlong a_pool_info, jbyteArray jbuf, jlong offset, jlong len)
+{
+    //use fixed size stack-allocated buffer if possible
+    char fixed_buf[FIXED_BUF_SIZE];
+
+    char * buf = fixed_buf;
+    bool dynBuf = false;
+    if (len > FIXED_BUF_SIZE) {
+        dynBuf = true;
+        buf = (char *)tsk_malloc((size_t)len);
+        if (buf == NULL) {
+            setThrowTskCoreError(env);
+            return -1;
+        }
+    }
+
+    TSK_POOL_INFO *pool_info = castPoolInfo(env, a_pool_info);
+    if (pool_info == 0) {
+        //exception already set
+        if (dynBuf) {
+            free(buf);
+        }
+        return -1;
+    }
+
+    ssize_t bytesread = tsk_pool_read(pool_info, (TSK_DADDR_T)offset, buf,
+        (size_t)len);
+    if (bytesread == -1) {
+        setThrowTskCoreError(env, tsk_error_get());
+        if (dynBuf) {
+            free(buf);
+        }
+        return -1;
+    }
+
+    // package it up for return
+    // adjust number bytes to copy
+    ssize_t copybytes = bytesread;
+    jsize jbuflen = env->GetArrayLength(jbuf);
+    if (jbuflen < copybytes)
+        copybytes = jbuflen;
+
+    ssize_t copiedbytes = copyBufToByteArray(env, jbuf, buf, copybytes);
+    if (dynBuf) {
+        free(buf);
+    }
+    if (copiedbytes == -1) {
+        setThrowTskCoreError(env, tsk_error_get());
+    }
+    return (jint)copiedbytes;
+}
+
 
 /*
  * Read bytes from the given volume system
@@ -2034,7 +2088,7 @@ JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_closeVsNat
 }
 
 /*
- * Close the given volume system
+ * Close the given file system
  * @param env pointer to java environment this was called from
  * @param obj the java object this was called from
  * @param a_fs_info the pointer to the file system object
@@ -2049,6 +2103,22 @@ JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_closeFsNat
     tsk_fs_close(fs_info);
 }
 
+/*
+* Close the given pool
+* @param env pointer to java environment this was called from
+* @param obj the java object this was called from
+* @param a_pool_info the pointer to the pool object
+*/
+JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_closePoolNat
+(JNIEnv * env, jclass obj, jlong a_pool_info) {
+    TSK_POOL_INFO *pool_info = castPoolInfo(env, a_pool_info);
+    if (pool_info == 0) {
+        //exception already set
+        return;
+    }
+    tsk_pool_close(pool_info);
+}
+
 /*
  * Close the given file
  * @param env pointer to java environment this was called from
diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.h b/bindings/java/jni/dataModel_SleuthkitJNI.h
index ef2523e30..14eb67533 100644
--- a/bindings/java/jni/dataModel_SleuthkitJNI.h
+++ b/bindings/java/jni/dataModel_SleuthkitJNI.h
@@ -297,19 +297,19 @@ JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_openPoolNat
 
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
- * Method:    openFsNat
+ * Method:    getImgInfoNat
  * Signature: (JJ)J
  */
-JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_openFsNat
+JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getImgInfoNat
   (JNIEnv *, jclass, jlong, jlong);
 
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
- * Method:    openFsPoolNat
- * Signature: (JJJJ)J
+ * Method:    openFsNat
+ * Signature: (JJ)J
  */
-JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_openFsPoolNat
-  (JNIEnv *, jclass, jlong, jlong, jlong, jlong);
+JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_openFsNat
+  (JNIEnv *, jclass, jlong, jlong);
 
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
@@ -335,6 +335,14 @@ JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_readImgNat
 JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_readVsNat
   (JNIEnv *, jclass, jlong, jbyteArray, jlong, jlong);
 
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    readPoolNat
+ * Signature: (J[BJJ)I
+ */
+JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_readPoolNat
+  (JNIEnv *, jclass, jlong, jbyteArray, jlong, jlong);
+
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
  * Method:    readVolNat
@@ -375,6 +383,14 @@ JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_saveFileMetaDat
 JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_closeImgNat
   (JNIEnv *, jclass, jlong);
 
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    closePoolNat
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_closePoolNat
+  (JNIEnv *, jclass, jlong);
+
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
  * Method:    closeVsNat
diff --git a/bindings/java/src/org/sleuthkit/datamodel/Pool.java b/bindings/java/src/org/sleuthkit/datamodel/Pool.java
index cae02f115..754daa56c 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/Pool.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/Pool.java
@@ -43,18 +43,17 @@ protected Pool(SleuthkitCase db, long obj_id, String name, long type, long imgOf
 		super(db, obj_id, name);
 		this.type = type;
 		this.imgOffset = imgOffset;
-		System.out.println("### made a pool!\n");
+		System.out.println("### made a pool! Image offset " + imgOffset + "\n");
 	}
 
 	@Override
 	public int read(byte[] readBuffer, long offset, long len) throws TskCoreException {
-		throw new TskCoreException("Not yet implemented");
-		//synchronized (this) {
-		//	if (volumeSystemHandle == 0) {
-		//		getVolumeSystemHandle();
-		//	}
-		//}
-		//return SleuthkitJNI.readVs(volumeSystemHandle, readBuffer, offset, len);
+		synchronized (this) {
+			if (poolHandle == 0) {
+				getPoolHandle();
+			}
+		}
+		return SleuthkitJNI.readPool(poolHandle, readBuffer, offset, len);
 	}
 
 	@Override
@@ -97,7 +96,7 @@ long getPoolHandle() throws TskCoreException {
 					Content dataSource = getDataSource();
 					if ((dataSource != null) && (dataSource instanceof Image)) {
 						Image image = (Image) dataSource;
-						poolHandle = SleuthkitJNI.openPool(image.getImageHandle(), imgOffset, getType().getPoolType());
+						poolHandle = SleuthkitJNI.openPool(image.getImageHandle(), imgOffset, getType().getPoolType(), getSleuthkitCase());
 					} else {
 						throw new TskCoreException("Data Source of pool is not an image");
 					}
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
index a0ba56532..d4a7c849e 100755
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
@@ -7346,7 +7346,7 @@ private Pool getPoolByIdHelper(long id, Content parent) throws TskCoreException
 					+ "where obj_id = " + id); //NON-NLS
 			if (rs.next()) {
 				
-				Pool pool = new Pool(this, rs.getLong("obj_id"), "POOL!", rs.getLong("pool_type"), rs.getLong("addr"));
+				Pool pool = new Pool(this, rs.getLong("obj_id"), "POOL!", rs.getLong("pool_type"), rs.getLong("img_offset"));
 				pool.setParent(parent);
 				
 				return pool;
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
index c76366de3..254f4f3e6 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
@@ -93,6 +93,10 @@ private static class CaseHandles {
 
 		private final Map<Long, List<Long>> fileSystemToFileHandles = new HashMap<>();
 		
+		private final Map<Long, Long> poolHandleCache = new HashMap<>();
+		
+		private final List<Long> poolImgCache = new ArrayList<>();
+		
 		private CaseHandles() {
 			// Nothing to do here
 		}
@@ -169,6 +173,7 @@ private static void removeCaseHandlesCache(long caseDbPointer) {
 					caseHandlesCache.get(caseDbPointer).imageHandleCache.clear();
 					caseHandlesCache.get(caseDbPointer).fileHandleCache.clear();
 					caseHandlesCache.get(caseDbPointer).fileSystemToFileHandles.clear();
+					caseHandlesCache.get(caseDbPointer).poolHandleCache.clear();
 					caseHandlesCache.remove(caseDbPointer);
 				}
 			}
@@ -270,6 +275,20 @@ private static void closeHandlesAndClearCache(long caseDbPointer) throws TskCore
 						closeFsNat(fsHandle);
 					}
 				}
+				
+				/*
+				 * Close any cached pools
+				 */
+				for (Long poolHandle : getCaseHandles(caseDbPointer).poolHandleCache.values()) {
+					closePoolNat(poolHandle);
+				}
+				
+				/*
+				 * Close any open pool images
+				 */
+				for (Long imageHandle : getCaseHandles(caseDbPointer).poolImgCache) {
+					closeImgNat(imageHandle);
+				}
 
 				/*
 				 * Close any cached image handles.
@@ -816,12 +835,34 @@ public static long openVsPart(long vsHandle, long volId) throws TskCoreException
 	 * @throws TskCoreException exception thrown if critical error occurs within
 	 *                          TSK
 	 */
-	public static long openPool(long imgHandle, long offset, long poolType) throws TskCoreException {
+	public static long openPool(long imgHandle, long offset, long poolType, SleuthkitCase skCase) throws TskCoreException {
 		getTSKReadLock();
 		try {
-			// TODO CACHE
-			//returned long is ptr to pool Handle object in tsk
-			return openPoolNat(imgHandle, offset, poolType);
+			if(! imgHandleIsValid(imgHandle)) {
+				throw new TskCoreException("Image handle " + imgHandle + " is closed");
+			}
+			
+			synchronized (HandleCache.cacheLock) {
+				long caseDbPointer;
+				if (skCase == null) {
+					caseDbPointer = HandleCache.getDefaultCaseDbPointer();
+				} else {
+					caseDbPointer = skCase.getCaseHandle().caseDbPointer;
+				}
+				
+				if (HandleCache.getCaseHandles(caseDbPointer).poolHandleCache.containsKey(offset)) {
+					System.out.println("\n#### Using the pool cache!");
+					return HandleCache.getCaseHandles(caseDbPointer).poolHandleCache.get(offset);
+				} else {
+					//returned long is ptr to pool Handle object in tsk
+					System.out.println("\n#### Trying to open pool at offset " + offset);
+					long poolHandle = openPoolNat(imgHandle, offset, poolType);
+					HandleCache.getCaseHandles(caseDbPointer).poolHandleCache.put(offset, poolHandle);
+					return poolHandle;
+				}
+			}
+			
+
 		} finally {
 			releaseTSKReadLock();
 		}
@@ -891,7 +932,9 @@ public static long openFsPool(long imgHandle, long fsOffset, long poolHandle, lo
 					//return cached
 					fsHandle = imgOffSetToFsHandle.get(combinedOffset);
 				} else {
-					fsHandle = openFsPoolNat(imgHandle, fsOffset, poolHandle, poolBlock);
+					long poolImgHandle = getImgInfoNat(poolHandle, poolBlock);
+					HandleCache.getCaseHandles(caseDbPointer).poolImgCache.add(poolImgHandle);
+					fsHandle = openFsNat(poolImgHandle, fsOffset);
 					//cache it
 					imgOffSetToFsHandle.put(combinedOffset, fsHandle);
 				}
@@ -1022,6 +1065,24 @@ public static int readVs(long vsHandle, byte[] readBuffer, long offset, long len
 			releaseTSKReadLock();
 		}
 	}
+	
+	/**
+	 * TODO
+	 * @param poolHandle
+	 * @param readBuffer
+	 * @param offset
+	 * @param len
+	 * @return
+	 * @throws TskCoreException 
+	 */
+	public static int readPool(long poolHandle, byte[] readBuffer, long offset, long len) throws TskCoreException {
+		getTSKReadLock();
+		try {
+			return readPoolNat(poolHandle, readBuffer, offset, len);
+		} finally {
+			releaseTSKReadLock();
+		}
+	}
 
 	/**
 	 * reads data from an volume
@@ -1720,15 +1781,17 @@ public static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM at
 	
 	private static native long openPoolNat(long imgHandle, long offset, long poolType) throws TskCoreException;
 	
+	private static native long getImgInfoNat(long poolHandle, long poolOffset) throws TskCoreException;
+	
 	private static native long openFsNat(long imgHandle, long fsId) throws TskCoreException;
 
-	private static native long openFsPoolNat(long imgHandle, long fsId, long poolHandle, long poolOffset) throws TskCoreException;
-
 	private static native long openFileNat(long fsHandle, long fileId, int attrType, int attrId) throws TskCoreException;
 
 	private static native int readImgNat(long imgHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
 
 	private static native int readVsNat(long vsHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
+	
+	private static native int readPoolNat(long poolHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;	
 
 	private static native int readVolNat(long volHandle, byte[] readBuffer, long offset, long len) throws TskCoreException;
 
@@ -1739,6 +1802,8 @@ public static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM at
 	private static native int saveFileMetaDataTextNat(long fileHandle, String fileName) throws TskCoreException;
 
 	private static native void closeImgNat(long imgHandle);
+	
+	private static native void closePoolNat(long poolHandle);
 
 	private static native void closeVsNat(long vsHandle);
 
diff --git a/tsk/auto/db_sqlite.cpp b/tsk/auto/db_sqlite.cpp
index 5b67f0516..921d27055 100755
--- a/tsk/auto/db_sqlite.cpp
+++ b/tsk/auto/db_sqlite.cpp
@@ -305,7 +305,7 @@ TskDbSqlite::initialize()
             "Error creating tsk_vol_info table: %s\n")
         ||
         attempt_exec
-        ("CREATE TABLE tsk_pool_info (obj_id INTEGER PRIMARY KEY, addr INTEGER NOT NULL, pool_type INTEGER NOT NULL, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id));",
+        ("CREATE TABLE tsk_pool_info (obj_id INTEGER PRIMARY KEY, img_offset INTEGER NOT NULL, pool_type INTEGER NOT NULL, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id));",
             "Error creating tsk_pool_info table: %s\n")
         ||
         attempt_exec
@@ -764,7 +764,7 @@ TskDbSqlite::addPoolInfo(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64
         return 1;
 
     snprintf(stmt, 1024,
-        "INSERT INTO tsk_pool_info (obj_id, addr, pool_type) VALUES (%" PRId64 ",%" PRIuDADDR ",%d)", poolObjId, 0, pool_info->ctype); // TODO - offset
+        "INSERT INTO tsk_pool_info (obj_id, img_offset, pool_type) VALUES (%" PRId64 ",%" PRIuDADDR ",%d)", poolObjId, pool_info->img_offset, pool_info->ctype); // TODO - offset
 
 
     int retVal = attempt_exec(stmt,
@@ -777,7 +777,7 @@ TskDbSqlite::addPoolInfo(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64
         return 1;
 
     snprintf(stmt, 1024,
-        "INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (%" PRId64 ", %d,%" PRIuDADDR ",%d)", objId, 0, 0, pool_info->block_size); // TODO - offset
+        "INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (%" PRId64 ", %d,%" PRIuDADDR ",%d)", objId, 0, pool_info->img_offset, pool_info->block_size); // TODO - offset
 
     return attempt_exec(stmt,
         "Error adding data to tsk_vs_info table: %s\n");
diff --git a/tsk/pool/apfs_pool_compat.cpp b/tsk/pool/apfs_pool_compat.cpp
index 4d514c467..9102776b7 100755
--- a/tsk/pool/apfs_pool_compat.cpp
+++ b/tsk/pool/apfs_pool_compat.cpp
@@ -270,14 +270,14 @@ apfs_img_close(TSK_IMG_INFO * img_info)
     IMG_POOL_INFO *pool_img_info = (IMG_POOL_INFO *)img_info;
 
     // Close the pool and original image
-    if (pool_img_info->pool_info != NULL) {
-        const auto pool = static_cast<APFSPoolCompat*>(pool_img_info->pool_info->impl);
-        TSK_IMG_INFO *origInfo = pool->getTSKImgInfo(0);
-        tsk_img_close(origInfo);
+    //if (pool_img_info->pool_info != NULL) {
+    //    const auto pool = static_cast<APFSPoolCompat*>(pool_img_info->pool_info->impl);
+    //    TSK_IMG_INFO *origInfo = pool->getTSKImgInfo(0);
+    //    tsk_img_close(origInfo);
 
-        pool_img_info->pool_info->close(pool_img_info->pool_info);
-        pool_img_info->pool_info = NULL;
-    }
+        //pool_img_info->pool_info->close(pool_img_info->pool_info);
+        //pool_img_info->pool_info = NULL;
+    //}
 
     // Close the pool image
     tsk_deinit_lock(&(img_info->cache_lock));
@@ -296,11 +296,13 @@ apfs_img_imgstat(TSK_IMG_INFO * img_info, FILE *file)
 static ssize_t
 apfs_img_read(TSK_IMG_INFO * img_info, TSK_OFF_T offset, char *buf, size_t len)
 {
+    printf("apfs_img_read: reading offset 0x%llx\n", offset);
+    fflush(stdout);
     IMG_POOL_INFO *pool_img_info = (IMG_POOL_INFO *)img_info;
     const auto pool = static_cast<APFSPoolCompat*>(pool_img_info->pool_info->impl);
     TSK_IMG_INFO *origInfo = pool->getTSKImgInfo(0);
 
-    return origInfo->read(origInfo, offset, buf, len);
+    return origInfo->read(origInfo, offset + pool->first_img_offset(), buf, len);
 }
 
 TSK_IMG_INFO * APFSPoolCompat::getImageInfo(const TSK_POOL_INFO *pool_info, TSK_DADDR_T pvol_block) noexcept try {
diff --git a/tsk/pool/pool_compat.hpp b/tsk/pool/pool_compat.hpp
index ec2cbd260..4cc7f5fd4 100644
--- a/tsk/pool/pool_compat.hpp
+++ b/tsk/pool/pool_compat.hpp
@@ -29,6 +29,7 @@ class TSKPoolCompat : public T {
     _info.ctype = type;
     _info.block_size = this->block_size();
     _info.num_blocks = this->num_blocks();
+    _info.img_offset = this->first_img_offset();
     _info.num_vols = this->num_vols();
     _info.vol_list = nullptr;
     _info.close = [](const TSK_POOL_INFO *pool) {
diff --git a/tsk/pool/tsk_pool.h b/tsk/pool/tsk_pool.h
index 7902617df..ee2b8c2a7 100644
--- a/tsk/pool/tsk_pool.h
+++ b/tsk/pool/tsk_pool.h
@@ -48,6 +48,7 @@ typedef struct _TSK_POOL_INFO {
   uint32_t block_size;       ///< Block size
   uint64_t num_blocks;       ///< Number of blocks
   int num_vols;              ///< Number of volumes
+  uint64_t img_offset;       ///< The image offset of the pool
   TSK_POOL_VOLUME_INFO *vol_list;  ///< Linked list of volume info structs
 
   // Callbacks
diff --git a/tsk/pool/tsk_pool.hpp b/tsk/pool/tsk_pool.hpp
index 4195b2ae3..a8d8d3104 100644
--- a/tsk/pool/tsk_pool.hpp
+++ b/tsk/pool/tsk_pool.hpp
@@ -34,6 +34,12 @@ class TSKPool {
   inline uint32_t block_size() const noexcept { return _block_size; }
   inline uint32_t dev_block_size() const noexcept { return _dev_block_size; }
   inline uint64_t num_blocks() const noexcept { return _num_blocks; }
+  inline uint64_t first_img_offset() const noexcept {
+      if (_members.size() >= 1) {
+          return _members[0].second;
+      }
+      return 0;
+  }
   inline int num_vols() const noexcept { return _num_vols; }
 
   virtual ssize_t read(uint64_t address, char *buf, size_t buf_size) const
-- 
GitLab