Autopsy  3.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExtractUnallocAction.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011 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 file 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.Frame;
23 import java.awt.event.ActionEvent;
24 import java.io.File;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.OutputStream;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.Comparator;
31 import java.util.List;
32 import java.util.concurrent.ExecutionException;
33 import java.util.logging.Level;
34 import javax.swing.AbstractAction;
35 import javax.swing.JFileChooser;
36 import javax.swing.JOptionPane;
37 import javax.swing.SwingWorker;
38 import org.netbeans.api.progress.ProgressHandle;
39 import org.netbeans.api.progress.ProgressHandleFactory;
40 import org.openide.util.Cancellable;
41 import org.openide.util.Exceptions;
42 import org.openide.util.NbBundle;
57 
61  final class ExtractUnallocAction extends AbstractAction {
62 
63  private final List<UnallocStruct> LstUnallocs = new ArrayList<UnallocStruct>();
64  private static final List<String> lockedVols = new ArrayList<String>();
65  private static final List<Long> lockedImages = new ArrayList<Long>();
66  private long currentImage = 0L;
67  private static final Logger logger = Logger.getLogger(ExtractUnallocAction.class.getName());
68  private boolean isImage = false;
69 
70  public ExtractUnallocAction(String title, Volume volu) {
71  super(title);
72  UnallocStruct us = new UnallocStruct(volu);
73  LstUnallocs.add(us);
74  }
75 
76  public ExtractUnallocAction(String title, Image img) {
77  super(title);
78  isImage = true;
79  currentImage = img.getId();
80  if (hasVolumeSystem(img)) {
81  for (Volume v : getVolumes(img)) {
82  UnallocStruct us = new UnallocStruct(v);
83  LstUnallocs.add(us);
84  }
85  } else {
86  UnallocStruct us = new UnallocStruct(img);
87  LstUnallocs.add(us);
88  }
89  }
90 
97  @Override
98  public void actionPerformed(ActionEvent e) {
99  if (LstUnallocs != null && LstUnallocs.size() > 0) {
100  if (lockedImages.contains(currentImage)) {
101  MessageNotifyUtil.Message.info(NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.notifyMsg.unallocAlreadyBeingExtr.msg"));
102  //JOptionPane.showMessageDialog(new Frame(), "Unallocated Space is already being extracted on this Image. Please select a different Image.");
103  return;
104  }
105  List<UnallocStruct> copyList = new ArrayList<UnallocStruct>() {
106  {
107  addAll(LstUnallocs);
108  }
109  };
110 
111 
112  JFileChooser fc = new JFileChooser() {
113  @Override
114  public void approveSelection() {
115  File f = getSelectedFile();
116  if (!f.exists() && getDialogType() == SAVE_DIALOG || !f.canWrite()) {
117  JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(),
118  "ExtractUnallocAction.msgDlg.folderDoesntExist.msg"));
119  return;
120  }
121  super.approveSelection();
122  }
123  };
124 
125  fc.setCurrentDirectory(new File(Case.getCurrentCase().getCaseDirectory() + File.separator + "Export"));
126  fc.setDialogTitle(
127  NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.dlgTitle.selectDirToSaveTo.msg"));
128  fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
129  fc.setAcceptAllFileFilterUsed(false);
130  int returnValue = fc.showSaveDialog((Component) e.getSource());
131  if (returnValue == JFileChooser.APPROVE_OPTION) {
132  String destination = fc.getSelectedFile().getPath();
133  for (UnallocStruct u : LstUnallocs) {
134  u.setPath(destination);
135  if (u.llf != null && u.llf.size() > 0 && !lockedVols.contains(u.getFileName())) {
136  //Format for single Unalloc File is ImgName-Unalloc-ImgObjectID-VolumeID.dat
137  if (u.FileInstance.exists()) {
138  int res = JOptionPane.showConfirmDialog(new Frame(), NbBundle.getMessage(this.getClass(),
139  "ExtractUnallocAction.confDlg.unallocFileAlreadyExist.msg",
140  u.getFileName()));
141  if (res == JOptionPane.YES_OPTION) {
142  u.FileInstance.delete();
143  } else {
144  copyList.remove(u);
145  }
146  }
147  if (!isImage & !copyList.isEmpty()) {
148  ExtractUnallocWorker uw = new ExtractUnallocWorker(u);
149  uw.execute();
150  }
151  } else {
152  logger.log(Level.WARNING, "Tried to get unallocated content from volume ID but " + u.VolumeId + u.llf == null ? "its list of unallocated files was null" : "the volume is locked" ); //NON-NLS
153  }
154  }
155  if (isImage && !copyList.isEmpty()) {
156  ExtractUnallocWorker uw = new ExtractUnallocWorker(copyList);
157  uw.execute();
158  }
159  }
160  }
161 
162  }
163 
170  private List<LayoutFile> getUnallocFiles(Content c) {
171  UnallocVisitor uv = new UnallocVisitor();
172  try {
173  List<Content> unallocFiles = c.getChildren();
174  if (null != unallocFiles && unallocFiles.isEmpty() == false) {
175  return unallocFiles.get(0).accept(uv); //Launching it on the root directory
176  }
177  } catch (TskCoreException tce) {
178  logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at sending out the visitor ", tce); //NON-NLS
179  }
180  return Collections.emptyList();
181  }
182 
186  private class ExtractUnallocWorker extends SwingWorker<Integer, Integer> {
187 
188  private ProgressHandle progress;
189  private boolean canceled = false;
190  private List<UnallocStruct> lus = new ArrayList<UnallocStruct>();
192  private int totalSizeinMegs;
193  long totalBytes = 0;
194 
196  //Getting the total megs this worker is going to be doing
197  if (!lockedVols.contains(us.getFileName())) {
198  this.lus.add(us);
199  totalBytes = us.getSizeInBytes();
200  totalSizeinMegs = toMb(totalBytes);
201  lockedVols.add(us.getFileName());
202  }
203  }
204 
205  ExtractUnallocWorker(List<UnallocStruct> lst) {
206  //Getting the total megs this worker is going to be doing
207  for (UnallocStruct lu : lst) {
208  if (!lockedVols.contains(lu.getFileName())) {
209  totalBytes += lu.getSizeInBytes();
210  lockedVols.add(lu.getFileName());
211  this.lus.add(lu);
212  }
213  }
214  totalSizeinMegs = toMb(totalBytes);
215  lockedImages.add(currentImage);
216  }
217 
218  private int toMb(long bytes) {
219  if (bytes > 1024 && (bytes / 1024.0) <= Double.MAX_VALUE) {
220  double Mb = ((bytes / 1024.0) / 1024.0);//Bytes -> Megabytes
221  if (Mb <= Integer.MAX_VALUE) {
222  return (int) Math.ceil(Mb);
223  }
224  }
225  return 0;
226  }
227 
228  @Override
229  protected Integer doInBackground() {
230  try {
231  progress = ProgressHandleFactory.createHandle(
232  NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.progress.extractUnalloc.title"), new Cancellable() {
233  @Override
234  public boolean cancel() {
235  logger.log(Level.INFO, "Canceling extraction of unallocated space"); //NON-NLS
236  canceled = true;
237  if (progress != null) {
238  progress.setDisplayName(NbBundle.getMessage(this.getClass(),
239  "ExtractUnallocAction.progress.displayName.cancelling.text"));
240  }
241  return true;
242  }
243  });
244  int MAX_BYTES = 8192;
245  byte[] buf = new byte[MAX_BYTES]; //read 8kb at a time
246 
247 
248  //Begin the actual File IO
249  progress.start(totalSizeinMegs);
250  int kbs = 0; //Each completion of the while loop adds one to kbs. 16kb * 64 = 1mb.
251  int mbs = 0; //Increments every 128th tick of kbs
252  for (UnallocStruct u : this.lus) {
253  currentlyProcessing = u.getFile();
254  logger.log(Level.INFO, "Writing Unalloc file to " + currentlyProcessing.getPath()); //NON-NLS
255  OutputStream dos = new FileOutputStream(currentlyProcessing);
256  long bytes = 0;
257  int i = 0;
258  while(i < u.getLayouts().size() && bytes != u.getSizeInBytes()){
259  LayoutFile f = u.getLayouts().get(i);
260  long offsetPerFile = 0L;
261  int bytesRead;
262  while(offsetPerFile != f.getSize() && !canceled){
263  if (++kbs % 128 == 0) {
264  mbs++;
265  progress.progress(NbBundle.getMessage(this.getClass(),
266  "ExtractUnallocAction.processing.counter.msg",
267  mbs, totalSizeinMegs), mbs-1);
268  }
269  bytesRead = f.read(buf, offsetPerFile, MAX_BYTES);
270  offsetPerFile+= bytesRead;
271  dos.write(buf, 0, bytesRead);
272  }
273  bytes+=f.getSize();
274  i++;
275  }
276  dos.flush();
277  dos.close();
278 
279  if (canceled) {
280  u.getFile().delete();
281  logger.log(Level.INFO, "Canceled extraction of " + u.getFileName() + " and deleted file"); //NON-NLS
282  } else {
283  logger.log(Level.INFO, "Finished writing unalloc file " + u.getFile().getPath()); //NON-NLS
284  }
285  }
286  progress.finish();
287 
288 
289  } catch (IOException ioe) {
290  logger.log(Level.WARNING, "Could not create Unalloc File; error writing file", ioe); //NON-NLS
291  return -1;
292  } catch (TskCoreException tce) {
293  logger.log(Level.WARNING, "Could not create Unalloc File; error getting image info", tce); //NON-NLS
294  return -1;
295  }
296  return 1;
297  }
298 
299  @Override
300  protected void done() {
301  if (isImage) {
302  lockedImages.remove(currentImage);
303  }
304  for (UnallocStruct u : lus) {
305  lockedVols.remove(u.getFileName());
306  }
307 
308  try {
309  get();
310  if (!canceled && !lus.isEmpty()) {
311  MessageNotifyUtil.Notify.info(NbBundle.getMessage(this.getClass(),
312  "ExtractUnallocAction.done.notifyMsg.completedExtract.title"),
313  NbBundle.getMessage(this.getClass(),
314  "ExtractUnallocAction.done.notifyMsg.completedExtract.msg",
315  lus.get(0).getFile().getParent()));
316  }
317  } catch (InterruptedException | ExecutionException ex) {
319  NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.done.errMsg.title"),
320  NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.done.errMsg.msg", ex.getMessage()));
321  }
322  // catch and ignore if we were cancelled
323  catch (java.util.concurrent.CancellationException ex ) { }
324  }
325  }
326 
333  private boolean hasVolumeSystem(Image img) {
334  try {
335  return (img.getChildren().get(0) instanceof VolumeSystem);
336  } catch (TskCoreException tce) {
337  logger.log(Level.WARNING, "Unable to determine if image has a volume system, extraction may be incomplete", tce); //NON-NLS
338  return false;
339  }
340  }
341 
349  private List<Volume> getVolumes(Image img) {
350  List<Volume> lstVol = new ArrayList<Volume>();
351  try {
352  for (Content v : img.getChildren().get(0).getChildren()) {
353  if (v instanceof Volume) {
354  lstVol.add((Volume) v);
355  }
356  }
357  } catch (TskCoreException tce) {
358  logger.log(Level.WARNING, "Could not get volume information from image. Extraction may be incomplete", tce); //NON-NLS
359  }
360  return lstVol;
361  }
362 
367  private static class UnallocVisitor extends ContentVisitor.Default<List<LayoutFile>> {
368 
376  @Override
377  public List<LayoutFile> visit(final org.sleuthkit.datamodel.LayoutFile lf) {
378  return new ArrayList<LayoutFile>() {
379  {
380  add(lf);
381  }
382  };
383  }
384 
393  @Override
394  public List<LayoutFile> visit(FileSystem fs) {
395  try {
396  for (Content c : fs.getChildren()) {
397  if (((AbstractFile) c).isRoot()) {
398  return c.accept(this);
399  }
400  }
401  } catch (TskCoreException tce) {
402  logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at visiting FileSystem " + fs.getId(), tce); //NON-NLS
403  }
404  return Collections.emptyList();
405  }
406 
414  @Override
415  public List<LayoutFile> visit(VirtualDirectory vd) {
416  try {
417  List<LayoutFile> lflst = new ArrayList<>();
418  for (Content layout : vd.getChildren()) {
419  lflst.add((LayoutFile) layout);
420  }
421  return lflst;
422  } catch (TskCoreException tce) {
423  logger.log(Level.WARNING, "Could not get list of Layout Files, failed at visiting Layout Directory", tce); //NON-NLS
424  }
425  return Collections.emptyList();
426  }
427 
436  @Override
437  public List<LayoutFile> visit(Directory dir) {
438  try {
439  for (Content c : dir.getChildren()) {
440  if (c instanceof VirtualDirectory) {
441  return c.accept(this);
442  }
443  }
444  } catch (TskCoreException tce) {
445  logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at visiting Directory " + dir.getId(), tce); //NON-NLS
446  }
447  return Collections.emptyList();
448  }
449 
450  @Override
451  protected List<LayoutFile> defaultVisit(Content cntnt) {
452  return Collections.emptyList();
453  }
454  }
455 
461  private class SortObjId implements Comparator<LayoutFile> {
462 
463  @Override
464  public int compare(LayoutFile o1, LayoutFile o2) {
465  if (o1.getId() == o2.getId()) {
466  return 0;
467  }
468  if (o1.getId() > o2.getId()) {
469  return 1;
470  } else {
471  return -1;
472  }
473  }
474  }
475 
480  private class UnallocStruct {
481 
482  private List<LayoutFile> llf;
483  private long SizeInBytes;
484  private long VolumeId;
485  private long ImageId;
486  private String ImageName;
487  private String FileName;
489 
495  UnallocStruct(Image img) {
496  this.llf = getUnallocFiles(img);
497  Collections.sort(llf, new SortObjId());
498  this.VolumeId = 0;
499  this.ImageId = img.getId();
500  this.ImageName = img.getName();
501  this.FileName = this.ImageName + "-Unalloc-" + this.ImageId + "-" + 0 + ".dat"; //NON-NLS
502  this.FileInstance = new File(Case.getCurrentCase().getCaseDirectory() + File.separator + "Export" + File.separator + this.FileName);
503  this.SizeInBytes = calcSizeInBytes();
504  }
505 
511  UnallocStruct(Volume volu) {
512  try {
513  this.ImageName = volu.getDataSource().getName();
514  this.ImageId = volu.getDataSource().getId();
515  this.VolumeId = volu.getId();
516  } catch (TskCoreException tce) {
517  logger.log(Level.WARNING, "Unable to properly create ExtractUnallocAction, extraction may be incomplete", tce); //NON-NLS
518  this.ImageName = "";
519  this.ImageId = 0;
520  }
521  this.FileName = this.ImageName + "-Unalloc-" + this.ImageId + "-" + VolumeId + ".dat"; //NON-NLS
522  this.FileInstance = new File(Case.getCurrentCase().getCaseDirectory() + File.separator + "Export" + File.separator + this.FileName);
523  this.llf = getUnallocFiles(volu);
524  Collections.sort(llf, new SortObjId());
525  this.SizeInBytes = calcSizeInBytes();
526  }
527 
528  //Getters
529  int size() {
530  return llf.size();
531  }
532 
533  private long calcSizeInBytes() {
534  long size = 0L;
535  for (LayoutFile f : llf) {
536  size += f.getSize();
537  }
538  return size;
539  }
540 
541  long getSizeInBytes(){
542  return this.SizeInBytes;
543  }
544 
545  long getVolumeId() {
546  return this.VolumeId;
547  }
548 
549  long getImageId() {
550  return this.ImageId;
551  }
552 
553  String getImageName() {
554  return this.ImageName;
555  }
556 
557  List<LayoutFile> getLayouts() {
558  return this.llf;
559  }
560 
561  String getFileName() {
562  return this.FileName;
563  }
564 
565  File getFile() {
566  return this.FileInstance;
567  }
568 
569  void setPath(String path) {
570  this.FileInstance = new File(path + File.separator + this.FileName);
571  }
572  }
573 }
List< LayoutFile > visit(final org.sleuthkit.datamodel.LayoutFile lf)
public< T > T accept(ContentVisitor< T > v)
final int read(byte[] buf, long offset, long len)

Copyright © 2012-2015 Basis Technology. Generated on: Mon Oct 19 2015
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.