mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 16:06:15 +00:00
Added ability to extract unallocated space to a single file per volume
This commit is contained in:
parent
e1d41a5b30
commit
6b84d33c40
@ -160,7 +160,7 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
List<Action> actions = new ArrayList<Action>();
|
List<Action> actions = new ArrayList<Action>();
|
||||||
actions.add(new NewWindowViewAction("View in New Window", vol));
|
actions.add(new NewWindowViewAction("View in New Window", vol));
|
||||||
actions.addAll(ShowDetailActionVisitor.getActions(vol.getLookup().lookup(Content.class)));
|
actions.addAll(ShowDetailActionVisitor.getActions(vol.getLookup().lookup(Content.class)));
|
||||||
|
actions.add(new ExtractUnallocAction("Extract Unallocated Space as Single File", vol));
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user