示例#1
0
文件: fs_dir.c 项目: egall/sleuthkit
/** \ingroup fslib
* Return a specific file or subdirectory from an open directory.
 * @param a_fs_dir Directory to analyze
 * @param a_idx Index of file in directory to open (0-based)
 * @returns NULL on error
 */
TSK_FS_FILE *
tsk_fs_dir_get(const TSK_FS_DIR * a_fs_dir, size_t a_idx)
{
    TSK_FS_NAME *fs_name;
    TSK_FS_FILE *fs_file;

    if ((a_fs_dir == NULL) || (a_fs_dir->tag != TSK_FS_DIR_TAG)
        || (a_fs_dir->fs_info == NULL)) {
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_dir_get: called with NULL or unallocated structures");
        return NULL;
    }
    if (a_fs_dir->names_used <= a_idx) {
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("tsk_fs_dir_get: Index (%" PRIuSIZE
            ") too large (%" PRIuSIZE ")", a_idx, a_fs_dir->names_used);
        return NULL;
    }

    // allocate a structure to return
    if ((fs_file = tsk_fs_file_alloc(a_fs_dir->fs_info)) == NULL)
        return NULL;

    fs_name = &(a_fs_dir->names[a_idx]);

    // copy the name into another structure that we can return and later free
    if ((fs_file->name =
            tsk_fs_name_alloc(fs_name->name ? strlen(fs_name->name) +
                1 : 0,
                fs_name->shrt_name ? strlen(fs_name->shrt_name) +
                1 : 0)) == NULL) {
        return NULL;
    }
    if (tsk_fs_name_copy(fs_file->name, fs_name))
        return NULL;

    /* load the fs_meta structure if possible.
     * Must have non-zero inode addr or have allocated name (if inode is 0) */
    if (((fs_name->meta_addr)
            || (fs_name->flags & TSK_FS_NAME_FLAG_ALLOC))) {
        if (a_fs_dir->fs_info->file_add_meta(a_fs_dir->fs_info, fs_file,
                fs_name->meta_addr)) {
            if (tsk_verbose)
                tsk_error_print(stderr);
            tsk_error_reset();
        }

        // if the sequence numbers don't match, then don't load the meta
        // should ideally have sequence in previous lookup, but it isn't 
        // in all APIs yet
        if (fs_file->meta->seq != fs_name->meta_seq) {
            tsk_fs_meta_close(fs_file->meta);
            fs_file->meta = NULL;
        }
    }
    return fs_file;
}
示例#2
0
/**
 * \internal
 * Prints file system category data for an exFAT file system to a file 
 * handle. 
 *
 * @param [in] a_fs Generic file system info structure for the file system.
 * @param [in] a_hFile The file handle.
 * @return 0 on success, 1 otherwise, per TSK convention.
 */
static uint8_t
exfatfs_fsstat_fs_info(TSK_FS_INFO *a_fs, FILE *a_hFile)
{
    FATFS_INFO *fatfs = NULL;
    EXFATFS_MASTER_BOOT_REC *exfatbs = NULL;
    TSK_FS_FILE *fs_file = NULL;

    assert(a_fs != NULL);
    assert(a_hFile != NULL);

    fatfs = (FATFS_INFO*)a_fs;
    exfatbs = (EXFATFS_MASTER_BOOT_REC*)&(fatfs->boot_sector_buffer);

    if ((fs_file = tsk_fs_file_alloc(a_fs)) == NULL) {
        return FATFS_FAIL;
    }

    if ((fs_file->meta = tsk_fs_meta_alloc(FATFS_FILE_CONTENT_LEN)) == NULL) {
        return FATFS_FAIL;
    }

    tsk_fprintf(a_hFile, "FILE SYSTEM INFORMATION\n");
    tsk_fprintf(a_hFile, "--------------------------------------------\n");

    tsk_fprintf(a_hFile, "File System Type: exFAT\n");

    tsk_fprintf(a_hFile, "\nVolume Serial Number: %x%x-%x%x\n", 
        exfatbs->vol_serial_no[3], exfatbs->vol_serial_no[2], 
        exfatbs->vol_serial_no[1], exfatbs->vol_serial_no[0]);

    if (exfatfs_find_volume_label_dentry(fatfs, fs_file) == 0) {
        tsk_fprintf(a_hFile, "Volume Label (from root directory): %s\n", fs_file->meta->name2->name);
    }
    else {
        tsk_fprintf(a_hFile, "Volume Label:\n");
    }

    tsk_fprintf(a_hFile, "File System Name (from MBR): %s\n", exfatbs->fs_name);

    tsk_fprintf(a_hFile, "File System Revision: %x.%x\n", 
        exfatbs->fs_revision[1], exfatbs->fs_revision[0]);

    tsk_fprintf(a_hFile, "Partition Offset: %" PRIuDADDR "\n", 
        tsk_getu64(a_fs->endian, exfatbs->partition_offset));

    tsk_fprintf(a_hFile, "Number of FATs: %d\n", fatfs->numfat);

    tsk_fs_file_close(fs_file);

    return FATFS_OK;
}
示例#3
0
/** \internal
 * Adds the fake metadata entry in the FS_DIR->fs_file struct for the orphan files directory
 *
 * @returns 1 on error
 */
static uint8_t
tsk_fs_dir_add_orphan_dir_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR * a_fs_dir)
{
    // populate the fake FS_FILE structure for the "Orphan Directory"
    if ((a_fs_dir->fs_file = tsk_fs_file_alloc(a_fs)) == NULL) {
        return 1;
    }

    if ((a_fs_dir->fs_file->meta =
            tsk_fs_meta_alloc(sizeof(TSK_DADDR_T))) == NULL) {
        return 1;
    }

    if (tsk_fs_dir_make_orphan_dir_meta(a_fs, a_fs_dir->fs_file->meta)) {
        return 1;
    }
    return 0;
}
示例#4
0
/** 
* \ingroup fslib
*
* Open a file given its metadata address. This function loads the metadata
* and returns a handle that can be used to read and process the file.   Note
* that the returned TSK_FS_FILE structure will not have the file name set because
* it was not used to load the file and this function does not search the 
* directory structure to find the name that points to the address.   In general,
* if you know the metadata address of a file, this function is more efficient 
* then tsk_fs_file_open, which first maps a file name to the metadata address 
* and then opens the file using this function. 
*
* @param a_fs File system to analyze
* @param a_fs_file Structure to store file data in or NULL to have one allocated. 
* @param a_addr Metadata address of file to lookup
* @returns NULL on error
*/
TSK_FS_FILE *
tsk_fs_file_open_meta(TSK_FS_INFO * a_fs,
    TSK_FS_FILE * a_fs_file, TSK_INUM_T a_addr)
{
    TSK_FS_FILE *fs_file;

    if ((a_fs == NULL) || (a_fs->tag != TSK_FS_INFO_TAG)) {
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_file_open_meta: called with NULL or unallocated structures");
        return NULL;
    }

    fs_file = a_fs_file;
    if (fs_file == NULL) {
        if ((fs_file = tsk_fs_file_alloc(a_fs)) == NULL)
            return NULL;
    }
    else {
        /* if the structure passed has a name structure, free it
         * because we won't use it. */
        if (fs_file->name) {
            tsk_fs_name_free(fs_file->name);
            fs_file->name = NULL;
        }

        // reset the rest of it
        tsk_fs_file_reset(fs_file);
    }

    if (a_fs->file_add_meta(a_fs, fs_file, a_addr)) {
        if (a_fs_file == NULL)
            tsk_fs_file_close(fs_file);
        return NULL;
    }

    return fs_file;
}
示例#5
0
/* dir_walk local function that is used for recursive calls.  Callers
 * should initially call the non-local version. */
static TSK_WALK_RET_ENUM
tsk_fs_dir_walk_lcl(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo,
    TSK_INUM_T a_addr, TSK_FS_DIR_WALK_FLAG_ENUM a_flags,
    TSK_FS_DIR_WALK_CB a_action, void *a_ptr)
{
    TSK_FS_DIR *fs_dir;
    TSK_FS_FILE *fs_file;
    size_t i;

    // get the list of entries in the directory
    if ((fs_dir = tsk_fs_dir_open_meta(a_fs, a_addr)) == NULL) {
        return TSK_WALK_ERROR;
    }

    /* Allocate a file structure for the callbacks.  We
     * will allocate fs_meta structures as needed and
     * point into the fs_dir structure for the names. */
    if ((fs_file = tsk_fs_file_alloc(a_fs)) == NULL) {
        tsk_fs_dir_close(fs_dir);
        return TSK_WALK_ERROR;
    }

    for (i = 0; i < fs_dir->names_used; i++) {
        TSK_WALK_RET_ENUM retval;

        /* Point name to the buffer of names.  We need to be
         * careful about resetting this before we free fs_file */
        fs_file->name = (TSK_FS_NAME *) & fs_dir->names[i];

        /* load the fs_meta structure if possible.
         * Must have non-zero inode addr or have allocated name (if inode is 0) */
        if (((fs_file->name->meta_addr)
                || (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC))) {
            if (a_fs->file_add_meta(a_fs, fs_file,
                    fs_file->name->meta_addr)) {
                if (tsk_verbose)
                    tsk_error_print(stderr);
                tsk_error_reset();
            }
        }

        // call the action if we have the right flags.
        if ((fs_file->name->flags & a_flags) == fs_file->name->flags) {
            retval = a_action(fs_file, a_dinfo->dirs, a_ptr);
            if (retval == TSK_WALK_STOP) {
                tsk_fs_dir_close(fs_dir);
                fs_file->name = NULL;
                tsk_fs_file_close(fs_file);

                /* free the list -- fs_dir_walk has no way
                 * of knowing that we stopped early w/out error.
                 */
                if (a_dinfo->save_inum_named) {
                    tsk_list_free(a_dinfo->list_inum_named);
                    a_dinfo->list_inum_named = NULL;
                    a_dinfo->save_inum_named = 0;
                }
                return TSK_WALK_STOP;
            }
            else if (retval == TSK_WALK_ERROR) {
                tsk_fs_dir_close(fs_dir);
                fs_file->name = NULL;
                tsk_fs_file_close(fs_file);
                return TSK_WALK_ERROR;
            }
        }

        // save the inode info for orphan finding - if requested
        if ((a_dinfo->save_inum_named) && (fs_file->meta)
            && (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC)) {

            if (tsk_list_add(&a_dinfo->list_inum_named,
                    fs_file->meta->addr)) {

                // if there is an error, then clear the list
                tsk_list_free(a_dinfo->list_inum_named);
                a_dinfo->list_inum_named = NULL;
                a_dinfo->save_inum_named = 0;
            }
        }

        /* Recurse into a directory if:
         * - Both dir entry and inode have DIR type (or name is undefined)
         * - Recurse flag is set
         * - dir entry is allocated OR both are unallocated
         * - not one of the '.' or '..' entries
         * - A Non-Orphan Dir or the Orphan Dir with the NOORPHAN flag not set.
         */
        if (((fs_file->name->type == TSK_FS_NAME_TYPE_DIR)
                || (fs_file->name->type == TSK_FS_NAME_TYPE_UNDEF))
            && (fs_file->meta)
            && (fs_file->meta->type == TSK_FS_META_TYPE_DIR)
            && (a_flags & TSK_FS_DIR_WALK_FLAG_RECURSE)
            && ((fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC)
                || ((fs_file->name->flags & TSK_FS_NAME_FLAG_UNALLOC)
                    && (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC))
            )
            && (!TSK_FS_ISDOT(fs_file->name->name))
            && ((fs_file->name->meta_addr != TSK_FS_ORPHANDIR_INUM(a_fs))
                || ((a_flags & TSK_FS_DIR_WALK_FLAG_NOORPHAN) == 0))
            ) {

            /* Make sure we do not get into an infinite loop */
            if (0 == tsk_stack_find(a_dinfo->stack_seen,
                    fs_file->name->meta_addr)) {
                int depth_added = 0;
                uint8_t save_bak = 0;

                if (tsk_stack_push(a_dinfo->stack_seen,
                        fs_file->name->meta_addr)) {
                    tsk_fs_dir_close(fs_dir);
                    fs_file->name = NULL;
                    tsk_fs_file_close(fs_file);
                    return TSK_WALK_ERROR;
                }

                if ((a_dinfo->depth < MAX_DEPTH) &&
                    (DIR_STRSZ >
                        strlen(a_dinfo->dirs) +
                        strlen(fs_file->name->name))) {
                    a_dinfo->didx[a_dinfo->depth] =
                        &a_dinfo->dirs[strlen(a_dinfo->dirs)];
                    strncpy(a_dinfo->didx[a_dinfo->depth],
                        fs_file->name->name,
                        DIR_STRSZ - strlen(a_dinfo->dirs));
                    strncat(a_dinfo->dirs, "/", DIR_STRSZ);
                    depth_added = 1;
                }
                a_dinfo->depth++;

                /* We do not want to save info about named unalloc files
                 * when we go into the Orphan directory (because then we have
                 * no orphans).  So, disable it for this recursion.
                 */
                if (fs_file->name->meta_addr ==
                    TSK_FS_ORPHANDIR_INUM(a_fs)) {
                    save_bak = a_dinfo->save_inum_named;
                    a_dinfo->save_inum_named = 0;
                }
                retval = tsk_fs_dir_walk_lcl(a_fs,
                    a_dinfo, fs_file->name->meta_addr, a_flags,
                    a_action, a_ptr);
                if (retval == TSK_WALK_ERROR) {
                    /* If this fails because the directory could not be
                     * loaded, then we still continue */
                    if (tsk_verbose) {
                        tsk_fprintf(stderr,
                            "tsk_fs_dir_walk_lcl: error reading directory: %"
                            PRIuINUM "\n", fs_file->name->meta_addr);
                        tsk_error_print(stderr);
                    }

                    tsk_error_reset();
                }
                else if (retval == TSK_WALK_STOP) {
                    tsk_fs_dir_close(fs_dir);
                    fs_file->name = NULL;
                    tsk_fs_file_close(fs_file);
                    return TSK_WALK_STOP;
                }

                // reset the save status
                if (fs_file->name->meta_addr ==
                    TSK_FS_ORPHANDIR_INUM(a_fs)) {
                    a_dinfo->save_inum_named = save_bak;
                }

                tsk_stack_pop(a_dinfo->stack_seen);
                a_dinfo->depth--;
                if (depth_added)
                    *a_dinfo->didx[a_dinfo->depth] = '\0';
            }
            else {
                if (tsk_verbose)
                    fprintf(stderr,
                        "tsk_fs_dir_walk_lcl: Loop detected with address %"
                        PRIuINUM, fs_file->name->meta_addr);
            }
        }

        // remove the pointer to name buffer
        fs_file->name = NULL;

        // free the metadata if we allocated it
        if (fs_file->meta) {
            tsk_fs_meta_close(fs_file->meta);
            fs_file->meta = NULL;
        }
    }

    tsk_fs_dir_close(fs_dir);
    fs_file->name = NULL;
    tsk_fs_file_close(fs_file);
    return TSK_WALK_CONT;
}