mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-06 02:24:30 +00:00
Merge remote-tracking branch 'upstream/develop' into jython_ingest_modules
This commit is contained in:
@@ -135,39 +135,29 @@ import org.sleuthkit.datamodel.TskException;
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
errorList.clear();
|
||||
|
||||
//lock DB for writes in this thread
|
||||
SleuthkitCase.acquireExclusiveLock();
|
||||
|
||||
addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
|
||||
dirFetcher = new Thread( new CurrentDirectoryFetcher(progressMonitor, addImageProcess));
|
||||
|
||||
public void run() {
|
||||
errorList.clear();
|
||||
try {
|
||||
progressMonitor.setIndeterminate(true);
|
||||
progressMonitor.setProgress(0);
|
||||
|
||||
dirFetcher.start();
|
||||
|
||||
addImageProcess.run(new String[]{this.imagePath});
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Core errors occurred while running add image. ", ex); //NON-NLS
|
||||
//critical core/system error and process needs to be interrupted
|
||||
hasCritError = true;
|
||||
errorList.add(ex.getMessage());
|
||||
} catch (TskDataException ex) {
|
||||
logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); //NON-NLS
|
||||
errorList.add(ex.getMessage());
|
||||
}
|
||||
|
||||
// handle addImage done
|
||||
postProcess();
|
||||
|
||||
// unclock the DB
|
||||
SleuthkitCase.releaseExclusiveLock();
|
||||
currentCase.getSleuthkitCase().acquireExclusiveLock();
|
||||
addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
|
||||
dirFetcher = new Thread( new CurrentDirectoryFetcher(progressMonitor, addImageProcess));
|
||||
try {
|
||||
progressMonitor.setIndeterminate(true);
|
||||
progressMonitor.setProgress(0);
|
||||
dirFetcher.start();
|
||||
addImageProcess.run(new String[]{this.imagePath});
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Core errors occurred while running add image. ", ex); //NON-NLS
|
||||
hasCritError = true;
|
||||
errorList.add(ex.getMessage());
|
||||
} catch (TskDataException ex) {
|
||||
logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); //NON-NLS
|
||||
errorList.add(ex.getMessage());
|
||||
}
|
||||
postProcess();
|
||||
} finally {
|
||||
currentCase.getSleuthkitCase().releaseExclusiveLock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -140,6 +140,9 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
private static final Logger logger = Logger.getLogger(Case.class.getName());
|
||||
static final String CASE_EXTENSION = "aut"; //NON-NLS
|
||||
static final String CASE_DOT_EXTENSION = "." + CASE_EXTENSION;
|
||||
|
||||
// we cache if the case has data in it yet since a few places ask for it and we dont' need to keep going to DB
|
||||
private boolean hasData = false;
|
||||
|
||||
/**
|
||||
* Constructor for the Case class
|
||||
@@ -795,11 +798,14 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
*/
|
||||
public Long[] getImageIDs() {
|
||||
Set<Long> ids = getImagePaths(db).keySet();
|
||||
hasData = (ids.size() > 0);
|
||||
return ids.toArray(new Long[ids.size()]);
|
||||
}
|
||||
|
||||
public List<Image> getImages() throws TskCoreException {
|
||||
return db.getImages();
|
||||
List<Image> list = db.getImages();
|
||||
hasData = (list.size() > 0);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -818,7 +824,9 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
*/
|
||||
public List<Content> getRootObjects() {
|
||||
try {
|
||||
return db.getRootObjects();
|
||||
List<Content> list = db.getRootObjects();
|
||||
hasData = (list.size() > 0);
|
||||
return list;
|
||||
} catch (TskException ex) {
|
||||
throw new RuntimeException(NbBundle.getMessage(this.getClass(), "Case.exception.errGetRootObj"), ex);
|
||||
}
|
||||
@@ -1113,7 +1121,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
|
||||
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); // Delete Case menu
|
||||
|
||||
if (toChangeTo.getRootObjectsCount() > 0) {
|
||||
if (toChangeTo.hasData()) {
|
||||
// open all top components
|
||||
CoreComponentControl.openCoreWindows();
|
||||
} else {
|
||||
@@ -1160,7 +1168,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
//delete image helper
|
||||
private void doDeleteImage() {
|
||||
// no more image left in this case
|
||||
if (currentCase.getRootObjectsCount() == 0) {
|
||||
if (currentCase.hasData()) {
|
||||
// close all top components
|
||||
CoreComponentControl.closeCoreWindows();
|
||||
}
|
||||
@@ -1193,4 +1201,16 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
public List<Report> getAllReports() throws TskCoreException {
|
||||
return this.db.getAllReports();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the case has data in it yet.
|
||||
* @return
|
||||
*/
|
||||
public boolean hasData() {
|
||||
// false is also the initial value, so make the DB trip if it is still false
|
||||
if (!hasData) {
|
||||
hasData = (getRootObjectsCount() > 0);
|
||||
}
|
||||
return hasData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
|
||||
@@ -36,13 +35,13 @@ import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.DerivedFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.Transaction;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskFileRange;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
|
||||
/**
|
||||
* Abstraction to facilitate access to files and directories.
|
||||
@@ -267,7 +266,7 @@ public class FileManager implements Closeable {
|
||||
rootsToAdd.add(localFile);
|
||||
}
|
||||
|
||||
Transaction trans = tskCase.createTransaction();
|
||||
CaseDbTransaction trans = tskCase.beginTransaction();
|
||||
// make a virtual top-level directory for this set of files/dirs
|
||||
final VirtualDirectory fileSetRootDir = addLocalFileSetRootDir(trans);
|
||||
|
||||
@@ -295,8 +294,6 @@ public class FileManager implements Closeable {
|
||||
trans.commit();
|
||||
} catch (TskCoreException ex) {
|
||||
trans.rollback();
|
||||
} finally {
|
||||
trans.close();
|
||||
}
|
||||
return fileSetRootDir;
|
||||
}
|
||||
@@ -309,7 +306,7 @@ public class FileManager implements Closeable {
|
||||
*
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
private VirtualDirectory addLocalFileSetRootDir(Transaction trans) throws TskCoreException {
|
||||
private VirtualDirectory addLocalFileSetRootDir(CaseDbTransaction trans) throws TskCoreException {
|
||||
|
||||
VirtualDirectory created = null;
|
||||
|
||||
@@ -343,7 +340,7 @@ public class FileManager implements Closeable {
|
||||
* directory.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
private AbstractFile addLocalDirInt(Transaction trans, VirtualDirectory parentVd,
|
||||
private AbstractFile addLocalDirInt(CaseDbTransaction trans, VirtualDirectory parentVd,
|
||||
java.io.File localFile, FileAddProgressUpdater addProgressUpdater) throws TskCoreException {
|
||||
|
||||
if (tskCase == null) {
|
||||
@@ -399,7 +396,7 @@ public class FileManager implements Closeable {
|
||||
* due to a critical system error or of the file
|
||||
* manager has already been closed
|
||||
*/
|
||||
private synchronized LocalFile addLocalFileInt(AbstractFile parentFile, java.io.File localFile, Transaction trans) throws TskCoreException {
|
||||
private synchronized LocalFile addLocalFileInt(AbstractFile parentFile, java.io.File localFile, CaseDbTransaction trans) throws TskCoreException {
|
||||
|
||||
if (tskCase == null) {
|
||||
throw new TskCoreException(
|
||||
|
||||
@@ -166,7 +166,7 @@ public final class DataContentTopComponent extends TopComponent implements DataC
|
||||
|
||||
@Override
|
||||
public boolean canClose() {
|
||||
return (!this.isDefault) || !Case.existsCurrentCase() || Case.getCurrentCase().getRootObjectsCount() == 0; // only allow this window to be closed when there's no case opened or no image in this case
|
||||
return (!this.isDefault) || !Case.existsCurrentCase() || Case.getCurrentCase().hasData() == false; // only allow this window to be closed when there's no case opened or no image in this case
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -457,7 +457,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
}
|
||||
|
||||
public boolean canClose() {
|
||||
return (!this.isMain) || !Case.existsCurrentCase() || Case.getCurrentCase().getRootObjectsCount() == 0; // only allow this window to be closed when there's no case opened or no image in this case
|
||||
return (!this.isMain) || !Case.existsCurrentCase() || Case.getCurrentCase().hasData() == false; // only allow this window to be closed when there's no case opened or no image in this case
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -298,7 +298,7 @@ public class DataResultTopComponent extends TopComponent implements DataResult,
|
||||
|
||||
@Override
|
||||
public boolean canClose() {
|
||||
return (!this.isMain) || !Case.existsCurrentCase() || Case.getCurrentCase().getRootObjectsCount() == 0; // only allow this window to be closed when there's no case opened or no image in this case
|
||||
return (!this.isMain) || !Case.existsCurrentCase() || Case.getCurrentCase().hasData() == false; // only allow this window to be closed when there's no case opened or no image in this case
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -299,14 +299,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
if (selectedNode == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Children ch = selectedNode.getChildren();
|
||||
for (Node n : ch.getNodes()) {
|
||||
if (ThumbnailViewChildren.isSupported(n)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -58,6 +58,16 @@ ContentTagNode.createSheet.filePath.name=File Path
|
||||
ContentTagNode.createSheet.filePath.displayName=File Path
|
||||
ContentTagNode.createSheet.comment.name=Comment
|
||||
ContentTagNode.createSheet.comment.displayName=Comment
|
||||
ContentTagNode.createSheet.fileModifiedTime.name=Modified Time
|
||||
ContentTagNode.createSheet.fileModifiedTime.displayName=Modified Time
|
||||
ContentTagNode.createSheet.fileChangedTime.name=Changed Time
|
||||
ContentTagNode.createSheet.fileChangedTime.displayName=Changed Time
|
||||
ContentTagNode.createSheet.fileAccessedTime.name=Accessed Time
|
||||
ContentTagNode.createSheet.fileAccessedTime.displayName=Accessed Time
|
||||
ContentTagNode.createSheet.fileCreatedTime.name=Created Time
|
||||
ContentTagNode.createSheet.fileCreatedTime.displayName=Created Time
|
||||
ContentTagNode.createSheet.fileSize.name=Size
|
||||
ContentTagNode.createSheet.fileSize.displayName=Size
|
||||
ContentTagTypeNode.displayName.text=File Tags
|
||||
ContentTagTypeNode.createSheet.name.name=Name
|
||||
ContentTagTypeNode.createSheet.name.displayName=Name
|
||||
|
||||
@@ -20,13 +20,15 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.actions.DeleteContentTagAction;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
@@ -51,24 +53,26 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Content content = tag.getContent();
|
||||
String contentPath;
|
||||
try {
|
||||
contentPath = content.getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + content.getId() + ")", ex); //NON-NLS
|
||||
contentPath = NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.unavail.path");
|
||||
}
|
||||
AbstractFile file = content instanceof AbstractFile ? (AbstractFile)content : null;
|
||||
|
||||
Sheet propertySheet = super.createSheet();
|
||||
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||
if (properties == null) {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.displayName"),
|
||||
"",
|
||||
tag.getContent().getName()));
|
||||
String contentPath;
|
||||
try {
|
||||
contentPath = tag.getContent().getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex); //NON-NLS
|
||||
contentPath = NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.unavail.path");
|
||||
}
|
||||
content.getName()));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.displayName"),
|
||||
"",
|
||||
@@ -77,7 +81,26 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.displayName"),
|
||||
"",
|
||||
tag.getComment()));
|
||||
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getMtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getCtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getAtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"),
|
||||
"",
|
||||
content.getSize()));
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
|
||||
@@ -226,6 +226,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
protected boolean createKeys(List<AbstractFile> list) {
|
||||
List<AbstractFile> queryList = runFsQuery();
|
||||
if (queryList.size() == MAX_OBJECTS) {
|
||||
queryList.remove(queryList.size() - 1);
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -235,8 +236,6 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
queryList.remove(queryList.size() - 1);
|
||||
list.addAll(queryList);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
|
||||
// close the top component if there's no image in this case
|
||||
if (currentCase.getRootObjectsCount() == 0) {
|
||||
if (currentCase.hasData() == false) {
|
||||
//this.close();
|
||||
((BeanTreeView) this.jScrollPane1).setRootVisible(false); // hide the root
|
||||
} else {
|
||||
@@ -483,7 +483,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
|
||||
@Override
|
||||
public boolean canClose() {
|
||||
return !Case.existsCurrentCase() || Case.getCurrentCase().getRootObjectsCount() == 0; // only allow this window to be closed when there's no case opened or no image in this case
|
||||
return !Case.existsCurrentCase() || Case.getCurrentCase().hasData() == false; // only allow this window to be closed when there's no case opened or no image in this case
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,9 +19,7 @@
|
||||
package org.sleuthkit.autopsy.ingest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
/**
|
||||
@@ -112,7 +110,7 @@ final class FileIngestPipeline {
|
||||
}
|
||||
file.close();
|
||||
if (!context.isJobCancelled()) {
|
||||
IngestManager.getInstance().fireFileIngestDone(file.getId());
|
||||
IngestManager.getInstance().fireFileIngestDone(file);
|
||||
}
|
||||
ingestManager.setIngestTaskProgressCompleted(task);
|
||||
return errors;
|
||||
|
||||
@@ -193,46 +193,54 @@ final class IngestJob {
|
||||
}
|
||||
|
||||
void process(DataSourceIngestTask task) throws InterruptedException {
|
||||
if (!isCancelled() && !dataSourceIngestPipeline.isEmpty()) {
|
||||
List<IngestModuleError> errors = new ArrayList<>();
|
||||
errors.addAll(dataSourceIngestPipeline.process(task, dataSourceIngestProgress));
|
||||
if (!errors.isEmpty()) {
|
||||
logIngestModuleErrors(errors);
|
||||
}
|
||||
}
|
||||
if (null != dataSourceIngestProgress) {
|
||||
dataSourceIngestProgress.finish();
|
||||
// This is safe because this method will be called at most once per
|
||||
// ingest job and finish() will not be called while that single
|
||||
// data source ingest task has not been reported complete by this
|
||||
// code to the ingest scheduler.
|
||||
dataSourceIngestProgress = null;
|
||||
}
|
||||
ingestTaskScheduler.notifyTaskCompleted(task);
|
||||
}
|
||||
|
||||
void process(FileIngestTask task) throws InterruptedException {
|
||||
if (!isCancelled()) {
|
||||
FileIngestPipeline pipeline = fileIngestPipelines.take();
|
||||
if (!pipeline.isEmpty()) {
|
||||
AbstractFile file = task.getFile();
|
||||
synchronized (this) {
|
||||
++processedFiles;
|
||||
if (processedFiles <= estimatedFilesToProcess) {
|
||||
fileIngestProgress.progress(file.getName(), (int) processedFiles);
|
||||
} else {
|
||||
fileIngestProgress.progress(file.getName(), (int) estimatedFilesToProcess);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (!isCancelled() && !dataSourceIngestPipeline.isEmpty()) {
|
||||
List<IngestModuleError> errors = new ArrayList<>();
|
||||
errors.addAll(pipeline.process(task));
|
||||
errors.addAll(dataSourceIngestPipeline.process(task, dataSourceIngestProgress));
|
||||
if (!errors.isEmpty()) {
|
||||
logIngestModuleErrors(errors);
|
||||
}
|
||||
}
|
||||
fileIngestPipelines.put(pipeline);
|
||||
if (null != dataSourceIngestProgress) {
|
||||
dataSourceIngestProgress.finish();
|
||||
// This is safe because this method will be called at most once per
|
||||
// ingest job and finish() will not be called while that single
|
||||
// data source ingest task has not been reported complete by this
|
||||
// code to the ingest scheduler.
|
||||
dataSourceIngestProgress = null;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
ingestTaskScheduler.notifyTaskCompleted(task);
|
||||
}
|
||||
}
|
||||
|
||||
void process(FileIngestTask task) throws InterruptedException {
|
||||
try {
|
||||
if (!isCancelled()) {
|
||||
FileIngestPipeline pipeline = fileIngestPipelines.take();
|
||||
if (!pipeline.isEmpty()) {
|
||||
AbstractFile file = task.getFile();
|
||||
synchronized (this) {
|
||||
++processedFiles;
|
||||
if (processedFiles <= estimatedFilesToProcess) {
|
||||
fileIngestProgress.progress(file.getName(), (int) processedFiles);
|
||||
} else {
|
||||
fileIngestProgress.progress(file.getName(), (int) estimatedFilesToProcess);
|
||||
}
|
||||
}
|
||||
List<IngestModuleError> errors = new ArrayList<>();
|
||||
errors.addAll(pipeline.process(task));
|
||||
if (!errors.isEmpty()) {
|
||||
logIngestModuleErrors(errors);
|
||||
}
|
||||
}
|
||||
fileIngestPipelines.put(pipeline);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
ingestTaskScheduler.notifyTaskCompleted(task);
|
||||
}
|
||||
ingestTaskScheduler.notifyTaskCompleted(task);
|
||||
}
|
||||
|
||||
void finish() {
|
||||
|
||||
@@ -31,17 +31,17 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import javax.swing.JOptionPane;
|
||||
import org.netbeans.api.progress.ProgressHandle;
|
||||
import org.netbeans.api.progress.ProgressHandleFactory;
|
||||
import org.openide.util.Cancellable;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import javax.swing.JOptionPane;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* Manages the execution of ingest jobs.
|
||||
@@ -288,7 +288,7 @@ public class IngestManager {
|
||||
/**
|
||||
* Property change event fired when the ingest of a file is completed.
|
||||
* The old value of the PropertyChangeEvent is the Autopsy object ID of
|
||||
* the file, and the new value is set to null.
|
||||
* the file. The new value is the AbstractFile for that ID.
|
||||
*/
|
||||
FILE_DONE,
|
||||
};
|
||||
@@ -383,10 +383,10 @@ public class IngestManager {
|
||||
/**
|
||||
* Fire an ingest event signifying the ingest of a file is completed.
|
||||
*
|
||||
* @param fileId The object id of file.
|
||||
* @param file The file that is completed.
|
||||
*/
|
||||
void fireFileIngestDone(long fileId) {
|
||||
fireIngestEventsThreadPool.submit(new FireIngestEventTask(ingestModuleEventPublisher, IngestModuleEvent.FILE_DONE, fileId, null));
|
||||
void fireFileIngestDone(AbstractFile file) {
|
||||
fireIngestEventsThreadPool.submit(new FireIngestEventTask(ingestModuleEventPublisher, IngestModuleEvent.FILE_DONE, file.getId(), file));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -52,30 +52,34 @@ final class IngestScheduler {
|
||||
private final AtomicLong nextIngestJobId = new AtomicLong(0L);
|
||||
private final ConcurrentHashMap<Long, IngestJob> ingestJobsById = new ConcurrentHashMap<>();
|
||||
private volatile boolean enabled = false;
|
||||
// private volatile boolean cancellingAllTasks = false; TODO: Uncomment this with related code, if desired
|
||||
// private volatile boolean cancellingAllTasks = false; TODO: Uncomment this with related code, if desired
|
||||
private final DataSourceIngestTaskQueue dataSourceTaskDispenser = new DataSourceIngestTaskQueue();
|
||||
private final FileIngestTaskQueue fileTaskDispenser = new FileIngestTaskQueue();
|
||||
|
||||
// The following five collections lie at the heart of the scheduler.
|
||||
//
|
||||
// The pending tasks queues are used to schedule tasks for an ingest job. If
|
||||
// multiple jobs are scheduled, tasks from different jobs may become
|
||||
// interleaved in these queues. Data source tasks go into a simple FIFO
|
||||
// queue that is consumed by the ingest threads. File tasks are "shuffled"
|
||||
// interleaved in these queues.
|
||||
|
||||
// FIFO queue for data source-level tasks.
|
||||
private final LinkedBlockingQueue<DataSourceIngestTask> pendingDataSourceTasks = new LinkedBlockingQueue<>(); // Guarded by this
|
||||
|
||||
// File tasks are "shuffled"
|
||||
// through root directory (priority queue), directory (LIFO), and file tasks
|
||||
// queues (LIFO). If a file task makes it into the pending file tasks queue,
|
||||
// it is consumed by the ingest threads.
|
||||
//
|
||||
// The "tasks in progress" list is used to determine when an ingest job is
|
||||
// completed and should be shut down, i.e., the job should shut down its
|
||||
// ingest pipelines and finish its progress bars. Tasks stay in the "tasks
|
||||
// in progress" list either until discarded by the scheduler or the ingest
|
||||
// thread that is working on the task notifies the scheduler that the task
|
||||
// is completed.
|
||||
private final LinkedBlockingQueue<DataSourceIngestTask> pendingDataSourceTasks = new LinkedBlockingQueue<>();
|
||||
private final TreeSet<FileIngestTask> pendingRootDirectoryTasks = new TreeSet<>(new RootDirectoryTaskComparator()); // Guarded by this
|
||||
private final List<FileIngestTask> pendingDirectoryTasks = new ArrayList<>(); // Guarded by this
|
||||
private final BlockingDeque<FileIngestTask> pendingFileTasks = new LinkedBlockingDeque<>();
|
||||
private final List<IngestTask> tasksInProgress = new ArrayList<>(); // Guarded by this
|
||||
private final BlockingDeque<FileIngestTask> pendingFileTasks = new LinkedBlockingDeque<>(); // Not guarded
|
||||
|
||||
// The "tasks in progress" list has:
|
||||
// - File and data source tasks that are running
|
||||
// - File tasks that are in the pending file queue
|
||||
// It is used to determine when a job is done. It has both pending and running
|
||||
// tasks because we do not lock the 'pendingFileTasks' and a task needs to be in
|
||||
// at least one of the pending or inprogress lists at all times before it is completed.
|
||||
// files are added to this when the are added to pendingFilesTasks and removed when they complete
|
||||
private final List<IngestTask> tasksInProgressAndPending = new ArrayList<>(); // Guarded by this
|
||||
|
||||
synchronized static IngestScheduler getInstance() {
|
||||
if (instance == null) {
|
||||
@@ -133,12 +137,12 @@ final class IngestScheduler {
|
||||
|
||||
synchronized private void scheduleDataSourceIngestTask(IngestJob job) throws InterruptedException {
|
||||
DataSourceIngestTask task = new DataSourceIngestTask(job);
|
||||
tasksInProgress.add(task);
|
||||
tasksInProgressAndPending.add(task);
|
||||
try {
|
||||
// Should not block, queue is (theoretically) unbounded.
|
||||
pendingDataSourceTasks.put(task);
|
||||
} catch (InterruptedException ex) {
|
||||
tasksInProgress.remove(task);
|
||||
tasksInProgressAndPending.remove(task);
|
||||
Logger.getLogger(IngestScheduler.class.getName()).log(Level.SEVERE, "Interruption of unexpected block on pending data source tasks queue", ex); //NON-NLS
|
||||
throw ex;
|
||||
}
|
||||
@@ -149,7 +153,6 @@ final class IngestScheduler {
|
||||
for (AbstractFile firstLevelFile : topLevelFiles) {
|
||||
FileIngestTask task = new FileIngestTask(job, firstLevelFile);
|
||||
if (shouldEnqueueFileTask(task)) {
|
||||
tasksInProgress.add(task);
|
||||
pendingRootDirectoryTasks.add(task);
|
||||
}
|
||||
}
|
||||
@@ -212,9 +215,7 @@ final class IngestScheduler {
|
||||
if (shouldEnqueueFileTask(directoryTask)) {
|
||||
addToPendingFileTasksQueue(directoryTask);
|
||||
tasksEnqueuedForDirectory = true;
|
||||
} else {
|
||||
tasksInProgress.remove(directoryTask);
|
||||
}
|
||||
}
|
||||
|
||||
// If the directory contains subdirectories or files, try to
|
||||
// enqueue tasks for them as well.
|
||||
@@ -227,13 +228,11 @@ final class IngestScheduler {
|
||||
if (file.hasChildren()) {
|
||||
// Found a subdirectory, put the task in the
|
||||
// pending directory tasks queue.
|
||||
tasksInProgress.add(childTask);
|
||||
pendingDirectoryTasks.add(childTask);
|
||||
tasksEnqueuedForDirectory = true;
|
||||
} else if (shouldEnqueueFileTask(childTask)) {
|
||||
// Found a file, put the task directly into the
|
||||
// pending file tasks queue.
|
||||
tasksInProgress.add(childTask);
|
||||
addToPendingFileTasksQueue(childTask);
|
||||
tasksEnqueuedForDirectory = true;
|
||||
}
|
||||
@@ -304,6 +303,7 @@ final class IngestScheduler {
|
||||
}
|
||||
|
||||
synchronized private void addToPendingFileTasksQueue(FileIngestTask task) throws IllegalStateException {
|
||||
tasksInProgressAndPending.add(task);
|
||||
try {
|
||||
// Should not block, queue is (theoretically) unbounded.
|
||||
/* add to top of list because we had one image that had a folder with
|
||||
@@ -313,7 +313,7 @@ final class IngestScheduler {
|
||||
*/
|
||||
pendingFileTasks.addFirst(task);
|
||||
} catch (IllegalStateException ex) {
|
||||
tasksInProgress.remove(task);
|
||||
tasksInProgressAndPending.remove(task);
|
||||
Logger.getLogger(IngestScheduler.class.getName()).log(Level.SEVERE, "Interruption of unexpected block on pending file tasks queue", ex); //NON-NLS
|
||||
throw ex;
|
||||
}
|
||||
@@ -326,7 +326,6 @@ final class IngestScheduler {
|
||||
// Send the file task directly to file tasks queue, no need to
|
||||
// update the pending root directory or pending directory tasks
|
||||
// queues.
|
||||
tasksInProgress.add(task);
|
||||
addToPendingFileTasksQueue(task);
|
||||
}
|
||||
}
|
||||
@@ -344,7 +343,7 @@ final class IngestScheduler {
|
||||
boolean jobIsCompleted;
|
||||
IngestJob job = task.getIngestJob();
|
||||
synchronized (this) {
|
||||
tasksInProgress.remove(task);
|
||||
tasksInProgressAndPending.remove(task);
|
||||
jobIsCompleted = ingestJobIsComplete(job);
|
||||
}
|
||||
if (jobIsCompleted) {
|
||||
@@ -382,7 +381,7 @@ final class IngestScheduler {
|
||||
while (iterator.hasNext()) {
|
||||
IngestTask task = (IngestTask) iterator.next();
|
||||
if (task.getIngestJob().getId() == jobId) {
|
||||
tasksInProgress.remove((IngestTask) task);
|
||||
tasksInProgressAndPending.remove((IngestTask) task);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
@@ -420,13 +419,13 @@ final class IngestScheduler {
|
||||
synchronized private <T> void removeAllPendingTasks(Collection<T> taskQueue) {
|
||||
Iterator<T> iterator = taskQueue.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
tasksInProgress.remove((IngestTask) iterator.next());
|
||||
tasksInProgressAndPending.remove((IngestTask) iterator.next());
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
synchronized private boolean ingestJobIsComplete(IngestJob job) {
|
||||
for (IngestTask task : tasksInProgress) {
|
||||
for (IngestTask task : tasksInProgressAndPending) {
|
||||
if (task.getIngestJob().getId() == job.getId()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ import org.sleuthkit.autopsy.corecomponents.DataContentTopComponent;
|
||||
|
||||
defaultItem.addActionListener(new OpenTopComponentAction(contentWin));
|
||||
|
||||
if (!Case.existsCurrentCase() || Case.getCurrentCase().getRootObjectsCount() == 0) {
|
||||
if (!Case.existsCurrentCase() || Case.getCurrentCase().hasData() == false) {
|
||||
defaultItem.setEnabled(false); // disable the menu items when no case is opened
|
||||
} else {
|
||||
defaultItem.setEnabled(true); // enable the menu items when there's a case opened / created
|
||||
|
||||
@@ -53,7 +53,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataExplorer;
|
||||
JMenuItem item = new JMenuItem(explorerWin.getName());
|
||||
item.addActionListener(new OpenTopComponentAction(explorerWin));
|
||||
|
||||
if(!Case.existsCurrentCase() || Case.getCurrentCase().getRootObjectsCount() == 0){
|
||||
if(!Case.existsCurrentCase() || Case.getCurrentCase().hasData() == false){
|
||||
item.setEnabled(false); // disable the menu when no case is opened
|
||||
}
|
||||
else{
|
||||
|
||||
@@ -80,7 +80,7 @@ class WWFMessageAnalyzer {
|
||||
|
||||
try {
|
||||
resultSet = statement.executeQuery(
|
||||
"SELECT message,created_at,user_id,game_id FROM chat_messages ORDER BY game_id DESC, created_at DESC;");
|
||||
"SELECT message,strftime('%s' ,created_at) as datetime,user_id,game_id FROM chat_messages ORDER BY game_id DESC, created_at DESC;");
|
||||
|
||||
String message; // WWF Message
|
||||
String user_id; // the ID of the user who sent the message.
|
||||
@@ -88,7 +88,7 @@ class WWFMessageAnalyzer {
|
||||
|
||||
while (resultSet.next()) {
|
||||
message = resultSet.getString("message");
|
||||
Long created_at = Long.valueOf(resultSet.getString("created_at")) / 1000;
|
||||
Long created_at = resultSet.getLong("datetime");
|
||||
user_id = resultSet.getString("user_id");
|
||||
game_id = resultSet.getString("game_id");
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ package org.sleuthkit.autopsy.report;
|
||||
/**
|
||||
* Interface for report modules that plug in to the reporting infrastructure.
|
||||
*/
|
||||
interface ReportModule {
|
||||
interface ReportModule {
|
||||
|
||||
/**
|
||||
* Get the name of the report this module generates.
|
||||
@@ -37,13 +37,14 @@ package org.sleuthkit.autopsy.report;
|
||||
* module generates.
|
||||
*/
|
||||
public String getDescription();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the path of the report file, if any, generated by this module. If
|
||||
* a report file is generated, the path should be relative to the reports
|
||||
* directory.
|
||||
*
|
||||
* @return File path relative to the reports directory, may be null.
|
||||
* Gets the relative path of the report file, if any, generated by this
|
||||
* module. The path should be relative to the time stamp subdirectory of
|
||||
* reports directory.
|
||||
*
|
||||
* @return Report file path relative to the time stamp subdirectory reports
|
||||
* directory, may be null if the module does not produce a report file.
|
||||
*/
|
||||
public String getRelativeFilePath();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1161,7 +1161,7 @@ public class Timeline extends CallableSystemAction implements Presenter.Toolbar,
|
||||
skCase = currentCase.getSleuthkitCase();
|
||||
|
||||
try {
|
||||
if (currentCase.getRootObjectsCount() == 0) {
|
||||
if (currentCase.hasData() == false) {
|
||||
logger.log(Level.INFO, "Error creating timeline, there are no data sources. "); //NON-NLS
|
||||
} else {
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ class ExtractRegistry extends Extract {
|
||||
|
||||
// parse the autopsy-specific output
|
||||
if (regOutputFiles.autopsyPlugins.isEmpty() == false) {
|
||||
if (parseAutopsyPluginOutput(regOutputFiles.autopsyPlugins, regFile.getId(), usbMapper) == false) {
|
||||
if (parseAutopsyPluginOutput(regOutputFiles.autopsyPlugins, regFile, usbMapper) == false) {
|
||||
this.addErrorMessage(
|
||||
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
|
||||
this.getName(), regFileName));
|
||||
@@ -371,7 +371,14 @@ class ExtractRegistry extends Extract {
|
||||
}
|
||||
|
||||
// @@@ VERIFY that we are doing the right thing when we parse multiple NTUSER.DAT
|
||||
private boolean parseAutopsyPluginOutput(String regRecord, long orgId, UsbDeviceIdMapper extrctr) {
|
||||
/**
|
||||
*
|
||||
* @param regRecord
|
||||
* @param regFile File object for registry that we are parsing (to make blackboard artifacts with)
|
||||
* @param extrctr
|
||||
* @return
|
||||
*/
|
||||
private boolean parseAutopsyPluginOutput(String regRecord, AbstractFile regFile, UsbDeviceIdMapper extrctr) {
|
||||
FileInputStream fstream = null;
|
||||
try {
|
||||
SleuthkitCase tempDb = currentCase.getSleuthkitCase();
|
||||
@@ -447,7 +454,7 @@ class ExtractRegistry extends Extract {
|
||||
Long usbMtime = Long.parseLong(artnode.getAttribute("mtime")); //NON-NLS
|
||||
usbMtime = Long.valueOf(usbMtime.toString());
|
||||
|
||||
BlackboardArtifact bbart = tempDb.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED);
|
||||
BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED);
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(),
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"ExtractRegistry.parentModuleName.noSpace"), usbMtime));
|
||||
@@ -494,7 +501,7 @@ class ExtractRegistry extends Extract {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(),
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"ExtractRegistry.parentModuleName.noSpace"), itemMtime));
|
||||
BlackboardArtifact bbart = tempDb.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_INSTALLED_PROG);
|
||||
BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_INSTALLED_PROG);
|
||||
bbart.addAttributes(bbattributes);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error adding installed program artifact to blackboard."); //NON-NLS
|
||||
@@ -526,7 +533,7 @@ class ExtractRegistry extends Extract {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(),
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"ExtractRegistry.parentModuleName.noSpace"), installtime));
|
||||
BlackboardArtifact bbart = tempDb.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_INSTALLED_PROG);
|
||||
BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_INSTALLED_PROG);
|
||||
bbart.addAttributes(bbattributes);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error adding installed program artifact to blackboard."); //NON-NLS
|
||||
@@ -537,7 +544,7 @@ class ExtractRegistry extends Extract {
|
||||
String name = artnode.getAttribute("name"); //NON-NLS
|
||||
|
||||
try {
|
||||
BlackboardArtifact bbart = tempDb.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_RECENT_OBJECT);
|
||||
BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_RECENT_OBJECT);
|
||||
// @@@ BC: Consider removing this after some more testing. It looks like an Mtime associated with the root key and not the individual item
|
||||
if (mtime != null) {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(),
|
||||
|
||||
Reference in New Issue
Block a user