mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-20 03:24:55 +00:00
fixes for deleted content
This commit is contained in:
parent
c556d26f55
commit
aceac88f06
@ -33,10 +33,17 @@ public class DeletedContentSearchParams {
|
|||||||
public static String getTypeId() {
|
public static String getTypeId() {
|
||||||
return TYPE_ID;
|
return TYPE_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final DeletedContentFilter filter;
|
private final DeletedContentFilter filter;
|
||||||
private final Long dataSourceId;
|
private final Long dataSourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param filter The filter (if null, indicates full refresh
|
||||||
|
* required).
|
||||||
|
* @param dataSourceId The data source id or null.
|
||||||
|
*/
|
||||||
public DeletedContentSearchParams(DeletedContentFilter filter, Long dataSourceId) {
|
public DeletedContentSearchParams(DeletedContentFilter filter, Long dataSourceId) {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.dataSourceId = dataSourceId;
|
this.dataSourceId = dataSourceId;
|
||||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.mainui.datamodel;
|
|||||||
import org.sleuthkit.autopsy.mainui.datamodel.events.DAOEvent;
|
import org.sleuthkit.autopsy.mainui.datamodel.events.DAOEvent;
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
@ -37,7 +38,6 @@ import java.util.Objects;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbPreparedStatement;
|
import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbPreparedStatement;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.TskData;
|
||||||
import org.sleuthkit.datamodel.TskData.FileKnown;
|
import org.sleuthkit.datamodel.TskData.FileKnown;
|
||||||
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||||
import org.sleuthkit.datamodel.TskData.TSK_FS_META_FLAG_ENUM;
|
import org.sleuthkit.datamodel.TskData.TSK_FS_META_FLAG_ENUM;
|
||||||
@ -200,8 +201,9 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DeletedContentEvent deletedContentEvt = (DeletedContentEvent) eventData;
|
DeletedContentEvent deletedContentEvt = (DeletedContentEvent) eventData;
|
||||||
return deletedContentEvt.getFilter().equals(params.getFilter())
|
return (deletedContentEvt.getFilter() == null || deletedContentEvt.getFilter().equals(params.getFilter()))
|
||||||
&& (params.getDataSourceId() == null || Objects.equals(params.getDataSourceId(), deletedContentEvt.getDataSourceId()));
|
&& (params.getDataSourceId() == null || deletedContentEvt.getDataSourceId() == null
|
||||||
|
|| Objects.equals(params.getDataSourceId(), deletedContentEvt.getDataSourceId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -546,6 +548,21 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
* @throws ExecutionException
|
* @throws ExecutionException
|
||||||
*/
|
*/
|
||||||
public TreeResultsDTO<DeletedContentSearchParams> getDeletedContentCounts(Long dataSourceId) throws IllegalArgumentException, ExecutionException {
|
public TreeResultsDTO<DeletedContentSearchParams> getDeletedContentCounts(Long dataSourceId) throws IllegalArgumentException, ExecutionException {
|
||||||
|
Set<DeletedContentFilter> indeterminateFilters = new HashSet<>();
|
||||||
|
for (DAOEvent evt : this.treeCounts.getEnqueued()) {
|
||||||
|
if (evt instanceof DeletedContentEvent) {
|
||||||
|
DeletedContentEvent deletedEvt = (DeletedContentEvent) evt;
|
||||||
|
if (dataSourceId == null || deletedEvt.getDataSourceId() == null || Objects.equals(deletedEvt.getDataSourceId(), dataSourceId)) {
|
||||||
|
if (deletedEvt.getFilter() == null) {
|
||||||
|
// if null filter, indicates full refresh and all file sizes need refresh.
|
||||||
|
indeterminateFilters.addAll(Arrays.asList(DeletedContentFilter.values()));
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
indeterminateFilters.add(deletedEvt.getFilter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String queryStr = Stream.of(DeletedContentFilter.values())
|
String queryStr = Stream.of(DeletedContentFilter.values())
|
||||||
.map((filter) -> {
|
.map((filter) -> {
|
||||||
@ -563,14 +580,18 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
if (resultSet.next()) {
|
if (resultSet.next()) {
|
||||||
for (DeletedContentFilter filter : DeletedContentFilter.values()) {
|
for (DeletedContentFilter filter : DeletedContentFilter.values()) {
|
||||||
long count = resultSet.getLong(filter.name());
|
long count = resultSet.getLong(filter.name());
|
||||||
treeList.add(createDeletedContentTreeItem(filter, dataSourceId, TreeDisplayCount.getDeterminate(count)));
|
TreeDisplayCount displayCount = indeterminateFilters.contains(filter)
|
||||||
|
? TreeDisplayCount.INDETERMINATE
|
||||||
|
: TreeDisplayCount.getDeterminate(count);
|
||||||
|
|
||||||
|
treeList.add(createDeletedContentTreeItem(filter, dataSourceId, displayCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logger.log(Level.WARNING, "An error occurred while fetching file type counts.", ex);
|
logger.log(Level.WARNING, "An error occurred while fetching file type counts.", ex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return new TreeResultsDTO<>(treeList);
|
return new TreeResultsDTO<>(treeList);
|
||||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||||
throw new ExecutionException("An error occurred while fetching file counts with query:\n" + queryStr, ex);
|
throw new ExecutionException("An error occurred while fetching file counts with query:\n" + queryStr, ex);
|
||||||
@ -582,7 +603,7 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
"DELETED_CONTENT",
|
"DELETED_CONTENT",
|
||||||
new DeletedContentSearchParams(filter, dataSourceId),
|
new DeletedContentSearchParams(filter, dataSourceId),
|
||||||
filter,
|
filter,
|
||||||
filter.getDisplayName(),
|
filter == null ? "" : filter.getDisplayName(),
|
||||||
displayCount);
|
displayCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -930,7 +951,7 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
@Override
|
@Override
|
||||||
Set<? extends DAOEvent> handleIngestComplete() {
|
Set<? extends DAOEvent> handleIngestComplete() {
|
||||||
SubDAOUtils.invalidateKeys(this.searchParamsCache,
|
SubDAOUtils.invalidateKeys(this.searchParamsCache,
|
||||||
(searchParams) -> searchParamsMatchEvent(null, null, null, null, true, searchParams));
|
(searchParams) -> searchParamsMatchEvent(null, null, null, null, null, true, searchParams));
|
||||||
|
|
||||||
Set<? extends DAOEvent> treeEvts = SubDAOUtils.getIngestCompleteEvents(this.treeCounts,
|
Set<? extends DAOEvent> treeEvts = SubDAOUtils.getIngestCompleteEvents(this.treeCounts,
|
||||||
(daoEvt, count) -> createTreeItem(daoEvt, count));
|
(daoEvt, count) -> createTreeItem(daoEvt, count));
|
||||||
@ -957,6 +978,7 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
Long dsId = null;
|
Long dsId = null;
|
||||||
boolean dataSourceAdded = false;
|
boolean dataSourceAdded = false;
|
||||||
Set<FileExtSearchFilter> evtExtFilters = null;
|
Set<FileExtSearchFilter> evtExtFilters = null;
|
||||||
|
Set<DeletedContentFilter> deletedContentFilters = null;
|
||||||
String evtMimeType = null;
|
String evtMimeType = null;
|
||||||
FileSizeFilter evtFileSize = null;
|
FileSizeFilter evtFileSize = null;
|
||||||
|
|
||||||
@ -978,7 +1000,7 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
evtExtFilters = EXTENSION_FILTER_MAP.getOrDefault("." + af.getNameExtension(), Collections.emptySet());
|
evtExtFilters = EXTENSION_FILTER_MAP.getOrDefault("." + af.getNameExtension(), Collections.emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<DeletedContentFilter> deletedContentFilters = getMatchingDeletedContentFilters(af);
|
deletedContentFilters = getMatchingDeletedContentFilters(af);
|
||||||
|
|
||||||
// create a mime type mapping if mime type present
|
// create a mime type mapping if mime type present
|
||||||
if (StringUtils.isBlank(af.getMIMEType()) || !TSK_FS_NAME_TYPE_ENUM.REG.equals(af.getDirType()) || !getMimeDbFilesTypes().contains(af.getType())) {
|
if (StringUtils.isBlank(af.getMIMEType()) || !TSK_FS_NAME_TYPE_ENUM.REG.equals(af.getDirType()) || !getMimeDbFilesTypes().contains(af.getType())) {
|
||||||
@ -993,26 +1015,29 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evtExtFilters == null || evtExtFilters.isEmpty() && deletedContentFilters.isEmpty() && evtMimeType == null && evtFileSize == null) {
|
if (evtExtFilters == null || evtExtFilters.isEmpty() && deletedContentFilters.isEmpty() && evtMimeType == null && evtFileSize == null) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return invalidateAndReturnEvents(evtExtFilters, evtMimeType, evtFileSize, dsId, dataSourceAdded);
|
return invalidateAndReturnEvents(evtExtFilters, evtMimeType, evtFileSize, deletedContentFilters, dsId, dataSourceAdded);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles invalidating caches and returning events based on digest.
|
* Handles invalidating caches and returning events based on digest.
|
||||||
*
|
*
|
||||||
* @param evtExtFilters The file extension filters or empty set.
|
* @param evtExtFilters The file extension filters or empty set.
|
||||||
* @param evtMimeType The mime type or null.
|
* @param evtMimeType The mime type or null.
|
||||||
* @param evtFileSize The file size filter or null.
|
* @param evtFileSize The file size filter or null.
|
||||||
* @param dsId The data source id or null.
|
* @param deletedContentFilters The set of affected deleted content filters.
|
||||||
* @param dataSourceAdded Whether or not this is a data source added event.
|
* @param dsId The data source id or null.
|
||||||
|
* @param dataSourceAdded Whether or not this is a data source added
|
||||||
|
* event.
|
||||||
*
|
*
|
||||||
* @return The set of dao events to be fired.
|
* @return The set of dao events to be fired.
|
||||||
*/
|
*/
|
||||||
private Set<DAOEvent> invalidateAndReturnEvents(Set<FileExtSearchFilter> evtExtFilters, String evtMimeType,
|
private Set<DAOEvent> invalidateAndReturnEvents(Set<FileExtSearchFilter> evtExtFilters, String evtMimeType,
|
||||||
FileSizeFilter evtFileSize, Long dsId, boolean dataSourceAdded) {
|
FileSizeFilter evtFileSize, Set<DeletedContentFilter> deletedContentFilters, Long dsId, boolean dataSourceAdded) {
|
||||||
|
|
||||||
SubDAOUtils.invalidateKeys(this.searchParamsCache,
|
SubDAOUtils.invalidateKeys(this.searchParamsCache,
|
||||||
(searchParams) -> searchParamsMatchEvent(evtExtFilters, deletedContentFilters,
|
(searchParams) -> searchParamsMatchEvent(evtExtFilters, deletedContentFilters,
|
||||||
@ -1049,8 +1074,8 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
&& (sizeParams.getDataSourceId() == null || dsId == null || Objects.equals(sizeParams.getDataSourceId(), dsId));
|
&& (sizeParams.getDataSourceId() == null || dsId == null || Objects.equals(sizeParams.getDataSourceId(), dsId));
|
||||||
} else if (searchParams instanceof DeletedContentSearchParams) {
|
} else if (searchParams instanceof DeletedContentSearchParams) {
|
||||||
DeletedContentSearchParams deletedParams = (DeletedContentSearchParams) searchParams;
|
DeletedContentSearchParams deletedParams = (DeletedContentSearchParams) searchParams;
|
||||||
return deletedContentFilters.contains(deletedParams.getFilter())
|
return (dataSourceAdded || (deletedContentFilters != null && deletedContentFilters.contains(deletedParams.getFilter())))
|
||||||
&& (deletedParams.getDataSourceId() == null || Objects.equals(deletedParams.getDataSourceId(), dsId));
|
&& (deletedParams.getDataSourceId() == null || dsId == null || Objects.equals(deletedParams.getDataSourceId(), dsId));
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1065,7 +1090,7 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
* @param mimeType The affected mime type or null.
|
* @param mimeType The affected mime type or null.
|
||||||
* @param sizeFilter The affected size filter or null.
|
* @param sizeFilter The affected size filter or null.
|
||||||
* @param dsId The file object id.
|
* @param dsId The file object id.
|
||||||
* @param dataSourceAdded A data source was added.
|
* @param dataSourceAdded A data source was added.
|
||||||
*
|
*
|
||||||
* @return The list of affected dao events.
|
* @return The list of affected dao events.
|
||||||
*/
|
*/
|
||||||
@ -1073,17 +1098,18 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
Set<DeletedContentFilter> deletedContentFilters,
|
Set<DeletedContentFilter> deletedContentFilters,
|
||||||
String mimeType,
|
String mimeType,
|
||||||
FileSizeFilter sizeFilter,
|
FileSizeFilter sizeFilter,
|
||||||
long dsId,
|
Long dsId,
|
||||||
boolean dataSourceAdded) {
|
boolean dataSourceAdded) {
|
||||||
|
|
||||||
List<DAOEvent> daoEvents = extFilters == null
|
Stream<DAOEvent> extEvents = extFilters == null
|
||||||
? new ArrayList<>()
|
? Stream.empty()
|
||||||
: extFilters.stream()
|
: extFilters.stream()
|
||||||
.map(extFilter -> new FileTypeExtensionsEvent(extFilter, dsId))
|
.map(extFilter -> new FileTypeExtensionsEvent(extFilter, dsId));
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
Stream<DAOEvent> deletedEvents = deletedContentFilters.stream()
|
Stream<DAOEvent> deletedEvents = deletedContentFilters == null
|
||||||
.map(deletedFilter -> new DeletedContentEvent(deletedFilter, dsId));
|
? Stream.empty()
|
||||||
|
: deletedContentFilters.stream()
|
||||||
|
.map(deletedFilter -> new DeletedContentEvent(deletedFilter, dsId));
|
||||||
|
|
||||||
List<DAOEvent> daoEvents = Stream.concat(extEvents, deletedEvents)
|
List<DAOEvent> daoEvents = Stream.concat(extEvents, deletedEvents)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
@ -1101,14 +1127,14 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
// data source added events are not necessarily fired before ingest completed/cancelled, so don't handle dataSourceAdded events with delay.
|
// data source added events are not necessarily fired before ingest completed/cancelled, so don't handle dataSourceAdded events with delay.
|
||||||
Set<DAOEvent> forceRefreshEvents = (dataSourceAdded)
|
Set<DAOEvent> forceRefreshEvents = (dataSourceAdded)
|
||||||
? getFileViewRefreshEvents(dsId)
|
? getFileViewRefreshEvents(dsId)
|
||||||
: Collections.emptySet();
|
: Collections.emptySet();
|
||||||
|
|
||||||
List<TreeEvent> forceRefreshTreeEvents = forceRefreshEvents.stream()
|
List<TreeEvent> forceRefreshTreeEvents = forceRefreshEvents.stream()
|
||||||
.map(evt -> new TreeEvent(createTreeItem(evt, TreeDisplayCount.UNSPECIFIED), true))
|
.map(evt -> new TreeEvent(createTreeItem(evt, TreeDisplayCount.UNSPECIFIED), true))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
return Stream.of(daoEvents, treeEvents, forceRefreshEvents, forceRefreshTreeEvents)
|
return Stream.of(daoEvents, treeEvents, forceRefreshEvents, forceRefreshTreeEvents)
|
||||||
.flatMap(lst -> lst.stream())
|
.flatMap(lst -> lst.stream())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
@ -1147,6 +1173,7 @@ public class ViewsDAO extends AbstractDAO {
|
|||||||
*/
|
*/
|
||||||
private Set<DAOEvent> getFileViewRefreshEvents(Long dataSourceId) {
|
private Set<DAOEvent> getFileViewRefreshEvents(Long dataSourceId) {
|
||||||
return ImmutableSet.of(
|
return ImmutableSet.of(
|
||||||
|
new DeletedContentEvent(null, dataSourceId),
|
||||||
new FileTypeSizeEvent(null, dataSourceId),
|
new FileTypeSizeEvent(null, dataSourceId),
|
||||||
new FileTypeExtensionsEvent(null, dataSourceId)
|
new FileTypeExtensionsEvent(null, dataSourceId)
|
||||||
);
|
);
|
||||||
|
@ -191,11 +191,29 @@ public class ViewsTypeFactory {
|
|||||||
return MainDAO.getInstance().getViewsDAO().getDeletedContentCounts(dataSourceId);
|
return MainDAO.getInstance().getViewsDAO().getDeletedContentCounts(dataSourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleDAOAggregateEvent(DAOAggregateEvent aggEvt) {
|
||||||
|
for (DAOEvent evt : aggEvt.getEvents()) {
|
||||||
|
if (evt instanceof TreeEvent) {
|
||||||
|
TreeResultsDTO.TreeItemDTO<DeletedContentSearchParams> treeItem = super.getTypedTreeItem((TreeEvent) evt, DeletedContentSearchParams.class);
|
||||||
|
// if search params has null filter, trigger full refresh
|
||||||
|
if (treeItem != null && treeItem.getSearchParams().getFilter() == null) {
|
||||||
|
super.update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.handleDAOAggregateEvent(aggEvt);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TreeResultsDTO.TreeItemDTO<? extends DeletedContentSearchParams> getOrCreateRelevantChild(TreeEvent treeEvt) {
|
protected TreeResultsDTO.TreeItemDTO<? extends DeletedContentSearchParams> getOrCreateRelevantChild(TreeEvent treeEvt) {
|
||||||
TreeResultsDTO.TreeItemDTO<DeletedContentSearchParams> originalTreeItem = super.getTypedTreeItem(treeEvt, DeletedContentSearchParams.class);
|
TreeResultsDTO.TreeItemDTO<DeletedContentSearchParams> originalTreeItem = super.getTypedTreeItem(treeEvt, DeletedContentSearchParams.class);
|
||||||
|
|
||||||
if (originalTreeItem != null
|
if (originalTreeItem != null
|
||||||
|
// only create child if size filter is present (if null, update should be triggered separately)
|
||||||
|
&& originalTreeItem.getSearchParams().getFilter() != null
|
||||||
&& (this.dataSourceId == null || Objects.equals(this.dataSourceId, originalTreeItem.getSearchParams().getDataSourceId()))) {
|
&& (this.dataSourceId == null || Objects.equals(this.dataSourceId, originalTreeItem.getSearchParams().getDataSourceId()))) {
|
||||||
|
|
||||||
// generate new type so that if it is a subtree event (i.e. keyword hits), the right tree item is created.
|
// generate new type so that if it is a subtree event (i.e. keyword hits), the right tree item is created.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user