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>();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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