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.openide.util.Cancellable;
40 import org.openide.util.NbBundle;
59 final class ExtractUnallocAction
extends AbstractAction {
61 private final List<UnallocStruct> LstUnallocs =
new ArrayList<UnallocStruct>();
62 private static final List<String> lockedVols =
new ArrayList<String>();
63 private static final List<Long> lockedImages =
new ArrayList<Long>();
64 private long currentImage = 0L;
65 private static final Logger logger = Logger.getLogger(ExtractUnallocAction.class.getName());
66 private boolean isImage =
false;
68 public ExtractUnallocAction(String title, Volume volu) {
70 UnallocStruct us =
new UnallocStruct(volu);
74 public ExtractUnallocAction(String title, Image img) {
77 currentImage = img.getId();
78 if (hasVolumeSystem(img)) {
79 for (Volume v : getVolumes(img)) {
80 UnallocStruct us =
new UnallocStruct(v);
84 UnallocStruct us =
new UnallocStruct(img);
96 public void actionPerformed(ActionEvent e) {
97 if (LstUnallocs != null && LstUnallocs.size() > 0) {
98 if (lockedImages.contains(currentImage)) {
99 MessageNotifyUtil.Message.info(NbBundle.getMessage(
this.getClass(),
"ExtractUnallocAction.notifyMsg.unallocAlreadyBeingExtr.msg"));
103 List<UnallocStruct> copyList =
new ArrayList<UnallocStruct>() {
109 JFileChooser fc =
new JFileChooser() {
111 public void approveSelection() {
112 File f = getSelectedFile();
113 if (!f.exists() && getDialogType() == SAVE_DIALOG || !f.canWrite()) {
114 JOptionPane.showMessageDialog(
this, NbBundle.getMessage(
this.getClass(),
115 "ExtractUnallocAction.msgDlg.folderDoesntExist.msg"));
118 super.approveSelection();
122 fc.setCurrentDirectory(
new File(Case.getCurrentCase().getExportDirectory()));
124 NbBundle.getMessage(
this.getClass(),
"ExtractUnallocAction.dlgTitle.selectDirToSaveTo.msg"));
125 fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
126 fc.setAcceptAllFileFilterUsed(
false);
127 int returnValue = fc.showSaveDialog((Component) e.getSource());
128 if (returnValue == JFileChooser.APPROVE_OPTION) {
129 String destination = fc.getSelectedFile().getPath();
130 for (UnallocStruct u : LstUnallocs) {
131 u.setPath(destination);
132 if (u.llf != null && u.llf.size() > 0 && !lockedVols.contains(u.getFileName())) {
134 if (u.FileInstance.exists()) {
135 int res = JOptionPane.showConfirmDialog(
new Frame(), NbBundle.getMessage(
this.getClass(),
136 "ExtractUnallocAction.confDlg.unallocFileAlreadyExist.msg",
138 if (res == JOptionPane.YES_OPTION) {
139 u.FileInstance.delete();
144 if (!isImage & !copyList.isEmpty()) {
145 ExtractUnallocWorker uw =
new ExtractUnallocWorker(u);
149 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");
152 if (isImage && !copyList.isEmpty()) {
153 ExtractUnallocWorker uw =
new ExtractUnallocWorker(copyList);
168 private List<LayoutFile> getUnallocFiles(Content c) {
169 UnallocVisitor uv =
new UnallocVisitor();
171 List<Content> unallocFiles = c.getChildren();
172 if (null != unallocFiles && unallocFiles.isEmpty() ==
false) {
173 return unallocFiles.get(0).accept(uv);
175 }
catch (TskCoreException tce) {
176 logger.log(Level.WARNING,
"Couldn't get a list of Unallocated Files, failed at sending out the visitor ", tce);
178 return Collections.emptyList();
188 private List<UnallocStruct>
lus =
new ArrayList<UnallocStruct>();
195 if (!lockedVols.contains(us.getFileName())) {
197 totalBytes = us.getSizeInBytes();
198 totalSizeinMegs =
toMb(totalBytes);
199 lockedVols.add(us.getFileName());
206 if (!lockedVols.contains(lu.getFileName())) {
207 totalBytes += lu.getSizeInBytes();
208 lockedVols.add(lu.getFileName());
212 totalSizeinMegs =
toMb(totalBytes);
213 lockedImages.add(currentImage);
217 if (bytes > 1024 && (bytes / 1024.0) <= Double.MAX_VALUE) {
218 double Mb = ((bytes / 1024.0) / 1024.0);
219 if (Mb <= Integer.MAX_VALUE) {
220 return (
int) Math.ceil(Mb);
229 progress = ProgressHandle.createHandle(
230 NbBundle.getMessage(
this.getClass(),
"ExtractUnallocAction.progress.extractUnalloc.title"),
new Cancellable() {
232 public boolean cancel() {
233 logger.log(Level.INFO,
"Canceling extraction of unallocated space");
235 if (progress != null) {
236 progress.setDisplayName(NbBundle.getMessage(
this.getClass(),
237 "ExtractUnallocAction.progress.displayName.cancelling.text"));
242 int MAX_BYTES = 8192;
243 byte[] buf =
new byte[MAX_BYTES];
246 progress.start(totalSizeinMegs);
250 currentlyProcessing = u.getFile();
251 logger.log(Level.INFO,
"Writing Unalloc file to " + currentlyProcessing.getPath());
252 OutputStream dos =
new FileOutputStream(currentlyProcessing);
255 while (i < u.getLayouts().size() && bytes != u.getSizeInBytes()) {
257 long offsetPerFile = 0L;
260 if (++kbs % 128 == 0) {
262 progress.progress(NbBundle.getMessage(
this.getClass(),
263 "ExtractUnallocAction.processing.counter.msg",
266 bytesRead = f.
read(buf, offsetPerFile, MAX_BYTES);
267 offsetPerFile += bytesRead;
268 dos.write(buf, 0, bytesRead);
277 u.getFile().delete();
278 logger.log(Level.INFO,
"Canceled extraction of " + u.getFileName() +
" and deleted file");
280 logger.log(Level.INFO,
"Finished writing unalloc file " + u.getFile().getPath());
285 }
catch (IOException ioe) {
286 logger.log(Level.WARNING,
"Could not create Unalloc File; error writing file", ioe);
289 logger.log(Level.WARNING,
"Could not create Unalloc File; error getting image info", tce);
298 lockedImages.remove(currentImage);
301 lockedVols.remove(u.getFileName());
306 if (!canceled && !lus.isEmpty()) {
308 "ExtractUnallocAction.done.notifyMsg.completedExtract.title"),
309 NbBundle.getMessage(
this.getClass(),
310 "ExtractUnallocAction.done.notifyMsg.completedExtract.msg",
311 lus.get(0).getFile().getParent()));
313 }
catch (InterruptedException | ExecutionException ex) {
315 NbBundle.getMessage(
this.getClass(),
"ExtractUnallocAction.done.errMsg.title"),
316 NbBundle.getMessage(
this.getClass(),
"ExtractUnallocAction.done.errMsg.msg", ex.getMessage()));
318 catch (java.util.concurrent.CancellationException ex) {
330 private boolean hasVolumeSystem(
Image img) {
333 }
catch (TskCoreException tce) {
334 logger.log(Level.WARNING,
"Unable to determine if image has a volume system, extraction may be incomplete", tce);
347 private List<Volume> getVolumes(Image img) {
348 List<Volume> lstVol =
new ArrayList<Volume>();
350 for (Content v : img.getChildren().get(0).getChildren()) {
351 if (v instanceof Volume) {
352 lstVol.add((Volume) v);
355 }
catch (TskCoreException tce) {
356 logger.log(Level.WARNING,
"Could not get volume information from image. Extraction may be incomplete", tce);
377 return new ArrayList<LayoutFile>() {
402 logger.log(Level.WARNING,
"Couldn't get a list of Unallocated Files, failed at visiting FileSystem " + fs.
getId(), tce);
404 return Collections.emptyList();
418 List<LayoutFile> lflst =
new ArrayList<>();
424 logger.log(Level.WARNING,
"Could not get list of Layout Files, failed at visiting Layout Directory", tce);
426 return Collections.emptyList();
443 return c.accept(
this);
447 logger.log(Level.WARNING,
"Couldn't get a list of Unallocated Files, failed at visiting Directory " + dir.
getId(), tce);
449 return Collections.emptyList();
454 return Collections.emptyList();
463 private class SortObjId implements Comparator<LayoutFile> {
484 private List<LayoutFile>
llf;
498 this.llf = getUnallocFiles(img);
501 this.ImageId = img.
getId();
502 this.ImageName = img.
getName();
503 this.FileName = this.ImageName +
"-Unalloc-" + this.ImageId +
"-" + 0 +
".dat";
517 this.VolumeId = volu.
getId();
519 logger.log(Level.WARNING,
"Unable to properly create ExtractUnallocAction, extraction may be incomplete", tce);
523 this.FileName = this.ImageName +
"-Unalloc-" + this.ImageId +
"-" + VolumeId +
".dat";
524 this.FileInstance =
new File(Case.getCurrentCase().getExportDirectory() + File.separator + this.
FileName);
525 this.llf = getUnallocFiles(volu);
526 Collections.sort(llf,
new SortObjId());
543 long getSizeInBytes() {
555 String getImageName() {
559 List<LayoutFile> getLayouts() {
563 String getFileName() {
571 void setPath(String path) {
572 this.FileInstance =
new File(path + File.separator +
this.FileName);
List< Content > getChildren()
List< Content > getChildren()
static void info(String title, String message)
List< Content > getChildren()
List< Content > getChildren()
static void error(String title, String message)
static Case getCurrentCase()
public< T > T accept(ContentVisitor< T > v)
String getExportDirectory()
final int read(byte[] buf, long offset, long len)