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.Exceptions;
42 import org.openide.util.NbBundle;
61 final class ExtractUnallocAction
extends AbstractAction {
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;
70 public ExtractUnallocAction(String title, Volume volu) {
72 UnallocStruct us =
new UnallocStruct(volu);
76 public ExtractUnallocAction(String title, Image img) {
79 currentImage = img.getId();
80 if (hasVolumeSystem(img)) {
81 for (Volume v : getVolumes(img)) {
82 UnallocStruct us =
new UnallocStruct(v);
86 UnallocStruct us =
new UnallocStruct(img);
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"));
105 List<UnallocStruct> copyList =
new ArrayList<UnallocStruct>() {
112 JFileChooser fc =
new JFileChooser() {
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"));
121 super.approveSelection();
125 fc.setCurrentDirectory(
new File(Case.getCurrentCase().getCaseDirectory() + File.separator +
"Export"));
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())) {
137 if (u.FileInstance.exists()) {
138 int res = JOptionPane.showConfirmDialog(
new Frame(), NbBundle.getMessage(
this.getClass(),
139 "ExtractUnallocAction.confDlg.unallocFileAlreadyExist.msg",
141 if (res == JOptionPane.YES_OPTION) {
142 u.FileInstance.delete();
147 if (!isImage & !copyList.isEmpty()) {
148 ExtractUnallocWorker uw =
new ExtractUnallocWorker(u);
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" );
155 if (isImage && !copyList.isEmpty()) {
156 ExtractUnallocWorker uw =
new ExtractUnallocWorker(copyList);
170 private List<LayoutFile> getUnallocFiles(Content c) {
171 UnallocVisitor uv =
new UnallocVisitor();
173 List<Content> unallocFiles = c.getChildren();
174 if (null != unallocFiles && unallocFiles.isEmpty() ==
false) {
175 return unallocFiles.get(0).accept(uv);
177 }
catch (TskCoreException tce) {
178 logger.log(Level.WARNING,
"Couldn't get a list of Unallocated Files, failed at sending out the visitor ", tce);
180 return Collections.emptyList();
190 private List<UnallocStruct>
lus =
new ArrayList<UnallocStruct>();
197 if (!lockedVols.contains(us.getFileName())) {
199 totalBytes = us.getSizeInBytes();
200 totalSizeinMegs =
toMb(totalBytes);
201 lockedVols.add(us.getFileName());
208 if (!lockedVols.contains(lu.getFileName())) {
209 totalBytes += lu.getSizeInBytes();
210 lockedVols.add(lu.getFileName());
214 totalSizeinMegs =
toMb(totalBytes);
215 lockedImages.add(currentImage);
219 if (bytes > 1024 && (bytes / 1024.0) <= Double.MAX_VALUE) {
220 double Mb = ((bytes / 1024.0) / 1024.0);
221 if (Mb <= Integer.MAX_VALUE) {
222 return (
int) Math.ceil(Mb);
231 progress = ProgressHandleFactory.createHandle(
232 NbBundle.getMessage(
this.getClass(),
"ExtractUnallocAction.progress.extractUnalloc.title"),
new Cancellable() {
234 public boolean cancel() {
235 logger.log(Level.INFO,
"Canceling extraction of unallocated space");
237 if (progress != null) {
238 progress.setDisplayName(NbBundle.getMessage(
this.getClass(),
239 "ExtractUnallocAction.progress.displayName.cancelling.text"));
244 int MAX_BYTES = 8192;
245 byte[] buf =
new byte[MAX_BYTES];
249 progress.start(totalSizeinMegs);
253 currentlyProcessing = u.getFile();
254 logger.log(Level.INFO,
"Writing Unalloc file to " + currentlyProcessing.getPath());
255 OutputStream dos =
new FileOutputStream(currentlyProcessing);
258 while(i < u.getLayouts().size() && bytes != u.getSizeInBytes()){
260 long offsetPerFile = 0L;
263 if (++kbs % 128 == 0) {
265 progress.progress(NbBundle.getMessage(
this.getClass(),
266 "ExtractUnallocAction.processing.counter.msg",
269 bytesRead = f.
read(buf, offsetPerFile, MAX_BYTES);
270 offsetPerFile+= bytesRead;
271 dos.write(buf, 0, bytesRead);
280 u.getFile().delete();
281 logger.log(Level.INFO,
"Canceled extraction of " + u.getFileName() +
" and deleted file");
283 logger.log(Level.INFO,
"Finished writing unalloc file " + u.getFile().getPath());
289 }
catch (IOException ioe) {
290 logger.log(Level.WARNING,
"Could not create Unalloc File; error writing file", ioe);
293 logger.log(Level.WARNING,
"Could not create Unalloc File; error getting image info", tce);
302 lockedImages.remove(currentImage);
305 lockedVols.remove(u.getFileName());
310 if (!canceled && !lus.isEmpty()) {
312 "ExtractUnallocAction.done.notifyMsg.completedExtract.title"),
313 NbBundle.getMessage(
this.getClass(),
314 "ExtractUnallocAction.done.notifyMsg.completedExtract.msg",
315 lus.get(0).getFile().getParent()));
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()));
323 catch (java.util.concurrent.CancellationException ex ) { }
333 private boolean hasVolumeSystem(
Image img) {
336 }
catch (TskCoreException tce) {
337 logger.log(Level.WARNING,
"Unable to determine if image has a volume system, extraction may be incomplete", tce);
349 private List<Volume> getVolumes(Image img) {
350 List<Volume> lstVol =
new ArrayList<Volume>();
352 for (Content v : img.getChildren().get(0).getChildren()) {
353 if (v instanceof Volume) {
354 lstVol.add((Volume) v);
357 }
catch (TskCoreException tce) {
358 logger.log(Level.WARNING,
"Could not get volume information from image. Extraction may be incomplete", tce);
378 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();
417 List<LayoutFile> lflst =
new ArrayList<>();
423 logger.log(Level.WARNING,
"Could not get list of Layout Files, failed at visiting Layout Directory", tce);
425 return Collections.emptyList();
441 return c.accept(
this);
445 logger.log(Level.WARNING,
"Couldn't get a list of Unallocated Files, failed at visiting Directory " + dir.
getId(), tce);
447 return Collections.emptyList();
452 return Collections.emptyList();
461 private class SortObjId implements Comparator<LayoutFile> {
482 private List<LayoutFile>
llf;
496 this.llf = getUnallocFiles(img);
499 this.ImageId = img.
getId();
500 this.ImageName = img.
getName();
501 this.FileName = this.ImageName +
"-Unalloc-" + this.ImageId +
"-" + 0 +
".dat";
515 this.VolumeId = volu.
getId();
517 logger.log(Level.WARNING,
"Unable to properly create ExtractUnallocAction, extraction may be incomplete", tce);
521 this.FileName = this.ImageName +
"-Unalloc-" + this.ImageId +
"-" + VolumeId +
".dat";
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());
541 long getSizeInBytes(){
553 String getImageName() {
557 List<LayoutFile> getLayouts() {
561 String getFileName() {
569 void setPath(String path) {
570 this.FileInstance =
new File(path + File.separator +
this.FileName);
String getCaseDirectory()
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)
final int read(byte[] buf, long offset, long len)