Finished first pass

This commit is contained in:
apriestman 2021-11-02 09:08:48 -04:00
parent bc74e44d38
commit fec212ee1f
8 changed files with 676 additions and 81 deletions

View File

@ -63,7 +63,6 @@ FileSystemColumnUtils.abstractFileColumns.metaAddrColLbl=Meta Addr.
FileSystemColumnUtils.abstractFileColumns.mimeType=MIME Type FileSystemColumnUtils.abstractFileColumns.mimeType=MIME Type
FileSystemColumnUtils.abstractFileColumns.modeColLbl=Mode FileSystemColumnUtils.abstractFileColumns.modeColLbl=Mode
FileSystemColumnUtils.abstractFileColumns.modifiedTimeColLbl=Modified Time FileSystemColumnUtils.abstractFileColumns.modifiedTimeColLbl=Modified Time
FileSystemColumnUtils.abstractFileColumns.nameColLbl=Name
FileSystemColumnUtils.abstractFileColumns.objectId=Object ID FileSystemColumnUtils.abstractFileColumns.objectId=Object ID
FileSystemColumnUtils.abstractFileColumns.originalName=Original Name FileSystemColumnUtils.abstractFileColumns.originalName=Original Name
FileSystemColumnUtils.abstractFileColumns.scoreName=S FileSystemColumnUtils.abstractFileColumns.scoreName=S
@ -72,5 +71,18 @@ FileSystemColumnUtils.abstractFileColumns.sizeColLbl=Size
FileSystemColumnUtils.abstractFileColumns.typeDirColLbl=Type(Dir) FileSystemColumnUtils.abstractFileColumns.typeDirColLbl=Type(Dir)
FileSystemColumnUtils.abstractFileColumns.typeMetaColLbl=Type(Meta) FileSystemColumnUtils.abstractFileColumns.typeMetaColLbl=Type(Meta)
FileSystemColumnUtils.abstractFileColumns.useridColLbl=UserID FileSystemColumnUtils.abstractFileColumns.useridColLbl=UserID
FileSystemColumnUtils.imageColumns.devID=Device ID
FileSystemColumnUtils.imageColumns.sectorSize=Sector Size (Bytes)
FileSystemColumnUtils.imageColumns.size=Size (Bytes)
FileSystemColumnUtils.imageColumns.timezone=Timezone
FileSystemColumnUtils.imageColumns.type=Type
FileSystemColumnUtils.imageColumns.typeValue=Image
FileSystemColumnUtils.nameColumn.name=Name
FileSystemColumnUtils.noDescription=No Description FileSystemColumnUtils.noDescription=No Description
FileSystemColumnUtils.poolColumns.type=Type
FileSystemColumnUtils.volumeColumns.desc=Description
FileSystemColumnUtils.volumeColumns.flags=Flags
FileSystemColumnUtils.volumeColumns.id=ID
FileSystemColumnUtils.volumeColumns.length=Length in Sectors
FileSystemColumnUtils.volumeColumns.startingSector=Starting Sector
FileTypesByMimeType.name.text=By MIME Type FileTypesByMimeType.name.text=By MIME Type

View File

@ -19,6 +19,8 @@
package org.sleuthkit.autopsy.mainui.datamodel; package org.sleuthkit.autopsy.mainui.datamodel;
import java.util.Arrays; import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
@ -26,6 +28,7 @@ import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.Pool; import org.sleuthkit.datamodel.Pool;
@ -39,7 +42,15 @@ class FileSystemColumnUtils {
private static final Logger logger = Logger.getLogger(FileSystemColumnUtils.class.getName()); private static final Logger logger = Logger.getLogger(FileSystemColumnUtils.class.getName());
@Messages({"FileSystemColumnUtils.abstractFileColumns.nameColLbl=Name", enum ContentType {
IMAGE,
POOL,
VOLUME,
ABSTRACT_FILE,
UNSUPPORTED;
}
@Messages({"FileSystemColumnUtils.nameColumn.name=Name",
"FileSystemColumnUtils.abstractFileColumns.originalName=Original Name", "FileSystemColumnUtils.abstractFileColumns.originalName=Original Name",
"FileSystemColumnUtils.abstractFileColumns.scoreName=S", "FileSystemColumnUtils.abstractFileColumns.scoreName=S",
"FileSystemColumnUtils.abstractFileColumns.commentName=C", "FileSystemColumnUtils.abstractFileColumns.commentName=C",
@ -65,30 +76,24 @@ class FileSystemColumnUtils {
"FileSystemColumnUtils.abstractFileColumns.objectId=Object ID", "FileSystemColumnUtils.abstractFileColumns.objectId=Object ID",
"FileSystemColumnUtils.abstractFileColumns.mimeType=MIME Type", "FileSystemColumnUtils.abstractFileColumns.mimeType=MIME Type",
"FileSystemColumnUtils.abstractFileColumns.extensionColLbl=Extension", "FileSystemColumnUtils.abstractFileColumns.extensionColLbl=Extension",
"FileSystemColumnUtils.volumeColumns.nameColLbl=Name",
"FileSystemColumnUtils.volumeColumns.id=ID", "FileSystemColumnUtils.volumeColumns.id=ID",
"FileSystemColumnUtils.volumeColumns.startingSector=Starting Sector", "FileSystemColumnUtils.volumeColumns.startingSector=Starting Sector",
"FileSystemColumnUtils.volumeColumns.length=Length in Sectors", "FileSystemColumnUtils.volumeColumns.length=Length in Sectors",
"FileSystemColumnUtils.volumeColumns.desc=Description", "FileSystemColumnUtils.volumeColumns.desc=Description",
"FileSystemColumnUtils.volumeColumns.flags=Flags", "FileSystemColumnUtils.volumeColumns.flags=Flags",
"FileSystemColumnUtils.imageColumns.nameColLbl=Name",
"FileSystemColumnUtils.imageColumns.type=Type", "FileSystemColumnUtils.imageColumns.type=Type",
"FileSystemColumnUtils.imageColumns.typeValue=Image", "FileSystemColumnUtils.imageColumns.typeValue=Image",
"FileSystemColumnUtils.imageColumns.size=Size (Bytes)", "FileSystemColumnUtils.imageColumns.size=Size (Bytes)",
"FileSystemColumnUtils.imageColumns.sectorSize=Sector Size (Bytes)", "FileSystemColumnUtils.imageColumns.sectorSize=Sector Size (Bytes)",
"FileSystemColumnUtils.imageColumns.timezone=Timezone", "FileSystemColumnUtils.imageColumns.timezone=Timezone",
"FileSystemColumnUtils.imageColumns.devID=Device ID", "FileSystemColumnUtils.imageColumns.devID=Device ID",
"FileSystemColumnUtils.hostColumns.nameColLbl=Name",
"FileSystemColumnUtils.poolColumns.nameColLbl=Name",
"FileSystemColumnUtils.poolColumns.type=Type", "FileSystemColumnUtils.poolColumns.type=Type",
"FileSystemColumnUtils.noDescription=No Description"}) "FileSystemColumnUtils.noDescription=No Description"})
private static final ColumnKey NAME_COLUMN = getColumnKey(Bundle.FileSystemColumnUtils_nameColumn_name());
static final List<ColumnKey> ABSTRACT_FILE_COLUMNS = Arrays.asList( private static final List<ColumnKey> ABSTRACT_FILE_COLUMNS = Arrays.asList(
getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_nameColLbl()),
getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_originalName()), getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_originalName()),
getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_scoreName()), getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_scoreName()),
getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_commentName()), getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_commentName()),
@ -108,23 +113,21 @@ class FileSystemColumnUtils {
// getFileColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_attrAddrColLbl()), // getFileColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_attrAddrColLbl()),
// getFileColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_typeDirColLbl()), // getFileColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_typeDirColLbl()),
// getFileColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_typeMetaColLbl()), // getFileColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_typeMetaColLbl()),
getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_knownColLbl()), getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_knownColLbl()),
getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_md5HashColLbl()), getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_md5HashColLbl()),
getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_sha256HashColLbl()), getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_sha256HashColLbl()),
// getFileColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_objectId()), // getFileColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_objectId()),
getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_mimeType()), getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_mimeType()),
getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_extensionColLbl())); getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_extensionColLbl()));
static final List<ColumnKey> VOLUME_COLUMNS = Arrays.asList( private static final List<ColumnKey> VOLUME_COLUMNS = Arrays.asList(
getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_nameColLbl()),
getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_id()), getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_id()),
getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_startingSector()), getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_startingSector()),
getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_length()), getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_length()),
getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_desc()), getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_desc()),
getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_flags())); getColumnKey(Bundle.FileSystemColumnUtils_volumeColumns_flags()));
static final List<ColumnKey> IMAGE_COLUMNS = Arrays.asList( private static final List<ColumnKey> IMAGE_COLUMNS = Arrays.asList(
getColumnKey(Bundle.FileSystemColumnUtils_imageColumns_nameColLbl()),
getColumnKey(Bundle.FileSystemColumnUtils_imageColumns_type()), getColumnKey(Bundle.FileSystemColumnUtils_imageColumns_type()),
getColumnKey(Bundle.FileSystemColumnUtils_imageColumns_size()), getColumnKey(Bundle.FileSystemColumnUtils_imageColumns_size()),
getColumnKey(Bundle.FileSystemColumnUtils_imageColumns_sectorSize()), getColumnKey(Bundle.FileSystemColumnUtils_imageColumns_sectorSize()),
@ -132,83 +135,145 @@ getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_mimeType()),
getColumnKey(Bundle.FileSystemColumnUtils_imageColumns_devID()) getColumnKey(Bundle.FileSystemColumnUtils_imageColumns_devID())
); );
static final List<ColumnKey> HOST_COLUMNS = Arrays.asList( // Note that Hosts aren't content and will not be combined with other types, so we include the name here
getColumnKey(Bundle.FileSystemColumnUtils_hostColumns_nameColLbl()) private static final List<ColumnKey> HOST_COLUMNS = Arrays.asList(
NAME_COLUMN
); );
static final List<ColumnKey> POOL_COLUMNS = Arrays.asList( private static final List<ColumnKey> POOL_COLUMNS = Arrays.asList(
getColumnKey(Bundle.FileSystemColumnUtils_poolColumns_nameColLbl()),
getColumnKey(Bundle.FileSystemColumnUtils_poolColumns_type()) getColumnKey(Bundle.FileSystemColumnUtils_poolColumns_type())
); );
static List<Object> getCellValuesForPool(Pool pool) throws TskCoreException { private static ContentType getContentType(Content content) {
return Arrays.asList( if (content instanceof Image) {
pool.getType().getName(), return ContentType.IMAGE;
pool.getType().getName() } else if (content instanceof Volume) {
); return ContentType.VOLUME;
} } else if (content instanceof Pool) {
return ContentType.POOL;
static List<Object> getCellValuesForHost(Host host) throws TskCoreException { } else if (content instanceof AbstractFile) {
return Arrays.asList( return ContentType.ABSTRACT_FILE;
host.getName()
);
}
static List<Object> getCellValuesForImage(Image image) throws TskCoreException {
return Arrays.asList(
image.getName(),
Bundle.FileSystemColumnUtils_imageColumns_typeValue(),
image.getSize(),
image.getSsize(),
image.getTimeZone(),
image.getDeviceId()
);
}
static List<Object> getCellValuesForVolume(Volume vol) throws TskCoreException {
return Arrays.asList(
getVolumeDisplayName(vol),
vol.getAddr(),
vol.getStart(),
vol.getLength(),
vol.getDescription(),
vol.getFlagsAsString()
);
}
private static String getVolumeDisplayName(Volume vol) {
// set name, display name, and icon
String volName = "vol" + Long.toString(vol.getAddr());
long end = vol.getStart() + (vol.getLength() - 1);
String tempVolName = volName + " (" + vol.getDescription() + ": " + vol.getStart() + "-" + end + ")";
// If this is a pool volume use a custom display name
try {
if (vol.getParent() != null
&& vol.getParent().getParent() instanceof Pool) {
// Pool volumes are not contiguous so printing a range of blocks is inaccurate
tempVolName = volName + " (" + vol.getDescription() + ": " + vol.getStart() + ")";
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error looking up parent(s) of volume with obj ID = " + vol.getId(), ex);
} }
return tempVolName; return ContentType.UNSUPPORTED;
} }
static boolean isDisplayable(Content content) {
return (getContentType(content) != ContentType.UNSUPPORTED);
}
static List<ContentType> getDisplayableTypesForContentList(List<Content> contentList) {
List<ContentType> displayableTypes = new ArrayList<>();
for (Content content : contentList) {
ContentType type = getContentType(content);
if (type != ContentType.UNSUPPORTED && ! displayableTypes.contains(type)) {
displayableTypes.add(type);
}
}
Collections.sort(displayableTypes);
return displayableTypes;
}
static List<ColumnKey> getColumnKeysForContent(List<ContentType> contentTypes) {
List<ColumnKey> colKeys = new ArrayList<>();
colKeys.add(NAME_COLUMN);
private static ColumnKey getColumnKey(String name) { // Make sure content types are processed in the same order as in getCellValuesForContent()
return new ColumnKey(name, name, Bundle.FileSystemColumnUtils_noDescription()); if (contentTypes.contains(ContentType.IMAGE)) {
colKeys.addAll(IMAGE_COLUMNS);
}
if (contentTypes.contains(ContentType.POOL)) {
colKeys.addAll(POOL_COLUMNS);
}
if (contentTypes.contains(ContentType.VOLUME)) {
colKeys.addAll(VOLUME_COLUMNS);
}
if (contentTypes.contains(ContentType.ABSTRACT_FILE)) {
colKeys.addAll(ABSTRACT_FILE_COLUMNS);
}
return colKeys;
}
static List<Object> getCellValuesForContent(Content content, List<ContentType> contentTypes) throws TskCoreException {
List<Object> cellValues = new ArrayList<>();
cellValues.add(getNameValueForContent(content));
// Make sure content types are processed in the same order as in getColumnKeysForContent()
if (contentTypes.contains(ContentType.IMAGE)) {
cellValues.addAll(getNonNameCellValuesForImage(content));
}
if (contentTypes.contains(ContentType.POOL)) {
cellValues.addAll(getNonNameCellValuesForPool(content));
}
if (contentTypes.contains(ContentType.VOLUME)) {
cellValues.addAll(getNonNameCellValuesForVolume(content));
}
if (contentTypes.contains(ContentType.ABSTRACT_FILE)) {
cellValues.addAll(getNonNameCellValuesForAbstractFile(content));
}
return cellValues;
}
private static String getNameValueForContent(Content content) {
if (content instanceof Image) {
Image image = (Image)content;
return image.getName();
} else if (content instanceof Volume) {
Volume vol = (Volume)content;
return getVolumeDisplayName(vol);
} else if (content instanceof Pool) {
Pool pool = (Pool)content;
return pool.getType().getName(); // We currently use the type name for both the name and type fields
} else if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile)content;
return file.getName(); // GVDTODO handle . and .. from getContentDisplayName()
}
return content.getName();
}
/**
* Only use this method if all rows contain AbstractFile objects.
* Make sure the order here matches that in getCellValuesForAbstractFile();
*
* @return The list of column keys.
*/
static List<ColumnKey> getColumnKeysForAbstractfile() {
List<ColumnKey> colKeys = new ArrayList<>();
colKeys.add(NAME_COLUMN);
colKeys.addAll(ABSTRACT_FILE_COLUMNS);
return colKeys;
}
/**
* Only use this method if all rows contain AbstractFile objects.
* Make sure the order here matches that in getColumnKeysForAbstractfile();
*
* @param file The file to use to populate the cells.
*
* @return List of cell values.
*/
static List<Object> getCellValuesForAbstractFile(AbstractFile file) throws TskCoreException {
List<Object> cells = new ArrayList<>();
cells.add(getNameValueForContent(file));
cells.addAll(getNonNameCellValuesForAbstractFile(file));
return cells;
} }
/** /**
* Make sure the order here matches that in ABSTRACT_FILE_COLUMNS * Make sure the order here matches that in ABSTRACT_FILE_COLUMNS
* *
* @param file * @param content The content to use to populate the cells (may not be an abstract file)
* *
* @return * @return List of cell values
*/ */
static List<Object> getCellValuesForAbstractFile(AbstractFile file) throws TskCoreException { private static List<Object> getNonNameCellValuesForAbstractFile(Content content) throws TskCoreException {
final int nColumns = 17;
if (! (content instanceof AbstractFile)) {
return Collections.nCopies(nColumns, null);
}
// Make sure to update nColumns if the number of columns here changes
AbstractFile file = (AbstractFile) content;
return Arrays.asList( return Arrays.asList(
file.getName(), // GVDTODO handle . and .. from getContentDisplayName()
// GVDTODO translation column // GVDTODO translation column
null, null,
//GVDTDO replace nulls with SCO //GVDTDO replace nulls with SCO
@ -240,4 +305,109 @@ getColumnKey(Bundle.FileSystemColumnUtils_abstractFileColumns_mimeType()),
file.getNameExtension() file.getNameExtension()
); );
} }
/**
* Make sure the order here matches that in POOL_COLUMNS
*
* @param conent The content to use to populate the cells (may not be a pool)
*
* @return List of cell values
*/
private static List<Object> getNonNameCellValuesForPool(Content content) throws TskCoreException {
final int nColumns = 1;
if (! (content instanceof Pool)) {
return Collections.nCopies(nColumns, null);
}
// Make sure to update nColumns if the number of columns here changes
Pool pool = (Pool) content;
return Arrays.asList(
pool.getType().getName() // We currently use the type name for both the name and type fields
);
}
/**
* Make sure the order here matches that in HOST_COLUMNS
*
* @param host The host to use to populate the cells
*
* @return List of cell values
*/
static List<Object> getCellValuesForHost(Host host) throws TskCoreException {
return Arrays.asList(
host.getName()
);
}
/**
* Make sure the order here matches that in IMAGE_COLUMNS
*
* @param content The content to use to populate the cells (may not be an image)
*
* @return List of cell values
*/
private static List<Object> getNonNameCellValuesForImage(Content content) throws TskCoreException {
final int nColumns = 5;
if (! (content instanceof Image)) {
return Collections.nCopies(nColumns, null);
}
// Make sure to update nColumns if the number of columns here changes
Image image = (Image) content;
return Arrays.asList(
Bundle.FileSystemColumnUtils_imageColumns_typeValue(),
image.getSize(),
image.getSsize(),
image.getTimeZone(),
image.getDeviceId()
);
}
/**
* Make sure the order here matches that in VOLUME_COLUMNS
*
* @param content The content to use to populate the cells (may not be a volume)
*
* @return List of cell values
*/
private static List<Object> getNonNameCellValuesForVolume(Content content) throws TskCoreException {
final int nColumns = 5;
if (! (content instanceof Volume)) {
return Collections.nCopies(nColumns, null);
}
// Make sure to update nColumns if the number of columns here changes
Volume vol = (Volume) content;
return Arrays.asList(
vol.getAddr(),
vol.getStart(),
vol.getLength(),
vol.getDescription(),
vol.getFlagsAsString()
);
}
private static String getVolumeDisplayName(Volume vol) {
// set name, display name, and icon
String volName = "vol" + Long.toString(vol.getAddr());
long end = vol.getStart() + (vol.getLength() - 1);
String tempVolName = volName + " (" + vol.getDescription() + ": " + vol.getStart() + "-" + end + ")";
// If this is a pool volume use a custom display name
try {
if (vol.getParent() != null
&& vol.getParent().getParent() instanceof Pool) {
// Pool volumes are not contiguous so printing a range of blocks is inaccurate
tempVolName = volName + " (" + vol.getDescription() + ": " + vol.getStart() + ")";
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error looking up parent(s) of volume with obj ID = " + vol.getId(), ex);
}
return tempVolName;
}
private static ColumnKey getColumnKey(String name) {
return new ColumnKey(name, name, Bundle.FileSystemColumnUtils_noDescription());
}
} }

View File

@ -0,0 +1,61 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.mainui.datamodel;
import java.util.Objects;
/**
* Key for content object in order to retrieve data from DAO.
*/
public class FileSystemContentSearchParam {
private final Long contentObjectId;
public FileSystemContentSearchParam(Long contentObjectId) {
this.contentObjectId = contentObjectId;
}
public Long getContentObjectId() {
return contentObjectId;
}
@Override
public int hashCode() {
int hash = 7;
hash = 67 * hash + Objects.hashCode(this.contentObjectId);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final FileSystemContentSearchParam other = (FileSystemContentSearchParam) obj;
if (!Objects.equals(this.contentObjectId, other.contentObjectId)) {
return false;
}
return true;
}
}

View File

@ -20,7 +20,20 @@ package org.sleuthkit.autopsy.mainui.datamodel;
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 java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/** /**
* *
@ -29,7 +42,7 @@ public class FileSystemDAO {
private static final int CACHE_SIZE = 15; // rule of thumb: 5 entries times number of cached SearchParams sub-types private static final int CACHE_SIZE = 15; // rule of thumb: 5 entries times number of cached SearchParams sub-types
private static final long CACHE_DURATION = 2; private static final long CACHE_DURATION = 2;
private static final TimeUnit CACHE_DURATION_UNITS = TimeUnit.MINUTES; private static final TimeUnit CACHE_DURATION_UNITS = TimeUnit.MINUTES;
private final Cache<SearchParams<?>, SearchResultsDTO> searchParamsCache = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build(); private final Cache<SearchParams<?>, BaseSearchResultsDTO> searchParamsCache = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build();
private static final String FILE_SYSTEM_TYPE_ID = "FILE_SYSTEM"; private static final String FILE_SYSTEM_TYPE_ID = "FILE_SYSTEM";
@ -42,5 +55,105 @@ public class FileSystemDAO {
return instance; return instance;
} }
private BaseSearchResultsDTO fetchContentForTableFromContent(SearchParams<FileSystemContentSearchParam> cacheKey) throws NoCurrentCaseException, TskCoreException {
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
Long objectId = cacheKey.getParamData().getContentObjectId();
List<Content> contentForTable = new ArrayList<>();
String parentName = "";
Content parentContent = skCase.getContentById(objectId);
if (parentContent != null) {
parentName = parentContent.getName();
for (Content content : parentContent.getChildren()) {
if (FileSystemColumnUtils.isDisplayable(content)) {
contentForTable.add(content);
}
}
} else {
// The parent object may be a Host
Optional<Host> host = skCase.getHostManager().getHostById(objectId);
if (host.isPresent()) {
parentName = host.get().getName();
contentForTable.addAll(skCase.getHostManager().getDataSourcesForHost(host.get()));
} else {
throw new TskCoreException("Error loading children of object with ID " + objectId + " - ID not found in tsk_objects or tsk_hosts");
}
}
return fetchContentForTable(cacheKey, contentForTable, parentName);
}
private BaseSearchResultsDTO fetchContentForTableFromHost(SearchParams<FileSystemHostSearchParam> cacheKey) throws NoCurrentCaseException, TskCoreException {
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
Long objectId = cacheKey.getParamData().getHostObjectId();
List<Content> contentForTable = new ArrayList<>();
String parentName = "";
Optional<Host> host = skCase.getHostManager().getHostById(objectId);
if (host.isPresent()) {
parentName = host.get().getName();
contentForTable.addAll(skCase.getHostManager().getDataSourcesForHost(host.get()));
} else {
throw new TskCoreException("Error loading children of object with ID " + objectId + " - ID not found in tsk_objects or tsk_hosts");
}
return fetchContentForTable(cacheKey, contentForTable, parentName);
}
private BaseSearchResultsDTO fetchContentForTable(SearchParams<?> cacheKey, List<Content> contentForTable,
String parentName) throws NoCurrentCaseException, TskCoreException {
// Ensure consistent columns for each page by doing this before paging
List<FileSystemColumnUtils.ContentType> displayableTypes = FileSystemColumnUtils.getDisplayableTypesForContentList(contentForTable);
List<Content> pagedContent = getPaged(contentForTable, cacheKey);
List<ColumnKey> columnKeys = FileSystemColumnUtils.getColumnKeysForContent(displayableTypes);
List<RowDTO> rows = new ArrayList<>();
for (Content content : pagedContent) {
List<Object> cellValues = FileSystemColumnUtils.getCellValuesForContent(content, displayableTypes);
rows.add(new BaseRowDTO(cellValues, FILE_SYSTEM_TYPE_ID, content.getId()));
}
return new BaseSearchResultsDTO(FILE_SYSTEM_TYPE_ID, parentName, columnKeys, rows, cacheKey.getStartItem(), contentForTable.size());
}
/**
* Returns a list of paged content.
*
* @param contentObjects The content objects.
* @param searchParams The search parameters including the paging.
*
* @return The list of paged artifacts.
*/
List<Content> getPaged(List<? extends Content> contentObjects, SearchParams<?> searchParams) {
Stream<? extends Content> pagedArtsStream = contentObjects.stream()
.sorted(Comparator.comparing((conent) -> conent.getId()))
.skip(searchParams.getStartItem());
if (searchParams.getMaxResultsCount() != null) {
pagedArtsStream = pagedArtsStream.limit(searchParams.getMaxResultsCount());
}
return pagedArtsStream.collect(Collectors.toList());
}
public BaseSearchResultsDTO getContentForTable(FileSystemContentSearchParam objectKey, long startItem, Long maxCount, boolean hardRefresh) throws ExecutionException, IllegalArgumentException {
SearchParams<FileSystemContentSearchParam> searchParams = new SearchParams<>(objectKey, startItem, maxCount);
if (hardRefresh) {
searchParamsCache.invalidate(searchParams);
}
return searchParamsCache.get(searchParams, () -> fetchContentForTableFromContent(searchParams));
}
public BaseSearchResultsDTO getContentForTable(FileSystemHostSearchParam objectKey, long startItem, Long maxCount, boolean hardRefresh) throws ExecutionException, IllegalArgumentException {
SearchParams<FileSystemHostSearchParam> searchParams = new SearchParams<>(objectKey, startItem, maxCount);
if (hardRefresh) {
searchParamsCache.invalidate(searchParams);
}
return searchParamsCache.get(searchParams, () -> fetchContentForTableFromHost(searchParams));
}
} }

View File

@ -0,0 +1,62 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.mainui.datamodel;
import java.util.Objects;
/**
* Key for content object in order to retrieve data from DAO.
*/
public class FileSystemHostSearchParam {
private final Long hostObjectId;
public FileSystemHostSearchParam(Long hostObjectId) {
this.hostObjectId = hostObjectId;
}
public Long getHostObjectId() {
return hostObjectId;
}
@Override
public int hashCode() {
int hash = 7;
hash = 67 * hash + Objects.hashCode(this.hostObjectId);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final FileSystemHostSearchParam other = (FileSystemHostSearchParam) obj;
if (!Objects.equals(this.hostObjectId, other.hostObjectId)) {
return false;
}
return true;
}
}

View File

@ -37,6 +37,7 @@ public class MainDAO {
private final DataArtifactDAO dataArtifactDAO = DataArtifactDAO.getInstance(); private final DataArtifactDAO dataArtifactDAO = DataArtifactDAO.getInstance();
private final AnalysisResultDAO analysisResultDAO = AnalysisResultDAO.getInstance(); private final AnalysisResultDAO analysisResultDAO = AnalysisResultDAO.getInstance();
private final ViewsDAO viewsDAO = ViewsDAO.getInstance(); private final ViewsDAO viewsDAO = ViewsDAO.getInstance();
private final FileSystemDAO fileSystemDAO = FileSystemDAO.getInstance();
public DataArtifactDAO getDataArtifactsDAO() { public DataArtifactDAO getDataArtifactsDAO() {
return dataArtifactDAO; return dataArtifactDAO;
@ -49,4 +50,8 @@ public class MainDAO {
public ViewsDAO getViewsDAO() { public ViewsDAO getViewsDAO() {
return viewsDAO; return viewsDAO;
} }
public FileSystemDAO getFileSystemDAO() {
return fileSystemDAO;
}
} }

View File

@ -328,7 +328,7 @@ public class ViewsDAO {
cellValues)); cellValues));
} }
return new BaseSearchResultsDTO(FILE_VIEW_EXT_TYPE_ID, displayName, FileSystemColumnUtils.ABSTRACT_FILE_COLUMNS, fileRows, startItem, totalResultsCount); return new BaseSearchResultsDTO(FILE_VIEW_EXT_TYPE_ID, displayName, FileSystemColumnUtils.getColumnKeysForAbstractfile(), fileRows, startItem, totalResultsCount);
} }
/** /**

View File

@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.testutils.CaseUtils;
import org.sleuthkit.autopsy.testutils.TestUtilsException; import org.sleuthkit.autopsy.testutils.TestUtilsException;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.Attribute;
import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.Blackboard.BlackboardException; import org.sleuthkit.datamodel.Blackboard.BlackboardException;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
@ -43,10 +44,18 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataArtifact; import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.FileSystem;
import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.Pool;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.Score;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.Volume;
import org.sleuthkit.datamodel.VolumeSystem;
/** /**
* *
@ -123,6 +132,19 @@ public class TableSearchTest extends NbTestCase {
// Keyword hits test // Keyword hits test
AnalysisResult keywordHitAnalysisResult = null; // A keyword hit AnalysisResult keywordHitAnalysisResult = null; // A keyword hit
Content keywordHitSource = null; // The source of the keyword hit above Content keywordHitSource = null; // The source of the keyword hit above
// File system test
Host fsTestHostA = null; // A host
Image fsTestImageA = null; // An image
VolumeSystem fsTestVsA = null; // A volume system
Volume fsTestVolumeA1 = null; // A volume
Volume fsTestVolumeA2 = null; // Another volume
Volume fsTestVolumeA3 = null; // Another volume
FileSystem fsTestFsA = null; // A file system
AbstractFile fsTestRootDirA = null; // The root directory
Image fsTestImageB = null; // Another image
Volume fsTestVolumeB1 = null; // Another volume
Pool fsTestPoolB = null; // A pool
public static Test suite() { public static Test suite() {
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(TableSearchTest.class). NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(TableSearchTest.class).
@ -148,12 +170,14 @@ public class TableSearchTest extends NbTestCase {
mimeSearchTest(); mimeSearchTest();
extensionSearchTest(); extensionSearchTest();
sizeSearchTest(); sizeSearchTest();
fileSystemTest();
} }
/** /**
* Create a case and add sample data. * Create a case and add sample data.
*/ */
private void setUpCaseDatabase() { private void setUpCaseDatabase() {
SleuthkitCase.CaseDbTransaction trans = null;
try { try {
// Create a test case // Create a test case
openCase = CaseUtils.createAsCurrentCase("testTableSearchCase"); openCase = CaseUtils.createAsCurrentCase("testTableSearchCase");
@ -161,11 +185,12 @@ public class TableSearchTest extends NbTestCase {
blackboard = db.getBlackboard(); blackboard = db.getBlackboard();
// Add two logical files data sources // Add two logical files data sources
SleuthkitCase.CaseDbTransaction trans = db.beginTransaction(); trans = db.beginTransaction();
dataSource1 = db.addLocalFilesDataSource("devId1", "C:\\Fake\\Path\\1", "EST", null, trans); dataSource1 = db.addLocalFilesDataSource("devId1", "C:\\Fake\\Path\\1", "EST", null, trans);
dataSource2 = db.addLocalFilesDataSource("devId2", "C:\\Fake\\Path\\2", "EST", null, trans); dataSource2 = db.addLocalFilesDataSource("devId2", "C:\\Fake\\Path\\2", "EST", null, trans);
dataSource3 = db.addLocalFilesDataSource("devId3", "C:\\Fake\\Path\\3", "EST", null, trans); dataSource3 = db.addLocalFilesDataSource("devId3", "C:\\Fake\\Path\\3", "EST", null, trans);
trans.commit(); trans.commit();
trans = null;
// Add files // Add files
AbstractFile folderA1 = db.addLocalDirectory(dataSource1.getId(), "folder1"); AbstractFile folderA1 = db.addLocalDirectory(dataSource1.getId(), "folder1");
@ -306,7 +331,81 @@ public class TableSearchTest extends NbTestCase {
null, KEYWORD_SET_1, null, attrs).getAnalysisResult(); null, KEYWORD_SET_1, null, attrs).getAnalysisResult();
keywordHitSource = hashHitAnalysisResult; keywordHitSource = hashHitAnalysisResult;
// Create a normal image
// fsTestImageA (Host: fsTestHostA)
// - fsTestVsA
// -- fsTestVolumeA1
// --- fsTestFsA
// ---- fsTestRootDirA
// ----- (3 files)
// -- fsTestVolumeA2
// -- fsTestVolumeA3
fsTestHostA = db.getHostManager().newHost("File system test host");
trans = db.beginTransaction();
fsTestImageA = db.addImage(TskData.TSK_IMG_TYPE_ENUM.TSK_IMG_TYPE_DETECT, 512, 1024, "image1", Arrays.asList("C:\\Fake\\Path\\4"),
"EST", null, null, null, "deviceID12345", fsTestHostA, trans);
fsTestVsA = db.addVolumeSystem(fsTestImageA.getId(), TskData.TSK_VS_TYPE_ENUM.TSK_VS_TYPE_DOS, 0, 1024, trans);
fsTestVolumeA1 = db.addVolume(fsTestVsA.getId(), 0, 0, 512, "Test vol A1", 0, trans);
fsTestVolumeA2 = db.addVolume(fsTestVsA.getId(), 1, 512, 512, "Test vol A2", 0, trans);
fsTestVolumeA3 = db.addVolume(fsTestVsA.getId(), 2, 1024, 512, "Test vol A3", 0, trans);
fsTestFsA = db.addFileSystem(fsTestVolumeA1.getId(), 0, TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_EXT2, 512, 1,
1, 1, 10, "Test file system", trans);
trans.commit();
trans = null;
fsTestRootDirA = db.addFileSystemFile(fsTestImageA.getId(), fsTestFsA.getId(),
"", 0, 0,
TskData.TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0,
TskData.TSK_FS_NAME_FLAG_ENUM.ALLOC, (short)0, 128,
0, 0, 0, 0, false, fsTestFsA);
db.addFileSystemFile(fsTestImageA.getId(), fsTestFsA.getId(),
"Test file 1", 0, 0,
TskData.TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0,
TskData.TSK_FS_NAME_FLAG_ENUM.ALLOC, (short)0, 123,
0, 0, 0, 0, false, fsTestRootDirA);
db.addFileSystemFile(fsTestImageA.getId(), fsTestFsA.getId(),
"Test file 2", 0, 0,
TskData.TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0,
TskData.TSK_FS_NAME_FLAG_ENUM.ALLOC, (short)0, 456,
0, 0, 0, 0, false, fsTestRootDirA);
db.addFileSystemFile(fsTestImageA.getId(), fsTestFsA.getId(),
"Test file 3", 0, 0,
TskData.TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0,
TskData.TSK_FS_NAME_FLAG_ENUM.ALLOC, (short)0, 789,
0, 0, 0, 0, false, fsTestRootDirA);
// Create an image with some odd structures for testing
trans = db.beginTransaction();
fsTestImageB = db.addImage(TskData.TSK_IMG_TYPE_ENUM.TSK_IMG_TYPE_DETECT, 512, 1024, "image2", Arrays.asList("C:\\Fake\\Path\\5"),
"EST", null, null, null, "deviceID678", fsTestHostA, trans);
// Images can have VS, pool, FS, file, artifact, and report children.
// Add a VS, pool, and local file
VolumeSystem vsB = db.addVolumeSystem(fsTestImageB.getId(), TskData.TSK_VS_TYPE_ENUM.TSK_VS_TYPE_BSD, 0, 2048, trans);
db.addPool(fsTestImageB.getId(), TskData.TSK_POOL_TYPE_ENUM.TSK_POOL_TYPE_APFS, trans);
db.addLocalFile("Test local file B1", "C:\\Fake\\Path\\6", 6000, 0, 0, 0, 0,
true, TskData.EncodingType.NONE, fsTestImageB, trans);
// Volumes can have pool, FS, file, and artifact children
fsTestVolumeB1 = db.addVolume(vsB.getId(), 0, 0, 512, "Test vol B1", 0, trans);
fsTestPoolB = db.addPool(fsTestVolumeB1.getId(), TskData.TSK_POOL_TYPE_ENUM.TSK_POOL_TYPE_APFS, trans);
db.addLocalFile("Test local file B2", "C:\\Fake\\Path\\7", 7000, 0, 0, 0, 0,
true, TskData.EncodingType.NONE, fsTestVolumeB1, trans);
// Pools can have VS, file, and artifact children
db.addVolumeSystem(fsTestPoolB.getId(), TskData.TSK_VS_TYPE_ENUM.TSK_VS_TYPE_GPT, 0, 2048, trans);
db.addLocalFile("Test local file B3", "C:\\Fake\\Path\\8", 8000, 0, 0, 0, 0,
true, TskData.EncodingType.NONE, fsTestPoolB, trans);
trans.commit();
trans = null;
} catch (TestUtilsException | TskCoreException | BlackboardException ex) { } catch (TestUtilsException | TskCoreException | BlackboardException ex) {
if (trans != null) {
try {
trans.rollback();
} catch (TskCoreException ex2) {
ex2.printStackTrace();
}
}
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
Assert.fail(ex.getMessage()); Assert.fail(ex.getMessage());
} }
@ -611,7 +710,7 @@ public class TableSearchTest extends NbTestCase {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
Assert.fail(ex.getMessage()); Assert.fail(ex.getMessage());
} }
} }
public void extensionSearchTest() { public void extensionSearchTest() {
// Quick test that everything is initialized // Quick test that everything is initialized
@ -673,6 +772,79 @@ public class TableSearchTest extends NbTestCase {
Assert.fail(ex.getMessage()); Assert.fail(ex.getMessage());
} }
} }
private void fileSystemTest() {
// Quick test that everything is initialized
assertTrue(db != null);
try {
FileSystemDAO fileSystemDAO = MainDAO.getInstance().getFileSystemDAO();
// HostA is associated with two images
FileSystemHostSearchParam hostParam = new FileSystemHostSearchParam(fsTestHostA.getHostId());
BaseSearchResultsDTO results = fileSystemDAO.getContentForTable(hostParam, 0, null, false);
assertEquals(2, results.getTotalResultsCount());
assertEquals(2, results.getItems().size());
// ImageA has one volumne system child which we don't display
FileSystemContentSearchParam param = new FileSystemContentSearchParam(fsTestImageA.getId());
results = fileSystemDAO.getContentForTable(param, 0, null, false);
assertEquals(0, results.getTotalResultsCount());
assertEquals(0, results.getItems().size());
// VsA has three volume children
param = new FileSystemContentSearchParam(fsTestVsA.getId());
results = fileSystemDAO.getContentForTable(param, 0, null, false);
assertEquals(3, results.getTotalResultsCount());
assertEquals(3, results.getItems().size());
// VolumeA1 has a file system child which we don't display
param = new FileSystemContentSearchParam(fsTestVolumeA1.getId());
results = fileSystemDAO.getContentForTable(param, 0, null, false);
assertEquals(0, results.getTotalResultsCount());
assertEquals(0, results.getItems().size());
// FsA has the root folder as its child. We don't actually display this,
// but I'm not sure the DAO is responible for figuring that out.
param = new FileSystemContentSearchParam(fsTestFsA.getId());
results = fileSystemDAO.getContentForTable(param, 0, null, false);
assertEquals(1, results.getTotalResultsCount());
assertEquals(1, results.getItems().size());
// The root dir contains three files
param = new FileSystemContentSearchParam(fsTestRootDirA.getId());
results = fileSystemDAO.getContentForTable(param, 0, null, false);
assertEquals(3, results.getTotalResultsCount());
assertEquals(3, results.getItems().size());
// ImageB has VS (not displayed), pool, and one local file children
param = new FileSystemContentSearchParam(fsTestImageB.getId());
results = fileSystemDAO.getContentForTable(param, 0, null, false);
assertEquals(2, results.getTotalResultsCount());
assertEquals(2, results.getItems().size());
// Check that we have the "Type" column from the Pool and the "Known" column from the file
List<String> columnDisplayNames = results.getColumns().stream().map(p -> p.getDisplayName()).collect(Collectors.toList());
assertTrue(columnDisplayNames.contains("Type"));
assertTrue(columnDisplayNames.contains("Known"));
// fsTestVolumeB1 has pool and one local file children
param = new FileSystemContentSearchParam(fsTestVolumeB1.getId());
results = fileSystemDAO.getContentForTable(param, 0, null, false);
assertEquals(2, results.getTotalResultsCount());
assertEquals(2, results.getItems().size());
// fsTestPoolB has VS (not displayed) and local file children
param = new FileSystemContentSearchParam(fsTestPoolB.getId());
results = fileSystemDAO.getContentForTable(param, 0, null, false);
assertEquals(1, results.getTotalResultsCount());
assertEquals(1, results.getItems().size());
} catch (ExecutionException ex) {
Exceptions.printStackTrace(ex);
Assert.fail(ex.getMessage());
}
}
private enum CustomRootFilter implements FileExtSearchFilter { private enum CustomRootFilter implements FileExtSearchFilter {