19 package org.sleuthkit.autopsy.imagewriter;
21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.util.EnumSet;
26 import java.util.concurrent.Callable;
27 import java.util.concurrent.Executors;
28 import java.util.concurrent.Future;
29 import java.util.concurrent.ScheduledFuture;
30 import java.util.concurrent.ScheduledThreadPoolExecutor;
31 import java.util.concurrent.TimeUnit;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.ExecutorService;
34 import java.util.logging.Level;
35 import org.netbeans.api.progress.ProgressHandle;
36 import org.openide.util.NbBundle.Messages;
56 class ImageWriter
implements PropertyChangeListener {
60 private final Long dataSourceId;
63 private Long imageHandle = null;
64 private Future<Integer> finishTask = null;
65 private ProgressHandle progressHandle = null;
66 private ScheduledFuture<?> progressUpdateTask = null;
67 private boolean isCancelled =
false;
68 private boolean isStarted =
false;
69 private final Object currentTasksLock =
new Object();
72 private ScheduledThreadPoolExecutor periodicTasksExecutor = null;
73 private final boolean doUI;
74 private SleuthkitCase caseDb = null;
83 this.dataSourceId = dataSourceId;
84 this.settings = settings;
93 logger.log(Level.SEVERE,
"Unable to load case. Image writer will be cancelled.");
94 this.isCancelled =
true;
101 void subscribeToEvents() {
109 void unsubscribeFromEvents() {
118 public void propertyChange(PropertyChangeEvent evt) {
121 DataSourceAnalysisCompletedEvent
event = (DataSourceAnalysisCompletedEvent) evt;
123 if (event.getDataSource() != null) {
124 long imageId =
event.getDataSource().getId();
125 String name =
event.getDataSource().getName();
128 if (imageId != dataSourceId) {
132 startFinishImage(name);
136 logger.log(Level.SEVERE,
"DataSourceAnalysisCompletedEvent did not contain a dataSource object");
142 "# {0} - data source name",
143 "ImageWriter.progressBar.message=Finishing acquisition of {0} (unplug device to cancel)"
145 private void startFinishImage(String dataSourceName) {
147 ExecutorService executor = Executors.newSingleThreadExecutor(
new ThreadFactoryBuilder().setNameFormat(
"ImageWriter-startFinishImage-%d").build());
148 synchronized (currentTasksLock) {
163 imageHandle = image.getImageHandle();
169 logger.log(Level.WARNING, String.format(
"Case closed before ImageWriter could start the finishing process for %s",
172 }
catch (TskCoreException ex) {
173 logger.log(Level.SEVERE,
"Error loading image", ex);
177 logger.log(Level.INFO, String.format(
"Finishing VHD image for %s",
181 periodicTasksExecutor =
new ScheduledThreadPoolExecutor(1,
new ThreadFactoryBuilder().setNameFormat(
"image-writer-progress-update-%d").build());
182 progressHandle = ProgressHandle.createHandle(Bundle.ImageWriter_progressBar_message(dataSourceName));
183 progressHandle.start(100);
184 progressUpdateTask = periodicTasksExecutor.scheduleWithFixedDelay(
185 new ProgressUpdateTask(progressHandle, imageHandle), 0, 250, TimeUnit.MILLISECONDS);
191 finishTask = executor.submit(
new Callable<Integer>() {
193 public Integer call()
throws TskCoreException {
195 int result = SleuthkitJNI.finishImageWriter(imageHandle);
201 caseDb.updateImagePath(settings.
getPath(), dataSourceId);
204 }
catch (Throwable ex) {
205 logger.log(Level.SEVERE,
"Error finishing VHD image", ex);
219 result = finishTask.get();
220 executor.shutdownNow();
221 }
catch (InterruptedException | ExecutionException ex) {
222 logger.log(Level.SEVERE,
"Error finishing VHD image", ex);
225 synchronized (currentTasksLock) {
228 progressUpdateTask.cancel(
true);
229 progressHandle.finish();
230 periodicTasksExecutor.shutdown();
235 logger.log(Level.INFO, String.format(
"Successfully finished writing VHD image for %s", dataSourceName));
237 logger.log(Level.INFO, String.format(
"Finished VHD image for %s with errors", dataSourceName));
246 void cancelIfNotStarted() {
247 synchronized (currentTasksLock) {
260 boolean jobIsInProgress() {
261 synchronized (currentTasksLock) {
262 return ((isStarted) && (!finishTask.isDone()));
271 synchronized (currentTasksLock) {
276 SleuthkitJNI.cancelFinishImage(imageHandle);
285 progressUpdateTask.cancel(
true);
286 progressHandle.finish();
296 void waitForJobToFinish() {
297 synchronized (currentTasksLock) {
302 }
catch (InterruptedException | ExecutionException ex) {
303 Logger.
getLogger(ImageWriter.class.getName()).log(Level.SEVERE,
"Error finishing VHD image", ex);
306 progressUpdateTask.cancel(
true);
317 final long imageHandle;
318 final ProgressHandle progressHandle;
321 this.imageHandle = imageHandle;
322 this.progressHandle = progressHandle;
328 int progress = SleuthkitJNI.getFinishImageProgress(imageHandle);
329 progressHandle.progress(progress);
330 }
catch (Exception ex) {
331 logger.log(Level.SEVERE,
"Unexpected exception in ProgressUpdateTask", ex);
static synchronized IngestManager getInstance()
static boolean runningWithGUI
DATA_SOURCE_ANALYSIS_COMPLETED
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)
SleuthkitCase getSleuthkitCase()
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
boolean getUpdateDatabasePath()