Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExtractAction.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this content except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.directorytree;
20 
21 import java.awt.Component;
22 import java.awt.event.ActionEvent;
23 import java.io.File;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Iterator;
27 import java.util.logging.Level;
28 import javax.swing.AbstractAction;
29 import javax.swing.JFileChooser;
30 import javax.swing.JOptionPane;
31 import javax.swing.SwingWorker;
32 import org.netbeans.api.progress.ProgressHandle;
33 import org.openide.util.Cancellable;
34 import org.openide.util.NbBundle;
35 import org.openide.util.Utilities;
42 import org.sleuthkit.datamodel.AbstractFile;
43 import org.sleuthkit.datamodel.Content;
44 import org.sleuthkit.datamodel.TskCoreException;
45 
49 public final class ExtractAction extends AbstractAction {
50 
51  private Logger logger = Logger.getLogger(ExtractAction.class.getName());
52 
53  // This class is a singleton to support multi-selection of nodes, since
54  // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
55  // node in the array returns a reference to the same action object from Node.getActions(boolean).
56  private static ExtractAction instance;
57 
58  public static synchronized ExtractAction getInstance() {
59  if (null == instance) {
60  instance = new ExtractAction();
61  }
62  return instance;
63  }
64 
65  private ExtractAction() {
66  super(NbBundle.getMessage(ExtractAction.class, "ExtractAction.title.extractFiles.text"));
67  }
68 
75  @Override
76  public void actionPerformed(ActionEvent e) {
77  Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
78  if (selectedFiles.size() > 1) {
79  extractFiles(e, selectedFiles);
80  } else if (selectedFiles.size() == 1) {
81  AbstractFile source = selectedFiles.iterator().next();
82  if (source.isDir()) {
83  extractFiles(e, selectedFiles);
84  } else {
85  extractFile(e, selectedFiles.iterator().next());
86  }
87  }
88  }
89 
96  private void extractFile(ActionEvent e, AbstractFile selectedFile) {
97  JFileChooser fileChooser = new JFileChooser();
98  fileChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory()));
99  // If there is an attribute name, change the ":". Otherwise the extracted file will be hidden
100  fileChooser.setSelectedFile(new File(FileUtil.escapeFileName(selectedFile.getName())));
101  if (fileChooser.showSaveDialog((Component) e.getSource()) == JFileChooser.APPROVE_OPTION) {
102  ArrayList<FileExtractionTask> fileExtractionTasks = new ArrayList<>();
103  fileExtractionTasks.add(new FileExtractionTask(selectedFile, fileChooser.getSelectedFile()));
104  runExtractionTasks(e, fileExtractionTasks);
105  }
106  }
107 
114  private void extractFiles(ActionEvent e, Collection<? extends AbstractFile> selectedFiles) {
115  JFileChooser folderChooser = new JFileChooser();
116  folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
117  folderChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory()));
118  if (folderChooser.showSaveDialog((Component) e.getSource()) == JFileChooser.APPROVE_OPTION) {
119  File destinationFolder = folderChooser.getSelectedFile();
120  if (!destinationFolder.exists()) {
121  try {
122  destinationFolder.mkdirs();
123  } catch (Exception ex) {
124  JOptionPane.showMessageDialog((Component) e.getSource(), NbBundle.getMessage(this.getClass(),
125  "ExtractAction.extractFiles.cantCreateFolderErr.msg"));
126  logger.log(Level.INFO, "Unable to create folder(s) for user " + destinationFolder.getAbsolutePath(), ex); //NON-NLS
127  return;
128  }
129  }
130 
131  // make a task for each file
132  ArrayList<FileExtractionTask> fileExtractionTasks = new ArrayList<>();
133  for (AbstractFile source : selectedFiles) {
134  // If there is an attribute name, change the ":". Otherwise the extracted file will be hidden
135  fileExtractionTasks.add(new FileExtractionTask(source, new File(destinationFolder, source.getId() + "-" + FileUtil.escapeFileName(source.getName()))));
136  }
137  runExtractionTasks(e, fileExtractionTasks);
138  }
139  }
140 
141  private void runExtractionTasks(ActionEvent e, ArrayList<FileExtractionTask> fileExtractionTasks) {
142 
143  // verify all of the sources and destinations are OK
144  for (Iterator<FileExtractionTask> it = fileExtractionTasks.iterator(); it.hasNext();) {
145  FileExtractionTask task = it.next();
146 
147  if (ContentUtils.isDotDirectory(task.source)) {
148  //JOptionPane.showMessageDialog((Component) e.getSource(), "Cannot extract virtual " + task.source.getName() + " directory.", "File is Virtual Directory", JOptionPane.WARNING_MESSAGE);
149  it.remove();
150  continue;
151  }
152 
153  /*
154  * @@@ Problems with this code: - does not prevent us from having
155  * multiple files with the same target name in the task list (in
156  * which case, the first ones are overwritten) Unique Id was added
157  * to set of names before calling this method to deal with that.
158  */
159  if (task.destination.exists()) {
160  if (JOptionPane.showConfirmDialog((Component) e.getSource(),
161  NbBundle.getMessage(this.getClass(), "ExtractAction.confDlg.destFileExist.msg", task.destination.getAbsolutePath()),
162  NbBundle.getMessage(this.getClass(), "ExtractAction.confDlg.destFileExist.title"),
163  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
164  if (!FileUtil.deleteFileDir(task.destination)) {
165  JOptionPane.showMessageDialog((Component) e.getSource(),
166  NbBundle.getMessage(this.getClass(), "ExtractAction.msgDlg.cantOverwriteFile.msg", task.destination.getAbsolutePath()));
167  it.remove();
168  }
169  } else {
170  it.remove();
171  }
172  }
173  }
174 
175  // launch a thread to do the work
176  if (!fileExtractionTasks.isEmpty()) {
177  try {
178  FileExtracter extracter = new FileExtracter(fileExtractionTasks);
179  extracter.execute();
180  } catch (Exception ex) {
181  logger.log(Level.WARNING, "Unable to start background file extraction thread", ex); //NON-NLS
182  }
183  } else {
185  NbBundle.getMessage(this.getClass(), "ExtractAction.notifyDlg.noFileToExtr.msg"));
186  }
187  }
188 
189  private class FileExtractionTask {
190 
191  AbstractFile source;
192  File destination;
193 
194  FileExtractionTask(AbstractFile source, File destination) {
195  this.source = source;
196  this.destination = destination;
197  }
198  }
199 
203  private class FileExtracter extends SwingWorker<Object, Void> {
204 
205  private Logger logger = Logger.getLogger(FileExtracter.class.getName());
206  private ProgressHandle progress;
207  private ArrayList<FileExtractionTask> extractionTasks;
208 
209  FileExtracter(ArrayList<FileExtractionTask> extractionTasks) {
210  this.extractionTasks = extractionTasks;
211  }
212 
213  @Override
214  protected Object doInBackground() throws Exception {
215  if (extractionTasks.isEmpty()) {
216  return null;
217  }
218 
219  // Setup progress bar.
220  final String displayName = NbBundle.getMessage(this.getClass(), "ExtractAction.progress.extracting");
221  progress = ProgressHandle.createHandle(displayName, new Cancellable() {
222  @Override
223  public boolean cancel() {
224  if (progress != null) {
225  progress.setDisplayName(
226  NbBundle.getMessage(this.getClass(), "ExtractAction.progress.cancellingExtraction", displayName));
227  }
228  return ExtractAction.FileExtracter.this.cancel(true);
229  }
230  });
231  progress.start();
232  progress.switchToIndeterminate();
233 
234  /*
235  * @@@ Add back in -> Causes exceptions int workUnits = 0; for
236  * (FileExtractionTask task : extractionTasks) { workUnits +=
237  * calculateProgressBarWorkUnits(task.source); }
238  * progress.switchToDeterminate(workUnits);
239  */
240  // Do the extraction tasks.
241  for (FileExtractionTask task : this.extractionTasks) {
242  // @@@ Note, we are no longer passing in progress
243  ExtractFscContentVisitor.extract(task.source, task.destination, null, this);
244  }
245 
246  return null;
247  }
248 
249  @Override
250  protected void done() {
251  boolean msgDisplayed = false;
252  try {
253  super.get();
254  } catch (Exception ex) {
255  logger.log(Level.SEVERE, "Fatal error during file extraction", ex); //NON-NLS
257  NbBundle.getMessage(this.getClass(), "ExtractAction.done.notifyMsg.extractErr", ex.getMessage()));
258  msgDisplayed = true;
259  } finally {
260  progress.finish();
261  if (!this.isCancelled() && !msgDisplayed) {
263  NbBundle.getMessage(this.getClass(), "ExtractAction.done.notifyMsg.fileExtr.text"));
264  }
265  }
266  }
267 
268  private int calculateProgressBarWorkUnits(AbstractFile file) {
269  int workUnits = 0;
270  if (file.isFile()) {
271  workUnits += file.getSize();
272  } else {
273  try {
274  for (Content child : file.getChildren()) {
275  if (child instanceof AbstractFile) {
276  workUnits += calculateProgressBarWorkUnits((AbstractFile) child);
277  }
278  }
279  } catch (TskCoreException ex) {
280  logger.log(Level.SEVERE, "Could not get children of content", ex); //NON-NLS
281  }
282  }
283  return workUnits;
284  }
285  }
286 }
static boolean deleteFileDir(File path)
Definition: FileUtil.java:87
static synchronized ExtractAction getInstance()
static< T, V > void extract(Content cntnt, java.io.File dest, ProgressHandle progress, SwingWorker< T, V > worker)
void extractFile(ActionEvent e, AbstractFile selectedFile)
static String escapeFileName(String fileName)
Definition: FileUtil.java:169
synchronized static Logger getLogger(String name)
Definition: Logger.java:161
void runExtractionTasks(ActionEvent e, ArrayList< FileExtractionTask > fileExtractionTasks)
void extractFiles(ActionEvent e, Collection<?extends AbstractFile > selectedFiles)
static boolean isDotDirectory(AbstractFile dir)

Copyright © 2012-2016 Basis Technology. Generated on: Mon Jan 2 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.