From c17c76a20fa91a400a30474ed5b419c72cfd17d0 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 6 Jul 2017 09:17:03 -0400 Subject: [PATCH] Adding local directory type --- .../casemodule/services/FileManager.java | 15 +- .../datamodel/AbstractContentChildren.java | 6 + .../autopsy/datamodel/ContentNodeVisitor.java | 7 + .../datamodel/DataModelActionsFactory.java | 33 +++ .../datamodel/DisplayableItemNodeVisitor.java | 7 + .../autopsy/datamodel/LocalDirectoryNode.java | 215 ++++++++++++++++++ .../directorytree/DataResultFilterNode.java | 4 + .../DirectoryTreeFilterChildren.java | 11 + .../ingest/GetFilesContentVisitor.java | 6 + .../ingest/GetRootDirectoryVisitor.java | 10 + 10 files changed, 308 insertions(+), 6 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java index eb810e708c..947dd9ef42 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java @@ -36,6 +36,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.LayoutFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction; import org.sleuthkit.datamodel.TskCoreException; @@ -510,14 +511,16 @@ public class FileManager implements Closeable { * @throws TskCoreException If there is a problem completing a database * operation. */ - private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile, + private AbstractFile addLocalFile(CaseDbTransaction trans, AbstractFile parentDirectory, java.io.File localFile, TskData.EncodingType encodingType, FileAddProgressUpdater progressUpdater) throws TskCoreException { if (localFile.isDirectory()) { /* * Add the directory as a virtual directory. */ - VirtualDirectory virtualDirectory = caseDb.addVirtualDirectory(parentDirectory.getId(), localFile.getName(), trans); - progressUpdater.fileAdded(virtualDirectory); + //VirtualDirectory virtualDirectory = caseDb.addVirtualDirectory(parentDirectory.getId(), localFile.getName(), trans); + //progressUpdater.fileAdded(virtualDirectory); + LocalDirectory localDirectory = caseDb.addLocalDirectory(parentDirectory.getId(), localFile.getName(), trans); + progressUpdater.fileAdded(localDirectory); /* * Add its children, if any. @@ -525,11 +528,11 @@ public class FileManager implements Closeable { final java.io.File[] childFiles = localFile.listFiles(); if (childFiles != null && childFiles.length > 0) { for (java.io.File childFile : childFiles) { - addLocalFile(trans, virtualDirectory, childFile, progressUpdater); + addLocalFile(trans, localDirectory, childFile, progressUpdater); } } - return virtualDirectory; + return localDirectory; } else { return caseDb.addLocalFile(localFile.getName(), localFile.getAbsolutePath(), localFile.length(), 0, 0, 0, 0, @@ -695,7 +698,7 @@ public class FileManager implements Closeable { * @deprecated Use the version with explicit EncodingType instead */ @Deprecated - private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile, FileAddProgressUpdater progressUpdater) throws TskCoreException { + private AbstractFile addLocalFile(CaseDbTransaction trans, AbstractFile parentDirectory, java.io.File localFile, FileAddProgressUpdater progressUpdater) throws TskCoreException { return addLocalFile(trans, parentDirectory, localFile, TskData.EncodingType.NONE, progressUpdater); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index eb736069a7..2fa07441f0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -32,6 +32,7 @@ import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.SleuthkitItemVisitor; import org.sleuthkit.datamodel.SleuthkitVisitableItem; @@ -110,6 +111,11 @@ abstract class AbstractContentChildren extends Keys { return new VirtualDirectoryNode(ld); } + @Override + public AbstractContentNode visit(LocalDirectory ld) { + return new LocalDirectoryNode(ld); + } + @Override public AbstractContentNode visit(SlackFile sf) { return new SlackFileNode(sf); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java index 6dbd8002ee..7f7be1376b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java @@ -31,6 +31,8 @@ interface ContentNodeVisitor { T visit(ImageNode in); T visit(VirtualDirectoryNode lcn); + + T visit(LocalDirectoryNode ldn); T visit(VolumeNode vn); @@ -96,6 +98,11 @@ interface ContentNodeVisitor { return defaultVisit(ldn); } + @Override + public T visit(LocalDirectoryNode ldn) { + return defaultVisit(ldn); + } + @Override public T visit(SlackFileNode sfn) { return defaultVisit(sfn); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java index dc1aa9a8bf..db9967b743 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -44,6 +44,7 @@ import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.VirtualDirectory; @@ -229,6 +230,38 @@ public class DataModelActionsFactory { actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } + + public static List getActions(LocalDirectory directory, boolean isArtifactSource) { + List actionsList = new ArrayList<>(); + actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory)); + LocalDirectoryNode directoryNode = new LocalDirectoryNode(directory); + actionsList.add(null); // creates a menu separator + actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode)); + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); + actionsList.add(null); // creates a menu separator + actionsList.add(AddContentTagAction.getInstance()); + if (isArtifactSource) { + actionsList.add(AddBlackboardArtifactTagAction.getInstance()); + } + + final Collection selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if(selectedFilesList.size() == 1) { + actionsList.add(DeleteFileContentTagAction.getInstance()); + } + if(isArtifactSource) { + final Collection selectedArtifactsList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if(selectedArtifactsList.size() == 1) { + actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); + } + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; + } public static List getActions(LocalFile file, boolean isArtifactSource) { List actionsList = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 5cc152e465..e6e8afed52 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -41,6 +41,8 @@ public interface DisplayableItemNodeVisitor { T visit(LocalFileNode dfn); T visit(VirtualDirectoryNode ldn); + + T visit(LocalDirectoryNode ldn); T visit(DirectoryNode dn); @@ -370,6 +372,11 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(ldn); } + @Override + public T visit(LocalDirectoryNode ldn) { + return defaultVisit(ldn); + } + @Override public T visit(Tags.RootNode node) { return defaultVisit(node); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java new file mode 100644 index 0000000000..a6d786b1c6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalDirectoryNode.java @@ -0,0 +1,215 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit 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.datamodel; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import javax.swing.Action; +import org.openide.nodes.Sheet; +import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.directorytree.FileSearchAction; +import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.LocalDirectory; + +/** + * Node for a local directory + */ +public class LocalDirectoryNode extends AbstractAbstractFileNode { + + private static final Logger logger = Logger.getLogger(VirtualDirectoryNode.class.getName()); + + public static String nameForLocalDir(LocalDirectory ld) { + return ld.getName(); + } + + public LocalDirectoryNode(LocalDirectory ld) { + super(ld); + + this.setDisplayName(nameForLocalDir(ld)); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-card.png"); //NON-NLS + + } + + /** + * Right click action for this node + * + * @param popup + * + * @return + */ + @Override + @NbBundle.Messages({"LocalDirectoryNode.action.runIngestMods.text=Run Ingest Modules", + "LocalDirectoryNode.getActions.viewInNewWin.text=View in New Window" + }) + public Action[] getActions(boolean popup) { + List actions = new ArrayList<>(); + for (Action a : super.getActions(true)) { + actions.add(a); + } + + actions.add(new NewWindowViewAction( + Bundle.LocalDirectoryNode_action_runIngestMods_text(), this)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + actions.add(null); // creates a menu separator + actions.add(new FileSearchAction( + Bundle.ImageNode_getActions_openFileSearchByAttr_text())); + actions.add(new RunIngestModulesAction(Collections.singletonList(content))); + actions.addAll(ContextMenuExtensionPoint.getActions()); + return actions.toArray(new Action[0]); + } + + @Override + @Messages({"LocalDirectoryNode.createSheet.size.name=Size (Bytes)", + "LocalDirectoryNode.createSheet.size.displayName=Size (Bytes)", + "LocalDirectoryNode.createSheet.size.desc=Size of the data source in bytes.", + "LocalDirectoryNode.createSheet.type.name=Type", + "LocalDirectoryNode.createSheet.type.displayName=Type", + "LocalDirectoryNode.createSheet.type.desc=Type of the image.", + "LocalDirectoryNode.createSheet.type.text=Logical File Set", + "LocalDirectoryNode.createSheet.timezone.name=Timezone", + "LocalDirectoryNode.createSheet.timezone.displayName=Timezone", + "LocalDirectoryNode.createSheet.timezone.desc=Timezone of the image", + "LocalDirectoryNode.createSheet.deviceId.name=Device ID", + "LocalDirectoryNode.createSheet.deviceId.displayName=Device ID", + "LocalDirectoryNode.createSheet.deviceId.desc=Device ID of the image", + "LocalDirectoryNode.createSheet.name.name=Name", + "LocalDirectoryNode.createSheet.name.displayName=Name", + "LocalDirectoryNode.createSheet.name.desc=no description", + "LocalDirectoryNode.createSheet.noDesc=no description"}) + protected Sheet createSheet() { + Sheet s = super.createSheet(); + Sheet.Set ss = s.get(Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet(); + s.put(ss); + } + + ss.put(new NodeProperty<>(Bundle.LocalDirectoryNode_createSheet_name_name(), + Bundle.LocalDirectoryNode_createSheet_name_displayName(), + Bundle.LocalDirectoryNode_createSheet_name_desc(), + getName())); + + if (!this.content.isDataSource()) { + Map map = new LinkedHashMap<>(); + fillPropertyMap(map, content); + + final String NO_DESCR = Bundle.LocalDirectoryNode_createSheet_noDesc(); + for (Map.Entry entry : map.entrySet()) { + ss.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue())); + } + addTagProperty(ss); + } else { + ss.put(new NodeProperty<>(Bundle.LocalDirectoryNode_createSheet_type_name(), + Bundle.LocalDirectoryNode_createSheet_type_displayName(), + Bundle.LocalDirectoryNode_createSheet_type_desc(), + Bundle.LocalDirectoryNode_createSheet_type_text())); + ss.put(new NodeProperty<>(Bundle.LocalDirectoryNode_createSheet_size_name(), + Bundle.LocalDirectoryNode_createSheet_size_displayName(), + Bundle.LocalDirectoryNode_createSheet_size_desc(), + this.content.getSize())); + try (SleuthkitCase.CaseDbQuery query = Case.getCurrentCase().getSleuthkitCase().executeQuery("SELECT time_zone FROM data_source_info WHERE obj_id = " + this.content.getId())) { + ResultSet timeZoneSet = query.getResultSet(); + if (timeZoneSet.next()) { + ss.put(new NodeProperty<>(Bundle.LocalDirectoryNode_createSheet_timezone_name(), + Bundle.LocalDirectoryNode_createSheet_timezone_displayName(), + Bundle.LocalDirectoryNode_createSheet_timezone_desc(), + timeZoneSet.getString("time_zone"))); + } + } catch (SQLException | TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get time zone for the following image: " + this.content.getId(), ex); + } + try (SleuthkitCase.CaseDbQuery query = Case.getCurrentCase().getSleuthkitCase().executeQuery("SELECT device_id FROM data_source_info WHERE obj_id = " + this.content.getId());) { + ResultSet deviceIdSet = query.getResultSet(); + if (deviceIdSet.next()) { + ss.put(new NodeProperty<>(Bundle.LocalDirectoryNode_createSheet_deviceId_name(), + Bundle.LocalDirectoryNode_createSheet_deviceId_displayName(), + Bundle.LocalDirectoryNode_createSheet_deviceId_desc(), + deviceIdSet.getString("device_id"))); + } + } catch (SQLException | TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get device id for the following image: " + this.content.getId(), ex); + } + + } + + return s; + } + + @Override + public T accept(ContentNodeVisitor v) { + return v.visit(this); + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + public boolean isLeafTypeNode() { + return false; + } + + /** + * Convert meta flag long to user-readable string / label + * + * @param metaFlag to convert + * + * @return string formatted meta flag representation + */ + public static String metaFlagToString(short metaFlag) { + + String result = ""; + + short allocFlag = TskData.TSK_FS_META_FLAG_ENUM.ALLOC.getValue(); + short unallocFlag = TskData.TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(); + + if ((metaFlag & allocFlag) == allocFlag) { + result = TskData.TSK_FS_META_FLAG_ENUM.ALLOC.toString(); + } + if ((metaFlag & unallocFlag) == unallocFlag) { + result = TskData.TSK_FS_META_FLAG_ENUM.UNALLOC.toString(); + } + + return result; + } + + @Override + public String getItemType() { + // use content.isDataSource if different column settings are desired + return DisplayableItemNode.FILE_PARENT_NODE_KEY; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 21146610da..587fe2665a 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -53,6 +53,7 @@ import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode; +import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode; import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.Reports; import org.sleuthkit.autopsy.datamodel.SlackFileNode; @@ -66,6 +67,7 @@ import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskException; @@ -350,6 +352,8 @@ public class DataResultFilterNode extends FilterNode { n = new DirectoryNode((Directory) c); } else if ((c = ban.getLookup().lookup(VirtualDirectory.class)) != null) { n = new VirtualDirectoryNode((VirtualDirectory) c); + } else if ((c = ban.getLookup().lookup(LocalDirectory.class)) != null) { + n = new LocalDirectoryNode((LocalDirectory) c); } else if ((c = ban.getLookup().lookup(LayoutFile.class)) != null) { n = new LayoutFileNode((LayoutFile) c); } else if ((c = ban.getLookup().lookup(LocalFile.class)) != null diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java index 2b10d57f09..4dc9d51241 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java @@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode; +import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode; import org.sleuthkit.autopsy.datamodel.SlackFileNode; import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode; import org.sleuthkit.autopsy.datamodel.VolumeNode; @@ -244,6 +245,11 @@ class DirectoryTreeFilterChildren extends FilterNode.Children { //return ! vdn.hasContentChildren(); } + @Override + public Boolean visit(LocalDirectoryNode ldn) { + return visitDeep(ldn); + } + @Override public Boolean visit(FileTypesNode ft) { return defaultVisit(ft); @@ -292,6 +298,11 @@ class DirectoryTreeFilterChildren extends FilterNode.Children { //return vdn.hasContentChildren(); } + @Override + public Boolean visit(LocalDirectoryNode ldn) { + return true; + } + @Override public Boolean visit(FileTypesNode fileTypes) { return defaultVisit(fileTypes); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/GetFilesContentVisitor.java b/Core/src/org/sleuthkit/autopsy/ingest/GetFilesContentVisitor.java index b45b7b307b..e6b5ee02fa 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/GetFilesContentVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/GetFilesContentVisitor.java @@ -28,6 +28,7 @@ import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.VirtualDirectory; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.VolumeSystem; @@ -43,6 +44,11 @@ abstract class GetFilesContentVisitor implements ContentVisitor visit(VirtualDirectory ld) { return getAllFromChildren(ld); } + + @Override + public Collection visit(LocalDirectory ld) { + return getAllFromChildren(ld); + } @Override public Collection visit(Directory drctr) { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java b/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java index 28085cee96..aaeae111f2 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java @@ -27,6 +27,7 @@ import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.VirtualDirectory; @@ -44,6 +45,15 @@ final class GetRootDirectoryVisitor extends GetFilesContentVisitor { ret.add(ld); return ret; } + + @Override + public Collection visit(LocalDirectory ld) { + //case when we hit a local directoryr, not under a real FS + //or when root virt dir is scheduled + Collection ret = new ArrayList<>(); + ret.add(ld); + return ret; + } @Override public Collection visit(LayoutFile lf) {