Autopsy  4.4.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-2017 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.openide.util.Cancellable;
40 import org.openide.util.NbBundle;
44 import org.sleuthkit.datamodel.AbstractContent;
45 import org.sleuthkit.datamodel.AbstractFile;
46 import org.sleuthkit.datamodel.Content;
47 import org.sleuthkit.datamodel.ContentVisitor;
48 import org.sleuthkit.datamodel.Directory;
49 import org.sleuthkit.datamodel.FileSystem;
50 import org.sleuthkit.datamodel.Image;
51 import org.sleuthkit.datamodel.LayoutFile;
52 import org.sleuthkit.datamodel.TskCoreException;
53 import org.sleuthkit.datamodel.VirtualDirectory;
54 import org.sleuthkit.datamodel.Volume;
55 import org.sleuthkit.datamodel.VolumeSystem;
56 
60 final class ExtractUnallocAction extends AbstractAction {
61 
62  private final List<UnallocStruct> LstUnallocs = new ArrayList<UnallocStruct>();
63  private static final List<String> lockedVols = new ArrayList<String>();
64  private static final List<Long> lockedImages = new ArrayList<Long>();
65  private long currentImage = 0L;
66  private static final Logger logger = Logger.getLogger(ExtractUnallocAction.class.getName());
67  private boolean isImage = false;
68 
69  public ExtractUnallocAction(String title, Volume volu) {
70  super(title);
71  UnallocStruct us = new UnallocStruct(volu);
72  LstUnallocs.add(us);
73  }
74 
75  public ExtractUnallocAction(String title, Image img) {
76  super(title);
77  isImage = true;
78  currentImage = img.getId();
79  if (hasVolumeSystem(img)) {
80  for (Volume v : getVolumes(img)) {
81  UnallocStruct us = new UnallocStruct(v);
82  LstUnallocs.add(us);
83  }
84  } else {
85  UnallocStruct us = new UnallocStruct(img);
86  LstUnallocs.add(us);
87  }
88  }
89 
96  @Override
97  public void actionPerformed(ActionEvent e) {
98  if (LstUnallocs != null && LstUnallocs.size() > 0) {
99  if (lockedImages.contains(currentImage)) {
100  MessageNotifyUtil.Message.info(NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.notifyMsg.unallocAlreadyBeingExtr.msg"));
101  //JOptionPane.showMessageDialog(new Frame(), "Unallocated Space is already being extracted on this Image. Please select a different Image.");
102  return;
103  }
104  List<UnallocStruct> copyList = new ArrayList<UnallocStruct>() {
105  {
106  addAll(LstUnallocs);
107  }
108  };
109 
110  JFileChooser fc = new JFileChooser() {
111  @Override
112  public void approveSelection() {
113  File f = getSelectedFile();
114  if (!f.exists() && getDialogType() == SAVE_DIALOG || !f.canWrite()) {
115  JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(),
116  "ExtractUnallocAction.msgDlg.folderDoesntExist.msg"));
117  return;
118  }
119  super.approveSelection();
120  }
121  };
122 
123  fc.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory()));
124  fc.setDialogTitle(
125  NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.dlgTitle.selectDirToSaveTo.msg"));
126  fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
127  fc.setAcceptAllFileFilterUsed(false);
128  int returnValue = fc.showSaveDialog((Component) e.getSource());
129  if (returnValue == JFileChooser.APPROVE_OPTION) {
130  String destination = fc.getSelectedFile().getPath();
131  for (UnallocStruct u : LstUnallocs) {
132  u.setPath(destination);
133  if (u.llf != null && u.llf.size() > 0 && !lockedVols.contains(u.getFileName())) {
134  //Format for single Unalloc File is ImgName-Unalloc-ImgObjectID-VolumeID.dat
135  if (u.FileInstance.exists()) {
136  int res = JOptionPane.showConfirmDialog(new Frame(), NbBundle.getMessage(this.getClass(),
137  "ExtractUnallocAction.confDlg.unallocFileAlreadyExist.msg",
138  u.getFileName()));
139  if (res == JOptionPane.YES_OPTION) {
140  u.FileInstance.delete();
141  } else {
142  copyList.remove(u);
143  }
144  }
145  if (!isImage & !copyList.isEmpty()) {
146  ExtractUnallocWorker uw = new ExtractUnallocWorker(u);
147  uw.execute();
148  }
149  } else {
150  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
151  }
152  }
153  if (isImage && !copyList.isEmpty()) {
154  ExtractUnallocWorker uw = new ExtractUnallocWorker(copyList);
155  uw.execute();
156  }
157  }
158  }
159 
160  }
161 
169  private List<LayoutFile> getUnallocFiles(Content c) {
170  UnallocVisitor uv = new UnallocVisitor();
171  try {
172  for (Content contentChild : c.getChildren()) {
173  if (contentChild instanceof AbstractContent) {
174  return contentChild.accept(uv); //call on first non-artifact child added to database
175  }
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>();
191  private File currentlyProcessing;
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 = ProgressHandle.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  //Begin the actual File IO
248  progress.start(totalSizeinMegs);
249  int kbs = 0; //Each completion of the while loop adds one to kbs. 16kb * 64 = 1mb.
250  int mbs = 0; //Increments every 128th tick of kbs
251  for (UnallocStruct u : this.lus) {
252  currentlyProcessing = u.getFile();
253  logger.log(Level.INFO, "Writing Unalloc file to " + currentlyProcessing.getPath()); //NON-NLS
254  OutputStream dos = new FileOutputStream(currentlyProcessing);
255  long bytes = 0;
256  int i = 0;
257  while (i < u.getLayouts().size() && bytes != u.getSizeInBytes()) {
258  LayoutFile f = u.getLayouts().get(i);
259  long offsetPerFile = 0L;
260  int bytesRead;
261  while (offsetPerFile != f.getSize() && !canceled) {
262  if (++kbs % 128 == 0) {
263  mbs++;
264  progress.progress(NbBundle.getMessage(this.getClass(),
265  "ExtractUnallocAction.processing.counter.msg",
266  mbs, totalSizeinMegs), mbs - 1);
267  }
268  bytesRead = f.read(buf, offsetPerFile, MAX_BYTES);
269  offsetPerFile += bytesRead;
270  dos.write(buf, 0, bytesRead);
271  }
272  bytes += f.getSize();
273  i++;
274  }
275  dos.flush();
276  dos.close();
277 
278  if (canceled) {
279  u.getFile().delete();
280  logger.log(Level.INFO, "Canceled extraction of " + u.getFileName() + " and deleted file"); //NON-NLS
281  } else {
282  logger.log(Level.INFO, "Finished writing unalloc file " + u.getFile().getPath()); //NON-NLS
283  }
284  }
285  progress.finish();
286 
287  } catch (IOException ioe) {
288  logger.log(Level.WARNING, "Could not create Unalloc File; error writing file", ioe); //NON-NLS
289  return -1;
290  } catch (TskCoreException tce) {
291  logger.log(Level.WARNING, "Could not create Unalloc File; error getting image info", tce); //NON-NLS
292  return -1;
293  }
294  return 1;
295  }
296 
297  @Override
298  protected void done() {
299  if (isImage) {
300  lockedImages.remove(currentImage);
301  }
302  for (UnallocStruct u : lus) {
303  lockedVols.remove(u.getFileName());
304  }
305 
306  try {
307  get();
308  if (!canceled && !lus.isEmpty()) {
309  MessageNotifyUtil.Notify.info(NbBundle.getMessage(this.getClass(),
310  "ExtractUnallocAction.done.notifyMsg.completedExtract.title"),
311  NbBundle.getMessage(this.getClass(),
312  "ExtractUnallocAction.done.notifyMsg.completedExtract.msg",
313  lus.get(0).getFile().getParent()));
314  }
315  } catch (InterruptedException | ExecutionException ex) {
317  NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.done.errMsg.title"),
318  NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.done.errMsg.msg", ex.getMessage()));
319  } // catch and ignore if we were cancelled
320  catch (java.util.concurrent.CancellationException ex) {
321  }
322  }
323  }
324 
332  private boolean hasVolumeSystem(Image img) {
333  try {
334  for (Content c : img.getChildren()) {
335  if (c instanceof VolumeSystem) {
336  return true;
337  }
338  }
339  } catch (TskCoreException tce) {
340  logger.log(Level.SEVERE, "Unable to determine if image has a volume system, extraction may be incomplete", tce); //NON-NLS
341  }
342  return false;
343  }
344 
353  private List<Volume> getVolumes(Image img) {
354  List<Volume> lstVol = new ArrayList<Volume>();
355  try {
356  for (Content v : img.getChildren().get(0).getChildren()) {
357  if (v instanceof Volume) {
358  lstVol.add((Volume) v);
359  }
360  }
361  } catch (TskCoreException tce) {
362  logger.log(Level.WARNING, "Could not get volume information from image. Extraction may be incomplete", tce); //NON-NLS
363  }
364  return lstVol;
365  }
366 
371  private static class UnallocVisitor extends ContentVisitor.Default<List<LayoutFile>> {
372 
381  @Override
382  public List<LayoutFile> visit(final org.sleuthkit.datamodel.LayoutFile lf) {
383  return new ArrayList<LayoutFile>() {
384  {
385  add(lf);
386  }
387  };
388  }
389 
399  @Override
400  public List<LayoutFile> visit(FileSystem fs) {
401  try {
402  for (Content c : fs.getChildren()) {
403  if (c instanceof AbstractFile) {
404  if (((AbstractFile) c).isRoot()) {
405  return c.accept(this);
406  }
407  }
408  }
409  } catch (TskCoreException tce) {
410  logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at visiting FileSystem " + fs.getId(), tce); //NON-NLS
411  }
412  return Collections.emptyList();
413  }
414 
423  @Override
424  public List<LayoutFile> visit(VirtualDirectory vd) {
425  try {
426  List<LayoutFile> lflst = new ArrayList<>();
427  for (Content layout : vd.getChildren()) {
428  if (layout instanceof LayoutFile) {
429  lflst.add((LayoutFile) layout);
430  }
431  }
432  return lflst;
433  } catch (TskCoreException tce) {
434  logger.log(Level.WARNING, "Could not get list of Layout Files, failed at visiting Layout Directory", tce); //NON-NLS
435  }
436  return Collections.emptyList();
437  }
438 
448  @Override
449  public List<LayoutFile> visit(Directory dir) {
450  try {
451  for (Content c : dir.getChildren()) {
452  if (c instanceof VirtualDirectory) {
453  return c.accept(this);
454  }
455  }
456  } catch (TskCoreException tce) {
457  logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at visiting Directory " + dir.getId(), tce); //NON-NLS
458  }
459  return Collections.emptyList();
460  }
461 
462  @Override
463  protected List<LayoutFile> defaultVisit(Content cntnt) {
464  return Collections.emptyList();
465  }
466  }
467 
473  private class SortObjId implements Comparator<LayoutFile> {
474 
475  @Override
476  public int compare(LayoutFile o1, LayoutFile o2) {
477  if (o1.getId() == o2.getId()) {
478  return 0;
479  }
480  if (o1.getId() > o2.getId()) {
481  return 1;
482  } else {
483  return -1;
484  }
485  }
486  }
487 
492  private class UnallocStruct {
493 
494  private List<LayoutFile> llf;
495  private long SizeInBytes;
496  private long VolumeId;
497  private long ImageId;
498  private String ImageName;
499  private String FileName;
500  private File FileInstance;
501 
507  UnallocStruct(Image img) {
508  this.llf = getUnallocFiles(img);
509  Collections.sort(llf, new SortObjId());
510  this.VolumeId = 0;
511  this.ImageId = img.getId();
512  this.ImageName = img.getName();
513  this.FileName = this.ImageName + "-Unalloc-" + this.ImageId + "-" + 0 + ".dat"; //NON-NLS
514  this.FileInstance = new File(Case.getCurrentCase().getExportDirectory() + File.separator + this.FileName);
515  this.SizeInBytes = calcSizeInBytes();
516  }
517 
523  UnallocStruct(Volume volu) {
524  try {
525  this.ImageName = volu.getDataSource().getName();
526  this.ImageId = volu.getDataSource().getId();
527  this.VolumeId = volu.getId();
528  } catch (TskCoreException tce) {
529  logger.log(Level.WARNING, "Unable to properly create ExtractUnallocAction, extraction may be incomplete", tce); //NON-NLS
530  this.ImageName = "";
531  this.ImageId = 0;
532  }
533  this.FileName = this.ImageName + "-Unalloc-" + this.ImageId + "-" + VolumeId + ".dat"; //NON-NLS
534  this.FileInstance = new File(Case.getCurrentCase().getExportDirectory() + File.separator + this.FileName);
535  this.llf = getUnallocFiles(volu);
536  Collections.sort(llf, new SortObjId());
537  this.SizeInBytes = calcSizeInBytes();
538  }
539 
540  //Getters
541  int size() {
542  return llf.size();
543  }
544 
545  private long calcSizeInBytes() {
546  long size = 0L;
547  for (LayoutFile f : llf) {
548  size += f.getSize();
549  }
550  return size;
551  }
552 
553  long getSizeInBytes() {
554  return this.SizeInBytes;
555  }
556 
557  long getVolumeId() {
558  return this.VolumeId;
559  }
560 
561  long getImageId() {
562  return this.ImageId;
563  }
564 
565  String getImageName() {
566  return this.ImageName;
567  }
568 
569  List<LayoutFile> getLayouts() {
570  return this.llf;
571  }
572 
573  String getFileName() {
574  return this.FileName;
575  }
576 
577  File getFile() {
578  return this.FileInstance;
579  }
580 
581  void setPath(String path) {
582  this.FileInstance = new File(path + File.separator + this.FileName);
583  }
584  }
585 }
static void info(String title, String message)
List< LayoutFile > visit(final org.sleuthkit.datamodel.LayoutFile lf)
static void error(String title, String message)

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