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)