Added ability to extract unallocated space to a single file per volume

This commit is contained in:
0xNF 2012-11-29 14:49:09 -05:00
parent e1d41a5b30
commit 6b84d33c40
2 changed files with 270 additions and 1 deletions

View File

@ -160,7 +160,7 @@ public class DataResultFilterNode extends FilterNode {
List<Action> actions = new ArrayList<Action>();
actions.add(new NewWindowViewAction("View in New Window", vol));
actions.addAll(ShowDetailActionVisitor.getActions(vol.getLookup().lookup(Content.class)));
actions.add(new ExtractUnallocAction("Extract Unallocated Space as Single File", vol));
return actions;
}

View File

@ -0,0 +1,269 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.directorytree;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.Cancellable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.VolumeNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.FileSystem;
import org.sleuthkit.datamodel.LayoutDirectory;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Extracts all the unallocated space as a single file
*/
public final class ExtractUnallocAction extends AbstractAction{
private static List<LayoutFile> llf;
private static Content vol;
private static final Logger logger = Logger.getLogger(ExtractUnallocAction.class.getName());
ExtractUnallocAction(String title, VolumeNode volume) {
super(title);
vol = volume.getLookup().lookup(Content.class);
llf = getUnallocFiles(vol);
Collections.sort(llf, new SortObjId());
}
/**
* Writes the unallocated files to $CaseDir/Export/ImgName-Unalloc-ImgObjectID-VolumeID.dat
* @param e
*/
@Override
public void actionPerformed(ActionEvent e) {
if (llf != null && llf.size() > 0) {
try {
String imgName = vol.getImage().getName(); //Image Name
long imgObjID = vol.getImage().getId(); //Image ID
long volumeID = vol.getId(); //Volume ID
String UnallocName = imgName + "-Unalloc-" + imgObjID + "-" + volumeID + ".dat";
//Format for single Unalloc File is ImgName-Unalloc-ImgObjectID-VolumeID.dat
File unalloc = new File(Case.getCurrentCase().getCaseDirectory() + File.separator + "Export" + File.separator + UnallocName);
if (unalloc.exists()) {
int res = JOptionPane.showConfirmDialog(new Frame(), "The Unalloc File for this volume, " + UnallocName + " already exists, do you want to replace it?");
if (res == JOptionPane.YES_OPTION) {
unalloc.delete();
} else {
return;
}
}
ExtractUnallocWorker uw = new ExtractUnallocWorker(unalloc, this);
uw.execute();
}catch (TskCoreException tce) {
logger.log(Level.WARNING, "Could not create Unalloc File; error getting image info", tce);
}
} else {
logger.log(Level.WARNING, "Tried to get unallocated content from volume ID " + vol.getId() + ", but its list of unallocated files was empty or null");
}
}
private List<LayoutFile> getUnallocFiles(Content c) {
UnallocVisitor uv = new UnallocVisitor();
logger.log(Level.INFO, "Sending out Unallocated File Visitor");
try {
return c.getChildren().get(0).accept(uv); //Launching it on the root directory
} catch (TskCoreException tce) {
logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at sending out the visitor ", tce);
}
return null;
}
/**
* Private class for dispatching the file IO in a background thread.
*/
private class ExtractUnallocWorker extends SwingWorker<Integer, Integer> {
ExtractUnallocAction ua;
File path;
private ProgressHandle progress;
private boolean canceled = false;
ExtractUnallocWorker(File path, ExtractUnallocAction ua) {
this.path = path;
this.ua = ua;
}
@Override
protected Integer doInBackground() {
try {
progress = ProgressHandleFactory.createHandle("Extracting " + path.getName(), new Cancellable() {
@Override
public boolean cancel() {
logger.log(Level.INFO, "Canceling extraction of Unalloc file " + path.getName());
canceled = true;
if (progress != null) {
progress.setDisplayName(path.getName() + " (Cancelling...)");
}
return true;
}
});
FileOutputStream fos = new FileOutputStream(path);
int MAX_BYTES = 8192;
byte[] buf = new byte[MAX_BYTES]; //read 8k at a time
logger.log(Level.INFO, "Writing Unalloc file to " + path.getPath());
progress.start(llf.size());
int count = 0;
for (LayoutFile f : llf) {
long offset = 0L;
while (offset != f.getSize() && !canceled) {
offset += f.read(buf, offset, MAX_BYTES); //Offset + Bytes read
fos.write(buf);
}
progress.progress(count++);
}
progress.finish();
fos.flush();
fos.close();
if(canceled){
path.delete();
logger.log(Level.INFO, "Canceled extraction of " + path.getName() + " and deleted file");
}
else{
logger.log(Level.INFO, "Finished writing unalloc file");
}
} catch (IOException ioe) {
logger.log(Level.WARNING, "Could not create Unalloc File; error writing file", ioe);
return -1;
} catch (TskCoreException tce) {
logger.log(Level.WARNING, "Could not create Unalloc File; error getting image info", tce);
return -1;
}
return 1;
}
}
private static class UnallocVisitor extends ContentVisitor.Default<List<LayoutFile>> {
/**
* If the volume has no FileSystem, then it will call this method to return the single instance of unallocated space.
* @param lf the LayoutFile the visitor encountered
* @return A list<LayoutFile> of size 1
*/
@Override
public List<LayoutFile> visit(final org.sleuthkit.datamodel.LayoutFile lf) {
return new ArrayList<LayoutFile>() {
{
add(lf);
}
};
}
/**
* If the visitor finds a FileSystem, it will filter the results for directories and return on the Root Dir.
* @param fs the FileSystem the visitor encountered
* @return A list<LayoutFile> containing the layout files from subsequent Visits()
*/
@Override
public List<LayoutFile> visit(FileSystem fs) {
try {
for (Content c : fs.getChildren()){
if(((AbstractFile)c).isRoot()){
return c.accept(this);
}
}
} catch (TskCoreException tce) {
logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at visiting FileSystem " + fs.getId(), tce);
}
return null;
}
/**
* LayoutDirectory has all the Layout(Unallocated) files
* @param ld LayoutDirectory the visitor encountered
* @return A list<LayoutFile> containing all the LayoutFile in ld
*/
@Override
public List<LayoutFile> visit(LayoutDirectory ld){
try{
List<LayoutFile> lflst = new ArrayList<LayoutFile>();
for(Content layout : ld.getChildren()){
lflst.add((LayoutFile)layout);
}
return lflst;
} catch(TskCoreException tce){
logger.log(Level.WARNING, "Could not get list of Layout Files, failed at visiting Layout Directory in " + vol.getId(), tce);
}
return null;
}
/**
* The only time this visitor should ever encounter a directory is when parsing over Root
* @param dir the directory this visitor encountered
* @return A list<LayoutFile> containing LayoutFiles encountered during subsequent Visits()
*/
@Override
public List<LayoutFile> visit(Directory dir) {
try {
for (Content c : dir.getChildren()) {
if(c instanceof LayoutDirectory){
return c.accept(this);
}
}
}catch (TskCoreException tce) {
logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at visiting Directory " + dir.getId(), tce);
}
return null;
}
@Override
protected List<LayoutFile> defaultVisit(Content cntnt) {
return null;
}
}
private class SortObjId implements Comparator<LayoutFile>{
@Override
public int compare(LayoutFile o1, LayoutFile o2) {
if(o1.getId() == o2.getId()){
return 0;
}
if(o1.getId() > o2.getId()){
return -1;
}
else{
return 1;
}
}
}
}