Moved file type export functionality

This commit is contained in:
Eugene Livis 2021-08-06 17:31:44 -04:00
parent 0aa708388c
commit e948b14c86
9 changed files with 653 additions and 198 deletions

View File

@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentutils;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
@ -45,10 +46,12 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM;
*/ */
public final class DataSourceInfoUtilities { public final class DataSourceInfoUtilities {
public static final String COMMA_FORMAT_STR = "#,###";
public static final DecimalFormat COMMA_FORMATTER = new DecimalFormat(COMMA_FORMAT_STR);
/** /**
* Gets a count of tsk_files for a particular datasource. * Gets a count of tsk_files for a particular datasource.
* *
* @param skCase The current SleuthkitCase.
* @param currentDataSource The datasource. * @param currentDataSource The datasource.
* @param additionalWhere Additional sql where clauses. * @param additionalWhere Additional sql where clauses.
* *
@ -56,11 +59,12 @@ public final class DataSourceInfoUtilities {
* *
* @throws TskCoreException * @throws TskCoreException
* @throws SQLException * @throws SQLException
* @throws NoCurrentCaseException
*/ */
public static Long getCountOfTskFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) public static Long getCountOfTskFiles(DataSource currentDataSource, String additionalWhere)
throws TskCoreException, SQLException { throws TskCoreException, SQLException, NoCurrentCaseException {
if (currentDataSource != null) { if (currentDataSource != null) {
return skCase.countFilesWhere( return Case.getCurrentCaseThrows().getSleuthkitCase().countFilesWhere(
"data_source_obj_id=" + currentDataSource.getId() "data_source_obj_id=" + currentDataSource.getId()
+ (StringUtils.isBlank(additionalWhere) ? "" : (" AND " + additionalWhere))); + (StringUtils.isBlank(additionalWhere) ? "" : (" AND " + additionalWhere)));
} }
@ -70,7 +74,6 @@ public final class DataSourceInfoUtilities {
/** /**
* Gets a count of regular files for a particular datasource. * Gets a count of regular files for a particular datasource.
* *
* @param skCase The current SleuthkitCase.
* @param currentDataSource The datasource. * @param currentDataSource The datasource.
* @param additionalWhere Additional sql where clauses. * @param additionalWhere Additional sql where clauses.
* *
@ -78,22 +81,22 @@ public final class DataSourceInfoUtilities {
* *
* @throws TskCoreException * @throws TskCoreException
* @throws SQLException * @throws SQLException
* @throws NoCurrentCaseException
*/ */
public static Long getCountOfRegularFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) public static Long getCountOfRegularFiles(DataSource currentDataSource, String additionalWhere)
throws TskCoreException, SQLException { throws TskCoreException, SQLException, NoCurrentCaseException {
String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue(); String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue();
if (StringUtils.isNotBlank(additionalWhere)) { if (StringUtils.isNotBlank(additionalWhere)) {
whereClause += " AND " + additionalWhere; whereClause += " AND " + additionalWhere;
} }
return getCountOfTskFiles(skCase, currentDataSource, whereClause); return getCountOfTskFiles(currentDataSource, whereClause);
} }
/** /**
* Gets a count of regular non-slack files for a particular datasource. * Gets a count of regular non-slack files for a particular datasource.
* *
* @param skCase The current SleuthkitCase.
* @param currentDataSource The datasource. * @param currentDataSource The datasource.
* @param additionalWhere Additional sql where clauses. * @param additionalWhere Additional sql where clauses.
* *
@ -101,9 +104,10 @@ public final class DataSourceInfoUtilities {
* *
* @throws TskCoreException * @throws TskCoreException
* @throws SQLException * @throws SQLException
* @throws NoCurrentCaseException
*/ */
public static Long getCountOfRegNonSlackFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) public static Long getCountOfRegNonSlackFiles(DataSource currentDataSource, String additionalWhere)
throws TskCoreException, SQLException { throws TskCoreException, SQLException, NoCurrentCaseException {
String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()
+ " AND type<>" + TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType(); + " AND type<>" + TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType();
@ -111,7 +115,7 @@ public final class DataSourceInfoUtilities {
whereClause += " AND " + additionalWhere; whereClause += " AND " + additionalWhere;
} }
return getCountOfTskFiles(skCase, currentDataSource, whereClause); return getCountOfTskFiles(currentDataSource, whereClause);
} }
/** /**
@ -429,4 +433,27 @@ public final class DataSourceInfoUtilities {
Long longVal = getLongOrNull(artifact, attributeType); Long longVal = getLongOrNull(artifact, attributeType);
return (longVal == null || longVal == 0) ? null : new Date(longVal * 1000); return (longVal == null || longVal == 0) ? null : new Date(longVal * 1000);
} }
/**
* Returns the long value or zero if longVal is null.
*
* @param longVal The long value.
*
* @return The long value or 0 if provided value is null.
*/
public static long getLongOrZero(Long longVal) {
return longVal == null ? 0 : longVal;
}
/**
* Returns string value of long with comma separators. If null returns a
* string of '0'.
*
* @param longVal The long value.
*
* @return The string value of the long.
*/
public static String getStringOrZero(Long longVal) {
return longVal == null ? "0" : COMMA_FORMATTER.format(longVal);
}
} }

View File

@ -22,14 +22,11 @@ import java.nio.file.Paths;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;

View File

@ -0,0 +1,182 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 - 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.contentutils;
import java.awt.Color;
import java.sql.SQLException;
import java.util.Set;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.FileTypeUtils;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Helper class for getting summary information on the known files present in the
* specified DataSource..
*/
public class TypesSummary {
private TypesSummary() {
}
/**
* Get count of regular files (not directories) in a data source.
*
* @param currentDataSource The data source.
*
* @return The count.
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfFiles(DataSource currentDataSource)
throws TskCoreException, SQLException, NoCurrentCaseException {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, null);
}
/**
* Get count of allocated files in a data source.
*
* @param currentDataSource The data source.
*
* @return The count.
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfAllocatedFiles(DataSource currentDataSource)
throws TskCoreException, SQLException, NoCurrentCaseException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.ALLOC));
}
/**
* Get count of unallocated files in a data source.
*
* @param currentDataSource The data source.
*
* @return The count.
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfUnallocatedFiles(DataSource currentDataSource)
throws NoCurrentCaseException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC));
}
/**
* Get count of directories in a data source.
*
* @param currentDataSource The data source.
*
* @return The count.
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfDirectories(DataSource currentDataSource)
throws NoCurrentCaseException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfTskFiles(currentDataSource,
"meta_type=" + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
+ " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
}
/**
* Get count of slack files in a data source.
*
* @param currentDataSource The data source.
*
* @return The count.
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfSlackFiles(DataSource currentDataSource)
throws NoCurrentCaseException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource,
"type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType());
}
/**
* Information concerning a particular file type category.
*/
public static class FileTypeCategoryData {
private final String label;
private final Set<String> mimeTypes;
private final Color color;
/**
* Main constructor.
*
* @param label The label for this slice.
* @param mimeTypes The mime types associated with this slice.
* @param color The color associated with this slice.
*/
public FileTypeCategoryData(String label, Set<String> mimeTypes, Color color) {
this.label = label;
this.mimeTypes = mimeTypes;
this.color = color;
}
/**
* Constructor that accepts FileTypeCategory.
*
* @param label The label for this slice.
* @param mimeTypes The mime types associated with this slice.
* @param color The color associated with this slice.
*/
public FileTypeCategoryData(String label, FileTypeUtils.FileTypeCategory fileCategory, Color color) {
this(label, fileCategory.getMediaTypes(), color);
}
/**
* @return The label for this category.
*/
public String getLabel() {
return label;
}
/**
* @return The mime types associated with this category.
*/
public Set<String> getMimeTypes() {
return mimeTypes;
}
/**
* @return The color associated with this category.
*/
public Color getColor() {
return color;
}
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2020 Basis Technology Corp. * Copyright 2020-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -21,10 +21,12 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
@ -34,11 +36,10 @@ import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Provides methods to query for datasource files by mime type. * Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary
* functionality into a DefaultArtifactUpdateGovernor used by TypesPanel tab.
*/ */
public class MimeTypeSummary implements DefaultUpdateGovernor { public class MimeTypeSummaryGetter implements DefaultUpdateGovernor {
private final SleuthkitCaseProvider provider;
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>( private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>(
Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED));
@ -46,17 +47,7 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
/** /**
* Main constructor. * Main constructor.
*/ */
public MimeTypeSummary() { public MimeTypeSummaryGetter() {
this(SleuthkitCaseProvider.DEFAULT);
}
/**
* Main constructor.
*
* @param provider The means of obtaining a sleuthkit case.
*/
public MimeTypeSummary(SleuthkitCaseProvider provider) {
this.provider = provider;
} }
@Override @Override
@ -76,7 +67,7 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
@Override @Override
public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() { public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() {
return INGEST_JOB_EVENTS; return Collections.unmodifiableSet(INGEST_JOB_EVENTS);
} }
/** /**
@ -99,12 +90,11 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
*/ */
public Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes) public Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
try {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles( return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes));
provider.get(), } catch (NoCurrentCaseException ex) {
currentDataSource, throw new SleuthkitCaseProviderException("No currently open case.", ex);
"mime_type IN " + getSqlSet(setOfMimeTypes) }
);
} }
/** /**
@ -125,13 +115,13 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
*/ */
public Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes) public Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
try {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles( return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
provider.get(),
currentDataSource,
"mime_type NOT IN " + getSqlSet(setOfMimeTypes) "mime_type NOT IN " + getSqlSet(setOfMimeTypes)
+ " AND mime_type IS NOT NULL AND mime_type <> '' " + " AND mime_type IS NOT NULL AND mime_type <> '' ");
); } catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
} }
/** /**
@ -147,8 +137,11 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
*/ */
public Long getCountOfAllRegularFiles(DataSource dataSource) public Long getCountOfAllRegularFiles(DataSource dataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
try {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), dataSource, null); return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(dataSource, null);
} catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
} }
/** /**
@ -165,12 +158,11 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
*/ */
public Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) public Long getCountOfFilesWithNoMimeType(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
try {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles( return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "(mime_type IS NULL OR mime_type = '') ");
provider.get(), } catch (NoCurrentCaseException ex) {
currentDataSource, throw new SleuthkitCaseProviderException("No currently open case.", ex);
"(mime_type IS NULL OR mime_type = '') " }
);
} }
/** /**

View File

@ -21,41 +21,31 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.contentutils.TypesSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/** /**
* Provides information for the DataSourceSummaryCountsPanel. * Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary functionality into a
* DefaultArtifactUpdateGovernor used by DataSourceSummaryCountsPanel.
*/ */
public class TypesSummary implements DefaultUpdateGovernor { public class TypesSummaryGetter implements DefaultUpdateGovernor {
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>( private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>(
Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED));
private final SleuthkitCaseProvider provider;
/** /**
* Main constructor. * Main constructor.
*/ */
public TypesSummary() { public TypesSummaryGetter() {
this(SleuthkitCaseProvider.DEFAULT);
}
/**
* Main constructor.
*
* @param provider The means of obtaining a sleuthkit case.
*/
public TypesSummary(SleuthkitCaseProvider provider) {
this.provider = provider;
} }
@Override @Override
@ -75,7 +65,7 @@ public class TypesSummary implements DefaultUpdateGovernor {
@Override @Override
public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() { public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() {
return INGEST_JOB_EVENTS; return Collections.unmodifiableSet(INGEST_JOB_EVENTS);
} }
/** /**
@ -91,11 +81,11 @@ public class TypesSummary implements DefaultUpdateGovernor {
*/ */
public Long getCountOfFiles(DataSource currentDataSource) public Long getCountOfFiles(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegularFiles( try {
provider.get(), return TypesSummary.getCountOfFiles(currentDataSource);
currentDataSource, } catch (NoCurrentCaseException ex) {
null throw new SleuthkitCaseProviderException("No currently open case.", ex);
); }
} }
/** /**
@ -111,9 +101,11 @@ public class TypesSummary implements DefaultUpdateGovernor {
*/ */
public Long getCountOfAllocatedFiles(DataSource currentDataSource) public Long getCountOfAllocatedFiles(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
try {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, return TypesSummary.getCountOfAllocatedFiles(currentDataSource);
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)); } catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
} }
/** /**
@ -129,9 +121,11 @@ public class TypesSummary implements DefaultUpdateGovernor {
*/ */
public Long getCountOfUnallocatedFiles(DataSource currentDataSource) public Long getCountOfUnallocatedFiles(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
try {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, return TypesSummary.getCountOfUnallocatedFiles(currentDataSource);
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)); } catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
} }
/** /**
@ -147,10 +141,11 @@ public class TypesSummary implements DefaultUpdateGovernor {
*/ */
public Long getCountOfDirectories(DataSource currentDataSource) public Long getCountOfDirectories(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
try {
return DataSourceInfoUtilities.getCountOfTskFiles(provider.get(), currentDataSource, return TypesSummary.getCountOfDirectories(currentDataSource);
"meta_type=" + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue() } catch (NoCurrentCaseException ex) {
+ " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()); throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
} }
/** /**
@ -166,8 +161,10 @@ public class TypesSummary implements DefaultUpdateGovernor {
*/ */
public Long getCountOfSlackFiles(DataSource currentDataSource) public Long getCountOfSlackFiles(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
try {
return DataSourceInfoUtilities.getCountOfRegularFiles(provider.get(), currentDataSource, return TypesSummary.getCountOfSlackFiles(currentDataSource);
"type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()); } catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2019 Basis Technology Corp. * Copyright 2019-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -23,17 +23,17 @@ import java.sql.SQLException;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary; import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities;
import org.sleuthkit.autopsy.contentutils.TypesSummary.FileTypeCategoryData;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummaryGetter;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummaryGetter; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummaryGetter;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummaryGetter;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType;
@ -90,7 +90,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
* @param usefulContent True if this is useful content; false if there * @param usefulContent True if this is useful content; false if there
* is 0 mime type information. * is 0 mime type information.
*/ */
public TypesPieChartData(List<PieChartItem> pieSlices, boolean usefulContent) { TypesPieChartData(List<PieChartItem> pieSlices, boolean usefulContent) {
this.pieSlices = pieSlices; this.pieSlices = pieSlices;
this.usefulContent = usefulContent; this.usefulContent = usefulContent;
} }
@ -98,78 +98,20 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
/** /**
* @return The pie chart data. * @return The pie chart data.
*/ */
public List<PieChartItem> getPieSlices() { List<PieChartItem> getPieSlices() {
return pieSlices; return pieSlices;
} }
/** /**
* @return Whether or not the data is usefulContent. * @return Whether or not the data is usefulContent.
*/ */
public boolean isUsefulContent() { boolean isUsefulContent() {
return usefulContent; return usefulContent;
} }
} }
/**
* Information concerning a particular category in the file types pie chart.
*/
private static class TypesPieCategory {
private final String label;
private final Set<String> mimeTypes;
private final Color color;
/**
* Main constructor.
*
* @param label The label for this slice.
* @param mimeTypes The mime types associated with this slice.
* @param color The color associated with this slice.
*/
TypesPieCategory(String label, Set<String> mimeTypes, Color color) {
this.label = label;
this.mimeTypes = mimeTypes;
this.color = color;
}
/**
* Constructor that accepts FileTypeCategory.
*
* @param label The label for this slice.
* @param mimeTypes The mime types associated with this slice.
* @param color The color associated with this slice.
*/
TypesPieCategory(String label, FileTypeCategory fileCategory, Color color) {
this(label, fileCategory.getMediaTypes(), color);
}
/**
* @return The label for this category.
*/
String getLabel() {
return label;
}
/**
* @return The mime types associated with this category.
*/
Set<String> getMimeTypes() {
return mimeTypes;
}
/**
* @return The color associated with this category.
*/
Color getColor() {
return color;
}
}
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#"); private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#");
private static final String COMMA_FORMAT_STR = "#,###";
private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat(COMMA_FORMAT_STR);
private static final Color IMAGES_COLOR = new Color(156, 39, 176); private static final Color IMAGES_COLOR = new Color(156, 39, 176);
private static final Color VIDEOS_COLOR = Color.YELLOW; private static final Color VIDEOS_COLOR = Color.YELLOW;
@ -181,13 +123,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
private static final Color NOT_ANALYZED_COLOR = Color.WHITE; private static final Color NOT_ANALYZED_COLOR = Color.WHITE;
// All file type categories. // All file type categories.
private static final List<TypesPieCategory> FILE_MIME_TYPE_CATEGORIES = Arrays.asList( private static final List<FileTypeCategoryData> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR), new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR),
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR), new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR),
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR), new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR),
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR), new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR),
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR), new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR),
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR) new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR)
); );
private final DataFetcher<DataSource, String> usageFetcher; private final DataFetcher<DataSource, String> usageFetcher;
@ -233,7 +175,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
* Creates a new TypesPanel. * Creates a new TypesPanel.
*/ */
public TypesPanel() { public TypesPanel() {
this(new MimeTypeSummary(), new TypesSummary(), new ContainerSummaryGetter()); this(new MimeTypeSummaryGetter(), new TypesSummaryGetter(), new ContainerSummaryGetter());
} }
@Override @Override
@ -250,8 +192,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
* @param containerData The service for container information. * @param containerData The service for container information.
*/ */
public TypesPanel( public TypesPanel(
MimeTypeSummary mimeTypeData, MimeTypeSummaryGetter mimeTypeData,
TypesSummary typeData, TypesSummaryGetter typeData,
ContainerSummaryGetter containerData) { ContainerSummaryGetter containerData) {
super(mimeTypeData, typeData, containerData); super(mimeTypeData, typeData, containerData);
@ -277,13 +219,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
size -> SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false)))), size -> SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false)))),
new DataFetchWorker.DataFetchComponents<>(typesFetcher, this::showMimeTypeCategories), new DataFetchWorker.DataFetchComponents<>(typesFetcher, this::showMimeTypeCategories),
new DataFetchWorker.DataFetchComponents<>(allocatedFetcher, new DataFetchWorker.DataFetchComponents<>(allocatedFetcher,
countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))), countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))),
new DataFetchWorker.DataFetchComponents<>(unallocatedFetcher, new DataFetchWorker.DataFetchComponents<>(unallocatedFetcher,
countRes -> unallocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))), countRes -> unallocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))),
new DataFetchWorker.DataFetchComponents<>(slackFetcher, new DataFetchWorker.DataFetchComponents<>(slackFetcher,
countRes -> slackLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))), countRes -> slackLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))),
new DataFetchWorker.DataFetchComponents<>(directoriesFetcher, new DataFetchWorker.DataFetchComponents<>(directoriesFetcher,
countRes -> directoriesLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))) countRes -> directoriesLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count))))
); );
initComponents(); initComponents();
@ -307,7 +249,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
* *
* @return The pie chart items. * @return The pie chart items.
*/ */
private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummary mimeTypeData, DataSource dataSource) private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummaryGetter mimeTypeData, DataSource dataSource)
throws SQLException, SleuthkitCaseProviderException, TskCoreException { throws SQLException, SleuthkitCaseProviderException, TskCoreException {
if (dataSource == null) { if (dataSource == null) {
@ -318,8 +260,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
List<PieChartItem> fileCategoryItems = new ArrayList<>(); List<PieChartItem> fileCategoryItems = new ArrayList<>();
long categoryTotalCount = 0; long categoryTotalCount = 0;
for (TypesPieCategory cat : FILE_MIME_TYPE_CATEGORIES) { for (FileTypeCategoryData cat : FILE_MIME_TYPE_CATEGORIES) {
long thisValue = getLongOrZero(mimeTypeData.getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes())); long thisValue = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes()));
categoryTotalCount += thisValue; categoryTotalCount += thisValue;
fileCategoryItems.add(new PieChartItem( fileCategoryItems.add(new PieChartItem(
@ -329,10 +271,10 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
} }
// get a count of all files with no mime type // get a count of all files with no mime type
long noMimeTypeCount = getLongOrZero(mimeTypeData.getCountOfFilesWithNoMimeType(dataSource)); long noMimeTypeCount = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfFilesWithNoMimeType(dataSource));
// get a count of all regular files // get a count of all regular files
long allRegularFiles = getLongOrZero(mimeTypeData.getCountOfAllRegularFiles(dataSource)); long allRegularFiles = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfAllRegularFiles(dataSource));
// create entry for mime types in other category // create entry for mime types in other category
long otherCount = allRegularFiles - (categoryTotalCount + noMimeTypeCount); long otherCount = allRegularFiles - (categoryTotalCount + noMimeTypeCount);
@ -385,29 +327,6 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
} }
} }
/**
* Returns the long value or zero if longVal is null.
*
* @param longVal The long value.
*
* @return The long value or 0 if provided value is null.
*/
private static long getLongOrZero(Long longVal) {
return longVal == null ? 0 : longVal;
}
/**
* Returns string value of long with comma separators. If null returns a
* string of '0'.
*
* @param longVal The long value.
*
* @return The string value of the long.
*/
private static String getStringOrZero(Long longVal) {
return longVal == null ? "0" : COMMA_FORMATTER.format(longVal);
}
/** /**
* Returns a key value pair to be exported in a sheet. * Returns a key value pair to be exported in a sheet.
* *

View File

@ -5,6 +5,7 @@ DataSourceSummaryReport.endReport.srcModuleName.text=Excel Report
ExcelExport_writeExcel_noSheetName=Sheet {0} ExcelExport_writeExcel_noSheetName=Sheet {0}
ExcelExportAction_exportToXLSX_beginExport=Beginning Export... ExcelExportAction_exportToXLSX_beginExport=Beginning Export...
ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data
ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data
ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data
ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data
ExcelExportAction_exportToXLSX_writingToFile=Writing to File... ExcelExportAction_exportToXLSX_writingToFile=Writing to File...
@ -32,6 +33,25 @@ ExportRecentFiles_col_header_path=Path
ExportRecentFiles_col_header_sender=Sender ExportRecentFiles_col_header_sender=Sender
ExportRecentFiles_docsTable_tabName=Recently Opened Documents ExportRecentFiles_docsTable_tabName=Recently Opened Documents
ExportRecentFiles_downloadsTable_tabName=Recently Downloads ExportRecentFiles_downloadsTable_tabName=Recently Downloads
ExportTypes_artifactsTypesPieChart_title=Artifact Types
ExportTypes_excelTabName=Types
ExportTypes_fileMimeTypesChart_audio_title=Audio
ExportTypes_fileMimeTypesChart_documents_title=Documents
ExportTypes_fileMimeTypesChart_executables_title=Executables
ExportTypes_fileMimeTypesChart_images_title=Images
ExportTypes_fileMimeTypesChart_notAnalyzed_title=Not Analyzed
ExportTypes_fileMimeTypesChart_other_title=Other
ExportTypes_fileMimeTypesChart_title=File Types
ExportTypes_fileMimeTypesChart_unknown_title=Unknown
ExportTypes_fileMimeTypesChart_valueLabel=Count
ExportTypes_fileMimeTypesChart_videos_title=Videos
ExportTypes_filesByCategoryTable_allocatedRow_title=Allocated Files
ExportTypes_filesByCategoryTable_directoryRow_title=Directories
ExportTypes_filesByCategoryTable_slackRow_title=Slack Files
ExportTypes_filesByCategoryTable_unallocatedRow_title=Unallocated Files
ExportTypes_osLabel_title=OS
ExportTypes_sizeLabel_title=Size
ExportTypes_usageLabel_title=Usage
SizeRepresentationUtil_units_bytes=bytes SizeRepresentationUtil_units_bytes=bytes
SizeRepresentationUtil_units_gigabytes=GB SizeRepresentationUtil_units_gigabytes=GB
SizeRepresentationUtil_units_kilobytes=KB SizeRepresentationUtil_units_kilobytes=KB

View File

@ -93,6 +93,7 @@ class ExcelExportAction {
"ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data", "ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data",
"ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data", "ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data",
"ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data", "ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data",
"ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data",
"ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",})
void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir) void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir)
@ -129,6 +130,14 @@ class ExcelExportAction {
sheetExports.addAll(exports); sheetExports.addAll(exports);
} }
// Export file and MIME type data
progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringFileData());
progressPanel.setProgress(4);
exports = ExportTypes.getExports(dataSource);
if (exports != null) {
sheetExports.addAll(exports);
}
progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile());
progressPanel.setProgress(9); progressPanel.setProgress(9);
ExcelExport.writeExcel(sheetExports, reportFile); ExcelExport.writeExcel(sheetExports, reportFile);

View File

@ -0,0 +1,312 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019-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.report.modules.datasourcesummaryexport;
import java.awt.Color;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.contentutils.ContainerSummary;
import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities;
import org.sleuthkit.autopsy.contentutils.TypesSummary;
import org.sleuthkit.autopsy.contentutils.TypesSummary.FileTypeCategoryData;
import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.KeyValueItemExportable;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Panel for displaying summary information on the known files present in the
* specified DataSource.
*/
@Messages({
"ExportTypes_artifactsTypesPieChart_title=Artifact Types",
"ExportTypes_filesByCategoryTable_allocatedRow_title=Allocated Files",
"ExportTypes_filesByCategoryTable_unallocatedRow_title=Unallocated Files",
"ExportTypes_filesByCategoryTable_slackRow_title=Slack Files",
"ExportTypes_filesByCategoryTable_directoryRow_title=Directories",
"ExportTypes_fileMimeTypesChart_title=File Types",
"ExportTypes_fileMimeTypesChart_valueLabel=Count",
"ExportTypes_fileMimeTypesChart_audio_title=Audio",
"ExportTypes_fileMimeTypesChart_documents_title=Documents",
"ExportTypes_fileMimeTypesChart_executables_title=Executables",
"ExportTypes_fileMimeTypesChart_images_title=Images",
"ExportTypes_fileMimeTypesChart_videos_title=Videos",
"ExportTypes_fileMimeTypesChart_other_title=Other",
"ExportTypes_fileMimeTypesChart_unknown_title=Unknown",
"ExportTypes_fileMimeTypesChart_notAnalyzed_title=Not Analyzed",
"ExportTypes_usageLabel_title=Usage",
"ExportTypes_osLabel_title=OS",
"ExportTypes_sizeLabel_title=Size",
"ExportTypes_excelTabName=Types"})
class ExportTypes {
/**
* Data for types pie chart.
*/
private static class TypesPieChartData {
private final List<PieChartItem> pieSlices;
private final boolean usefulContent;
/**
* Main constructor.
*
* @param pieSlices The pie slices.
* @param usefulContent True if this is useful content; false if there
* is 0 mime type information.
*/
TypesPieChartData(List<PieChartItem> pieSlices, boolean usefulContent) {
this.pieSlices = pieSlices;
this.usefulContent = usefulContent;
}
/**
* @return The pie chart data.
*/
List<PieChartItem> getPieSlices() {
return pieSlices;
}
/**
* @return Whether or not the data is usefulContent.
*/
boolean isUsefulContent() {
return usefulContent;
}
}
private static final Color IMAGES_COLOR = new Color(156, 39, 176);
private static final Color VIDEOS_COLOR = Color.YELLOW;
private static final Color AUDIO_COLOR = Color.BLUE;
private static final Color DOCUMENTS_COLOR = Color.GREEN;
private static final Color EXECUTABLES_COLOR = new Color(0, 188, 212);
private static final Color UNKNOWN_COLOR = Color.ORANGE;
private static final Color OTHER_COLOR = new Color(78, 52, 46);
private static final Color NOT_ANALYZED_COLOR = Color.WHITE;
// All file type categories.
private static final List<FileTypeCategoryData> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR),
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR),
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR),
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR),
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR),
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR)
);
private ExportTypes() {
}
/**
* Derives a sql set string (i.e. "('val1', 'val2', 'val3')"). A naive
* attempt is made to sanitize the strings by removing single quotes from
* values.
*
* @param setValues The values that should be present in the set. Single
* quotes are removed.
*
* @return The sql set string.
*/
private static String getSqlSet(Set<String> setValues) {
List<String> quotedValues = setValues
.stream()
.map(str -> String.format("'%s'", str.replace("'", "")))
.collect(Collectors.toList());
String commaSeparatedQuoted = String.join(", ", quotedValues);
return String.format("(%s) ", commaSeparatedQuoted);
}
/**
* Get the number of files in the case database for the current data source
* which have the specified mimetypes.
*
* @param currentDataSource the data source which we are finding a file
* count
*
* @param setOfMimeTypes the set of mime types which we are finding the
* number of occurences of
*
* @return a Long value which represents the number of occurrences of the
* specified mime types in the current case for the specified data
* source, null if no count was retrieved
*
* @throws NoCurrentCaseException
* @throws TskCoreException
* @throws SQLException
*/
private static Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes) throws TskCoreException, SQLException, NoCurrentCaseException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes));
}
/**
* Gets the number of files in the data source with no assigned mime type.
*
* @param currentDataSource The data source.
*
* @return The number of files with no mime type or null if there is an
* issue searching the data source.
*
* @throws NoCurrentCaseException
* @throws TskCoreException
* @throws SQLException
*/
private static Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) throws TskCoreException, SQLException, NoCurrentCaseException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "(mime_type IS NULL OR mime_type = '') ");
}
/**
* Gets all the data for the file type pie chart.
*
* @param mimeTypeData The means of acquiring data.
* @param dataSource The datasource.
*
* @return The pie chart items.
*/
private static TypesPieChartData getMimeTypeCategoriesModel(DataSource dataSource)
throws SQLException, TskCoreException, NoCurrentCaseException {
if (dataSource == null) {
return null;
}
// for each category of file types, get the counts of files
List<PieChartItem> fileCategoryItems = new ArrayList<>();
long categoryTotalCount = 0;
for (FileTypeCategoryData cat : FILE_MIME_TYPE_CATEGORIES) {
long thisValue = DataSourceInfoUtilities.getLongOrZero(getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes()));
categoryTotalCount += thisValue;
fileCategoryItems.add(new PieChartItem(
cat.getLabel(),
thisValue,
cat.getColor()));
}
// get a count of all files with no mime type
long noMimeTypeCount = DataSourceInfoUtilities.getLongOrZero(getCountOfFilesWithNoMimeType(dataSource));
// get a count of all regular files
long allRegularFiles = DataSourceInfoUtilities.getLongOrZero(DataSourceInfoUtilities.getCountOfRegNonSlackFiles(dataSource, null));
// create entry for mime types in other category
long otherCount = allRegularFiles - (categoryTotalCount + noMimeTypeCount);
PieChartItem otherPieItem = new PieChartItem(Bundle.ExportTypes_fileMimeTypesChart_other_title(),
otherCount, OTHER_COLOR);
// check at this point to see if these are all 0; if so, we don't have useful content.
boolean usefulContent = categoryTotalCount > 0 || otherCount > 0;
// create entry for not analyzed mime types category
PieChartItem notAnalyzedItem = new PieChartItem(Bundle.ExportTypes_fileMimeTypesChart_notAnalyzed_title(),
noMimeTypeCount, NOT_ANALYZED_COLOR);
// combine categories with 'other' and 'not analyzed'
List<PieChartItem> items = Stream.concat(
fileCategoryItems.stream(),
Stream.of(otherPieItem, notAnalyzedItem))
// remove items that have no value
.filter(slice -> slice.getValue() > 0)
.collect(Collectors.toList());
return new TypesPieChartData(items, usefulContent);
}
/**
* Returns a key value pair to be exported in a sheet.
*
* @param fetcher The means of fetching the data.
* @param key The key to use.
* @param dataSource The data source containing the data.
*
* @return The key value pair to be exported.
*/
private static KeyValueItemExportable getStrExportable(DataFetcher<DataSource, String> fetcher, String key, DataSource dataSource) {
String result = ExcelExportAction.getFetchResult(fetcher, "Types", dataSource);
return (result == null) ? null : new KeyValueItemExportable(key, new DefaultCellModel<>(result));
}
/**
* Returns a key value pair to be exported in a sheet formatting the long
* with commas separated by orders of 1000.
*
* @param fetcher The means of fetching the data.
* @param key The string key for this key value pair.
* @param dataSource The data source.
*
* @return The key value pair.
*/
private static KeyValueItemExportable getCountExportable(DataFetcher<DataSource, Long> fetcher, String key, DataSource dataSource) {
Long count = ExcelExportAction.getFetchResult(fetcher, "Types", dataSource);
return (count == null) ? null : new KeyValueItemExportable(key,
new DefaultCellModel<Long>(count, DataSourceInfoUtilities.COMMA_FORMATTER::format, DataSourceInfoUtilities.COMMA_FORMAT_STR));
}
static List<ExcelExport.ExcelSheetExport> getExports(DataSource dataSource) {
if (dataSource == null) {
return Collections.emptyList();
}
DataFetcher<DataSource, String> usageFetcher = (ds) -> ContainerSummary.getDataSourceType(ds);
DataFetcher<DataSource, String> osFetcher = (ds) -> ContainerSummary.getOperatingSystems(ds);
DataFetcher<DataSource, Long> sizeFetcher = (ds) -> ds == null ? null : ds.getSize();
DataFetcher<DataSource, TypesPieChartData> typesFetcher = (ds) -> getMimeTypeCategoriesModel(ds);
DataFetcher<DataSource, Long> allocatedFetcher = (ds) -> TypesSummary.getCountOfAllocatedFiles(ds);
DataFetcher<DataSource, Long> unallocatedFetcher = (ds) -> TypesSummary.getCountOfUnallocatedFiles(ds);
DataFetcher<DataSource, Long> slackFetcher = (ds) -> TypesSummary.getCountOfSlackFiles(ds);
DataFetcher<DataSource, Long> directoriesFetcher = (ds) -> TypesSummary.getCountOfDirectories(ds);
// Retrieve data to create the types pie chart
TypesPieChartData typesData = ExcelExportAction.getFetchResult(typesFetcher, "Types", dataSource);
PieChartExport typesChart = (typesData == null || !typesData.isUsefulContent()) ? null
: new PieChartExport(
Bundle.ExportTypes_fileMimeTypesChart_title(),
Bundle.ExportTypes_fileMimeTypesChart_valueLabel(),
"#,###",
Bundle.ExportTypes_fileMimeTypesChart_title(),
typesData.getPieSlices());
return Arrays.asList(new ExcelSpecialFormatExport(Bundle.ExportTypes_excelTabName(),
Stream.of(
getStrExportable(usageFetcher, Bundle.ExportTypes_usageLabel_title(), dataSource),
getStrExportable(osFetcher, Bundle.ExportTypes_osLabel_title(), dataSource),
new KeyValueItemExportable(Bundle.ExportTypes_sizeLabel_title(),
SizeRepresentationUtil.getBytesCell(ExcelExportAction.getFetchResult(sizeFetcher, "Types", dataSource))),
typesChart,
getCountExportable(allocatedFetcher, Bundle.ExportTypes_filesByCategoryTable_allocatedRow_title(), dataSource),
getCountExportable(unallocatedFetcher, Bundle.ExportTypes_filesByCategoryTable_unallocatedRow_title(), dataSource),
getCountExportable(slackFetcher, Bundle.ExportTypes_filesByCategoryTable_slackRow_title(), dataSource),
getCountExportable(directoriesFetcher, Bundle.ExportTypes_filesByCategoryTable_directoryRow_title(), dataSource))
.filter(sheet -> sheet != null)
.collect(Collectors.toList())
));
}
}