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()) {
 
  256                         LayoutFile f = u.getLayouts().get(i);
 
  257                         long offsetPerFile = 0L;
 
  259                         while (offsetPerFile != f.getSize() && !
canceled) {
 
  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);
 
  270                         bytes += f.getSize();
 
  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); 
 
  288             } 
catch (TskCoreException tce) {
 
  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) {
 
  332             return (img.getChildren().get(0) instanceof VolumeSystem);
 
  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); 
 
  365     private static class UnallocVisitor extends ContentVisitor.Default<List<LayoutFile>> {
 
  377             return new ArrayList<LayoutFile>() {
 
  394         public List<LayoutFile> 
visit(FileSystem fs) {
 
  396                 for (Content c : fs.getChildren()) {
 
  397                     if (((AbstractFile) c).isRoot()) {
 
  398                         return c.accept(
this);
 
  401             } 
catch (TskCoreException tce) {
 
  402                 logger.log(Level.WARNING, 
"Couldn't get a list of Unallocated Files, failed at visiting FileSystem " + fs.getId(), tce); 
 
  404             return Collections.emptyList();
 
  416         public List<LayoutFile> 
visit(VirtualDirectory vd) {
 
  418                 List<LayoutFile> lflst = 
new ArrayList<>();
 
  419                 for (Content layout : vd.getChildren()) {
 
  420                     lflst.add((LayoutFile) layout);
 
  423             } 
catch (TskCoreException tce) {
 
  424                 logger.log(Level.WARNING, 
"Could not get list of Layout Files, failed at visiting Layout Directory", tce); 
 
  426             return Collections.emptyList();
 
  439         public List<LayoutFile> 
visit(Directory dir) {
 
  441                 for (Content c : dir.getChildren()) {
 
  442                     if (c instanceof VirtualDirectory) {
 
  443                         return c.accept(
this);
 
  446             } 
catch (TskCoreException tce) {
 
  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> {
 
  466         public int compare(LayoutFile o1, LayoutFile o2) {
 
  467             if (o1.getId() == o2.getId()) {
 
  470             if (o1.getId() > o2.getId()) {
 
  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"; 
 
  515                 this.ImageName = volu.getDataSource().getName();
 
  516                 this.ImageId = volu.getDataSource().getId();
 
  517                 this.VolumeId = volu.getId();
 
  518             } 
catch (TskCoreException tce) {
 
  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());
 
  537             for (LayoutFile f : llf) {
 
  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);
 
static void info(String title, String message)
static void error(String title, String message)
static Case getCurrentCase()
String getExportDirectory()