diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.cpp b/bindings/java/jni/dataModel_SleuthkitJNI.cpp
index db251c6d28a516229f2ad4a4516452f7fb6eed33..d86fc715757f0718213e7ead92280eb8895018b8 100644
--- a/bindings/java/jni/dataModel_SleuthkitJNI.cpp
+++ b/bindings/java/jni/dataModel_SleuthkitJNI.cpp
@@ -13,6 +13,7 @@
 #include "tsk/hashdb/tsk_hash_info.h"
 #include "tsk/auto/tsk_is_image_supported.h"
 #include "tsk/img/img_writer.h"
+#include "tsk/img/raw.h"
 #include "jni.h"
 #include "dataModel_SleuthkitJNI.h"
 #include <locale.h>
@@ -2159,3 +2160,52 @@ JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_isImageSupp
     return (jboolean) result;
 }
 
+
+/*
+ * Finish the image being created by image writer.
+ * @param env pointer to java environment this was called from
+ * @param obj the java object this was called from
+ * @param a_img_info the image info pointer
+ */
+JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_finishImageWriterNat
+(JNIEnv * env, jclass obj, jlong a_img_info) {
+    // Set up the TSK_IMG_INFO object
+    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
+    IMG_RAW_INFO *raw_info = (IMG_RAW_INFO*)img_info;
+
+    if (raw_info->img_writer != NULL) {
+        raw_info->img_writer->finish_image(raw_info->img_writer);
+    }
+
+}
+
+/*
+ * Get the progess of the finishImage process as an integer from 0 to 100
+ */
+JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getFinishImageProgressNat
+(JNIEnv * env, jclass obj, jlong a_img_info) {
+    // Set up the TSK_IMG_INFO object
+    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
+    IMG_RAW_INFO *raw_info = (IMG_RAW_INFO*)img_info;
+
+    if (raw_info->img_writer != NULL) {
+        return (raw_info->img_writer->finishProgress);
+    }
+    return 0;
+
+}
+
+/*
+* Cancel the finishImage process
+*/
+JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_cancelFinishImageNat
+(JNIEnv * env, jclass obj, jlong a_img_info) {
+    // Set up the TSK_IMG_INFO object
+    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
+    IMG_RAW_INFO *raw_info = (IMG_RAW_INFO*)img_info;
+
+    if (raw_info->img_writer != NULL) {
+        raw_info->img_writer->cancelFinish = 1;
+    }
+    return ;
+}
diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.h b/bindings/java/jni/dataModel_SleuthkitJNI.h
index 74b4c7808a1a693f38cb313830ab4bfc18163015..4fc585d766fb62acc06d49f42016dbed06d6b633 100644
--- a/bindings/java/jni/dataModel_SleuthkitJNI.h
+++ b/bindings/java/jni/dataModel_SleuthkitJNI.h
@@ -407,6 +407,30 @@ JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getCurDirNat
 JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_isImageSupportedNat
   (JNIEnv *, jclass, jstring);
 
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    finishImageWriterNat
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_finishImageWriterNat
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    getFinishImageProgressNat
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getFinishImageProgressNat
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    cancelFinishImageNat
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_cancelFinishImageNat
+  (JNIEnv *, jclass, jlong);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
index a9c47834d8b73ee45a052695997fbb97f8b7a876..5caa27e9a4d5f8fdd1ee8769fdd24ef65790ca9e 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
@@ -975,7 +975,36 @@ private static String timezoneLongToShort(String timezoneLongForm) {
 		}
 		return timezoneShortForm;
 	}
+	
+	/**
+	 * Fills in any gaps in the image created by image writer.
+	 *
+	 * @param imgHandle
+	 *
+	 * @throws TskCoreException exception thrown if critical error occurs within
+	 *                          TSK
+	 */
+	public static void finishImageWriter(long imgHandle) throws TskCoreException {
+		finishImageWriterNat(imgHandle);
+	}
+	
+	/**
+	 * Get the current progress of the finish image process (0-100)
+	 * @param imgHandle 
+	 * @return Percentage of blocks completed (0-100)
+	 */
+	public static int getFinishImageProgress(long imgHandle){
+		return getFinishImageProgressNat(imgHandle);
+	}
 
+	/**
+	 * Cancel the finish image process
+	 * @param imgHandle
+	 */
+	public static void cancelFinishImage(long imgHandle){
+		cancelFinishImageNat(imgHandle);
+	}
+	
 	/**
 	 * Get size of a device (physical, logical device, image) pointed to by
 	 * devPath
@@ -1094,5 +1123,11 @@ public static boolean isImageSupported(String imagePath){
 	private static native String getCurDirNat(long process);
 	
 	private static native boolean isImageSupportedNat(String imagePath);
+	
+	private static native void finishImageWriterNat(long a_img_info);
+	
+	private static native int getFinishImageProgressNat(long a_img_info);
+	
+	private static native void cancelFinishImageNat(long a_img_info);
 
 }
diff --git a/tsk/img/img_writer.cpp b/tsk/img/img_writer.cpp
index c8f6587b8661024c84f3a1bf97d61fd6eeed3186..15f8a3f75482fc586cdca163d14d1f65caac42ed 100644
--- a/tsk/img/img_writer.cpp
+++ b/tsk/img/img_writer.cpp
@@ -18,6 +18,9 @@
 #include "tsk_img_i.h"
 #include "img_writer.h"
 #include "raw.h"
+#include <unistd.h> // TEMP TEMP TEMP
+#include <chrono> // TEMP
+#include <thread> // TEMP 
 #include <time.h>
 
 #ifdef TSK_WIN32
@@ -32,64 +35,6 @@
 
 TSK_RETVAL_ENUM writeFooter(TSK_IMG_WRITER* writer);
 
-// TEMP LOGGING TEMP
-// This will be removed once finishImage is complete
-char messageBuffer[0x2000];
-char logBuffer[0x2000];
-bool openLogFileFailed = false;
-void openLogFile(TSK_IMG_WRITER * writer);
-void writeLogFile(TSK_IMG_WRITER * writer, const char * message) {
-    if (openLogFileFailed) {
-        return;
-    }
-    if (writer->logFileHandle == 0) {
-        // Open it up
-        openLogFile(writer);
-    }
-    if (openLogFileFailed) {
-        return;
-    }
-
-    time_t ltime; /* calendar time */
-    ltime = time(NULL); /* get current cal time */
-    sprintf(logBuffer, "%s : ", asctime(localtime(&ltime)));
-    logBuffer[24] = ' ';
-    logBuffer[25] = ' ';
-    strcat(logBuffer, message);
-
-    DWORD bytesWritten;
-    if (FALSE == WriteFile(writer->logFileHandle, logBuffer,
-        strlen(logBuffer), &bytesWritten, NULL)) {
-        int lastError = GetLastError();
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_IMG_WRITE);
-        tsk_error_set_errstr("writeLogFile: error writing log",
-            lastError);
-    }
-}
-
-void openLogFile(TSK_IMG_WRITER * writer) {
-    writer->logFileHandle = CreateFile(L"C:\\cygwin\\home\\apriestman\\Work\\autopsy\\vhdTesting\\tskOutput\\tskLog.txt", FILE_APPEND_DATA,
-        FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0,
-        NULL);
-    if (writer->logFileHandle == INVALID_HANDLE_VALUE) {
-        tsk_fprintf(stderr, "Error opening VHD!!!"); // temp
-        fflush(stderr);
-        int lastError = (int)GetLastError();
-        writer->outputFileHandle = 0; /* so we don't close it next time */
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_IMG_OPEN);
-        tsk_error_set_errstr("openLogFile: file  %d", lastError);
-        openLogFileFailed = true;
-        return;
-    }
-    openLogFileFailed = false;
-    writeLogFile(writer, "Opened log file\n");
-
-}
-// END TEMP LOGGING
-
-
 /*
  * Considering the buffer to be an array of bits, get the entry at
  * the given index.
@@ -481,12 +426,24 @@ static TSK_RETVAL_ENUM tsk_img_writer_finish_image(TSK_IMG_WRITER* img_writer) {
         return TSK_OK;
     }
 
+    if (img_writer->cancelFinish) {
+        return TSK_ERR;
+    }
+
     IMG_RAW_INFO * raw_info = (IMG_RAW_INFO *)(img_writer->img_info);
     TSK_OFF_T offset;
     TSK_OFF_T startOfBlock;
 
     char * buffer = (char*)tsk_malloc(TSK_IMG_INFO_CACHE_LEN * sizeof(char));
     for (uint32_t i = 0; i < img_writer->totalBlocks; i++) {
+        if (img_writer->cancelFinish) {
+            return TSK_ERR;
+        }
+
+        /* Simple progress indicator - current block / totalBlocks (as an integer)
+         */
+        img_writer->finishProgress = (i * 100) / img_writer->totalBlocks;
+
         if (img_writer->blockStatus[i] != IMG_WRITER_BLOCK_STATUS_FINISHED) {
 
             /* Read in the entire block in cache-length chunks. Each read will lead to a call to
@@ -496,6 +453,9 @@ static TSK_RETVAL_ENUM tsk_img_writer_finish_image(TSK_IMG_WRITER* img_writer) {
             */
             startOfBlock = i * img_writer->blockSize;
             for(offset = startOfBlock; offset < startOfBlock + img_writer->blockSize;offset += TSK_IMG_INFO_CACHE_LEN){
+                if (img_writer->cancelFinish) {
+                    return TSK_ERR;
+                }
                 raw_info->img_info.read(img_writer->img_info, offset, buffer, TSK_IMG_INFO_CACHE_LEN);
             }
         }
@@ -685,6 +645,8 @@ TSK_RETVAL_ENUM tsk_img_writer_create(TSK_IMG_INFO * img_info, const TSK_TCHAR *
         return TSK_ERR;
     TSK_IMG_WRITER* writer = raw_info->img_writer;
     writer->is_finished = 0;
+    writer->finishProgress = 0;
+    writer->cancelFinish = 0;
     writer->footer = NULL;
     writer->img_info = img_info;
     writer->add = tsk_img_writer_add;
diff --git a/tsk/img/img_writer.h b/tsk/img/img_writer.h
index a632dd227d43b3c7d02c0acd21c1a1f1c76ebc7e..9bc19adf3acd11206ded4b89cf7dc6a420af00d3 100644
--- a/tsk/img/img_writer.h
+++ b/tsk/img/img_writer.h
@@ -32,6 +32,8 @@ extern "C" {
     struct TSK_IMG_WRITER {
         TSK_IMG_INFO * img_info;
         int is_finished;
+        int finishProgress;
+        int cancelFinish;
 
         TSK_TCHAR* fileName;
         HANDLE outputFileHandle;