示例#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
 * Copy the contents of one directory structure to another.
 * Note that this currently does not copy the FS_FILE info.
 * It is only used to make a copy of the orphan directory.
 * It does not check for duplicate entries.
 * @returns 1 on error
 */
static uint8_t
tsk_fs_dir_copy(const TSK_FS_DIR * a_src_dir, TSK_FS_DIR * a_dst_dir)
{
    size_t i;

    a_dst_dir->names_used = 0;

    // make sure we got the room
    if (a_src_dir->names_used > a_dst_dir->names_alloc) {
        if (tsk_fs_dir_realloc(a_dst_dir, a_src_dir->names_used))
            return 1;
    }

    for (i = 0; i < a_src_dir->names_used; i++) {
        if (tsk_fs_name_copy(&a_dst_dir->names[i], &a_src_dir->names[i]))
            return 1;
    }

    a_dst_dir->names_used = a_src_dir->names_used;
    a_dst_dir->addr = a_src_dir->addr;
    return 0;
}
示例#3
0
/** \internal
 * Add a FS_DENT structure to a FS_DIR structure by copying its
 * contents into the internal buffer. Checks for
 * duplicates and expands buffer as needed.
 * @param a_fs_dir DIR to add to
 * @param a_fs_name DENT to add
 * @returns 1 on error (memory allocation problems) and 0 on success
 */
uint8_t
tsk_fs_dir_add(TSK_FS_DIR * a_fs_dir, const TSK_FS_NAME * a_fs_name)
{
    TSK_FS_NAME *fs_name_dest = NULL;
    size_t i;

    /* see if we already have it in the buffer / queue
     * We skip this check for FAT because it will always fail because two entries
     * never have the same meta address. */
    // @@@ We could do something more effecient here too with orphan files because we do not 
    // need to check the contents of that directory either and this takes a lot of time on those
    // large images.
	if (TSK_FS_TYPE_ISFAT(a_fs_dir->fs_info->ftype) == 0) {
		for (i = 0; i < a_fs_dir->names_used; i++) {
			if ((a_fs_name->meta_addr == a_fs_dir->names[i].meta_addr) &&
				(strcmp(a_fs_name->name, a_fs_dir->names[i].name) == 0)) {

				if (tsk_verbose)
					tsk_fprintf(stderr,
						"tsk_fs_dir_add: removing duplicate entry: %s (%"
						PRIuINUM ")\n", a_fs_name->name, a_fs_name->meta_addr);

				/* We do not check type because then we cannot detect NTFS orphan file
				 * duplicates that are added as "-/r" while a similar entry exists as "r/r"
				 (a_fs_name->type == a_fs_dir->names[i].type)) { */

				// if the one in the list is unalloc and we have an alloc, replace it
				if ((a_fs_dir->names[i].flags & TSK_FS_NAME_FLAG_UNALLOC) &&
					(a_fs_name->flags & TSK_FS_NAME_FLAG_ALLOC)) {
					fs_name_dest = &a_fs_dir->names[i];

					// free the memory - not the most effecient, but prevents
					// duplicate code.
					if (fs_name_dest->name) {
						free(fs_name_dest->name);
						fs_name_dest->name = NULL;
						fs_name_dest->name_size = 0;
					}
					if (fs_name_dest->shrt_name) {
						free(fs_name_dest->shrt_name);
						fs_name_dest->shrt_name = NULL;
						fs_name_dest->shrt_name_size = 0;
					}
					break;
				}
				else {
					return 0;
				}
			}
		}
	}

    if (fs_name_dest == NULL) {
        // make sure we got the room
        if (a_fs_dir->names_used >= a_fs_dir->names_alloc) {
            if (tsk_fs_dir_realloc(a_fs_dir, a_fs_dir->names_used + 512))
                return 1;
        }

        fs_name_dest = &a_fs_dir->names[a_fs_dir->names_used++];
    }

    if (tsk_fs_name_copy(fs_name_dest, a_fs_name))
        return 1;

    // add the parent address
    if (a_fs_dir->addr)
        fs_name_dest->par_addr = a_fs_dir->addr;

    return 0;
}
示例#4
0
/** \internal
 * Search the file system for orphan files and create the orphan file directory.
 * @param a_fs File system to search
 * @param a_fs_dir Structure to store the orphan file directory info in.
 */
TSK_RETVAL_ENUM
tsk_fs_dir_find_orphans(TSK_FS_INFO * a_fs, TSK_FS_DIR * a_fs_dir)
{
    FIND_ORPHAN_DATA data;
    size_t i;

    tsk_take_lock(&a_fs->orphan_dir_lock);

    if (a_fs->orphan_dir != NULL) {
        if (tsk_fs_dir_copy(a_fs->orphan_dir, a_fs_dir)) {
            tsk_release_lock(&a_fs->orphan_dir_lock);
            return TSK_ERR;
        }

        if (tsk_fs_dir_add_orphan_dir_meta(a_fs, a_fs_dir)) {
            tsk_release_lock(&a_fs->orphan_dir_lock);
            return TSK_ERR;
        }

        tsk_release_lock(&a_fs->orphan_dir_lock);
        return TSK_OK;
    }

    if (tsk_verbose)
        fprintf(stderr,
            "tsk_fs_dir_find_orphans: Searching for orphan files\n");

    memset(&data, 0, sizeof(FIND_ORPHAN_DATA));

    /* We first need to determine which of the unallocated meta structures
     * have a name pointing to them.  We cache this data, so see if it is
     * already known. */
    if (tsk_fs_dir_load_inum_named(a_fs) != TSK_OK) {
        tsk_release_lock(&a_fs->orphan_dir_lock);
        return TSK_ERR;
    }
    // note that list_inum_named could still be NULL if there are no deleted names.

    /* Now we walk the unallocated metadata structures and find ones that are
     * not named.  The callback will add the names to the FS_DIR structure.
     */
    data.fs_dir = a_fs_dir;

    // allocate a name once so that we will reuse for each name we add to FS_DIR
    if ((data.fs_name = tsk_fs_name_alloc(256, 0)) == NULL) {
        tsk_release_lock(&a_fs->orphan_dir_lock);
        return TSK_ERR;
    }

    if (tsk_verbose)
        fprintf(stderr,
            "tsk_fs_dir_find_orphans: Performing inode_walk to find unnamed metadata structures\n");

    if (tsk_fs_meta_walk(a_fs, a_fs->first_inum, a_fs->last_inum,
            TSK_FS_META_FLAG_UNALLOC | TSK_FS_META_FLAG_USED,
            find_orphan_meta_walk_cb, &data)) {
        tsk_fs_name_free(data.fs_name);
        tsk_release_lock(&a_fs->orphan_dir_lock);
        return TSK_ERR;
    }

    tsk_fs_name_free(data.fs_name);
    data.fs_name = NULL;


    if (tsk_verbose)
        fprintf(stderr,
            "tsk_fs_dir_find_orphans: De-duping orphan files and directories\n");

    /* do some cleanup on the final list. This cleanup will compare the
     * entries in the root orphan directory with files that can be accessed
     * from subdirectories of the orphan directory.  These entries will exist if
     * they were added before their parent directory was added to the orphan directory. */
    for (i = 0; i < a_fs_dir->names_used; i++) {
        if (tsk_list_find(data.orphan_subdir_list,
                a_fs_dir->names[i].meta_addr)) {
            if (a_fs_dir->names_used > 1) {
                tsk_fs_name_copy(&a_fs_dir->names[i],
                    &a_fs_dir->names[a_fs_dir->names_used - 1]);
            }
            a_fs_dir->names_used--;
        }
    }

    if (data.orphan_subdir_list) {
        tsk_list_free(data.orphan_subdir_list);
        data.orphan_subdir_list = NULL;
    }


    // make copy of this so that we don't need to do it again.
    if ((a_fs->orphan_dir =
            tsk_fs_dir_alloc(a_fs, a_fs_dir->addr,
                a_fs_dir->names_used)) == NULL) {
        tsk_release_lock(&a_fs->orphan_dir_lock);
        return TSK_ERR;
    }

    if (tsk_fs_dir_copy(a_fs_dir, a_fs->orphan_dir)) {
        tsk_release_lock(&a_fs->orphan_dir_lock);
        return TSK_ERR;
    }

    // populate the fake FS_FILE structure in the struct to be returned for the "Orphan Directory"
    if (tsk_fs_dir_add_orphan_dir_meta(a_fs, a_fs_dir)) {
        tsk_release_lock(&a_fs->orphan_dir_lock);
        return TSK_ERR;
    }

    tsk_release_lock(&a_fs->orphan_dir_lock);
    return TSK_OK;
}
示例#5
0
/** \internal
 * Add a FS_DENT structure to a FS_DIR structure by copying its
 * contents into the internal buffer. Checks for
 * duplicates and expands buffer as needed.
 * @param a_fs_dir DIR to add to
 * @param a_fs_name DENT to add
 * @returns 1 on error (memory allocation problems) and 0 on success
 */
uint8_t
tsk_fs_dir_add(TSK_FS_DIR * a_fs_dir, const TSK_FS_NAME * a_fs_name)
{
    TSK_FS_NAME *fs_name_dest = NULL;
    size_t i;

    // see if we already have it in the buffer / queue
    for (i = 0; i < a_fs_dir->names_used; i++) {
        if ((a_fs_name->meta_addr == a_fs_dir->names[i].meta_addr) &&
            (strcmp(a_fs_name->name, a_fs_dir->names[i].name) == 0)) {

            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "tsk_fs_dir_add: removing duplicate entry: %s (%"
                    PRIuINUM ")\n", a_fs_name->name, a_fs_name->meta_addr);

            /* We do not check type because then we cannot detect NTFS orphan file
             * duplicates that are added as "-/r" while a similar entry exists as "r/r"
             (a_fs_name->type == a_fs_dir->names[i].type)) { */

            // if the one in the list is unalloc and we have an alloc, replace it
            if ((a_fs_dir->names[i].flags & TSK_FS_NAME_FLAG_UNALLOC) &&
                (a_fs_name->flags & TSK_FS_NAME_FLAG_ALLOC)) {
                fs_name_dest = &a_fs_dir->names[i];

                // free the memory - not the most effecient, but prevents
                // duplicate code.
                if (fs_name_dest->name) {
                    free(fs_name_dest->name);
                    fs_name_dest->name = NULL;
                    fs_name_dest->name_size = 0;
                }
                if (fs_name_dest->shrt_name) {
                    free(fs_name_dest->shrt_name);
                    fs_name_dest->shrt_name = NULL;
                    fs_name_dest->shrt_name_size = 0;
                }
                break;
            }
            else {
                return 0;
            }
        }
    }

    if (fs_name_dest == NULL) {
        // make sure we got the room
        if (a_fs_dir->names_used >= a_fs_dir->names_alloc) {
            if (tsk_fs_dir_realloc(a_fs_dir, a_fs_dir->names_used + 256))
                return 1;
        }

        fs_name_dest = &a_fs_dir->names[a_fs_dir->names_used++];
    }

    if (tsk_fs_name_copy(fs_name_dest, a_fs_name))
        return 1;

    // add the parent address
    if (a_fs_dir->addr)
        fs_name_dest->par_addr = a_fs_dir->addr;

    return 0;
}
示例#6
0
/**
 * \ingroup fslib
 *
 * Find the meta data address for a given file name (UTF-8).
 * The basic idea of the function is to break the given name into its
 * subdirectories and start looking for each (starting in the root
 * directory).
 *
 * @param a_fs FS to analyze
 * @param a_path UTF-8 path of file to search for
 * @param [out] a_result Meta data address of file
 * @param [out] a_fs_name Copy of name details (or NULL if details not wanted)
 * @returns -1 on (system) error, 0 if found, and 1 if not found
 */
int8_t
tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path,
    TSK_INUM_T * a_result, TSK_FS_NAME * a_fs_name)
{
    char *cpath;
    size_t clen;
    char *cur_dir;              // The "current" directory or file we are looking for
    char *cur_attr;             // The "current" attribute of the dir we are looking for
    TSK_INUM_T next_meta;
    uint8_t is_done;
    char *strtok_last;
    *a_result = 0;

    // copy path to a buffer that we can modify
    clen = strlen(a_path) + 1;
    if ((cpath = (char *) tsk_malloc(clen)) == NULL) {
        return -1;
    }
    strncpy(cpath, a_path, clen);

    // Get the first part of the directory path.
    cur_dir = (char *) strtok_r(cpath, "/", &strtok_last);
    cur_attr = NULL;

    /* If there is no token, then only a '/' was given */
    if (cur_dir == NULL) {
        free(cpath);
        *a_result = a_fs->root_inum;

        // create the dummy entry if needed
        if (a_fs_name) {
            a_fs_name->meta_addr = a_fs->root_inum;
            // Note that we are not filling in meta_seq -- we could, we just aren't

            a_fs_name->type = TSK_FS_NAME_TYPE_DIR;
            a_fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
            if (a_fs_name->name)
                a_fs_name->name[0] = '\0';
            if (a_fs_name->shrt_name)
                a_fs_name->shrt_name[0] = '\0';
        }
        return 0;
    }

    /* If this is NTFS, separate out the attribute of the current directory */
    if (TSK_FS_TYPE_ISNTFS(a_fs->ftype)
        && ((cur_attr = strchr(cur_dir, ':')) != NULL)) {
        *(cur_attr) = '\0';
        cur_attr++;
    }

    if (tsk_verbose)
        tsk_fprintf(stderr, "Looking for %s\n", cur_dir);

    // initialize the first place to look, the root dir
    next_meta = a_fs->root_inum;

    // we loop until we know the outcome and then exit.
    // everything should return from inside the loop.
    is_done = 0;
    while (is_done == 0) {
        size_t i;
        TSK_FS_FILE *fs_file_alloc = NULL;      // set to the allocated file that is our target
        TSK_FS_FILE *fs_file_del = NULL;        // set to an unallocated file that matches our criteria

        TSK_FS_DIR *fs_dir = NULL;

        // open the next directory in the recursion
        if ((fs_dir = tsk_fs_dir_open_meta(a_fs, next_meta)) == NULL) {
            free(cpath);
            return -1;
        }

        /* Verify this is indeed a directory.  We had one reported
         * problem where a file was a disk image and opening it as
         * a directory found the directory entries inside of the file
         * and this caused problems... */
        if ( !TSK_FS_IS_DIR_META(fs_dir->fs_file->meta->type)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
            tsk_error_set_errstr("Address %" PRIuINUM
                " is not for a directory\n", next_meta);
            free(cpath);
            return -1;
        }

        // cycle through each entry
        for (i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) {

            TSK_FS_FILE *fs_file;
            uint8_t found_name = 0;

            if ((fs_file = tsk_fs_dir_get(fs_dir, i)) == NULL) {
                tsk_fs_dir_close(fs_dir);
                free(cpath);
                return -1;
            }

            /*
             * Check if this is the name that we are currently looking for,
             * as identified in 'cur_dir'
             */
            if ((fs_file->name->name)
                && (a_fs->name_cmp(a_fs, fs_file->name->name,
                        cur_dir) == 0)) {
                found_name = 1;
            }
            else if ((fs_file->name->shrt_name)
                && (a_fs->name_cmp(a_fs, fs_file->name->shrt_name,
                        cur_dir) == 0)) {
                found_name = 1;
            }

            /* For NTFS, we have to check the attribute name. */
            if ((found_name == 1) && (TSK_FS_TYPE_ISNTFS(a_fs->ftype))) {
                /*  ensure we have the right attribute name */
                if (cur_attr != NULL) {
                    found_name = 0;
                    if (fs_file->meta) {
                        int cnt, i;

                        // cycle through the attributes
                        cnt = tsk_fs_file_attr_getsize(fs_file);
                        for (i = 0; i < cnt; i++) {
                            const TSK_FS_ATTR *fs_attr =
                                tsk_fs_file_attr_get_idx(fs_file, i);
                            if (!fs_attr)
                                continue;

                            if ((fs_attr->name)
                                && (a_fs->name_cmp(a_fs, fs_attr->name,
                                        cur_attr) == 0)) {
                                found_name = 1;
                                break;
                            }
                        }
                    }
                }
            }

            if (found_name) {
                /* If we found our file and it is allocated, then stop. If
                 * it is unallocated, keep on going to see if we can get
                 * an allocated hit */
                if (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) {
                    fs_file_alloc = fs_file;
                    break;
                }
                else {
                    // if we already have an unalloc and its addr is 0, then use the new one
                    if ((fs_file_del)
                        && (fs_file_del->name->meta_addr == 0)) {
                        tsk_fs_file_close(fs_file_del);
                    }
                    fs_file_del = fs_file;
                }
            }
            // close the file if we did not save it for future analysis.
            else {
                tsk_fs_file_close(fs_file);
                fs_file = NULL;
            }
        }

        // we found a directory, go into it
        if ((fs_file_alloc) || (fs_file_del)) {

            const char *pname;
            TSK_FS_FILE *fs_file_tmp;

            // choose the alloc one first (if they both exist)
            if (fs_file_alloc)
                fs_file_tmp = fs_file_alloc;
            else
                fs_file_tmp = fs_file_del;

            pname = cur_dir;    // save a copy of the current name pointer

            // advance to the next name
            cur_dir = (char *) strtok_r(NULL, "/", &(strtok_last));
            cur_attr = NULL;

            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "Found it (%s), now looking for %s\n", pname, cur_dir);

            /* That was the last name in the path -- we found the file! */
            if (cur_dir == NULL) {
                *a_result = fs_file_tmp->name->meta_addr;

                // make a copy if one was requested
                if (a_fs_name) {
                    tsk_fs_name_copy(a_fs_name, fs_file_tmp->name);
                }

                if (fs_file_alloc)
                    tsk_fs_file_close(fs_file_alloc);
                if (fs_file_del)
                    tsk_fs_file_close(fs_file_del);

                tsk_fs_dir_close(fs_dir);
                free(cpath);
                return 0;
            }

            // update the attribute field, if needed
            if (TSK_FS_TYPE_ISNTFS(a_fs->ftype)
                && ((cur_attr = strchr(cur_dir, ':')) != NULL)) {
                *(cur_attr) = '\0';
                cur_attr++;
            }

            // update the value for the next directory to open
            next_meta = fs_file_tmp->name->meta_addr;

            if (fs_file_alloc) {
                tsk_fs_file_close(fs_file_alloc);
                fs_file_alloc = NULL;
            }
            if (fs_file_del) {
                tsk_fs_file_close(fs_file_del);
                fs_file_del = NULL;
            }
        }

        // no hit in directory
        else {
            is_done = 1;
        }

        tsk_fs_dir_close(fs_dir);
        fs_dir = NULL;
    }

    free(cpath);
    return 1;
}