19 package org.sleuthkit.autopsy.modules.photoreccarver;
 
   22 import java.io.IOException;
 
   23 import java.lang.ProcessBuilder.Redirect;
 
   24 import java.nio.file.DirectoryStream;
 
   25 import java.nio.file.FileAlreadyExistsException;
 
   26 import java.nio.file.Files;
 
   27 import java.nio.file.Path;
 
   28 import java.nio.file.Paths;
 
   29 import java.text.DateFormat;
 
   30 import java.text.SimpleDateFormat;
 
   31 import java.util.ArrayList;
 
   32 import java.util.Date;
 
   33 import java.util.List;
 
   35 import java.util.concurrent.ConcurrentHashMap;
 
   36 import java.util.logging.Level;
 
   37 import org.openide.modules.InstalledFileLocator;
 
   38 import org.openide.util.NbBundle;
 
   66     private static final String PHOTOREC_DIRECTORY = 
"photorec_exec"; 
 
   67     private static final String PHOTOREC_EXECUTABLE = 
"photorec_win.exe"; 
 
   68     private static final String PHOTOREC_RESULTS_BASE = 
"results"; 
 
   69     private static final String PHOTOREC_RESULTS_EXTENDED = 
"results.1"; 
 
   70     private static final String PHOTOREC_REPORT = 
"report.xml"; 
 
   71     private static final String LOG_FILE = 
"run_log.txt"; 
 
   72     private static final String TEMP_DIR_NAME = 
"temp"; 
 
   73     private static final Logger logger = 
Logger.
getLogger(PhotoRecCarverFileIngestModule.class.getName());
 
   75     private static final Map<Long, WorkingPaths> pathsByJob = 
new ConcurrentHashMap<>();
 
   77     private Path rootOutputDirPath;
 
   78     private File executableFile;
 
   86         this.context = context;
 
   97         this.rootOutputDirPath = PhotoRecCarverFileIngestModule.createModuleOutputDirectoryForCase();
 
   99         Path execName = Paths.get(PHOTOREC_DIRECTORY, PHOTOREC_EXECUTABLE);
 
  100         executableFile = locateExecutable(execName.toString());
 
  102         if (PhotoRecCarverFileIngestModule.refCounter.incrementAndGet(
this.context.getJobId()) == 1) {
 
  105                 DateFormat dateFormat = 
new SimpleDateFormat(
"MM-dd-yyyy-HH-mm-ss-SSSS");  
 
  106                 Date date = 
new Date();
 
  108                 Path outputDirPath = Paths.get(this.rootOutputDirPath.toAbsolutePath().toString(), folder);
 
  109                 Files.createDirectories(outputDirPath);
 
  112                 Path tempDirPath = Paths.get(outputDirPath.toString(), PhotoRecCarverFileIngestModule.TEMP_DIR_NAME);
 
  113                 Files.createDirectory(tempDirPath);
 
  116                 PhotoRecCarverFileIngestModule.pathsByJob.put(this.context.
getJobId(), 
new WorkingPaths(outputDirPath, tempDirPath));
 
  118             catch (SecurityException | IOException | UnsupportedOperationException ex) {
 
  134         Path tempFilePath = null;
 
  136             long id = getRootId(file);
 
  139                 return ProcessResult.ERROR;
 
  143             if (null == this.executableFile) {
 
  144                 logger.log(Level.SEVERE, 
"PhotoRec carver called after failed start up");  
 
  153             if ((freeDiskSpace != -1) && ((file.
getSize() * 1.2) > freeDiskSpace)) {
 
  154                 logger.log(Level.SEVERE, 
"PhotoRec error processing {0} with {1} Not enough space on primary disk to save unallocated space.", 
 
  155                         new Object[]{file.getName(), PhotoRecCarverIngestModuleFactory.getModuleName()}); 
 
  157                         NbBundle.getMessage(
this.getClass(), 
"PhotoRecIngestModule.NotEnoughDiskSpace"));
 
  163             WorkingPaths paths = PhotoRecCarverFileIngestModule.pathsByJob.get(this.context.
getJobId());
 
  164             tempFilePath = Paths.get(paths.getTempDirPath().toString(), file.
getName());
 
  168             Path outputDirPath = Paths.get(paths.getOutputDirPath().toString(), file.
getName());
 
  169             Files.createDirectory(outputDirPath);
 
  170             File log = 
new File(Paths.get(outputDirPath.toString(), LOG_FILE).toString()); 
 
  173             ProcessBuilder processAndSettings = 
new ProcessBuilder(
 
  174                     "\"" + executableFile + 
"\"",
 
  176                     "\"" + outputDirPath.toAbsolutePath() + File.separator + PHOTOREC_RESULTS_BASE + 
"\"",
 
  178                     "\"" + tempFilePath.toFile() + 
"\"",
 
  182             processAndSettings.environment().put(
"__COMPAT_LAYER", 
"RunAsInvoker"); 
 
  183             processAndSettings.redirectErrorStream(
true);
 
  184             processAndSettings.redirectOutput(Redirect.appendTo(log));
 
  190                 cleanup(outputDirPath, tempFilePath);
 
  191                 logger.log(Level.INFO, 
"PhotoRec cancelled by user"); 
 
  193             } 
else if (0 != exitValue) {
 
  195                 cleanup(outputDirPath, tempFilePath);
 
  196                 logger.log(Level.SEVERE, 
"PhotoRec carver returned error exit value = {0} when scanning {1}", 
 
  197                         new Object[]{exitValue, file.getName()}); 
 
  202             java.io.File oldAuditFile = 
new java.io.File(Paths.get(outputDirPath.toString(), PHOTOREC_RESULTS_EXTENDED, PHOTOREC_REPORT).toString()); 
 
  203             java.io.File newAuditFile = 
new java.io.File(Paths.get(outputDirPath.toString(), PHOTOREC_REPORT).toString()); 
 
  204             oldAuditFile.renameTo(newAuditFile);
 
  206             Path pathToRemove = Paths.get(outputDirPath.toAbsolutePath().toString());
 
  207             try (DirectoryStream<Path> stream = Files.newDirectoryStream(pathToRemove)) {
 
  208                 for (Path entry : stream) {
 
  209                     if (Files.isDirectory(entry)) {
 
  216             PhotoRecCarverOutputParser parser = 
new PhotoRecCarverOutputParser(outputDirPath);
 
  217             List<LayoutFile> theList = parser.parse(newAuditFile, 
id, file);
 
  218             if (theList != null) { 
 
  223         catch (IOException ex) {
 
  224             logger.log(Level.SEVERE, 
"Error processing " + file.
getName() + 
" with PhotoRec carver", ex); 
 
  229             if (null != tempFilePath && Files.exists(tempFilePath)) {
 
  231                 tempFilePath.toFile().delete();
 
  238     private void cleanup(Path outputDirPath, Path tempFilePath) {
 
  241         if (null != tempFilePath && Files.exists(tempFilePath)) {
 
  242             tempFilePath.toFile().delete();
 
  251     public void shutDown() {
 
  252         if (this.context != null && refCounter.
decrementAndGet(
this.context.getJobId()) == 0) {
 
  256                 WorkingPaths paths = PhotoRecCarverFileIngestModule.pathsByJob.remove(this.context.
getJobId());
 
  259             catch (SecurityException ex) {
 
  260                 logger.log(Level.SEVERE, 
"Error shutting down PhotoRec carver module", ex); 
 
  275         Path getOutputDirPath() {
 
  279         Path getTempDirPath() {
 
  290     synchronized static Path createModuleOutputDirectoryForCase() throws IngestModule.IngestModuleException {
 
  291         Path path = Paths.get(Case.getCurrentCase().getModulesOutputDirAbsPath(), PhotoRecCarverIngestModuleFactory.getModuleName());
 
  293             Files.createDirectory(path);
 
  295         catch (FileAlreadyExistsException ex) {
 
  298         catch (IOException | SecurityException | UnsupportedOperationException ex) {
 
  299             throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, 
"cannotCreateOutputDir.message", ex.getLocalizedMessage()));
 
  310     private static long getRootId(AbstractFile file) {
 
  312         Content parent = null;
 
  314             parent = file.getParent();
 
  315             while (parent != null) {
 
  316                 if (parent instanceof Volume || parent instanceof Image) {
 
  320                 parent = parent.getParent();
 
  323         catch (TskCoreException ex) {
 
  324             logger.log(Level.SEVERE, 
"PhotoRec carver exception while trying to get parent of AbstractFile.", ex); 
 
  336     public static File locateExecutable(String executableToFindName) 
throws IngestModule.IngestModuleException {
 
  338         if (!PlatformUtil.isWindowsOS()) {
 
  339             throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, 
"unsupportedOS.message"));
 
  342         File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, PhotoRecCarverFileIngestModule.class.getPackage().getName(), 
false);
 
  343         if (null == exeFile) {
 
  344             throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, 
"missingExecutable.message"));
 
  347         if (!exeFile.canExecute()) {
 
  348             throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, 
"cannotRunExecutable.message"));
 
synchronized long decrementAndGet(long jobId)
 
static< T, V > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, SwingWorker< T, V > worker, boolean source)
 
static int execute(ProcessBuilder processBuilder)
 
TskData.TSK_DB_FILES_TYPE_ENUM getType()
 
void addFilesToJob(List< AbstractFile > files)
 
boolean fileIngestIsCancelled()
 
void fireModuleContentEvent(ModuleContentEvent moduleContentEvent)
 
static void error(String title, String message)
 
static boolean deleteDir(File dirPath)
 
static Logger getLogger(String name)
 
boolean processingUnallocatedSpace()
 
static synchronized IngestServices getInstance()