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;