Package org.sleuthkit.autopsy.casemodule.services

Source Code of org.sleuthkit.autopsy.casemodule.services.FileManager$FileAddProgressUpdater

/*
*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
*
* Copyright 2012 42six Solutions.
* Contact: aebadirad <at> 42six <dot> com
* Project Contact/Architect: 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.casemodule.services;

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.LocalFile;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskFileRange;
import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.CarvedFileContainer;

/**
* Abstraction to facilitate access to files and directories.
*/
public class FileManager implements Closeable {

    private SleuthkitCase tskCase;
    private static final Logger logger = Logger.getLogger(FileManager.class.getName());
    private volatile int curNumFileSets;  //current number of filesets (root virt dir objects)

    public FileManager(SleuthkitCase tskCase) {
        this.tskCase = tskCase;
        init();
    }

    /**
     * initialize the file manager for the case
     */
    private synchronized void init() {
        //get the number of local file sets in db
        List<VirtualDirectory> virtRoots;
        curNumFileSets = 0;
        try {
            virtRoots = tskCase.getVirtualDirectoryRoots();
            for (VirtualDirectory vd : virtRoots) {
                if (vd.getName().startsWith(VirtualDirectoryNode.LOGICAL_FILE_SET_PREFIX)) {
                    ++curNumFileSets;
                }
            }
        } catch (TskCoreException ex) {
            logger.log(Level.SEVERE, "Error initializing FileManager and getting number of local file sets"); //NON-NLS
        }


    }

    /**
     * Finds a set of files that meets the name criteria.
     *
     * @param dataSource Root data source to limit search results to (Image,
     *                   VirtualDirectory, etc.).
     * @param fileName   Pattern of the name of the file or directory to match
     *                   (case insensitive, used in LIKE SQL statement).
     *
     * @return a list of AbstractFile for files/directories whose name matches
     *         the given fileName
     */
    public synchronized List<AbstractFile> findFiles(Content dataSource, String fileName) throws TskCoreException {
        if (tskCase == null) {
            throw new TskCoreException(NbBundle.getMessage(this.getClass(), "FileManager.findFiles.exception.msg"));
        }
        return tskCase.findFiles(dataSource, fileName);
    }

    /**
     * Finds a set of files that meets the name criteria.
     *
     * @param dataSource Root data source to limit search results to (Image,
     *                   VirtualDirectory, etc.).
     * @param fileName   Pattern of the name of the file or directory to match
     *                   (case insensitive, used in LIKE SQL statement).
     * @param dirName    Pattern of the name of the parent directory to use as
     *                   the root of the search (case insensitive, used in LIKE
     *                   SQL statement).
     *
     * @return a list of AbstractFile for files/directories whose name matches
     *         fileName and whose parent directory contains dirName.
     */
    public synchronized List<AbstractFile> findFiles(Content dataSource, String fileName, String dirName) throws TskCoreException {
        if (tskCase == null) {
            throw new TskCoreException(NbBundle.getMessage(this.getClass(), "FileManager.findFiles2.exception.msg"));
        }
        return tskCase.findFiles(dataSource, fileName, dirName);
    }

    /**
     * Finds a set of files that meets the name criteria.
     *
     * @param dataSource Root data source to limit search results to (Image,
     *                   VirtualDirectory, etc.).
     * @param fileName   Pattern of the name of the file or directory to match
     *                   (case insensitive, used in LIKE SQL statement).
     * @param parentFile Object of root/parent directory to restrict search to.
     *
     * @return a list of AbstractFile for files/directories whose name matches
     *         fileName and that were inside a directory described by
     *         parentFsContent.
     */
    public synchronized List<AbstractFile> findFiles(Content dataSource, String fileName, AbstractFile parentFile) throws TskCoreException {
        if (tskCase == null) {
            throw new TskCoreException(NbBundle.getMessage(this.getClass(), "FileManager.findFiles3.exception.msg"));
        }
        return findFiles(dataSource, fileName, parentFile.getName());
    }

    /**
     * @param dataSource data source Content (Image, parent-less
     *                   VirtualDirectory) where to find files
     * @param filePath   The full path to the file(s) of interest. This can
     *                   optionally include the image and volume names.
     *
     * @return a list of AbstractFile that have the given file path.
     */
    public synchronized List<AbstractFile> openFiles(Content dataSource, String filePath) throws TskCoreException {
        if (tskCase == null) {
            throw new TskCoreException(NbBundle.getMessage(this.getClass(), "FileManager.openFiles.exception.msg"));
        }
        return tskCase.openFiles(dataSource, filePath);
    }

    /**
     * Creates a derived file, adds it to the database and returns it.
     *
     * @param fileName        file name the derived file
     * @param localPath       local path of the derived file, including the file
     *                        name. The path is relative to the case folder.
     * @param size            size of the derived file in bytes
     * @param ctime
     * @param crtime
     * @param atime
     * @param mtime
     * @param isFile          whether a file or directory, true if a file
     * @param parentFile      the parent file object this the new file was
     *                        derived from, either a fs file or parent derived
     *                        file/dikr\\r
     * @param rederiveDetails details needed to re-derive file (will be specific
     *                        to the derivation method), currently unused
     * @param toolName        name of derivation method/tool, currently unused
     * @param toolVersion     version of derivation method/tool, currently
     *                        unused
     * @param otherDetails    details of derivation method/tool, currently
     *                        unused
     *
     * @return newly created derived file object added to the database
     *
     * @throws TskCoreException exception thrown if the object creation failed
     *                          due to a critical system error or of the file
     *                          manager has already been closed
     *
     */
    public synchronized DerivedFile addDerivedFile(String fileName, String localPath, long size,
            long ctime, long crtime, long atime, long mtime,
            boolean isFile, AbstractFile parentFile,
            String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {

        if (tskCase == null) {
            throw new TskCoreException(NbBundle.getMessage(this.getClass(), "FileManager.addDerivedFile.exception.msg"));
        }

        return tskCase.addDerivedFile(fileName, localPath, size,
                ctime, crtime, atime, mtime,
                isFile, parentFile, rederiveDetails, toolName, toolVersion, otherDetails);
    }

    /**
     * Adds a carved file to the VirtualDirectory '$CarvedFiles' in the volume or image given by systemId.
     *
     * @param carvedFileName the name of the carved file (containing appropriate
     *                       extension)
     * @param carvedFileSize size of the carved file to add
     * @param systemId       the ID of the parent volume or file system
     * @param sectors        a list of SectorGroups giving this sectors that
     *                       make up this carved file.
     *
     * @throws TskCoreException exception thrown when critical tsk error
     *                          occurred and carved file could not be added
     */
    public synchronized LayoutFile addCarvedFile(String carvedFileName, long carvedFileSize,
            long systemId, List<TskFileRange> sectors) throws TskCoreException {

        if (tskCase == null) {
            throw new TskCoreException(NbBundle.getMessage(this.getClass(), "FileManager.addCarvedFile.exception.msg"));
        }

        return tskCase.addCarvedFile(carvedFileName, carvedFileSize, systemId, sectors);
    }

    /**
     * Adds a collection of carved files to the VirtualDirectory '$CarvedFiles' in the volume or image given by
     * systemId. Creates $CarvedFiles if it does not exist already.
     *
     * @param filesToAdd a list of CarvedFileContainer files to add as carved files
     * @return List<LayoutFile> This is a list of the files added to the database
     * @throws org.sleuthkit.datamodel.TskCoreException
     */
    public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) throws TskCoreException {
     if (tskCase == null) {
         throw new TskCoreException(NbBundle.getMessage(this.getClass(), "FileManager.addCarvedFile.exception.msg"));
     }
     else {
         return tskCase.addCarvedFiles(filesToAdd);
     }
    }

    /**
     *
     * Interface for receiving notifications on folders being added via a
     * callback
     */
    public interface FileAddProgressUpdater {

        /**
         * Called when new folders has been added
         *
         * @param newFile the file/folder added to the Case
         */
        public void fileAdded(AbstractFile newFile);
    }

    /**
     * Add a set of local/logical files and dirs.
     *
     * @param localAbsPaths      list of absolute paths to local files and dirs
     * @param addProgressUpdater notifier to receive progress notifications on
     *                           folders added, or null if not used
     *
     * @return file set root VirtualDirectory contained containing all
     *         AbstractFile objects added
     *
     * @throws TskCoreException exception thrown if the object creation failed
     *                          due to a critical system error or of the file
     *                          manager has already been closed. There is no
     *                          "revert" logic if one of the additions fails.
     *                          The addition stops with the first error
     *                          encountered.
     */
    public synchronized VirtualDirectory addLocalFilesDirs(List<String> localAbsPaths, FileAddProgressUpdater addProgressUpdater) throws TskCoreException {
        final List<java.io.File> rootsToAdd = new ArrayList<>();
        //first validate all the inputs before any additions
        for (String absPath : localAbsPaths) {
            java.io.File localFile = new java.io.File(absPath);
            if (!localFile.exists() || !localFile.canRead()) {
                String msg = NbBundle
                        .getMessage(this.getClass(), "FileManager.addLocalFilesDirs.exception.notReadable.msg",
                                    localFile.getAbsolutePath());
                logger.log(Level.SEVERE, msg);
                throw new TskCoreException(msg);
            }
            rootsToAdd.add(localFile);
        }

        CaseDbTransaction trans = tskCase.beginTransaction();
        // make a virtual top-level directory for this set of files/dirs
        final VirtualDirectory fileSetRootDir = addLocalFileSetRootDir(trans);

        try {
            // recursively add each item in the set
            for (java.io.File localRootToAdd : rootsToAdd) {
                AbstractFile localFileAdded = addLocalDirInt(trans, fileSetRootDir, localRootToAdd, addProgressUpdater);

                if (localFileAdded == null) {
                    String msg = NbBundle
                            .getMessage(this.getClass(), "FileManager.addLocalFilesDirs.exception.cantAdd.msg",
                                        localRootToAdd.getAbsolutePath());
                    logger.log(Level.SEVERE, msg);
                    throw new TskCoreException(msg);
                } else {
                    //added.add(localFileAdded);
                    //send new content event
                    //for now reusing ingest events, in future this will be replaced by datamodel / observer sending out events
                    // @@@ Is this the right place for this? A directory tree refresh will be triggered, so this may be creating a race condition
                    // since the transaction is not yet committed.  
                    IngestServices.getInstance().fireModuleContentEvent(new ModuleContentEvent(localFileAdded));
                }
            }

            trans.commit();
        } catch (TskCoreException ex) {
            trans.rollback();
        }
        return fileSetRootDir;
    }

    /**
     * Adds a new virtual directory root object with FileSet X name and
     * consecutive sequence number characteristic to every add operation
     *
     * @return the virtual dir root container created
     *
     * @throws TskCoreException
     */
    private VirtualDirectory addLocalFileSetRootDir(CaseDbTransaction trans) throws TskCoreException {

        VirtualDirectory created = null;

        int newFileSetCount = curNumFileSets + 1;
        final String fileSetName = VirtualDirectoryNode.LOGICAL_FILE_SET_PREFIX + newFileSetCount;

        try {
            created = tskCase.addVirtualDirectory(0, fileSetName, trans);
            curNumFileSets = newFileSetCount;
        } catch (TskCoreException ex) {
            String msg = NbBundle
                    .getMessage(this.getClass(), "FileManager.addLocalFileSetRootDir.exception.errCreateDir.msg",
                                fileSetName);
            logger.log(Level.SEVERE, msg, ex);
            throw new TskCoreException(msg, ex);
        }

        return created;
    }

    /**
     * Helper (internal) method to recursively add contents of a folder. Node
     * passed in can be a file or directory. Children of directories are added.
     *
     * @param parentVd           Dir that is the parent of localFile
     * @param localFile          File/Dir that we are adding
     * @param addProgressUpdater notifier to receive progress notifications on
     *                           folders added, or null if not used
     *
     * @returns File object of file added or new virtualdirectory for the
     * directory.
     * @throws TskCoreException
     */
    private AbstractFile addLocalDirInt(CaseDbTransaction trans, VirtualDirectory parentVd,
            java.io.File localFile, FileAddProgressUpdater addProgressUpdater) throws TskCoreException {

        if (tskCase == null) {
            throw new TskCoreException(
                    NbBundle.getMessage(this.getClass(), "FileManager.addLocalDirInt.exception.closed.msg"));
        }

        //final String localName = localDir.getName();
        if (!localFile.exists()) {
            throw new TskCoreException(
                    NbBundle.getMessage(this.getClass(), "FileManager.addLocalDirInt.exception.doesntExist.msg",
                                        localFile.getAbsolutePath()));
        }
        if (!localFile.canRead()) {
            throw new TskCoreException(
                    NbBundle.getMessage(this.getClass(), "FileManager.addLocalDirInt.exception.notReadable.msg",
                                        localFile.getAbsolutePath()));
        }


        if (localFile.isDirectory()) {
            //create virtual folder (we don't have a notion of a 'local folder')
            final VirtualDirectory childVd = tskCase.addVirtualDirectory(parentVd.getId(), localFile.getName(), trans);
            if (childVd != null && addProgressUpdater != null) {
                addProgressUpdater.fileAdded(childVd);
            }
            //add children recursively
            final java.io.File[] childrenFiles = localFile.listFiles();
            if (childrenFiles != null) {
                for (java.io.File childFile : childrenFiles) {
                    addLocalDirInt(trans, childVd, childFile, addProgressUpdater);
                }
            }
            return childVd;
        } else {
            //add leaf file, base case
            return this.addLocalFileInt(parentVd, localFile, trans);
        }
    }

    /**
     * Adds a single local/logical file to the case. Adds it to the database.
     * Does not refresh the views of data. Assumes that the local file exists
     * and can be read. This checking is done by addLocalDirInt().
     *
     * @param parentFile parent file object container (such as virtual
     *                   directory, another local file, or fscontent File),
     * @param localFile  File that we are adding
     *
     * @return newly created local file object added to the database
     *
     * @throws TskCoreException exception thrown if the object creation failed
     *                          due to a critical system error or of the file
     *                          manager has already been closed
     */
    private synchronized LocalFile addLocalFileInt(AbstractFile parentFile, java.io.File localFile, CaseDbTransaction trans) throws TskCoreException {

        if (tskCase == null) {
            throw new TskCoreException(
                    NbBundle.getMessage(this.getClass(), "FileManager.addLocalDirInt2.exception.closed.msg"));
        }

        long size = localFile.length();
        boolean isFile = localFile.isFile();

        long ctime = 0;
        long crtime = 0;
        long atime = 0;
        long mtime = 0;

        String fileName = localFile.getName();

        LocalFile lf = tskCase.addLocalFile(fileName, localFile.getAbsolutePath(), size,
                ctime, crtime, atime, mtime,
                isFile, parentFile, trans);

        return lf;
    }

    @Override
    public synchronized void close() throws IOException {
        tskCase = null;
    }
}
TOP

Related Classes of org.sleuthkit.autopsy.casemodule.services.FileManager$FileAddProgressUpdater

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.