mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 17:06:16 +00:00
Recursive local file support in FileManager and dir tree
This commit is contained in:
parent
e5c83bc9ce
commit
ce4ee992ea
@ -25,7 +25,8 @@ package org.sleuthkit.autopsy.casemodule.services;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
import java.util.logging.Level;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.DerivedFile;
|
import org.sleuthkit.datamodel.DerivedFile;
|
||||||
import org.sleuthkit.datamodel.FsContent;
|
import org.sleuthkit.datamodel.FsContent;
|
||||||
@ -33,6 +34,7 @@ import org.sleuthkit.datamodel.Image;
|
|||||||
import org.sleuthkit.datamodel.LocalFile;
|
import org.sleuthkit.datamodel.LocalFile;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstraction to facilitate access to files and directories.
|
* Abstraction to facilitate access to files and directories.
|
||||||
@ -40,6 +42,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
public class FileManager implements Closeable {
|
public class FileManager implements Closeable {
|
||||||
|
|
||||||
private SleuthkitCase tskCase;
|
private SleuthkitCase tskCase;
|
||||||
|
private static final Logger logger = Logger.getLogger(FileManager.class.getName());
|
||||||
|
|
||||||
public FileManager(SleuthkitCase tskCase) {
|
public FileManager(SleuthkitCase tskCase) {
|
||||||
this.tskCase = tskCase;
|
this.tskCase = tskCase;
|
||||||
@ -138,6 +141,90 @@ public class FileManager implements Closeable {
|
|||||||
isFile, parentFile, rederiveDetails, toolName, toolVersion, otherDetails);
|
isFile, parentFile, rederiveDetails, toolName, toolVersion, otherDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper (internal) to add child of local dir recursively
|
||||||
|
* @param parentVd
|
||||||
|
* @param childLocalFile
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
private void addLocalDirectoryRecInt(VirtualDirectory parentVd,
|
||||||
|
java.io.File childLocalFile) throws TskCoreException {
|
||||||
|
|
||||||
|
final boolean isDir = childLocalFile.isDirectory();
|
||||||
|
|
||||||
|
if (isDir) {
|
||||||
|
//create virtual folder
|
||||||
|
final VirtualDirectory childVd = tskCase.addVirtualDirectory(parentVd.getId(), childLocalFile.getName());
|
||||||
|
//add children recursively
|
||||||
|
for (java.io.File childChild : childLocalFile.listFiles()) {
|
||||||
|
addLocalDirectoryRecInt(childVd, childChild);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//add leaf file, base case
|
||||||
|
this.addLocalFileSingle(childLocalFile.getAbsolutePath(), parentVd);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a local directory and its children recursively.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param localAbsPath local absolute path of root folder whose children are
|
||||||
|
* to be added recursively
|
||||||
|
* @return parent virtual directory folder created representing the
|
||||||
|
* localAbsPath node
|
||||||
|
* @throws TskCoreException exception thrown if the object creation failed
|
||||||
|
* due to a critical system error or of the file manager has already been
|
||||||
|
* closed, or if the localAbsPath could not be accessed
|
||||||
|
*/
|
||||||
|
public synchronized VirtualDirectory addLocalDir(String localAbsPath) throws TskCoreException {
|
||||||
|
if (tskCase == null) {
|
||||||
|
throw new TskCoreException("Attempted to use FileManager after it was closed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
java.io.File localDir = new java.io.File(localAbsPath);
|
||||||
|
if (!localDir.exists()) {
|
||||||
|
throw new TskCoreException("Attempted to add a local dir that does not exist: " + localAbsPath);
|
||||||
|
}
|
||||||
|
if (!localDir.canRead()) {
|
||||||
|
throw new TskCoreException("Attempted to add a local dir that is not readable: " + localAbsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!localDir.isDirectory()) {
|
||||||
|
throw new TskCoreException("Attempted to add a local dir that is not a directory: " + localAbsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String rootVdName = localDir.getName();
|
||||||
|
|
||||||
|
VirtualDirectory rootVd = null;
|
||||||
|
try {
|
||||||
|
final long localFilesRootId = tskCase.getLocalFilesRootDirectoryId();
|
||||||
|
rootVd = tskCase.addVirtualDirectory(localFilesRootId, rootVdName);
|
||||||
|
} catch (TskCoreException e) {
|
||||||
|
//log and rethrow
|
||||||
|
final String msg = "Error creating root dir for local dir to be added, can't addLocalDir: " + localDir;
|
||||||
|
logger.log(Level.SEVERE, msg, e);
|
||||||
|
throw new TskCoreException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
java.io.File[] localChildren = localDir.listFiles();
|
||||||
|
for (java.io.File localChild : localChildren) {
|
||||||
|
//add childrnen recursively, at a time in separate transaction
|
||||||
|
//consider a single transaction for everything
|
||||||
|
addLocalDirectoryRecInt(rootVd, localChild);
|
||||||
|
}
|
||||||
|
} catch (TskCoreException e) {
|
||||||
|
final String msg = "Error creating local children for local dir to be added, can't fully add addLocalDir: " + localDir;
|
||||||
|
logger.log(Level.SEVERE, msg, e);
|
||||||
|
throw new TskCoreException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return rootVd;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a single local file under $LocalFiles for the case, adds it to
|
* Creates a single local file under $LocalFiles for the case, adds it to
|
||||||
* the database and returns it.
|
* the database and returns it.
|
||||||
@ -147,7 +234,7 @@ public class FileManager implements Closeable {
|
|||||||
* @return newly created local file object added to the database
|
* @return newly created local file object added to the database
|
||||||
* @throws TskCoreException exception thrown if the object creation failed
|
* @throws TskCoreException exception thrown if the object creation failed
|
||||||
* due to a critical system error or of the file manager has already been
|
* due to a critical system error or of the file manager has already been
|
||||||
* closed
|
* closed, or if the localAbsPath could not be accessed
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public synchronized LocalFile addLocalFileSingle(String localAbsPath) throws TskCoreException {
|
public synchronized LocalFile addLocalFileSingle(String localAbsPath) throws TskCoreException {
|
||||||
@ -201,11 +288,11 @@ public class FileManager implements Closeable {
|
|||||||
LocalFile lf = tskCase.addLocalFile(fileName, localAbsPath, size,
|
LocalFile lf = tskCase.addLocalFile(fileName, localAbsPath, size,
|
||||||
ctime, crtime, atime, mtime,
|
ctime, crtime, atime, mtime,
|
||||||
isFile, parentFile);
|
isFile, parentFile);
|
||||||
|
|
||||||
//refresh the content tree
|
//refresh the content tree
|
||||||
//TODO decouple, use Node autorefresh once implemented
|
//TODO decouple at least using events, and later use Node autorefresh once implemented
|
||||||
DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe();
|
//DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe();
|
||||||
|
|
||||||
return lf;
|
return lf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,11 +25,13 @@ import org.openide.nodes.Children;
|
|||||||
import org.sleuthkit.autopsy.datamodel.DirectoryNode;
|
import org.sleuthkit.autopsy.datamodel.DirectoryNode;
|
||||||
import org.openide.nodes.FilterNode;
|
import org.openide.nodes.FilterNode;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
|
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.VolumeNode;
|
import org.sleuthkit.autopsy.datamodel.VolumeNode;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
@ -37,6 +39,7 @@ import org.sleuthkit.datamodel.Directory;
|
|||||||
import org.sleuthkit.datamodel.LayoutFile;
|
import org.sleuthkit.datamodel.LayoutFile;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskException;
|
import org.sleuthkit.datamodel.TskException;
|
||||||
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
import org.sleuthkit.datamodel.Volume;
|
import org.sleuthkit.datamodel.Volume;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,7 +126,11 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
for (Content c : vol.getChildren()) {
|
for (Content c : vol.getChildren()) {
|
||||||
if (!(c instanceof LayoutFile)) {
|
if (!(c instanceof LayoutFile
|
||||||
|
|| c instanceof VirtualDirectory
|
||||||
|
)
|
||||||
|
|
||||||
|
) {
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -173,14 +180,13 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
|||||||
return isLeafDirectory(dn);
|
return isLeafDirectory(dn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private Boolean visitDeep(AbstractAbstractFileNode node) {
|
||||||
public Boolean visit(FileNode fn) {
|
|
||||||
//is a leaf if has no children, or children are files not dirs
|
//is a leaf if has no children, or children are files not dirs
|
||||||
boolean hasChildren = fn.hasContentChildren();
|
boolean hasChildren = node.hasContentChildren();
|
||||||
if (!hasChildren) {
|
if (!hasChildren) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
List<Content> derivedChildren = fn.getContentChildren();
|
List<Content> derivedChildren = node.getContentChildren();
|
||||||
//child of a file, must be a (derived) file too
|
//child of a file, must be a (derived) file too
|
||||||
for (Content childContent : derivedChildren) {
|
for (Content childContent : derivedChildren) {
|
||||||
if (((AbstractFile) childContent).isDir()) {
|
if (((AbstractFile) childContent).isDir()) {
|
||||||
@ -198,36 +204,34 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean visit(LocalFileNode dfn) {
|
public Boolean visit(FileNode fn) {
|
||||||
//is a leaf if has no children, or children are files not dirs
|
return visitDeep(fn);
|
||||||
boolean hasChildren = dfn.hasContentChildren();
|
|
||||||
if (!hasChildren) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
List<Content> derivedChildren = dfn.getContentChildren();
|
|
||||||
//child of a file, must be a (derived) file too
|
|
||||||
for (Content childContent : derivedChildren) {
|
|
||||||
if (((AbstractFile) childContent).isDir()) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
if (childContent.hasChildren()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error checking if derived file node is leaf.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean visit(LocalFileNode lfn) {
|
||||||
|
return visitDeep(lfn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean visit(LayoutFileNode fn) {
|
||||||
|
return visitDeep(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean visit(VolumeNode vn) {
|
public Boolean visit(VolumeNode vn) {
|
||||||
return isLeafVolume(vn);
|
return isLeafVolume(vn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean visit(VirtualDirectoryNode vdn) {
|
||||||
|
//return visitDeep(vdn);
|
||||||
|
return ! vdn.hasContentChildren();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ShowItemVisitor extends DisplayableItemNodeVisitor.Default<Boolean> {
|
private static class ShowItemVisitor extends DisplayableItemNodeVisitor.Default<Boolean> {
|
||||||
@ -251,13 +255,18 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean visit(LocalFileNode dfn) {
|
public Boolean visit(LocalFileNode lfn) {
|
||||||
return dfn.hasContentChildren();
|
return lfn.hasContentChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean visit(LayoutFileNode ln) {
|
public Boolean visit(LayoutFileNode ln) {
|
||||||
return false;
|
return ln.hasContentChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean visit(VirtualDirectoryNode vdn) {
|
||||||
|
return vdn.hasContentChildren();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user