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

View File

@ -80,6 +80,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
commentsOccurencesColumnWrapAroundText.setEnabled(EamDbUtil.useCentralRepo()); commentsOccurencesColumnWrapAroundText.setEnabled(EamDbUtil.useCentralRepo());
commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences()); commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences());
hideOtherUsersTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags());
deletedFilesLimitCheckbox.setSelected(DeletedFilePreferences.getDefault().getShouldLimitDeletedFiles()); deletedFilesLimitCheckbox.setSelected(DeletedFilePreferences.getDefault().getShouldLimitDeletedFiles());
translateNamesInTableRadioButton.setSelected(UserPreferences.displayTranslatedFileNames()); translateNamesInTableRadioButton.setSelected(UserPreferences.displayTranslatedFileNames());
@ -91,8 +92,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
currentCaseSettingsPanel.setEnabled(caseIsOpen); currentCaseSettingsPanel.setEnabled(caseIsOpen);
groupByDataSourceCheckbox.setEnabled(caseIsOpen); groupByDataSourceCheckbox.setEnabled(caseIsOpen);
hideOtherUsersTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags()); if (caseIsOpen) {
groupByDataSourceCheckbox.setSelected(Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)); groupByDataSourceCheckbox.setSelected(Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true));
} else {
groupByDataSourceCheckbox.setSelected(false);
}
// Current Session Settings // Current Session Settings
hideRejectedResultsCheckbox.setSelected(DirectoryTreeTopComponent.getDefault().getShowRejectedResults() == false); hideRejectedResultsCheckbox.setSelected(DirectoryTreeTopComponent.getDefault().getShowRejectedResults() == false);
@ -174,10 +178,12 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
currentSessionSettingsPanel = new javax.swing.JPanel(); currentSessionSettingsPanel = new javax.swing.JPanel();
hideRejectedResultsCheckbox = new javax.swing.JCheckBox(); hideRejectedResultsCheckbox = new javax.swing.JCheckBox();
viewPreferencesScrollPane.setBorder(null); setPreferredSize(new java.awt.Dimension(625, 465));
viewPreferencesScrollPane.setPreferredSize(new java.awt.Dimension(625, 452));
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 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(); CorrelationAttributeInstance attribute = getCorrelationAttributeInstance();
updateSheet(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(),NO_DESCR,getCommentProperty(tags, attribute))); 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())) { } else if (eventType.equals(NodeSpecificEvents.TRANSLATION_AVAILABLE.toString())) {
updateSheet(new NodeProperty<>(TRANSLATION.toString(),TRANSLATION.toString(),NO_DESCR,evt.getNewValue())); 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.sizeColLbl=Size",
"AbstractAbstractFileNode.flagsDirColLbl=Flags(Dir)", "AbstractAbstractFileNode.flagsDirColLbl=Flags(Dir)",
"AbstractAbstractFileNode.flagsMetaColLbl=Flags(Meta)", "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.knownColLbl=Known",
"AbstractAbstractFileNode.md5HashColLbl=MD5 Hash", "AbstractAbstractFileNode.md5HashColLbl=MD5 Hash",
"AbstractAbstractFileNode.objectId=Object ID",
"AbstractAbstractFileNode.mimeType=MIME Type", "AbstractAbstractFileNode.mimeType=MIME Type",
"AbstractAbstractFileNode.extensionColLbl=Extension"}) "AbstractAbstractFileNode.extensionColLbl=Extension"})
public enum AbstractFilePropertyType { public enum AbstractFilePropertyType {
@ -323,8 +327,16 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
SIZE(AbstractAbstractFileNode_sizeColLbl()), SIZE(AbstractAbstractFileNode_sizeColLbl()),
FLAGS_DIR(AbstractAbstractFileNode_flagsDirColLbl()), FLAGS_DIR(AbstractAbstractFileNode_flagsDirColLbl()),
FLAGS_META(AbstractAbstractFileNode_flagsMetaColLbl()), 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()), KNOWN(AbstractAbstractFileNode_knownColLbl()),
MD5HASH(AbstractAbstractFileNode_md5HashColLbl()), MD5HASH(AbstractAbstractFileNode_md5HashColLbl()),
ObjectID(AbstractAbstractFileNode_objectId()),
MIMETYPE(AbstractAbstractFileNode_mimeType()), MIMETYPE(AbstractAbstractFileNode_mimeType()),
EXTENSION(AbstractAbstractFileNode_extensionColLbl()); EXTENSION(AbstractAbstractFileNode_extensionColLbl());

View File

@ -6,6 +6,9 @@ AbstractAbstractFileNode.changeTimeColLbl=\u5909\u66f4\u65e5\u6642
AbstractAbstractFileNode.accessTimeColLbl=\u30a2\u30af\u30bb\u30b9\u65e5\u6642 AbstractAbstractFileNode.accessTimeColLbl=\u30a2\u30af\u30bb\u30b9\u65e5\u6642
AbstractAbstractFileNode.createdTimeColLbl=\u4f5c\u6210\u65e5\u6642 AbstractAbstractFileNode.createdTimeColLbl=\u4f5c\u6210\u65e5\u6642
AbstractAbstractFileNode.sizeColLbl=\u30b5\u30a4\u30ba 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.knownColLbl=\u65e2\u77e5
AbstractAbstractFileNode.md5HashColLbl=MD5\u30cf\u30c3\u30b7\u30e5 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 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 TagsNode.createSheet.name.name=\u540d\u524d
AbstractAbstractFileNode.flagsDirColLbl=\u30d5\u30e9\u30b0\uff08\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\uff09 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.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 ArtifactTypeNode.createSheet.childCnt.displayName=\u30c1\u30e3\u30a4\u30eb\u30c9\u6570
TagsNode.createSheet.name.displayName=\u540d\u524d TagsNode.createSheet.name.displayName=\u540d\u524d
ViewsNode.name.text=\u30d3\u30e5\u30fc 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.createSheet.numChildren.displayName=\u30c1\u30e3\u30a4\u30eb\u30c9\u6570
KeywordHits.simpleLiteralSearch.text=\u30b7\u30f3\u30b0\u30eb\u30ea\u30c6\u30e9\u30eb\u691c\u7d22 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 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 ArtifactStringContent.getStr.artifactId.text=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8ID
OpenReportAction.actionDisplayName=\u30ec\u30dd\u30fc\u30c8\u3092\u958b\u304f OpenReportAction.actionDisplayName=\u30ec\u30dd\u30fc\u30c8\u3092\u958b\u304f
OpenReportAction.actionPerformed.MessageBoxTitle=\u5931\u6557\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 static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandle;
import org.openide.util.Cancellable; import org.openide.util.Cancellable;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.Case.CaseType;
@ -99,7 +100,7 @@ public final class ImageGalleryController {
private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false); private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false);
@ThreadConfined(type = ThreadConfined.ThreadType.JFX) @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 ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false);
private final SimpleDoubleProperty thumbnailSizeProp = new SimpleDoubleProperty(100); private final SimpleDoubleProperty thumbnailSizeProp = new SimpleDoubleProperty(100);
@ -160,26 +161,34 @@ public final class ImageGalleryController {
} }
} }
boolean isListeningEnabled() { public boolean isListeningEnabled() {
synchronized (listeningEnabled) { synchronized (listeningEnabled) {
return listeningEnabled.get(); return listeningEnabled.get();
} }
} }
/**
*
* @param b True if any data source in the case is stale
*/
@ThreadConfined(type = ThreadConfined.ThreadType.ANY) @ThreadConfined(type = ThreadConfined.ThreadType.ANY)
void setStale(Boolean b) { void setCaseStale(Boolean b) {
Platform.runLater(() -> { Platform.runLater(() -> {
stale.set(b); isCaseStale.set(b);
}); });
} }
public ReadOnlyBooleanProperty staleProperty() { 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) @ThreadConfined(type = ThreadConfined.ThreadType.JFX)
boolean isStale() { boolean isCaseStale() {
return stale.get(); return isCaseStale.get();
} }
ImageGalleryController(@Nonnull Case newCase) throws TskCoreException { ImageGalleryController(@Nonnull Case newCase) throws TskCoreException {
@ -197,7 +206,7 @@ public final class ImageGalleryController {
tagsManager.registerListener(categoryManager); tagsManager.registerListener(categoryManager);
hashSetManager = new HashSetManager(drawableDB); hashSetManager = new HashSetManager(drawableDB);
setStale(isDataSourcesTableStale()); setCaseStale(isDataSourcesTableStale());
dbExecutor = getNewDBExecutor(); dbExecutor = getNewDBExecutor();
@ -344,7 +353,7 @@ public final class ImageGalleryController {
* Returns a set of data source object ids that are stale. * Returns a set of data source object ids that are stale.
* *
* This includes any data sources already in the table, that are not in * 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. * case, but are not in the datasources table.
* *
* @return list of data source object ids that are stale. * @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 // collect all data sources already in the table, that are not yet COMPLETE
knownDataSourceIds.entrySet().stream().forEach((Map.Entry<Long, DrawableDbBuildStatusEnum> t) -> { knownDataSourceIds.entrySet().stream().forEach((Map.Entry<Long, DrawableDbBuildStatusEnum> t) -> {
DrawableDbBuildStatusEnum status = t.getValue(); DrawableDbBuildStatusEnum status = t.getValue();
if (DrawableDbBuildStatusEnum.COMPLETE != status) { 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()); 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. // 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); logger.log(Level.SEVERE, "Image Gallery failed to check if datasources table is stale.", ex);
return staleDataSourceIds; return staleDataSourceIds;
} }
} }
/** /**
@ -451,12 +477,12 @@ public final class ImageGalleryController {
* *
* @throws TskCoreException * @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 // 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, // The IngestTasksScheduler does not push them down to the ingest modules,
// and hence they do not have any assigned mimetype // 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 ( meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() + ")"
+ " AND ( mime_type IS NULL )" + " AND ( mime_type IS NULL )"
+ " AND ( meta_addr >= 32 ) " + " AND ( meta_addr >= 32 ) "
@ -466,6 +492,15 @@ public final class ImageGalleryController {
return sleuthKitCase.countFilesWhere(whereClause) > 0; 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() { synchronized private void shutDownDBExecutor() {
if (dbExecutor != null) { if (dbExecutor != null) {
dbExecutor.shutdownNow(); dbExecutor.shutdownNow();
@ -645,12 +680,6 @@ public final class ImageGalleryController {
"BulkTask.stopCopy.status=Stopping copy to drawable db task.", "BulkTask.stopCopy.status=Stopping copy to drawable db task.",
"BulkTask.errPopulating.errMsg=There was an error populating Image Gallery database."}) "BulkTask.errPopulating.errMsg=There was an error populating Image Gallery database."})
abstract static class BulkTransferTask extends BackgroundTask { 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 static private final String MIMETYPE_CLAUSE
= "(mime_type LIKE '" //NON-NLS = "(mime_type LIKE '" //NON-NLS
+ String.join("' OR mime_type LIKE '", FileTypeUtils.getAllSupportedMimeTypes()) //NON-NLS + String.join("' OR mime_type LIKE '", FileTypeUtils.getAllSupportedMimeTypes()) //NON-NLS
@ -679,20 +708,16 @@ public final class ImageGalleryController {
= DATASOURCE_CLAUSE = DATASOURCE_CLAUSE
+ " AND ( meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() + ")" + " AND ( meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() + ")"
+ " AND ( " + " AND ( "
+ //grab files with supported extension
FILE_EXTENSION_CLAUSE
//grab files with supported mime-types //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 //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 + " OR mime_type LIKE 'video/%' OR mime_type LIKE 'image/%' )"; //NON-NLS
} }
/** /**
* Do any cleanup for this task. * 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; 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; DrawableDB.DrawableTransaction drawableDbTransaction = null;
CaseDbTransaction caseDbTransaction = null; CaseDbTransaction caseDbTransaction = null;
boolean hasFilesWithNoMime = true;
boolean endedEarly = false;
try { 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(); final List<AbstractFile> files = getFiles();
progressHandle.switchToDeterminate(files.size()); progressHandle.switchToDeterminate(files.size());
taskDB.insertOrUpdateDataSource(dataSourceObjId, DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS); taskDB.insertOrUpdateDataSource(dataSourceObjId, DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS);
updateProgress(0.0); updateProgress(0.0);
taskCompletionStatus = true;
int workDone = 0; int workDone = 0;
// Cycle through all of the files returned and call processFile on each // Cycle through all of the files returned and call processFile on each
//do in transaction //do in transaction
drawableDbTransaction = taskDB.beginTransaction(); drawableDbTransaction = taskDB.beginTransaction();
@ -743,9 +774,10 @@ public final class ImageGalleryController {
if (isCancelled() || Thread.interrupted()) { if (isCancelled() || Thread.interrupted()) {
logger.log(Level.WARNING, "Task cancelled or interrupted: not all contents may be transfered to drawable database."); //NON-NLS 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(); progressHandle.finish();
break; break;
} }
@ -798,27 +830,25 @@ public final class ImageGalleryController {
progressHandle.progress(Bundle.BulkTask_stopCopy_status()); 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 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()); MessageNotifyUtil.Notify.warn(Bundle.BulkTask_errPopulating_errMsg(), ex.getMessage());
cleanup(false); endedEarly = true;
} finally { } finally {
progressHandle.finish(); 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 DrawableDB.DrawableDbBuildStatusEnum datasourceDrawableDBStatus
= (taskCompletionStatus) = ((hasFilesWithNoMime == true) || (endedEarly == true))
? DrawableDB.DrawableDbBuildStatusEnum.COMPLETE ? DrawableDB.DrawableDbBuildStatusEnum.REBUILT_STALE
: DrawableDB.DrawableDbBuildStatusEnum.DEFAULT; : DrawableDB.DrawableDbBuildStatusEnum.COMPLETE;
taskDB.insertOrUpdateDataSource(dataSourceObjId, datasourceDrawableDBStatus); taskDB.insertOrUpdateDataSource(dataSourceObjId, datasourceDrawableDBStatus);
updateMessage(""); updateMessage("");
updateProgress(-1.0); updateProgress(-1.0);
} }
cleanup(taskCompletionStatus); cleanup();
} }
abstract ProgressHandle getInitialProgressHandle(); abstract ProgressHandle getInitialProgressHandle();
protected void setTaskCompletionStatus(boolean status) {
taskCompletionStatus = status;
}
} }
/** /**
@ -839,11 +869,11 @@ public final class ImageGalleryController {
} }
@Override @Override
protected void cleanup(boolean success) { protected void cleanup() {
taskDB.freeFileMetaDataCache(); taskDB.freeFileMetaDataCache();
// at the end of the task, set the stale status based on the // at the end of the task, set the stale status based on the
// cumulative status of all data sources // cumulative status of all data sources
controller.setStale(controller.isDataSourcesTableStale()); controller.setCaseStale(controller.isDataSourcesTableStale());
} }
@Override @Override
@ -853,12 +883,9 @@ public final class ImageGalleryController {
if (known) { if (known) {
taskDB.removeFile(f.getId(), tr); //remove known files taskDB.removeFile(f.getId(), tr); //remove known files
} else { } else {
// if mimetype of the file hasn't been ascertained, ingest might not have completed yet. // NOTE: Files are being processed because they have the right MIME type,
if (null == f.getMIMEType()) { // so we do not need to worry about this calculating them
// set to false to force the DB to be marked as stale if (FileTypeUtils.hasDrawableMIMEType(f)) {
this.setTaskCompletionStatus(false);
} //supported mimetype => analyzed
else if (FileTypeUtils.hasDrawableMIMEType(f)) {
taskDB.updateFile(DrawableFile.create(f, true, false), tr, caseDbTransaction); taskDB.updateFile(DrawableFile.create(f, true, false), tr, caseDbTransaction);
} //unsupported mimtype => analyzed but shouldn't include } //unsupported mimtype => analyzed but shouldn't include
else { else {

View File

@ -277,7 +277,7 @@ public class ImageGalleryModule {
if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.LOCAL) { if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.LOCAL) {
Content newDataSource = (Content) evt.getNewValue(); Content newDataSource = (Content) evt.getNewValue();
if (con.isListeningEnabled()) { if (con.isListeningEnabled()) {
controller.getDatabase().insertOrUpdateDataSource(newDataSource.getId(), DrawableDB.DrawableDbBuildStatusEnum.DEFAULT); controller.getDatabase().insertOrUpdateDataSource(newDataSource.getId(), DrawableDB.DrawableDbBuildStatusEnum.UNKNOWN);
} }
} }
break; break;
@ -332,7 +332,11 @@ public class ImageGalleryModule {
DataSourceAnalysisStartedEvent dataSourceAnalysisStartedEvent = (DataSourceAnalysisStartedEvent) evt; DataSourceAnalysisStartedEvent dataSourceAnalysisStartedEvent = (DataSourceAnalysisStartedEvent) evt;
Content dataSource = dataSourceAnalysisStartedEvent.getDataSource(); 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) { } else if (eventType == IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED) {
@ -342,20 +346,26 @@ public class ImageGalleryModule {
DataSourceAnalysisCompletedEvent dataSourceAnalysisCompletedEvent = (DataSourceAnalysisCompletedEvent) evt; DataSourceAnalysisCompletedEvent dataSourceAnalysisCompletedEvent = (DataSourceAnalysisCompletedEvent) evt;
Content dataSource = dataSourceAnalysisCompletedEvent.getDataSource(); Content dataSource = dataSourceAnalysisCompletedEvent.getDataSource();
DrawableDB drawableDb = controller.getDatabase();
if (drawableDb.getDataSourceDbBuildStatus(dataSource.getId()) == DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS) {
// 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 = DrawableDB.DrawableDbBuildStatusEnum datasourceDrawableDBStatus =
controller.hasFilesWithNoMimetype(dataSource) ? controller.hasFilesWithMimeType(dataSource.getId()) ?
DrawableDB.DrawableDbBuildStatusEnum.DEFAULT : DrawableDB.DrawableDbBuildStatusEnum.COMPLETE :
DrawableDB.DrawableDbBuildStatusEnum.COMPLETE; DrawableDB.DrawableDbBuildStatusEnum.UNKNOWN;
controller.getDatabase().insertOrUpdateDataSource(dataSource.getId(), datasourceDrawableDBStatus); controller.getDatabase().insertOrUpdateDataSource(dataSource.getId(), datasourceDrawableDBStatus);
} }
}
return; return;
} }
if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.REMOTE) { if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.REMOTE) {
// A remote node added a new data source and just finished ingest on it. // 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 //drawable db is stale, and if ImageGallery is open, ask user what to do
controller.setStale(true); controller.setCaseStale(true);
if (controller.isListeningEnabled()) { if (controller.isListeningEnabled()) {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
if (ImageGalleryTopComponent.isImageGalleryOpen()) { if (ImageGalleryTopComponent.isImageGalleryOpen()) {

View File

@ -41,7 +41,7 @@ import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils;
*/ */
@NbBundle.Messages({ @NbBundle.Messages({
"NextUnseenGroup.markGroupSeen=Mark Group Seen", "NextUnseenGroup.markGroupSeen=Mark Group Seen",
"NextUnseenGroup.nextUnseenGroup=Next Unseen group", "NextUnseenGroup.nextUnseenGroup=Next Unseen Group",
"NextUnseenGroup.allGroupsSeen=All Groups Have Been Seen"}) "NextUnseenGroup.allGroupsSeen=All Groups Have Been Seen"})
public class NextUnseenGroup extends Action { 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.ActionReference;
import org.openide.awt.ActionReferences; import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration; import org.openide.awt.ActionRegistration;
import org.openide.util.Exceptions;
import org.openide.util.HelpCtx; import org.openide.util.HelpCtx;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
@ -192,36 +193,36 @@ public final class OpenAction extends CallableSystemAction {
addFXCallback(dataSourceStatusMapFuture, addFXCallback(dataSourceStatusMapFuture,
dataSourceStatusMap -> { 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()) { for (Map.Entry<Long, DrawableDbBuildStatusEnum> entry : dataSourceStatusMap.entrySet()) {
DrawableDbBuildStatusEnum status = entry.getValue(); DrawableDbBuildStatusEnum status = entry.getValue();
if (DrawableDbBuildStatusEnum.COMPLETE != status) { if (DrawableDbBuildStatusEnum.UNKNOWN == status) {
dbIsStale = true; 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++;
//back on fx thread. // likely a data source (local or remote) that has no analysis yet (note there is also IN_PROGRESS state)
if (false == dbIsStale) {
//drawable db is not stale, just open it
openTopComponent();
} else { } else {
numNoAnalysis++;
// If there is only one datasource and it's in DEFAULT State - }
// ingest modules need to be run on the data source } catch (TskCoreException ex) {
if (dataSourceStatusMap.size()== 1) { logger.log(Level.SEVERE, "Error querying case database", ex);
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); // was already rebuilt, but wasn't complete at the end
alert.setTitle(Bundle.OpenAction_stale_confDlg_title()); else if (DrawableDbBuildStatusEnum.REBUILT_STALE == status) {
alert.initModality(Modality.APPLICATION_MODAL); numStale++;
alert.showAndWait();
return;
} }
} }
//drawable db is stale, // NOTE: we are running on the fx thread.
//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, Alert alert = new Alert(Alert.AlertType.WARNING,
Bundle.OpenAction_stale_confDlg_msg(), Bundle.OpenAction_stale_confDlg_msg(),
ButtonType.YES, ButtonType.NO, ButtonType.CANCEL); ButtonType.YES, ButtonType.NO, ButtonType.CANCEL);
@ -229,10 +230,13 @@ public final class OpenAction extends CallableSystemAction {
alert.setTitle(Bundle.OpenAction_stale_confDlg_title()); alert.setTitle(Bundle.OpenAction_stale_confDlg_title());
GuiUtils.setDialogIcons(alert); GuiUtils.setDialogIcons(alert);
ButtonType answer = alert.showAndWait().orElse(ButtonType.CANCEL); ButtonType answer = alert.showAndWait().orElse(ButtonType.CANCEL);
if (answer == ButtonType.CANCEL) { if (answer == ButtonType.CANCEL) {
//just do nothing //just do nothing - don't open window
return;
} else if (answer == ButtonType.NO) { } 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) { } else if (answer == ButtonType.YES) {
if (controller.getAutopsyCase().getCaseType() == Case.CaseType.SINGLE_USER_CASE) { if (controller.getAutopsyCase().getCaseType() == Case.CaseType.SINGLE_USER_CASE) {
/* For a single-user case, we favor user /* For a single-user case, we favor user
@ -255,9 +259,23 @@ public final class OpenAction extends CallableSystemAction {
*/ */
controller.rebuildDB(); 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 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. * DO NOT add in the middle.
*/ */
public enum DrawableDbBuildStatusEnum { public enum DrawableDbBuildStatusEnum {
UNKNOWN, /// no known status UNKNOWN, /// no known status - not yet analyzed
IN_PROGRESS, /// ingest or db rebuild is in progress IN_PROGRESS, /// ingest or db rebuild is in progress
COMPLETE, /// 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.
DEFAULT; /// Not all files in the data source have had file type detected REBUILT_STALE; /// data source was rebuilt, but MIME types were missing during rebuild
} }
private void dbWriteLock() { private void dbWriteLock() {
@ -1210,6 +1210,15 @@ public final class DrawableDB {
return map; 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 * Insert/update given data source object id and it's DB rebuild status in
* the datasources table. * the datasources table.
@ -1554,16 +1563,9 @@ public final class DrawableDB {
} }
public long countAllFiles() throws TskCoreException { public long countAllFiles() throws TskCoreException {
return countAllFiles(null);
}
public long countAllFiles(DataSource dataSource) throws TskCoreException {
if (null != dataSource) {
return countFilesWhere(" data_source_obj_id = ");
} else {
return countFilesWhere(" 1 "); return countFilesWhere(" 1 ");
} }
}
/** /**
* delete the row with obj_id = id. * 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 @Override
protected void updateItem(Optional<DataSource> item, boolean empty) { protected void updateItem(Optional<DataSource> item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
@ -57,31 +62,42 @@ public class DataSourceCell extends ListCell<Optional<DataSource>> {
setText(""); setText("");
} else { } else {
DataSource dataSource = item.orElse(null); DataSource dataSource = item.orElse(null);
String text = (dataSource == null) ? "All" : dataSource.getName() + " (Id: " + dataSource.getId() + ")"; String dataSourceName;
Boolean tooManyFilesInDataSource = dataSourcesTooManyFiles.getOrDefault(dataSource, false); boolean shouldEnable = true; // false if user should not be able to select the item
DrawableDbBuildStatusEnum dataSourceDBStatus = (dataSource != null) ? if (dataSource == null) {
dataSourcesDrawableDBStatus.get(dataSource.getId()) : DrawableDbBuildStatusEnum.UNKNOWN; dataSourceName = "All";
// NOTE: openAction verifies that there is at least one data source with data.
Boolean dataSourceNotAnalyzed = (dataSourceDBStatus == DrawableDbBuildStatusEnum.DEFAULT); // So, at this point, "All" should never need to be disabled because none of the data sources
if (tooManyFilesInDataSource) { // are analyzed.
text += " - Too many files"; }
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;
} }
if (dataSourceNotAnalyzed) {
text += " - Not Analyzed";
} }
// check if item should be disabled // check if item should be disabled
if (tooManyFilesInDataSource || dataSourceNotAnalyzed) { if (shouldEnable) {
setDisable(true);
setStyle("-fx-opacity : .5");
}
else {
setGraphic(null); setGraphic(null);
setStyle("-fx-opacity : 1"); setStyle("-fx-opacity : 1");
} }
else {
setDisable(true);
setStyle("-fx-opacity : .5");
}
setText(text); setText(dataSourceName);
} }
} }
} }

View File

@ -16,7 +16,7 @@
<right> <right>
<HBox alignment="CENTER_RIGHT" prefHeight="-1.0" prefWidth="-1.0" spacing="5.0" BorderPane.alignment="CENTER_RIGHT"> <HBox alignment="CENTER_RIGHT" prefHeight="-1.0" prefWidth="-1.0" spacing="5.0" BorderPane.alignment="CENTER_RIGHT">
<children> <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> <graphic>
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true"> <ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<image> <image>