19 package org.sleuthkit.autopsy.modules.photoreccarver;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.nio.file.Path;
25 import java.nio.file.Paths;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.logging.Level;
30 import org.openide.util.NbBundle;
43 import org.w3c.dom.Document;
44 import org.w3c.dom.Element;
45 import org.w3c.dom.NodeList;
46 import org.w3c.dom.Node;
52 class PhotoRecCarverOutputParser {
54 private final Path basePath;
55 private static final Logger logger = Logger.getLogger(PhotoRecCarverFileIngestModule.class.getName());
57 PhotoRecCarverOutputParser(Path base) {
77 List<LayoutFile> parse(File xmlInputFile, AbstractFile af, IngestJobContext context)
throws FileNotFoundException, IOException {
79 final Document doc = XMLUtil.loadDoc(PhotoRecCarverOutputParser.class, xmlInputFile.toString());
81 return new ArrayList<>();
84 Element root = doc.getDocumentElement();
86 logger.log(Level.SEVERE,
"Error loading config file: invalid file format (bad root).");
87 return new ArrayList<>();
90 NodeList fileObjects = root.getElementsByTagName(
"fileobject");
91 final int numberOfFiles = fileObjects.getLength();
93 if (numberOfFiles == 0) {
94 return new ArrayList<>();
103 FileManager fileManager = Case.getCurrentCaseThrows().getServices().getFileManager();
106 List<CarvingResult.CarvedFile> carvedFiles =
new ArrayList<>();
107 for (
int fileIndex = 0; fileIndex < numberOfFiles; ++fileIndex) {
108 if (context.fileIngestIsCancelled() ==
true) {
110 logger.log(Level.INFO,
"PhotoRec cancelled by user");
111 MessageNotifyUtil.Notify.info(PhotoRecCarverIngestModuleFactory.getModuleName(), NbBundle.getMessage(PhotoRecCarverFileIngestModule.class,
"PhotoRecIngestModule.cancelledByUser"));
114 entry = (Element) fileObjects.item(fileIndex);
115 fileNames = entry.getElementsByTagName(
"filename");
116 fileSizes = entry.getElementsByTagName(
"filesize");
117 fileRanges = entry.getElementsByTagName(
"byte_run");
119 fileSize = Long.parseLong(fileSizes.item(0).getTextContent());
120 fileName = fileNames.item(0).getTextContent();
121 filePath = Paths.get(fileName);
122 if (filePath.startsWith(basePath)) {
123 fileName = filePath.getFileName().toString();
126 List<TskFileRange> tskRanges =
new ArrayList<>();
127 for (
int rangeIndex = 0; rangeIndex < fileRanges.getLength(); ++rangeIndex) {
129 Long unallocFileOffset = null;
133 Node rangeNode = fileRanges.item(rangeIndex);
134 if (rangeNode instanceof Element) {
135 Element rangeElement = (Element) rangeNode;
136 String imgOffsetStr = rangeElement.getAttribute(
"img_offset");
137 String lenStr = rangeElement.getAttribute(
"len");
140 unallocFileOffset = Long.parseLong(imgOffsetStr);
141 len = Long.parseLong(lenStr);
142 }
catch (NumberFormatException ex) {
143 logger.log(Level.SEVERE,
144 String.format(
"There was an error parsing ranges in %s with file index: %d and range index: %d.",
145 xmlInputFile.getPath(), fileIndex, rangeIndex), ex);
148 logger.log(Level.SEVERE,
149 String.format(
"Malformed node in %s with file index: %d and range index: %d.",
150 xmlInputFile.getPath(), fileIndex, rangeIndex));
154 if (unallocFileOffset != null && unallocFileOffset >= 0 && len != null && len > 0) {
155 for (TskFileRange rangeToAdd : af.convertToImgRanges(unallocFileOffset, len)) {
156 tskRanges.add(
new TskFileRange(rangeToAdd.getByteStart(), rangeToAdd.getByteLen(), tskRanges.size()));
162 if (!tskRanges.isEmpty()) {
163 carvedFiles.add(
new CarvingResult.CarvedFile(fileName, fileSize, tskRanges));
166 return fileManager.addCarvedFiles(
new CarvingResult(af, carvedFiles));
167 }
catch (NumberFormatException | TskCoreException | NoCurrentCaseException ex) {
168 logger.log(Level.SEVERE,
"Error parsing PhotoRec output and inserting it into the database", ex);
171 List<LayoutFile> empty = Collections.emptyList();