19 package org.sleuthkit.autopsy.directorytree;
21 import java.awt.Component;
22 import java.awt.Frame;
23 import java.awt.event.ActionEvent;
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.NbBundle;
60 final class ExtractUnallocAction
extends AbstractAction {
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;
69 public ExtractUnallocAction(String title, Volume volu) {
71 UnallocStruct us =
new UnallocStruct(volu);
75 public ExtractUnallocAction(String title, Image img) {
78 currentImage = img.getId();
79 if (hasVolumeSystem(img)) {
80 for (Volume v : getVolumes(img)) {
81 UnallocStruct us =
new UnallocStruct(v);
85 UnallocStruct us =
new UnallocStruct(img);
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"));
104 List<UnallocStruct> copyList =
new ArrayList<UnallocStruct>() {
110 JFileChooser fc =
new JFileChooser() {
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"));
119 super.approveSelection();
123 fc.setCurrentDirectory(
new File(Case.getCurrentCase().getExportDirectory()));
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())) {
135 if (u.FileInstance.exists()) {
136 int res = JOptionPane.showConfirmDialog(
new Frame(), NbBundle.getMessage(
this.getClass(),
137 "ExtractUnallocAction.confDlg.unallocFileAlreadyExist.msg",
139 if (res == JOptionPane.YES_OPTION) {
140 u.FileInstance.delete();
145 if (!isImage & !copyList.isEmpty()) {
146 ExtractUnallocWorker uw =
new ExtractUnallocWorker(u);
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");
153 if (isImage && !copyList.isEmpty()) {
154 ExtractUnallocWorker uw =
new ExtractUnallocWorker(copyList);
169 private List<LayoutFile> getUnallocFiles(Content c) {
170 UnallocVisitor uv =
new UnallocVisitor();
172 List<Content> unallocFiles = c.getChildren();
173 if (null != unallocFiles && unallocFiles.isEmpty() ==
false) {
174 return unallocFiles.get(0).accept(uv);
176 }
catch (TskCoreException tce) {
177 logger.log(Level.WARNING,
"Couldn't get a list of Unallocated Files, failed at sending out the visitor ", tce);
179 return Collections.emptyList();
189 private List<UnallocStruct>
lus =
new ArrayList<UnallocStruct>();
196 if (!lockedVols.contains(us.getFileName())) {
198 totalBytes = us.getSizeInBytes();
199 totalSizeinMegs =
toMb(totalBytes);
200 lockedVols.add(us.getFileName());
207 if (!lockedVols.contains(lu.getFileName())) {
208 totalBytes += lu.getSizeInBytes();
209 lockedVols.add(lu.getFileName());
213 totalSizeinMegs =
toMb(totalBytes);
214 lockedImages.add(currentImage);
218 if (bytes > 1024 && (bytes / 1024.0) <= Double.MAX_VALUE) {
219 double Mb = ((bytes / 1024.0) / 1024.0);
220 if (Mb <= Integer.MAX_VALUE) {
221 return (
int) Math.ceil(Mb);
230 progress = ProgressHandleFactory.createHandle(
231 NbBundle.getMessage(
this.getClass(),
"ExtractUnallocAction.progress.extractUnalloc.title"),
new Cancellable() {
233 public boolean cancel() {
234 logger.log(Level.INFO,
"Canceling extraction of unallocated space");
236 if (progress != null) {
237 progress.setDisplayName(NbBundle.getMessage(
this.getClass(),
238 "ExtractUnallocAction.progress.displayName.cancelling.text"));
243 int MAX_BYTES = 8192;
244 byte[] buf =
new byte[MAX_BYTES];
247 progress.start(totalSizeinMegs);
251 currentlyProcessing = u.getFile();
252 logger.log(Level.INFO,
"Writing Unalloc file to " + currentlyProcessing.getPath());
253 OutputStream dos =
new FileOutputStream(currentlyProcessing);
256 while (i < u.getLayouts().size() && bytes != u.getSizeInBytes()) {
257 LayoutFile f = u.getLayouts().get(i);
258 long offsetPerFile = 0L;
260 while (offsetPerFile != f.getSize() && !
canceled) {
261 if (++kbs % 128 == 0) {
263 progress.progress(NbBundle.getMessage(
this.getClass(),
264 "ExtractUnallocAction.processing.counter.msg",
267 bytesRead = f.read(buf, offsetPerFile, MAX_BYTES);
268 offsetPerFile += bytesRead;
269 dos.write(buf, 0, bytesRead);
271 bytes += f.getSize();
278 u.getFile().delete();
279 logger.log(Level.INFO,
"Canceled extraction of " + u.getFileName() +
" and deleted file");
281 logger.log(Level.INFO,
"Finished writing unalloc file " + u.getFile().getPath());
286 }
catch (IOException ioe) {
287 logger.log(Level.WARNING,
"Could not create Unalloc File; error writing file", ioe);
289 }
catch (TskCoreException tce) {
290 logger.log(Level.WARNING,
"Could not create Unalloc File; error getting image info", tce);
299 lockedImages.remove(currentImage);
302 lockedVols.remove(u.getFileName());
307 if (!canceled && !lus.isEmpty()) {
309 "ExtractUnallocAction.done.notifyMsg.completedExtract.title"),
310 NbBundle.getMessage(
this.getClass(),
311 "ExtractUnallocAction.done.notifyMsg.completedExtract.msg",
312 lus.get(0).getFile().getParent()));
314 }
catch (InterruptedException | ExecutionException ex) {
316 NbBundle.getMessage(
this.getClass(),
"ExtractUnallocAction.done.errMsg.title"),
317 NbBundle.getMessage(
this.getClass(),
"ExtractUnallocAction.done.errMsg.msg", ex.getMessage()));
319 catch (java.util.concurrent.CancellationException ex) {
331 private boolean hasVolumeSystem(Image img) {
333 return (img.getChildren().get(0) instanceof VolumeSystem);
334 }
catch (TskCoreException tce) {
335 logger.log(Level.WARNING,
"Unable to determine if image has a volume system, extraction may be incomplete", tce);
348 private List<Volume> getVolumes(Image img) {
349 List<Volume> lstVol =
new ArrayList<Volume>();
351 for (Content v : img.getChildren().get(0).getChildren()) {
352 if (v instanceof Volume) {
353 lstVol.add((Volume) v);
356 }
catch (TskCoreException tce) {
357 logger.log(Level.WARNING,
"Could not get volume information from image. Extraction may be incomplete", tce);
366 private static class UnallocVisitor extends ContentVisitor.Default<List<LayoutFile>> {
378 return new ArrayList<LayoutFile>() {
395 public List<LayoutFile>
visit(FileSystem fs) {
397 for (Content c : fs.getChildren()) {
398 if (((AbstractFile) c).isRoot()) {
399 return c.accept(
this);
402 }
catch (TskCoreException tce) {
403 logger.log(Level.WARNING,
"Couldn't get a list of Unallocated Files, failed at visiting FileSystem " + fs.getId(), tce);
405 return Collections.emptyList();
417 public List<LayoutFile>
visit(VirtualDirectory vd) {
419 List<LayoutFile> lflst =
new ArrayList<>();
420 for (Content layout : vd.getChildren()) {
421 lflst.add((LayoutFile) layout);
424 }
catch (TskCoreException tce) {
425 logger.log(Level.WARNING,
"Could not get list of Layout Files, failed at visiting Layout Directory", tce);
427 return Collections.emptyList();
440 public List<LayoutFile>
visit(Directory dir) {
442 for (Content c : dir.getChildren()) {
443 if (c instanceof VirtualDirectory) {
444 return c.accept(
this);
447 }
catch (TskCoreException tce) {
448 logger.log(Level.WARNING,
"Couldn't get a list of Unallocated Files, failed at visiting Directory " + dir.getId(), tce);
450 return Collections.emptyList();
455 return Collections.emptyList();
464 private class SortObjId implements Comparator<LayoutFile> {
467 public int compare(LayoutFile o1, LayoutFile o2) {
468 if (o1.getId() == o2.getId()) {
471 if (o1.getId() > o2.getId()) {
485 private List<LayoutFile>
llf;
499 this.llf = getUnallocFiles(img);
502 this.ImageId = img.getId();
503 this.ImageName = img.getName();
504 this.FileName = this.ImageName +
"-Unalloc-" + this.ImageId +
"-" + 0 +
".dat";
516 this.ImageName = volu.getDataSource().getName();
517 this.ImageId = volu.getDataSource().getId();
518 this.VolumeId = volu.getId();
519 }
catch (TskCoreException tce) {
520 logger.log(Level.WARNING,
"Unable to properly create ExtractUnallocAction, extraction may be incomplete", tce);
524 this.FileName = this.ImageName +
"-Unalloc-" + this.ImageId +
"-" + VolumeId +
".dat";
525 this.FileInstance =
new File(Case.getCurrentCase().getExportDirectory() + File.separator + this.
FileName);
526 this.llf = getUnallocFiles(volu);
527 Collections.sort(llf,
new SortObjId());
538 for (LayoutFile f : llf) {
544 long getSizeInBytes() {
556 String getImageName() {
560 List<LayoutFile> getLayouts() {
564 String getFileName() {
572 void setPath(String path) {
573 this.FileInstance =
new File(path + File.separator +
this.FileName);
static void info(String title, String message)
static void error(String title, String message)
static Case getCurrentCase()
String getExportDirectory()