Merge branch 'develop' of https://github.com/sleuthkit/autopsy into 4402-FlagPastOccurences

This commit is contained in:
William Schaefer 2018-11-29 15:31:20 -05:00
commit 103702b64e
11 changed files with 233 additions and 129 deletions

View File

@ -1,6 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[625, 465]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
@ -32,7 +37,7 @@
<Border info="null"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[625, 452]"/>
<Dimension value="[625, 465]"/>
</Property>
</Properties>
@ -41,7 +46,7 @@
<Container class="javax.swing.JPanel" name="viewPreferencesPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[625, 452]"/>
<Dimension value="[625, 465]"/>
</Property>
</Properties>

View File

@ -80,6 +80,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
commentsOccurencesColumnWrapAroundText.setEnabled(EamDbUtil.useCentralRepo());
commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences());
hideOtherUsersTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags());
deletedFilesLimitCheckbox.setSelected(DeletedFilePreferences.getDefault().getShouldLimitDeletedFiles());
translateNamesInTableRadioButton.setSelected(UserPreferences.displayTranslatedFileNames());
@ -91,8 +92,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
currentCaseSettingsPanel.setEnabled(caseIsOpen);
groupByDataSourceCheckbox.setEnabled(caseIsOpen);
hideOtherUsersTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags());
groupByDataSourceCheckbox.setSelected(Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true));
if (caseIsOpen) {
groupByDataSourceCheckbox.setSelected(Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true));
} else {
groupByDataSourceCheckbox.setSelected(false);
}
// Current Session Settings
hideRejectedResultsCheckbox.setSelected(DirectoryTreeTopComponent.getDefault().getShowRejectedResults() == false);
@ -174,10 +178,12 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
currentSessionSettingsPanel = new javax.swing.JPanel();
hideRejectedResultsCheckbox = new javax.swing.JCheckBox();
viewPreferencesScrollPane.setBorder(null);
viewPreferencesScrollPane.setPreferredSize(new java.awt.Dimension(625, 452));
setPreferredSize(new java.awt.Dimension(625, 465));
viewPreferencesPanel.setPreferredSize(new java.awt.Dimension(625, 452));
viewPreferencesScrollPane.setBorder(null);
viewPreferencesScrollPane.setPreferredSize(new java.awt.Dimension(625, 465));
viewPreferencesPanel.setPreferredSize(new java.awt.Dimension(625, 465));
globalSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.globalSettingsPanel.border.title"))); // NOI18N

View File

@ -214,10 +214,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
CorrelationAttributeInstance attribute = getCorrelationAttributeInstance();
updateSheet(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(),NO_DESCR,getCommentProperty(tags, attribute)));
}
/*
* Data that was being computed in the background task. Kicked off by a
* call to createSheet().
*/
} else if (eventType.equals(NodeSpecificEvents.TRANSLATION_AVAILABLE.toString())) {
updateSheet(new NodeProperty<>(TRANSLATION.toString(),TRANSLATION.toString(),NO_DESCR,evt.getNewValue()));
}
@ -304,8 +300,16 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
"AbstractAbstractFileNode.sizeColLbl=Size",
"AbstractAbstractFileNode.flagsDirColLbl=Flags(Dir)",
"AbstractAbstractFileNode.flagsMetaColLbl=Flags(Meta)",
"AbstractAbstractFileNode.modeColLbl=Mode",
"AbstractAbstractFileNode.useridColLbl=UserID",
"AbstractAbstractFileNode.groupidColLbl=GroupID",
"AbstractAbstractFileNode.metaAddrColLbl=Meta Addr.",
"AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr.",
"AbstractAbstractFileNode.typeDirColLbl=Type(Dir)",
"AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)",
"AbstractAbstractFileNode.knownColLbl=Known",
"AbstractAbstractFileNode.md5HashColLbl=MD5 Hash",
"AbstractAbstractFileNode.objectId=Object ID",
"AbstractAbstractFileNode.mimeType=MIME Type",
"AbstractAbstractFileNode.extensionColLbl=Extension"})
public enum AbstractFilePropertyType {
@ -323,8 +327,16 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
SIZE(AbstractAbstractFileNode_sizeColLbl()),
FLAGS_DIR(AbstractAbstractFileNode_flagsDirColLbl()),
FLAGS_META(AbstractAbstractFileNode_flagsMetaColLbl()),
MODE(AbstractAbstractFileNode_modeColLbl()),
USER_ID(AbstractAbstractFileNode_useridColLbl()),
GROUP_ID(AbstractAbstractFileNode_groupidColLbl()),
META_ADDR(AbstractAbstractFileNode_metaAddrColLbl()),
ATTR_ADDR(AbstractAbstractFileNode_attrAddrColLbl()),
TYPE_DIR(AbstractAbstractFileNode_typeDirColLbl()),
TYPE_META(AbstractAbstractFileNode_typeMetaColLbl()),
KNOWN(AbstractAbstractFileNode_knownColLbl()),
MD5HASH(AbstractAbstractFileNode_md5HashColLbl()),
ObjectID(AbstractAbstractFileNode_objectId()),
MIMETYPE(AbstractAbstractFileNode_mimeType()),
EXTENSION(AbstractAbstractFileNode_extensionColLbl());

View File

@ -6,6 +6,9 @@ AbstractAbstractFileNode.changeTimeColLbl=\u5909\u66f4\u65e5\u6642
AbstractAbstractFileNode.accessTimeColLbl=\u30a2\u30af\u30bb\u30b9\u65e5\u6642
AbstractAbstractFileNode.createdTimeColLbl=\u4f5c\u6210\u65e5\u6642
AbstractAbstractFileNode.sizeColLbl=\u30b5\u30a4\u30ba
AbstractAbstractFileNode.modeColLbl=\u30e2\u30fc\u30c9
AbstractAbstractFileNode.useridColLbl=\u30e6\u30fc\u30b6ID
AbstractAbstractFileNode.groupidColLbl=\u30b0\u30eb\u30fc\u30d7ID
AbstractAbstractFileNode.knownColLbl=\u65e2\u77e5
AbstractAbstractFileNode.md5HashColLbl=MD5\u30cf\u30c3\u30b7\u30e5
AbstractContentChildren.CreateTSKNodeVisitor.exception.noNodeMsg=\u6307\u5b9a\u3055\u308c\u305fSleuthkitItem\u306e\u30ce\u30fc\u30c9\u304c\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u305b\u3093
@ -195,6 +198,10 @@ TagsNode.displayName.text=\u30bf\u30b0
TagsNode.createSheet.name.name=\u540d\u524d
AbstractAbstractFileNode.flagsDirColLbl=\u30d5\u30e9\u30b0\uff08\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\uff09
AbstractAbstractFileNode.flagsMetaColLbl=\u30d5\u30e9\u30b0\uff08\u30e1\u30bf\u30c7\u30fc\u30bf\uff09
AbstractAbstractFileNode.metaAddrColLbl=\u30e1\u30bf\u30c7\u30fc\u30bf\u30a2\u30c9\u30ec\u30b9
AbstractAbstractFileNode.attrAddrColLbl=\u5c5e\u6027\u30a2\u30c9\u30ec\u30b9
AbstractAbstractFileNode.typeDirColLbl=\u30bf\u30a4\u30d7\uff08\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\uff09
AbstractAbstractFileNode.typeMetaColLbl=\u30bf\u30a4\u30d7\uff08\u30e1\u30bf\u30c7\u30fc\u30bf\uff09
ArtifactTypeNode.createSheet.childCnt.displayName=\u30c1\u30e3\u30a4\u30eb\u30c9\u6570
TagsNode.createSheet.name.displayName=\u540d\u524d
ViewsNode.name.text=\u30d3\u30e5\u30fc
@ -231,6 +238,7 @@ KeywordHits.createSheet.numChildren.name=\u30c1\u30e3\u30a4\u30eb\u30c9\u6570
KeywordHits.createSheet.numChildren.displayName=\u30c1\u30e3\u30a4\u30eb\u30c9\u6570
KeywordHits.simpleLiteralSearch.text=\u30b7\u30f3\u30b0\u30eb\u30ea\u30c6\u30e9\u30eb\u691c\u7d22
KeywordHits.singleRegexSearch.text=\u30b7\u30f3\u30b0\u30eb\u6b63\u898f\u8868\u73fe\u691c\u7d22
AbstractAbstractFileNode.objectId=\u30aa\u30d6\u30b8\u30a7\u30af\u30c8ID
ArtifactStringContent.getStr.artifactId.text=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8ID
OpenReportAction.actionDisplayName=\u30ec\u30dd\u30fc\u30c8\u3092\u958b\u304f
OpenReportAction.actionPerformed.MessageBoxTitle=\u5931\u6557\u30ec\u30dd\u30fc\u30c8\u3092\u958b\u304f

View File

@ -51,6 +51,7 @@ import javax.annotation.Nonnull;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import org.netbeans.api.progress.ProgressHandle;
import org.openide.util.Cancellable;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
@ -99,7 +100,7 @@ public final class ImageGalleryController {
private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false);
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false);
private final ReadOnlyBooleanWrapper isCaseStale = new ReadOnlyBooleanWrapper(false);
private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false);
private final SimpleDoubleProperty thumbnailSizeProp = new SimpleDoubleProperty(100);
@ -160,26 +161,34 @@ public final class ImageGalleryController {
}
}
boolean isListeningEnabled() {
public boolean isListeningEnabled() {
synchronized (listeningEnabled) {
return listeningEnabled.get();
}
}
/**
*
* @param b True if any data source in the case is stale
*/
@ThreadConfined(type = ThreadConfined.ThreadType.ANY)
void setStale(Boolean b) {
void setCaseStale(Boolean b) {
Platform.runLater(() -> {
stale.set(b);
isCaseStale.set(b);
});
}
public ReadOnlyBooleanProperty staleProperty() {
return stale.getReadOnlyProperty();
return isCaseStale.getReadOnlyProperty();
}
/**
*
* @return true if any data source in the case is stale
*/
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
boolean isStale() {
return stale.get();
boolean isCaseStale() {
return isCaseStale.get();
}
ImageGalleryController(@Nonnull Case newCase) throws TskCoreException {
@ -197,7 +206,7 @@ public final class ImageGalleryController {
tagsManager.registerListener(categoryManager);
hashSetManager = new HashSetManager(drawableDB);
setStale(isDataSourcesTableStale());
setCaseStale(isDataSourcesTableStale());
dbExecutor = getNewDBExecutor();
@ -344,7 +353,7 @@ public final class ImageGalleryController {
* Returns a set of data source object ids that are stale.
*
* This includes any data sources already in the table, that are not in
* COMPLETE status, or any data sources that might have been added to the
* COMPLETE or IN_PROGRESS status, or any data sources that might have been added to the
* case, but are not in the datasources table.
*
* @return list of data source object ids that are stale.
@ -368,9 +377,27 @@ public final class ImageGalleryController {
// collect all data sources already in the table, that are not yet COMPLETE
knownDataSourceIds.entrySet().stream().forEach((Map.Entry<Long, DrawableDbBuildStatusEnum> t) -> {
DrawableDbBuildStatusEnum status = t.getValue();
if (DrawableDbBuildStatusEnum.COMPLETE != status) {
staleDataSourceIds.add(t.getKey());
switch (status) {
case COMPLETE:
case IN_PROGRESS:
// not stale
break;
case REBUILT_STALE:
staleDataSourceIds.add(t.getKey());
break;
case UNKNOWN:
try {
// stale if there are files in CaseDB with MIME types
if (hasFilesWithMimeType(t.getKey())) {
staleDataSourceIds.add(t.getKey());
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting MIME types", ex);
}
break;
}
});
// collect any new data sources in the case.
@ -385,7 +412,6 @@ public final class ImageGalleryController {
logger.log(Level.SEVERE, "Image Gallery failed to check if datasources table is stale.", ex);
return staleDataSourceIds;
}
}
/**
@ -451,12 +477,12 @@ public final class ImageGalleryController {
*
* @throws TskCoreException
*/
public boolean hasFilesWithNoMimetype(Content datasource) throws TskCoreException {
public boolean hasFilesWithNoMimeType(long dataSourceId) throws TskCoreException {
// There are some special files/attributes in the root folder, like $BadClus:$Bad and $Security:$SDS
// The IngestTasksScheduler does not push them down to the ingest modules,
// and hence they do not have any assigned mimetype
String whereClause = "data_source_obj_id = " + datasource.getId()
String whereClause = "data_source_obj_id = " + dataSourceId
+ " AND ( meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() + ")"
+ " AND ( mime_type IS NULL )"
+ " AND ( meta_addr >= 32 ) "
@ -466,6 +492,15 @@ public final class ImageGalleryController {
return sleuthKitCase.countFilesWhere(whereClause) > 0;
}
public boolean hasFilesWithMimeType(long dataSourceId) throws TskCoreException {
String whereClause = "data_source_obj_id = " + dataSourceId
+ " AND ( meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() + ")"
+ " AND ( mime_type IS NOT NULL )";
return sleuthKitCase.countFilesWhere(whereClause) > 0;
}
synchronized private void shutDownDBExecutor() {
if (dbExecutor != null) {
dbExecutor.shutdownNow();
@ -645,12 +680,6 @@ public final class ImageGalleryController {
"BulkTask.stopCopy.status=Stopping copy to drawable db task.",
"BulkTask.errPopulating.errMsg=There was an error populating Image Gallery database."})
abstract static class BulkTransferTask extends BackgroundTask {
static private final String FILE_EXTENSION_CLAUSE
= "(extension LIKE '" //NON-NLS
+ String.join("' OR extension LIKE '", FileTypeUtils.getAllSupportedExtensions()) //NON-NLS
+ "') ";
static private final String MIMETYPE_CLAUSE
= "(mime_type LIKE '" //NON-NLS
+ String.join("' OR mime_type LIKE '", FileTypeUtils.getAllSupportedMimeTypes()) //NON-NLS
@ -679,20 +708,16 @@ public final class ImageGalleryController {
= DATASOURCE_CLAUSE
+ " AND ( meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() + ")"
+ " AND ( "
+ //grab files with supported extension
FILE_EXTENSION_CLAUSE
//grab files with supported mime-types
+ " OR " + MIMETYPE_CLAUSE //NON-NLS
+ MIMETYPE_CLAUSE //NON-NLS
//grab files with image or video mime-types even if we don't officially support them
+ " OR mime_type LIKE 'video/%' OR mime_type LIKE 'image/%' )"; //NON-NLS
}
/**
* Do any cleanup for this task.
*
* @param success true if the transfer was successful
*/
abstract void cleanup(boolean success);
abstract void cleanup();
abstract void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr, CaseDbTransaction caseDBTransaction) throws TskCoreException;
@ -715,17 +740,23 @@ public final class ImageGalleryController {
DrawableDB.DrawableTransaction drawableDbTransaction = null;
CaseDbTransaction caseDbTransaction = null;
boolean hasFilesWithNoMime = true;
boolean endedEarly = false;
try {
//grab all files with supported extension or detected mime types
// See if there are any files in the DS w/out a MIME TYPE
hasFilesWithNoMime = controller.hasFilesWithNoMimeType(dataSourceObjId);
//grab all files with detected mime types
final List<AbstractFile> files = getFiles();
progressHandle.switchToDeterminate(files.size());
taskDB.insertOrUpdateDataSource(dataSourceObjId, DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS);
updateProgress(0.0);
taskCompletionStatus = true;
int workDone = 0;
// Cycle through all of the files returned and call processFile on each
//do in transaction
drawableDbTransaction = taskDB.beginTransaction();
@ -743,9 +774,10 @@ public final class ImageGalleryController {
if (isCancelled() || Thread.interrupted()) {
logger.log(Level.WARNING, "Task cancelled or interrupted: not all contents may be transfered to drawable database."); //NON-NLS
taskCompletionStatus = false;
endedEarly = true;
progressHandle.finish();
break;
}
@ -798,27 +830,25 @@ public final class ImageGalleryController {
progressHandle.progress(Bundle.BulkTask_stopCopy_status());
logger.log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents", ex); //NON-NLS
MessageNotifyUtil.Notify.warn(Bundle.BulkTask_errPopulating_errMsg(), ex.getMessage());
cleanup(false);
endedEarly = true;
} finally {
progressHandle.finish();
// Mark to REBUILT_STALE if some files didnt' have MIME (ingest was still ongoing) or
// if there was cancellation or errors
DrawableDB.DrawableDbBuildStatusEnum datasourceDrawableDBStatus
= (taskCompletionStatus)
? DrawableDB.DrawableDbBuildStatusEnum.COMPLETE
: DrawableDB.DrawableDbBuildStatusEnum.DEFAULT;
= ((hasFilesWithNoMime == true) || (endedEarly == true))
? DrawableDB.DrawableDbBuildStatusEnum.REBUILT_STALE
: DrawableDB.DrawableDbBuildStatusEnum.COMPLETE;
taskDB.insertOrUpdateDataSource(dataSourceObjId, datasourceDrawableDBStatus);
updateMessage("");
updateProgress(-1.0);
}
cleanup(taskCompletionStatus);
cleanup();
}
abstract ProgressHandle getInitialProgressHandle();
protected void setTaskCompletionStatus(boolean status) {
taskCompletionStatus = status;
}
}
/**
@ -839,11 +869,11 @@ public final class ImageGalleryController {
}
@Override
protected void cleanup(boolean success) {
protected void cleanup() {
taskDB.freeFileMetaDataCache();
// at the end of the task, set the stale status based on the
// cumulative status of all data sources
controller.setStale(controller.isDataSourcesTableStale());
controller.setCaseStale(controller.isDataSourcesTableStale());
}
@Override
@ -853,12 +883,9 @@ public final class ImageGalleryController {
if (known) {
taskDB.removeFile(f.getId(), tr); //remove known files
} else {
// if mimetype of the file hasn't been ascertained, ingest might not have completed yet.
if (null == f.getMIMEType()) {
// set to false to force the DB to be marked as stale
this.setTaskCompletionStatus(false);
} //supported mimetype => analyzed
else if (FileTypeUtils.hasDrawableMIMEType(f)) {
// NOTE: Files are being processed because they have the right MIME type,
// so we do not need to worry about this calculating them
if (FileTypeUtils.hasDrawableMIMEType(f)) {
taskDB.updateFile(DrawableFile.create(f, true, false), tr, caseDbTransaction);
} //unsupported mimtype => analyzed but shouldn't include
else {

View File

@ -277,7 +277,7 @@ public class ImageGalleryModule {
if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.LOCAL) {
Content newDataSource = (Content) evt.getNewValue();
if (con.isListeningEnabled()) {
controller.getDatabase().insertOrUpdateDataSource(newDataSource.getId(), DrawableDB.DrawableDbBuildStatusEnum.DEFAULT);
controller.getDatabase().insertOrUpdateDataSource(newDataSource.getId(), DrawableDB.DrawableDbBuildStatusEnum.UNKNOWN);
}
}
break;
@ -329,10 +329,14 @@ public class ImageGalleryModule {
if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.LOCAL) {
if (controller.isListeningEnabled()) {
DataSourceAnalysisStartedEvent dataSourceAnalysisStartedEvent = (DataSourceAnalysisStartedEvent) evt;
DataSourceAnalysisStartedEvent dataSourceAnalysisStartedEvent = (DataSourceAnalysisStartedEvent) evt;
Content dataSource = dataSourceAnalysisStartedEvent.getDataSource();
controller.getDatabase().insertOrUpdateDataSource(dataSource.getId(), DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS);
DrawableDB drawableDb = controller.getDatabase();
// Don't update status if it is is already marked as COMPLETE
if (drawableDb.getDataSourceDbBuildStatus(dataSource.getId()) != DrawableDB.DrawableDbBuildStatusEnum.COMPLETE) {
drawableDb.insertOrUpdateDataSource(dataSource.getId(), DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS);
}
}
}
} else if (eventType == IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED) {
@ -342,12 +346,18 @@ public class ImageGalleryModule {
DataSourceAnalysisCompletedEvent dataSourceAnalysisCompletedEvent = (DataSourceAnalysisCompletedEvent) evt;
Content dataSource = dataSourceAnalysisCompletedEvent.getDataSource();
DrawableDB.DrawableDbBuildStatusEnum datasourceDrawableDBStatus =
controller.hasFilesWithNoMimetype(dataSource) ?
DrawableDB.DrawableDbBuildStatusEnum.DEFAULT :
DrawableDB.DrawableDbBuildStatusEnum.COMPLETE;
DrawableDB drawableDb = controller.getDatabase();
if (drawableDb.getDataSourceDbBuildStatus(dataSource.getId()) == DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS) {
controller.getDatabase().insertOrUpdateDataSource(dataSource.getId(), datasourceDrawableDBStatus);
// If at least one file in CaseDB has mime type, then set to COMPLETE
// Otherwise, back to UNKNOWN since we assume file type module was not run
DrawableDB.DrawableDbBuildStatusEnum datasourceDrawableDBStatus =
controller.hasFilesWithMimeType(dataSource.getId()) ?
DrawableDB.DrawableDbBuildStatusEnum.COMPLETE :
DrawableDB.DrawableDbBuildStatusEnum.UNKNOWN;
controller.getDatabase().insertOrUpdateDataSource(dataSource.getId(), datasourceDrawableDBStatus);
}
}
return;
}
@ -355,7 +365,7 @@ public class ImageGalleryModule {
if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.REMOTE) {
// A remote node added a new data source and just finished ingest on it.
//drawable db is stale, and if ImageGallery is open, ask user what to do
controller.setStale(true);
controller.setCaseStale(true);
if (controller.isListeningEnabled()) {
SwingUtilities.invokeLater(() -> {
if (ImageGalleryTopComponent.isImageGalleryOpen()) {

View File

@ -41,7 +41,7 @@ import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils;
*/
@NbBundle.Messages({
"NextUnseenGroup.markGroupSeen=Mark Group Seen",
"NextUnseenGroup.nextUnseenGroup=Next Unseen group",
"NextUnseenGroup.nextUnseenGroup=Next Unseen Group",
"NextUnseenGroup.allGroupsSeen=All Groups Have Been Seen"})
public class NextUnseenGroup extends Action {

View File

@ -39,6 +39,7 @@ import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.util.Exceptions;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
@ -192,47 +193,50 @@ public final class OpenAction extends CallableSystemAction {
addFXCallback(dataSourceStatusMapFuture,
dataSourceStatusMap -> {
boolean dbIsStale = false;
int numStale = 0;
int numNoAnalysis = 0;
// NOTE: There is some overlapping code here with Controller.getStaleDataSourceIds(). We could possibly just use
// that method to figure out stale and then do more simple stuff here to figure out if there is no data at all
for (Map.Entry<Long, DrawableDbBuildStatusEnum> entry : dataSourceStatusMap.entrySet()) {
DrawableDbBuildStatusEnum status = entry.getValue();
if (DrawableDbBuildStatusEnum.COMPLETE != status) {
dbIsStale = true;
if (DrawableDbBuildStatusEnum.UNKNOWN == status) {
try {
// likely a data source analyzed on a remote node in multi-user case OR single-user case with listening off
if (controller.hasFilesWithMimeType(entry.getKey())) {
numStale++;
// likely a data source (local or remote) that has no analysis yet (note there is also IN_PROGRESS state)
} else {
numNoAnalysis++;
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error querying case database", ex);
}
}
// was already rebuilt, but wasn't complete at the end
else if (DrawableDbBuildStatusEnum.REBUILT_STALE == status) {
numStale++;
}
}
//back on fx thread.
if (false == dbIsStale) {
//drawable db is not stale, just open it
openTopComponent();
} else {
// NOTE: we are running on the fx thread.
// If there is only one datasource and it's in DEFAULT State -
// ingest modules need to be run on the data source
if (dataSourceStatusMap.size()== 1) {
Map.Entry<Long, DrawableDB.DrawableDbBuildStatusEnum> entry = dataSourceStatusMap.entrySet().iterator().next();
if (entry.getValue() == DrawableDbBuildStatusEnum.DEFAULT ) {
Alert alert = new Alert(Alert.AlertType.WARNING, Bundle.OpenAction_notAnalyzedDlg_msg(), ButtonType.OK);
alert.setTitle(Bundle.OpenAction_stale_confDlg_title());
alert.initModality(Modality.APPLICATION_MODAL);
alert.showAndWait();
return;
}
}
//drawable db is stale,
//ask what to do
// If there are any that are STALE, give them a prompt to do so.
if (numStale > 0) {
// See if user wants to rebuild, cancel out, or open as is
Alert alert = new Alert(Alert.AlertType.WARNING,
Bundle.OpenAction_stale_confDlg_msg(),
ButtonType.YES, ButtonType.NO, ButtonType.CANCEL);
Bundle.OpenAction_stale_confDlg_msg(),
ButtonType.YES, ButtonType.NO, ButtonType.CANCEL);
alert.initModality(Modality.APPLICATION_MODAL);
alert.setTitle(Bundle.OpenAction_stale_confDlg_title());
GuiUtils.setDialogIcons(alert);
ButtonType answer = alert.showAndWait().orElse(ButtonType.CANCEL);
if (answer == ButtonType.CANCEL) {
//just do nothing
//just do nothing - don't open window
return;
} else if (answer == ButtonType.NO) {
openTopComponent();
// They don't want to rebuild. Just open the UI as is.
// NOTE: There could be no data....
} else if (answer == ButtonType.YES) {
if (controller.getAutopsyCase().getCaseType() == Case.CaseType.SINGLE_USER_CASE) {
/* For a single-user case, we favor user
@ -255,9 +259,23 @@ public final class OpenAction extends CallableSystemAction {
*/
controller.rebuildDB();
}
openTopComponent();
}
openTopComponent();
return;
}
// if there is no data to display, then let them know
if (numNoAnalysis == dataSourceStatusMap.size()) {
// give them a dialog to enable modules if no data sources have been analyzed
Alert alert = new Alert(Alert.AlertType.WARNING, Bundle.OpenAction_notAnalyzedDlg_msg(), ButtonType.OK);
alert.setTitle(Bundle.OpenAction_stale_confDlg_title());
alert.initModality(Modality.APPLICATION_MODAL);
alert.showAndWait();
return;
}
// otherwise, lets open the UI
openTopComponent();
},
throwable -> logger.log(Level.SEVERE, "Error checking if drawable db is stale.", throwable)//NON-NLS
);

View File

@ -178,10 +178,10 @@ public final class DrawableDB {
* DO NOT add in the middle.
*/
public enum DrawableDbBuildStatusEnum {
UNKNOWN, /// no known status
UNKNOWN, /// no known status - not yet analyzed
IN_PROGRESS, /// ingest or db rebuild is in progress
COMPLETE, /// All files in the data source have had file type detected
DEFAULT; /// Not all files in the data source have had file type detected
COMPLETE, /// At least one file in the data source had a MIME type. Ingest filters may have been applied.
REBUILT_STALE; /// data source was rebuilt, but MIME types were missing during rebuild
}
private void dbWriteLock() {
@ -1210,6 +1210,15 @@ public final class DrawableDB {
return map;
}
public DrawableDbBuildStatusEnum getDataSourceDbBuildStatus(Long dataSourceId) throws TskCoreException {
Map<Long, DrawableDbBuildStatusEnum> statusMap = getDataSourceDbBuildStatus();
if (statusMap.containsKey(dataSourceId) == false) {
throw new TskCoreException("Data Source ID not found: " + dataSourceId);
}
return statusMap.get(dataSourceId);
}
/**
* Insert/update given data source object id and it's DB rebuild status in
* the datasources table.
@ -1554,16 +1563,9 @@ public final class DrawableDB {
}
public long countAllFiles() throws TskCoreException {
return countAllFiles(null);
return countFilesWhere(" 1 ");
}
public long countAllFiles(DataSource dataSource) throws TskCoreException {
if (null != dataSource) {
return countFilesWhere(" data_source_obj_id = ");
} else {
return countFilesWhere(" 1 ");
}
}
/**
* delete the row with obj_id = id.

View File

@ -50,6 +50,11 @@ public class DataSourceCell extends ListCell<Optional<DataSource>> {
}
/**
*
* @param item
* @param empty
*/
@Override
protected void updateItem(Optional<DataSource> item, boolean empty) {
super.updateItem(item, empty);
@ -57,31 +62,42 @@ public class DataSourceCell extends ListCell<Optional<DataSource>> {
setText("");
} else {
DataSource dataSource = item.orElse(null);
String text = (dataSource == null) ? "All" : dataSource.getName() + " (Id: " + dataSource.getId() + ")";
Boolean tooManyFilesInDataSource = dataSourcesTooManyFiles.getOrDefault(dataSource, false);
String dataSourceName;
boolean shouldEnable = true; // false if user should not be able to select the item
DrawableDbBuildStatusEnum dataSourceDBStatus = (dataSource != null) ?
dataSourcesDrawableDBStatus.get(dataSource.getId()) : DrawableDbBuildStatusEnum.UNKNOWN;
Boolean dataSourceNotAnalyzed = (dataSourceDBStatus == DrawableDbBuildStatusEnum.DEFAULT);
if (tooManyFilesInDataSource) {
text += " - Too many files";
if (dataSource == null) {
dataSourceName = "All";
// NOTE: openAction verifies that there is at least one data source with data.
// So, at this point, "All" should never need to be disabled because none of the data sources
// are analyzed.
}
if (dataSourceNotAnalyzed) {
text += " - Not Analyzed";
else {
dataSourceName = dataSource.getName() + " (Id: " + dataSource.getId() + ")";
if (dataSourcesDrawableDBStatus.get(dataSource.getId()) == DrawableDbBuildStatusEnum.UNKNOWN) {
dataSourceName += " - Not Analyzed";
shouldEnable = false;
}
}
// if it's analyzed, then make sure there aren't too many files
if (shouldEnable) {
if (dataSourcesTooManyFiles.getOrDefault(dataSource, false)) {
dataSourceName += " - Too Many Files";
shouldEnable = false;
}
}
// check if item should be disabled
if (tooManyFilesInDataSource || dataSourceNotAnalyzed) {
setDisable(true);
setStyle("-fx-opacity : .5");
}
else {
if (shouldEnable) {
setGraphic(null);
setStyle("-fx-opacity : 1");
}
else {
setDisable(true);
setStyle("-fx-opacity : .5");
}
setText(text);
setText(dataSourceName);
}
}
}

View File

@ -16,7 +16,7 @@
<right>
<HBox alignment="CENTER_RIGHT" prefHeight="-1.0" prefWidth="-1.0" spacing="5.0" BorderPane.alignment="CENTER_RIGHT">
<children>
<Label fx:id="staleLabel" text="Some data may be out of date. Enable listening to ingest to update.">
<Label fx:id="staleLabel" text="Additional data may be available after rebuild or enabling listeners.">
<graphic>
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<image>