From 909313947f1922a7c0e20cef2217d6a9c2b0c8cd Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 7 Feb 2022 11:21:08 -0500 Subject: [PATCH 1/5] hold on to a reference to the extract action helper --- .../src/org/sleuthkit/autopsy/directorytree/ExtractAction.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java index 0efe3bdcfb..6a585d724f 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java @@ -43,6 +43,8 @@ public final class ExtractAction extends AbstractAction { } return instance; } + + private final ExtractActionHelper extractor = new ExtractActionHelper(); /** * Private constructor for the action. @@ -61,7 +63,6 @@ public final class ExtractAction extends AbstractAction { public void actionPerformed(ActionEvent e) { Lookup lookup = Utilities.actionsGlobalContext(); Collection selectedFiles =lookup.lookupAll(AbstractFile.class); - ExtractActionHelper extractor = new ExtractActionHelper(); extractor.extract(e, selectedFiles); } From c69c058c1858b7c0c663ef7df566c52aa63405db Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 7 Feb 2022 11:59:50 -0500 Subject: [PATCH 2/5] overwrite confirm --- .../actionhelpers/ExtractActionHelper.java | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java index 5a28bd9c12..5181c005dd 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java @@ -36,6 +36,7 @@ import org.netbeans.api.progress.ProgressHandle; import org.openide.util.Cancellable; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; +import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.FileUtil; @@ -68,12 +69,7 @@ public class ExtractActionHelper { if (selectedFiles.size() > 1) { extractFiles(event, selectedFiles); } else if (selectedFiles.size() == 1) { - AbstractFile source = selectedFiles.iterator().next(); - if (source.isDir()) { - extractFiles(event, selectedFiles); - } else { - extractFile(event, selectedFiles.iterator().next()); - } + extractFile(event, selectedFiles.iterator().next()); } } @@ -83,7 +79,11 @@ public class ExtractActionHelper { * @param event * @param selectedFile Selected file */ - @NbBundle.Messages({"ExtractActionHelper.noOpenCase.errMsg=No open case available."}) + @NbBundle.Messages({"ExtractActionHelper.noOpenCase.errMsg=No open case available.", + "ExtractActionHelper.extractOverwrite.title=Export to csv file", + "# {0} - fileName", + "ExtractActionHelper.extractOverwrite.msg=A file already exists at {0}. Do you want to overwrite the existing file?" + }) private void extractFile(ActionEvent event, AbstractFile selectedFile) { Case openCase; try { @@ -98,7 +98,19 @@ public class ExtractActionHelper { // If there is an attribute name, change the ":". Otherwise the extracted file will be hidden fileChooser.setSelectedFile(new File(FileUtil.escapeFileName(selectedFile.getName()))); if (fileChooser.showSaveDialog((Component) event.getSource()) == JFileChooser.APPROVE_OPTION) { - updateExportDirectory(fileChooser.getSelectedFile().getParent(), openCase); + File saveLocation = fileChooser.getSelectedFile(); + if (saveLocation.exists()) { + if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), + Bundle.ExtractActionHelper_extractOverwrite_msg(saveLocation.getPath()), + Bundle.ExtractActionHelper_extractOverwrite_title(), + JOptionPane.YES_NO_OPTION)) { + } else { + return; + } + } + + String exportDirectory = saveLocation.getParent(); + updateExportDirectory(exportDirectory, openCase); ArrayList fileExtractionTasks = new ArrayList<>(); fileExtractionTasks.add(new FileExtractionTask(selectedFile, fileChooser.getSelectedFile())); From 3af245e41186b024a4f531dcda3ee65c42dbb8d0 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Feb 2022 09:05:44 -0500 Subject: [PATCH 3/5] don't overwrite on conflict --- .../autopsy/datamodel/ContentUtils.java | 90 ++++++++----------- .../actionhelpers/ExtractActionHelper.java | 84 ++++++++++++++--- 2 files changed, 108 insertions(+), 66 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java index 6def78b83d..c73ccb80a4 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java @@ -392,85 +392,69 @@ public final class ContentUtils { public static void extract(Content cntnt, java.io.File dest, ProgressHandle progress, SwingWorker worker) { cntnt.accept(new ExtractFscContentVisitor<>(dest, progress, worker, true)); } + + /** + * Base method writing a file to disk. + * + * @param file The TSK content file. + * @param dest The disk location where the content will be written. + * @param progress progress bar handle to update, if available. null + * otherwise + * @param worker the swing worker background thread the process runs + * within, or null, if in the main thread, used to + * handle task cancellation + * @param source true if source file + * + * @throws IOException + */ + protected void writeFile(Content file, java.io.File dest, ProgressHandle progress, SwingWorker worker, boolean source) throws IOException { + ContentUtils.writeToFile(file, dest, progress, worker, source); + } - @Override - public Void visit(File file) { + /** + * Visits a TSK content file and writes that file to disk. + * @param file The file to be written. + * @param fileType The file type (i.e. "derived file") for error logging. + * @return null. + */ + protected Void visitFile(Content file, String fileType) { try { - ContentUtils.writeToFile(file, dest, progress, worker, source); + writeFile(file, dest, progress, worker, source); } catch (ReadContentInputStreamException ex) { logger.log(Level.WARNING, String.format("Error reading file '%s' (id=%d).", file.getName(), file.getId()), ex); //NON-NLS } catch (IOException ex) { logger.log(Level.SEVERE, - String.format("Error extracting file '%s' (id=%d) to '%s'.", - file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS + String.format("Error extracting %s '%s' (id=%d) to '%s'.", + fileType, file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS } return null; } + + @Override + public Void visit(File file) { + return visitFile(file, "file"); + } @Override public Void visit(LayoutFile file) { - try { - ContentUtils.writeToFile(file, dest, progress, worker, source); - } catch (ReadContentInputStreamException ex) { - logger.log(Level.WARNING, - String.format("Error reading file '%s' (id=%d).", - file.getName(), file.getId()), ex); //NON-NLS - } catch (IOException ex) { - logger.log(Level.SEVERE, - String.format("Error extracting unallocated content file '%s' (id=%d) to '%s'.", - file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS - } - return null; + return visitFile(file, "unallocated content file"); } @Override public Void visit(DerivedFile file) { - try { - ContentUtils.writeToFile(file, dest, progress, worker, source); - } catch (ReadContentInputStreamException ex) { - logger.log(Level.WARNING, - String.format("Error reading file '%s' (id=%d).", - file.getName(), file.getId()), ex); //NON-NLS - } catch (IOException ex) { - logger.log(Level.SEVERE, - String.format("Error extracting derived file '%s' (id=%d) to '%s'.", - file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS - } - return null; + return visitFile(file, "derived file"); } @Override public Void visit(LocalFile file) { - try { - ContentUtils.writeToFile(file, dest, progress, worker, source); - } catch (ReadContentInputStreamException ex) { - logger.log(Level.WARNING, - String.format("Error reading file '%s' (id=%d).", - file.getName(), file.getId()), ex); //NON-NLS - } catch (IOException ex) { - logger.log(Level.SEVERE, - String.format("Error extracting local file '%s' (id=%d) to '%s'.", - file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS - } - return null; + return visitFile(file, "local file"); } @Override public Void visit(SlackFile file) { - try { - ContentUtils.writeToFile(file, dest, progress, worker, source); - } catch (ReadContentInputStreamException ex) { - logger.log(Level.WARNING, - String.format("Error reading file '%s' (id=%d).", - file.getName(), file.getId()), ex); //NON-NLS - } catch (IOException ex) { - logger.log(Level.SEVERE, - String.format("Error extracting slack file '%s' (id=%d) to '%s'.", - file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS - } - return null; + return visitFile(file, "slack file"); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java index 5181c005dd..48714e31e9 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java @@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.directorytree.actionhelpers; import java.awt.Component; import java.awt.event.ActionEvent; import java.io.File; +import java.io.IOException; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -36,15 +38,16 @@ import org.netbeans.api.progress.ProgressHandle; import org.openide.util.Cancellable; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; -import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; /** * Helper class for methods needed by actions which extract files. @@ -53,7 +56,7 @@ public class ExtractActionHelper { private final Logger logger = Logger.getLogger(ExtractActionHelper.class.getName()); private String userDefinedExportPath; - + private final JFileChooserFactory extractFileHelper = new JFileChooserFactory(); private final JFileChooserFactory extractFilesHelper = new JFileChooserFactory(); @@ -99,15 +102,15 @@ public class ExtractActionHelper { fileChooser.setSelectedFile(new File(FileUtil.escapeFileName(selectedFile.getName()))); if (fileChooser.showSaveDialog((Component) event.getSource()) == JFileChooser.APPROVE_OPTION) { File saveLocation = fileChooser.getSelectedFile(); - if (saveLocation.exists()) { - if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), - Bundle.ExtractActionHelper_extractOverwrite_msg(saveLocation.getPath()), - Bundle.ExtractActionHelper_extractOverwrite_title(), - JOptionPane.YES_NO_OPTION)) { - } else { - return; - } - } +// if (saveLocation.exists()) { +// if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), +// Bundle.ExtractActionHelper_extractOverwrite_msg(saveLocation.getPath()), +// Bundle.ExtractActionHelper_extractOverwrite_title(), +// JOptionPane.YES_NO_OPTION)) { +// } else { +// return; +// } +// } String exportDirectory = saveLocation.getParent(); updateExportDirectory(exportDirectory, openCase); @@ -281,6 +284,62 @@ public class ExtractActionHelper { } } + /** + * A file content extraction visitor that handles for the UI designed to + * handle file name conflicts by appending the object id to the file name. + */ + private static class UIExtractionVisitor extends ExtractFscContentVisitor { + + /** + * @param file The TSK content file. + * @param dest The disk location where the content will be written. + * @param progress progress bar handle to update, if available. null + * otherwise + * @param worker the swing worker background thread the process runs + * within, or null, if in the main thread, used to + * handle task cancellation + * @param source true if source file + */ + UIExtractionVisitor(File dest, ProgressHandle progress, SwingWorker worker, boolean source) { + super(dest, progress, worker, source); + } + + /** + * Writes content and children to disk. + * + * @param content The root content. + * @param file The TSK content file. + * @param dest The disk location where the content will be written. + * @param progress progress bar handle to update, if available. null + * otherwise + * @param worker the swing worker background thread the process runs + * within, or null, if in the main thread, used to + * handle task cancellation + * @param source true if source file + */ + static void writeContent(Content content, File dest, ProgressHandle progress, SwingWorker worker) { + content.accept(new UIExtractionVisitor<>(dest, progress, worker, true)); + } + + + @Override + protected void writeFile(Content file, File dest, ProgressHandle progress, SwingWorker worker, boolean source) throws IOException { + File destFile; + if (dest.exists()) { + String parent = dest.getParent(); + String fileName = dest.getName(); + String objIdFileName = MessageFormat.format("{0}-{1}", file.getId(), fileName); + destFile = new File(parent, objIdFileName); + } else { + destFile = dest; + } + + super.writeFile(file, destFile, progress, worker, source); + } + + + } + /** * Thread that does the actual extraction work */ @@ -333,8 +392,7 @@ public class ExtractActionHelper { // Do the extraction tasks. for (FileExtractionTask task : this.extractionTasks) { progress.progress(Bundle.ExtractActionHelper_progress_fileExtracting(task.destination.getName())); - - ContentUtils.ExtractFscContentVisitor.extract(task.source, task.destination, null, this); + UIExtractionVisitor.writeContent(task.source, task.destination, null, this); } return null; From 06f7c5456413df717e400bb6698ca4acece8bdba Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Feb 2022 09:09:25 -0500 Subject: [PATCH 4/5] remove commented out code --- .../actionhelpers/ExtractActionHelper.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java index 48714e31e9..f42b5f1a62 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java @@ -101,19 +101,7 @@ public class ExtractActionHelper { // If there is an attribute name, change the ":". Otherwise the extracted file will be hidden fileChooser.setSelectedFile(new File(FileUtil.escapeFileName(selectedFile.getName()))); if (fileChooser.showSaveDialog((Component) event.getSource()) == JFileChooser.APPROVE_OPTION) { - File saveLocation = fileChooser.getSelectedFile(); -// if (saveLocation.exists()) { -// if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), -// Bundle.ExtractActionHelper_extractOverwrite_msg(saveLocation.getPath()), -// Bundle.ExtractActionHelper_extractOverwrite_title(), -// JOptionPane.YES_NO_OPTION)) { -// } else { -// return; -// } -// } - - String exportDirectory = saveLocation.getParent(); - updateExportDirectory(exportDirectory, openCase); + updateExportDirectory(fileChooser.getSelectedFile().getParent(), openCase); ArrayList fileExtractionTasks = new ArrayList<>(); fileExtractionTasks.add(new FileExtractionTask(selectedFile, fileChooser.getSelectedFile())); From 87d7a40c42e50824bfd2d1ffbda44a0157c5dfda Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Feb 2022 09:40:18 -0500 Subject: [PATCH 5/5] child visitor fix --- .../autopsy/datamodel/ContentUtils.java | 17 +++++++++++++++-- .../actionhelpers/ExtractActionHelper.java | 6 ++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java index c73ccb80a4..0766316e67 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java @@ -477,6 +477,20 @@ public final class ContentUtils { + content.getName(); return new java.io.File(path); } + + /** + * Returns a visitor to visit any child content. + * @param childFile The disk location where the content will be written. + * @param progress progress bar handle to update, if available. null + * otherwise + * @param worker the swing worker background thread the process runs + * within, or null, if in the main thread, used to + * handle task cancellation + * @return + */ + protected ExtractFscContentVisitor getChildVisitor(java.io.File childFile, ProgressHandle progress, SwingWorker worker) { + return new ExtractFscContentVisitor<>(childFile, progress, worker, false); + } public Void visitDir(AbstractFile dir) { @@ -493,8 +507,7 @@ public final class ContentUtils { for (Content child : dir.getChildren()) { if (child instanceof AbstractFile) { //ensure the directory's artifact children are ignored java.io.File childFile = getFsContentDest(child); - ExtractFscContentVisitor childVisitor - = new ExtractFscContentVisitor<>(childFile, progress, worker, false); + ExtractFscContentVisitor childVisitor = getChildVisitor(childFile, progress, worker); // If this is the source directory of an extract it // will have a progress and worker, and will keep track // of the progress bar's progress diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java index f42b5f1a62..386240ea86 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java @@ -325,6 +325,12 @@ public class ExtractActionHelper { super.writeFile(file, destFile, progress, worker, source); } + @Override + protected ExtractFscContentVisitor getChildVisitor(File childFile, ProgressHandle progress, SwingWorker worker) { + return new UIExtractionVisitor(childFile, progress, worker, false); + } + + }