Exemplo n.º 1
0
/**
* Creates a new single-user case with a new database and initializes its tables.
* Fails if there's already a file at the given path. 
*
* @param path Full path to create new database at.
* @returns Pointer to a new TskCaseDb object, NULL on error
*/
TskCaseDb *
TskCaseDb::newDb(const TSK_TCHAR * const path)
{
    TskDb *db = new TskDbSqlite(path, true);

    // Check if the database already exsists
    if (db->dbExists()) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_AUTO_DB);
        tsk_error_set_errstr("Database %" PRIttocTSK
            " already exists.  Must be deleted first.", path);
        delete(db);
        return NULL;
    }

    // Open the database.
    if (db->open(true)) {
        delete(db);
        return NULL;
    }

    return new TskCaseDb(db);
}
Exemplo n.º 2
0
/**
* Opens a single-user case from an existing database.
*
* @param path Full path to open database from.
* @returns Pointer to a new TskCaseDb object, NULL on error
*/
TskCaseDb *
TskCaseDb::openDb(const TSK_TCHAR * path)
{
    TskDb *db = new TskDbSqlite(path, true);

    // Confirm that database already exsists
    if (!db->dbExists()) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_AUTO_DB);
        tsk_error_set_errstr("Database %" PRIttocTSK
            " does not exist.  Must be created first.", path);
        delete(db);
        return NULL;
    }

    // Open the database.
    if (db->open(false)) {
        delete(db);
        return NULL;
    }

    return new TskCaseDb(db);
}
Exemplo n.º 3
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 effecient 
* 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)
            free(fs_file);
        return NULL;
    }
    return fs_file;
}
Exemplo n.º 4
0
/**
 * \internal
 * Copy resident data to an attribute. 
 *
 * @param a_fs_attr Attribute to add data to (cannot be NULL)
 * @param name Name of the attribute to set
 * @param type Type of the attribute to set
 * @param id Id of the attribute to set
 * @param res_data Pointer to where resident data is located (data will
 * be copied from here into FS_DATA)
 * @param len Length of resident data
 * @return 1 on error and 0 on success
 */
uint8_t
tsk_fs_attr_set_str(TSK_FS_FILE * a_fs_file, TSK_FS_ATTR * a_fs_attr,
    const char *name, TSK_FS_ATTR_TYPE_ENUM type, uint16_t id,
    void *res_data, size_t len)
{
    if (a_fs_attr == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("Null fs_attr in tsk_fs_attr_set_str");
        return 1;
    }

    a_fs_attr->fs_file = a_fs_file;
    a_fs_attr->flags = (TSK_FS_ATTR_INUSE | TSK_FS_ATTR_RES);
    a_fs_attr->type = type;
    a_fs_attr->id = id;
    a_fs_attr->nrd.compsize = 0;

    if (fs_attr_put_name(a_fs_attr, name)) {
        return 1;
    }

    if (a_fs_attr->rd.buf_size < len) {
        a_fs_attr->rd.buf =
            (uint8_t *) tsk_realloc((char *) a_fs_attr->rd.buf, len);
        if (a_fs_attr->rd.buf == NULL)
            return 1;
        a_fs_attr->rd.buf_size = len;
    }

    memset(a_fs_attr->rd.buf, 0, a_fs_attr->rd.buf_size);
    memcpy(a_fs_attr->rd.buf, res_data, len);
    a_fs_attr->size = len;

    return 0;
}
Exemplo n.º 5
0
/** 
 * \internal
 * Allocates and initializes a new structure.  
 *
 * @param type The type of attribute to create (Resident or Non-resident)
 * @returns NULL on error
 */
TSK_FS_ATTR *
tsk_fs_attr_alloc(TSK_FS_ATTR_FLAG_ENUM type)
{
    TSK_FS_ATTR *fs_attr = (TSK_FS_ATTR *) tsk_malloc(sizeof(TSK_FS_ATTR));
    if (fs_attr == NULL) {
        return NULL;
    }

    fs_attr->name_size = 128;
    if ((fs_attr->name = (char *) tsk_malloc(fs_attr->name_size)) == NULL) {
        free(fs_attr);
        return NULL;
    }

    if (type == TSK_FS_ATTR_NONRES) {
        fs_attr->flags = (TSK_FS_ATTR_NONRES | TSK_FS_ATTR_INUSE);
    }
    else if (type == TSK_FS_ATTR_RES) {
        fs_attr->rd.buf_size = 1024;
        fs_attr->rd.buf = (uint8_t *) tsk_malloc(fs_attr->rd.buf_size);
        if (fs_attr->rd.buf == NULL) {
            free(fs_attr->name);
            return NULL;
        }
        fs_attr->flags = (TSK_FS_ATTR_RES | TSK_FS_ATTR_INUSE);
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("tsk_fs_attr_alloc: Invalid Type: %d\n",
            type);
        return NULL;
    }

    return fs_attr;
}
Exemplo n.º 6
0
/** \internal
 * Processes a non-resident TSK_FS_ATTR structure and calls the callback with the associated
 * data. 
 *
 * @param fs_attr Resident data structure to be walked
 * @param a_flags Flags for walking
 * @param a_action Callback action
 * @param a_ptr Pointer to data that is passed to callback
 * @returns 1 on error or 0 on success
 */
static uint8_t
tsk_fs_attr_walk_nonres(const TSK_FS_ATTR * fs_attr,
    TSK_FS_FILE_WALK_FLAG_ENUM a_flags, TSK_FS_FILE_WALK_CB a_action,
    void *a_ptr)
{
    char *buf = NULL;
    TSK_OFF_T tot_size;
    TSK_OFF_T off = 0;
    TSK_FS_ATTR_RUN *fs_attr_run;
    int retval;
    uint32_t skip_remain;
    TSK_FS_INFO *fs = fs_attr->fs_file->fs_info;
    uint8_t stop_loop = 0;

    if ((fs_attr->flags & TSK_FS_ATTR_NONRES) == 0) {
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_file_walk_nonres: called with non-non-resident data");
        return 1;
    }

    /* if we want the slack space too, then use the allocsize  */
    if (a_flags & TSK_FS_FILE_WALK_FLAG_SLACK)
        tot_size = fs_attr->nrd.allocsize;
    else
        tot_size = fs_attr->size;

    skip_remain = fs_attr->nrd.skiplen;

    if ((a_flags & TSK_FS_FILE_WALK_FLAG_AONLY) == 0) {
        if ((buf = (char *) tsk_malloc(fs->block_size)) == NULL) {
            return 1;
        }
    }


    /* cycle through the number of runs we have */
    retval = TSK_WALK_CONT;
    for (fs_attr_run = fs_attr->nrd.run; fs_attr_run;
        fs_attr_run = fs_attr_run->next) {
        TSK_DADDR_T addr, len_idx;

        addr = fs_attr_run->addr;

        /* cycle through each block in the run */
        for (len_idx = 0; len_idx < fs_attr_run->len; len_idx++) {

            TSK_FS_BLOCK_FLAG_ENUM myflags;

            /* If the address is too large then give an error */
            if (addr + len_idx > fs->last_block) {
                if (fs_attr->fs_file->meta->
                    flags & TSK_FS_META_FLAG_UNALLOC)
                    tsk_error_set_errno(TSK_ERR_FS_RECOVER);
                else
                    tsk_error_set_errno(TSK_ERR_FS_BLK_NUM);
                tsk_error_set_errstr
                    ("Invalid address in run (too large): %" PRIuDADDR "",
                    addr + len_idx);
                return 1;
            }

            // load the buffer if they want more than just the address
            if ((a_flags & TSK_FS_FILE_WALK_FLAG_AONLY) == 0) {

                /* sparse files just get 0s */
                if (fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE) {
                    memset(buf, 0, fs->block_size);
                }
                /* FILLER entries exist when the source file system can store run
                 * info out of order and we did not get all of the run info.  We
                 * return 0s if data is read from this type of run. */
                else if (fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) {
                    memset(buf, 0, fs->block_size);
                    if (tsk_verbose)
                        fprintf(stderr,
                            "tsk_fs_attr_walk_nonres: File %" PRIuINUM
                            " has FILLER entry, using 0s\n",
                            fs_attr->fs_file->meta->addr);
                }

                // we return 0s for reads past the initsize
                else if ((off >= fs_attr->nrd.initsize)
                    && ((a_flags & TSK_FS_FILE_READ_FLAG_SLACK) == 0)) {
                    memset(buf, 0, fs->block_size);
                }
                else {
                    ssize_t cnt;

                    cnt = tsk_fs_read_block
                        (fs, addr + len_idx, buf, fs->block_size);
                    if (cnt != fs->block_size) {
                        if (cnt >= 0) {
                            tsk_error_reset();
                            tsk_error_set_errno(TSK_ERR_FS_READ);
                        }
                        tsk_error_set_errstr2
                            ("tsk_fs_file_walk: Error reading block at %"
                            PRIuDADDR, addr + len_idx);
                        return 1;
                    }
                    if ((off + fs->block_size > fs_attr->nrd.initsize)
                        && ((a_flags & TSK_FS_FILE_READ_FLAG_SLACK) == 0)) {
                        memset(&buf[fs_attr->nrd.initsize - off], 0,
                            fs->block_size -
                            (size_t) (fs_attr->nrd.initsize - off));
                    }
                }
            }

            /* Need to account for the skip length, which is the number of bytes
             * in the start of the attribute that are skipped and that are not
             * included in the overall length.  We will seek past those and not
             * return those in the action.  We just read a block size so check
             * if there is data to be returned in this buffer. */
            if (skip_remain >= fs->block_size) {
                skip_remain -= fs->block_size;
            }
            else {
                size_t ret_len;

                /* Do we want to return a full block, or just the end? */
                if ((TSK_OFF_T) fs->block_size - skip_remain <
                    tot_size - off)
                    ret_len = fs->block_size - skip_remain;
                else
                    ret_len = (size_t) (tot_size - off);

                /* Only do sparse or FILLER clusters if NOSPARSE is not set */
                if ((fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE) ||
                    (fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) ||
                    (off > fs_attr->nrd.initsize)) {
                    myflags = fs->block_getflags(fs, 0);
                    myflags |= TSK_FS_BLOCK_FLAG_SPARSE;

                    if ((a_flags & TSK_FS_FILE_WALK_FLAG_NOSPARSE) == 0) {
                        retval =
                            a_action(fs_attr->fs_file, off, 0,
                            &buf[skip_remain], ret_len, myflags, a_ptr);
                    }
                }
                else {
                    myflags = fs->block_getflags(fs, addr + len_idx);
                    myflags |= TSK_FS_BLOCK_FLAG_RAW;

                    retval =
                        a_action(fs_attr->fs_file, off, addr + len_idx,
                        &buf[skip_remain], ret_len, myflags, a_ptr);
                }
                off += ret_len;
                skip_remain = 0;

                if (retval != TSK_WALK_CONT) {
                    stop_loop = 1;
                    break;
                }

                if (off >= tot_size) {
                    stop_loop = 1;
                    break;
                }
            }
        }
        if (stop_loop)
            break;
    }

    if (buf)
        free(buf);

    if (retval == TSK_WALK_ERROR)
        return 1;
    else
        return 0;
}
Exemplo n.º 7
0
/** \internal
 * Processes a resident TSK_FS_ATTR structure and calls the callback with the associated
 * data. The size of the buffer in the callback will be block_size at max. 
 *
 * @param a_fs File system being analyzed
 * @param fs_attr Resident data structure to be walked
 * @param a_flags Flags for walking
 * @param a_action Callback action
 * @param a_ptr Pointer to data that is passed to callback
 * @returns 1 on error or 0 on success
 */
static uint8_t
tsk_fs_attr_walk_res(const TSK_FS_ATTR * fs_attr,
    TSK_FS_FILE_WALK_FLAG_ENUM a_flags, TSK_FS_FILE_WALK_CB a_action,
    void *a_ptr)
{
    char *buf = NULL;
    int myflags;
    int retval;
    size_t buf_len = 0;
    TSK_OFF_T off;
    size_t read_len;
    TSK_FS_INFO *fs;

    fs = fs_attr->fs_file->fs_info;

    if ((fs_attr->flags & TSK_FS_ATTR_RES) == 0) {
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_file_walk_res: called with non-resident data");
        return 1;
    }

    /* Allocate a buffer that is at most a block size in length */
    buf_len = (size_t) fs_attr->size;
    if (buf_len > fs->block_size)
        buf_len = fs->block_size;

    if ((a_flags & TSK_FS_FILE_WALK_FLAG_AONLY) == 0) {
        if ((buf = tsk_malloc(buf_len)) == NULL) {
            return 1;
        }
    }

    myflags =
        TSK_FS_BLOCK_FLAG_CONT | TSK_FS_BLOCK_FLAG_ALLOC |
        TSK_FS_BLOCK_FLAG_RES;

    // Call the callback in (at max) block-sized chunks.
    retval = TSK_WALK_CONT;
    for (off = 0; off < fs_attr->size; off += read_len) {

        if (fs_attr->size - off > buf_len)
            read_len = buf_len;
        else
            read_len = (size_t) (fs_attr->size - off);

        if (buf) {
            // wipe rest of buffer if we are not going to read into all of it
            if (read_len != buf_len)
                memset(&buf[read_len], 0, buf_len - read_len);

            memcpy(buf, &fs_attr->rd.buf[off], read_len);
        }
        retval =
            a_action(fs_attr->fs_file, off, 0, buf, read_len, myflags,
            a_ptr);

        if (retval != TSK_WALK_CONT)
            break;
    }

    if (buf)
        free(buf);

    if (retval == TSK_WALK_ERROR)
        return 1;
    else
        return 0;
}
Exemplo n.º 8
0
/**
 * Find the corresponding name at a
 * given offset.  The offset was likely determined from the index.
 * The entries in the DB following the one specified are also processed
 * if they have the same hash value and their name is different. 
 * The callback is called for each entry. 
 *
 * @param hdb_info Database to get data from.
 * @param hash MD5/SHA-1 hash value that was searched for
 * @param offset Byte offset where hash value should be located in db_file
 * @param flags (not used)
 * @param action Callback used for each entry found in lookup
 * @param cb_ptr Pointer to data passed to callback
 *
 * @return 1 on error and 0 on success
 */
uint8_t
nsrl_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset,
              TSK_HDB_FLAG_ENUM flags,
              TSK_HDB_LOOKUP_FN action, void *cb_ptr)
{
    char buf[TSK_HDB_MAXLEN], *name, *cur_hash, pname[TSK_HDB_MAXLEN];
    int found = 0;
    int ver;

    if (tsk_verbose)
        fprintf(stderr,
                "nsrl_getentry: Lookup up hash %s at offset %" PRIuOFF
                "\n", hash, offset);

    if ((hdb_info->hash_type == TSK_HDB_HTYPE_MD5_ID)
        && (strlen(hash) != TSK_HDB_HTYPE_MD5_LEN)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_ARG);
        tsk_error_set_errstr(
                 "nsrl_getentry: Invalid hash value (expected to be MD5): %s\n",
                 hash);
        return 1;
    }
    else if ((hdb_info->hash_type == TSK_HDB_HTYPE_SHA1_ID)
             && (strlen(hash) != TSK_HDB_HTYPE_SHA1_LEN)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_ARG);
        tsk_error_set_errstr(
                 "nsrl_getentry: Invalid hash value (expected to be SHA1): %s\n",
                 hash);
        return 1;
    }

    /* read the header line ... -- this should be done only once... */
    fseeko(hdb_info->hDb, 0, SEEK_SET);
    if (NULL == fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_READDB);
        tsk_error_set_errstr(
                 "nsrl_getentry: Error reading NSRLFile.txt header\n");
        return 1;
    }

    if ((ver = get_format_ver(buf)) == -1) {
        tsk_error_set_errstr2( "nsrl_getentry");
        return 1;
    }

    memset(pname, '0', TSK_HDB_MAXLEN);

    /* Loop so that we can find consecutive occurances of the same hash */
    while (1) {
        size_t len;

        if (0 != fseeko(hdb_info->hDb, offset, SEEK_SET)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_READDB);
            tsk_error_set_errstr(
                     "nsrl_getentry: Error seeking to get file name: %lu",
                     (unsigned long) offset);
            return 1;
        }

        if (NULL == fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb)) {
            if (feof(hdb_info->hDb))
                break;

            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_READDB);
            tsk_error_set_errstr(
                     "nsrl_getentry: Error reading database");
            return 1;
        }

        len = strlen(buf);
        if (len < TSK_HDB_HTYPE_SHA1_LEN + 5) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
            tsk_error_set_errstr(
                     "nsrl_getentry: Invalid entry in database (too short): %s",
                     buf);
            return 1;
        }

        /* Which field are we looking for */
        if (hdb_info->hash_type == TSK_HDB_HTYPE_SHA1_ID) {
            if (nsrl_parse_sha1(buf, &cur_hash, &name, ver)) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
                tsk_error_set_errstr(
                         "nsrl_getentry: Invalid entry in database: %s",
                         buf);
                return 1;
            }
        }
        else if (hdb_info->hash_type == TSK_HDB_HTYPE_MD5_ID) {
            if (nsrl_parse_md5(buf, &cur_hash, &name, ver)) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
                tsk_error_set_errstr(
                         "nsrl_getentry: Invalid entry in database: %s",
                         buf);
                return 1;
            }
        }

        /* Verify that this is the hash we are looking for */
        if (0 != strcasecmp(cur_hash, hash)) {
            break;
        }

        /* Check if this is the same name as the previous entry */
        if (strcmp(name, pname) != 0) {
            int retval;
            retval = action(hdb_info, hash, name, cb_ptr);
            if (retval == TSK_WALK_STOP)
                return 0;
            else if (retval == TSK_WALK_ERROR)
                return 1;

            found = 1;
            strncpy(pname, name, TSK_HDB_MAXLEN);
        }

        /* Advance to the next row */
        offset += len;
    }

    if (found == 0) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_ARG);
        tsk_error_set_errstr(
                 "nsrl_getentry: Hash not found in file at offset: %lu",
                 (unsigned long) offset);
        return 1;
    }

    return 0;
}
Exemplo n.º 9
0
/** \internal
 * Process a directory and load up FS_DIR with the entries. If a pointer to
 * an already allocated FS_DIR struture is given, it will be cleared.  If no existing
 * FS_DIR structure is passed (i.e. NULL), then a new one will be created. If the return
 * value is error or corruption, then the FS_DIR structure could
 * have entries (depending on when the error occured).
 *
 * @param a_fs File system to analyze
 * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated
 * structure or a new structure.
 * @param a_addr Address of directory to process.
 * @returns error, corruption, ok etc.
 */
TSK_RETVAL_ENUM
ffs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
                  TSK_INUM_T a_addr)
{
    TSK_OFF_T size;
    FFS_INFO *ffs = (FFS_INFO *) a_fs;
    char *dirbuf;
    int nchnk, cidx;
    TSK_FS_LOAD_FILE load_file;
    TSK_FS_DIR *fs_dir;

    /* If we get corruption in one of the blocks, then continue processing.
     * retval_final will change when corruption is detected.  Errors are
     * returned immediately. */
    TSK_RETVAL_ENUM retval_tmp;
    TSK_RETVAL_ENUM retval_final = TSK_OK;


    if (a_addr < a_fs->first_inum || a_addr > a_fs->last_inum) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("ffs_dir_open_meta: Invalid inode value: %"
                             PRIuINUM, a_addr);
        return TSK_ERR;
    }
    else if (a_fs_dir == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
        ("ffs_dir_open_meta: NULL fs_attr argument given");
        return TSK_ERR;
    }

    if (tsk_verbose)
        tsk_fprintf(stderr,
                    "ffs_dir_open_meta: Processing directory %" PRIuINUM "\n",
                    a_addr);

    fs_dir = *a_fs_dir;
    if (fs_dir) {
        tsk_fs_dir_reset(fs_dir);
    }
    else {
        if ((*a_fs_dir = fs_dir =
                             tsk_fs_dir_alloc(a_fs, a_addr, 128)) == NULL) {
            return TSK_ERR;
        }
    }

    //  handle the orphan directory if its contents were requested
    if (a_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) {
        return tsk_fs_dir_find_orphans(a_fs, fs_dir);
    }

    if ((fs_dir->fs_file =
                tsk_fs_file_open_meta(a_fs, NULL, a_addr)) == NULL) {
        tsk_error_reset();
        tsk_error_errstr2_concat("- ffs_dir_open_meta");
        return TSK_COR;
    }

    /* make a copy of the directory contents that we can process */
    /* round up cause we want the slack space too */
    size = roundup(fs_dir->fs_file->meta->size, FFS_DIRBLKSIZ);
    if ((dirbuf = tsk_malloc((size_t) size)) == NULL) {
        return TSK_ERR;
    }

    load_file.total = load_file.left = (size_t) size;
    load_file.base = load_file.cur = dirbuf;

    if (tsk_fs_file_walk(fs_dir->fs_file,
                         TSK_FS_FILE_WALK_FLAG_SLACK,
                         tsk_fs_load_file_action, (void *) &load_file)) {
        tsk_error_reset();
        tsk_error_errstr2_concat("- ffs_dir_open_meta");
        free(dirbuf);
        return TSK_COR;
    }

    /* Not all of the directory was copied, so we return */
    if (load_file.left > 0) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_FWALK);
        tsk_error_set_errstr("ffs_dir_open_meta: Error reading directory %"
                             PRIuINUM, a_addr);
        free(dirbuf);
        return TSK_COR;
    }

    /* Directory entries are written in chunks of DIRBLKSIZ
     ** determine how many chunks of this size we have to read to
     ** get a full block
     **
     ** Entries do not cross over the DIRBLKSIZ boundary
     */
    nchnk = (int) (size) / (FFS_DIRBLKSIZ) + 1;

    for (cidx = 0; cidx < nchnk && (int64_t) size > 0; cidx++) {
        int len = (FFS_DIRBLKSIZ < size) ? FFS_DIRBLKSIZ : (int) size;

        retval_tmp =
            ffs_dent_parse_block(ffs, fs_dir,
                                 (fs_dir->fs_file->
                                  meta->flags & TSK_FS_META_FLAG_UNALLOC) ? 1 : 0,
                                 dirbuf + cidx * FFS_DIRBLKSIZ, len);

        if (retval_tmp == TSK_ERR) {
            retval_final = TSK_ERR;
            break;
        }
        else if (retval_tmp == TSK_COR) {
            retval_final = TSK_COR;
        }
        size -= len;
    }
    free(dirbuf);

    // if we are listing the root directory, add the Orphan directory entry
    if (a_addr == a_fs->root_inum) {
        TSK_FS_NAME *fs_name = tsk_fs_name_alloc(256, 0);
        if (fs_name == NULL)
            return TSK_ERR;

        if (tsk_fs_dir_make_orphan_dir_name(a_fs, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }

        if (tsk_fs_dir_add(fs_dir, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }
        tsk_fs_name_free(fs_name);
    }

    return retval_final;
}
Exemplo n.º 10
0
/** \ingroup fslib
* Walk the file names in a directory and obtain the details of the files via a callback.
*
* @param a_fs File system to analyze
* @param a_addr Metadata address of the directory to analyze
* @param a_flags Flags used during analysis
* @param a_action Callback function that is called for each file name
* @param a_ptr Pointer to data that is passed to the callback function each time
* @returns 1 on error and 0 on success
*/
uint8_t
tsk_fs_dir_walk(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr,
    TSK_FS_DIR_WALK_FLAG_ENUM a_flags, TSK_FS_DIR_WALK_CB a_action,
    void *a_ptr)
{
    DENT_DINFO dinfo;
    TSK_WALK_RET_ENUM retval;

    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_dir_walk: called with NULL or unallocated structures");
        return 1;
    }


    memset(&dinfo, 0, sizeof(DENT_DINFO));
    if ((dinfo.stack_seen = tsk_stack_create()) == NULL)
        return 1;

    /* Sanity check on flags -- make sure at least one ALLOC is set */
    if (((a_flags & TSK_FS_DIR_WALK_FLAG_ALLOC) == 0) &&
        ((a_flags & TSK_FS_DIR_WALK_FLAG_UNALLOC) == 0)) {
        a_flags |=
            (TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC);
    }

    /* if the flags are right, we can collect info that may be needed
     * for an orphan walk.  If the walk fails or stops, the code that
     * calls the action will clear this stuff.
     */
    tsk_take_lock(&a_fs->list_inum_named_lock);
    if ((a_fs->list_inum_named == NULL) && (a_addr == a_fs->root_inum)
        && (a_flags & TSK_FS_DIR_WALK_FLAG_RECURSE)) {
        dinfo.save_inum_named = 1;
    }
    tsk_release_lock(&a_fs->list_inum_named_lock);

    retval = tsk_fs_dir_walk_lcl(a_fs, &dinfo, a_addr, a_flags,
        a_action, a_ptr);

    if (dinfo.save_inum_named == 1) {
        if (retval != TSK_WALK_CONT) {
            /* There was an error and we stopped early, so we should get
             * rid of the partial list we were making.
             */
            tsk_list_free(dinfo.list_inum_named);
            dinfo.list_inum_named = NULL;
        }
        else {
            /* We finished the dir walk successfully, so reassign
             * ownership of the dinfo's list_inum_named to the shared
             * list_inum_named in TSK_FS_INFO, under a lock, if
             * another thread hasn't already done so.
             */
            tsk_take_lock(&a_fs->list_inum_named_lock);
            if (a_fs->list_inum_named == NULL) {
                a_fs->list_inum_named = dinfo.list_inum_named;
            }
            else {
                tsk_list_free(dinfo.list_inum_named);
            }
            tsk_release_lock(&a_fs->list_inum_named_lock);
            dinfo.list_inum_named = NULL;
        }
    }

    tsk_stack_free(dinfo.stack_seen);

    if (retval == TSK_WALK_ERROR)
        return 1;
    else
        return 0;
}
Exemplo n.º 11
0
/**
 * Find the corresponding name at the
 * given offset.  The offset was likely determined from the index.
 * The entries in the DB following the one specified are also processed
 * if they have the same hash value and their name is different. 
 * The callback is called for each entry. 
 *
 * Note: This routine assumes that &hdb_info->lock is locked by the caller.
 *
 * @param hdb_info Data base to get data from.
 * @param hash MD5 hash value that was searched for
 * @param offset Byte offset where hash value should be located in db_file
 * @param flags 
 * @param action Callback used for each entry found in lookup
 * @param cb_ptr Pointer to data passed to callback
 *
 * @return 1 on error and 0 on success
 */
uint8_t
hk_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset,
            TSK_HDB_FLAG_ENUM flags,
            TSK_HDB_LOOKUP_FN action, void *cb_ptr)
{
    char buf[TSK_HDB_MAXLEN], name[TSK_HDB_MAXLEN], *ptr =
        NULL, pname[TSK_HDB_MAXLEN], other[TSK_HDB_MAXLEN];
    int found = 0;

    if (tsk_verbose)
        fprintf(stderr,
                "hk_getentry: Lookup up hash %s at offset %" PRIuOFF "\n",
                hash, offset);

    if (strlen(hash) != TSK_HDB_HTYPE_MD5_LEN) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_ARG);
        tsk_error_set_errstr(
                 "hk_getentry: Invalid hash value: %s", hash);
        return 1;
    }

    memset(pname, '0', TSK_HDB_MAXLEN);

    /* Loop so that we can find multiple occurances of the same hash */
    while (1) {
        size_t len;

        if (0 != fseeko(hdb_info->hDb, offset, SEEK_SET)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_READDB);
            tsk_error_set_errstr(
                     "hk_getentry: Error seeking to get file name: %lu",
                     (unsigned long) offset);
            return 1;
        }

        if (NULL ==
            fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb)) {
            if (feof(hdb_info->hDb)) {
                break;
            }
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_READDB);
            tsk_error_set_errstr(
                     "hk_getentry: Error reading database");
            return 1;
        }

        len = strlen(buf);
        if (len < TSK_HDB_HTYPE_MD5_LEN) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
            tsk_error_set_errstr(
                     "hk_getentry: Invalid entry in database (too short): %s",
                     buf);
            return 1;
        }

        if (hk_parse_md5(buf, &ptr, name, TSK_HDB_MAXLEN,
                         ((flags & TSK_HDB_FLAG_EXT) ? other : NULL),
                         ((flags & TSK_HDB_FLAG_EXT) ? TSK_HDB_MAXLEN :
                          0))) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
            tsk_error_set_errstr(
                     "hk_getentry: Invalid entry in database: %s", buf);
            return 1;
        }

        /* Is this the one that we want? */
        if (0 != strcasecmp(ptr, hash)) {
            break;
        }

        if (strcmp(name, pname) != 0) {
            int retval;
            retval = action(hdb_info, hash, name, cb_ptr);
            if (retval == TSK_WALK_ERROR) {
                return 1;
            }
            else if (retval == TSK_WALK_STOP) {
                return 0;
            }
            //if (flags & FLAG_EXT)
            //      printf("%s\t%s\t(%s)\n", hash, name, other);
            //  else
            //      printf("%s\t%s\n", hash, name);

            found = 1;
            strncpy(pname, name, TSK_HDB_MAXLEN);
        }

        /* Advance to the next row */
        offset += len;
    }

    if (found == 0) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_ARG);
        tsk_error_set_errstr(
                 "hk_getentry: Hash not found in file at offset: %lu",
                 (unsigned long) offset);
        return 1;
    }

    return 0;
}
/**
 * /internal
 * Parse a buffer containing the contents of a directory and add TSK_FS_NAME 
 * objects for each named file found to the TSK_FS_DIR representation of the 
 * directory.
 *
 * @param fatfs File system information structure for file system that
 * contains the directory.
 * @param a_fs_dir Directory structure into to which parsed file metadata will
 * be added.
 * @param buf Buffer that contains the directory contents.
 * @param len Length of buffer in bytes (must be a multiple of sector
*  size).
 * @param addrs Array where each element is the original address of
 * the corresponding sector in a_buf (size of array is number of sectors in
 * the directory).
 * @return TSK_RETVAL_ENUM
*/
TSK_RETVAL_ENUM
fatxxfs_dent_parse_buf(FATFS_INFO *fatfs, TSK_FS_DIR *a_fs_dir, char *buf,
    TSK_OFF_T len, TSK_DADDR_T *addrs)
{
    char *func_name = "fatxxfs_dent_parse_buf";
    unsigned int idx = 0; 
    unsigned int sidx = 0;
    int a = 0;
    int b = 0;
    TSK_INUM_T ibase = 0;
    FATXXFS_DENTRY *dep = NULL;
    TSK_FS_INFO *fs = (TSK_FS_INFO*)&fatfs->fs_info;
    int sectalloc = 0;
    TSK_FS_NAME *fs_name = NULL;
    FATXXFS_LFN lfninfo;
    int entrySeenCount = 0;
    int entryInvalidCount = 0;
    uint8_t isCorruptDir = 0;

    tsk_error_reset();
    if (fatfs_ptr_arg_is_null(fatfs, "fatfs", func_name) ||
        fatfs_ptr_arg_is_null(a_fs_dir, "a_fs_dir", func_name) ||
        fatfs_ptr_arg_is_null(buf, "buf", func_name) ||
        fatfs_ptr_arg_is_null(addrs, "addrs", func_name)) {
        return TSK_ERR; 
    }

    assert(len > 0);
    if (len < 0) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("%s: invalid buffer length", func_name);
        return TSK_ERR; 
    }

    dep = (FATXXFS_DENTRY*)buf;

    if ((fs_name = tsk_fs_name_alloc(FATFS_MAXNAMLEN_UTF8, 32)) == NULL) {
        return TSK_ERR;
    }

    memset(&lfninfo, 0, sizeof(FATXXFS_LFN));
    lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1;

    /* Loop through the sectors in the buffer. */ 
    for (sidx = 0; sidx < (unsigned int) (len / fatfs->ssize); sidx++) {

        /* Get the base inode for the current sector */
        ibase = FATFS_SECT_2_INODE(fatfs, addrs[sidx]);
        if (ibase > fs->last_inum) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_ARG);
            tsk_error_set_errstr
                ("fatfs_parse: inode address is too large");
            tsk_fs_name_free(fs_name);
            return TSK_COR;
        }

        if (tsk_verbose)
            tsk_fprintf(stderr,
            "fatfs_dent_parse_buf: Parsing sector %" PRIuDADDR
            " for dir %" PRIuINUM "\n", addrs[sidx], a_fs_dir->addr);

        /* Get the allocation status of the current sector. */
        if ((sectalloc = fatfs_is_sectalloc(fatfs, addrs[sidx])) == -1) {
            if (tsk_verbose) {
                tsk_fprintf(stderr,
                    "fatfs_dent_parse_buf: Error looking up sector allocation: %"
                    PRIuDADDR "\n", addrs[sidx]);
                tsk_error_print(stderr);
            }
            tsk_error_reset();
            continue;
        }

        /* Loop through the putative directory entries in the current sector. */
        for (idx = 0; idx < fatfs->dentry_cnt_se; idx++, dep++) {
            FATXXFS_DENTRY *dir;
            TSK_INUM_T inode;

            entrySeenCount++;

            /* Is the current entry a valid entry? */
            if (0 == fatxxfs_is_dentry(fatfs, (FATFS_DENTRY*)dep, 
                (FATFS_DATA_UNIT_ALLOC_STATUS_ENUM)sectalloc,
                ((isCorruptDir == 0) && (sectalloc)) ? 1 : 0)) {
                    if (tsk_verbose)
                        tsk_fprintf(stderr,
                        "fatfs_dent_parse_buf: Entry %u is invalid\n",
                        idx);
                    entryInvalidCount++;
                    /* If we have seen four entries and all of them are corrupt,
                    * then test every remaining entry in this folder -- 
                    * even if the sector is allocated. The scenario is one
                    * where we are processing a cluster that is allocated
                    * to a file and we happen to get some data that matches
                    * every now and then. */
                    if ((entrySeenCount == 4) && (entryInvalidCount == 4)) {
                        isCorruptDir = 1;
                    }
                    continue;
            }

            dir = dep;

            /* Compute the inode address corresponding to this directory entry. */
            inode = ibase + idx;

            if ((dir->attrib & FATFS_ATTR_LFN) == FATFS_ATTR_LFN) {
                /* The current entry is a long file name entry. */
                FATXXFS_DENTRY_LFN *dirl = (FATXXFS_DENTRY_LFN *) dir;

                /* Store the name in dinfo until we get the 8.3 name
                 * Use the checksum to identify a new sequence. */
                if (((dirl->seq & FATXXFS_LFN_SEQ_FIRST) && (dirl->seq != FATXXFS_SLOT_DELETED)) || 
                    (dirl->chksum != lfninfo.chk)) {
                    // @@@ Do a partial output here
                    
                    /* This is the last long file name entry in a sequence. 
                     * Reset the sequence number, check sum, and next char
                     * address. */
                    lfninfo.seq = dirl->seq & FATXXFS_LFN_SEQ_MASK;
                    lfninfo.chk = dirl->chksum;
                    lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1;
                }
                else if (dirl->seq != lfninfo.seq - 1) {
                    // @@@ Check the sequence number - the checksum is correct though...
                }

                /* Copy the UTF16 values starting at end of buffer */
                for (a = 3; a >= 0; a--) {
                    if ((lfninfo.start > 0))
                        lfninfo.name[lfninfo.start--] = dirl->part3[a];
                }
                for (a = 11; a >= 0; a--) {
                    if ((lfninfo.start > 0))
                        lfninfo.name[lfninfo.start--] = dirl->part2[a];
                }
                for (a = 9; a >= 0; a--) {
                    if ((lfninfo.start > 0))
                        lfninfo.name[lfninfo.start--] = dirl->part1[a];
                }

                // Skip ahead until we get a new sequence num or the 8.3 name
                continue;
            }
            else if ((dir->attrib & FATFS_ATTR_VOLUME) == FATFS_ATTR_VOLUME) {
                /* Special case for volume label: name does not have an
                * extension and we add a note at the end that it is a label */
                a = 0;

                for (b = 0; b < 8; b++) {
                    if ((dir->name[b] >= 0x20) && (dir->name[b] != 0xff)) {
                        fs_name->name[a++] = dir->name[b];
                    }
                    else {
                        fs_name->name[a++] = '^';
                    }
                }
                for (b = 0; b < 3; b++) {
                    if ((dir->ext[b] >= 0x20) && (dir->ext[b] != 0xff)) {
                        fs_name->name[a++] = dir->ext[b];
                    }
                    else {
                        fs_name->name[a++] = '^';
                    }
                }

                fs_name->name[a] = '\0';
                /* Append a string to show it is a label */
                if (a + 22 < FATFS_MAXNAMLEN_UTF8) {
                    const char *volstr = " (Volume Label Entry)";
                    strncat(fs_name->name, volstr,
                        FATFS_MAXNAMLEN_UTF8 - a);
                }
            }
            else {
                /* A short (8.3) entry */
                char *name_ptr; // The dest location for the short name

                /* if we have a lfn, copy it into fs_name->name
                * and put the short name in fs_name->shrt_name */
                if (lfninfo.start != FATFS_MAXNAMLEN_UTF8 - 1) {
                    int retVal;

                    /* @@@ Check the checksum */

                    /* Convert the UTF16 to UTF8 */
                    UTF16 *name16 =
                        (UTF16 *) ((uintptr_t) & lfninfo.
                        name[lfninfo.start + 1]);
                    UTF8 *name8 = (UTF8 *) fs_name->name;

                    retVal =
                        tsk_UTF16toUTF8(fs->endian,
                        (const UTF16 **) &name16,
                        (UTF16 *) & lfninfo.name[FATFS_MAXNAMLEN_UTF8],
                        &name8,
                        (UTF8 *) ((uintptr_t) name8 +
                        FATFS_MAXNAMLEN_UTF8), TSKlenientConversion);

                    if (retVal != TSKconversionOK) {
                        tsk_error_reset();
                        tsk_error_set_errno(TSK_ERR_FS_UNICODE);
                        tsk_error_set_errstr
                            ("fatfs_parse: Error converting FAT LFN to UTF8: %d",
                            retVal);
                        continue;
                    }

                    /* Make sure it is NULL Terminated */
                    if ((uintptr_t) name8 >
                        (uintptr_t) fs_name->name + FATFS_MAXNAMLEN_UTF8)
                        fs_name->name[FATFS_MAXNAMLEN_UTF8 - 1] = '\0';
                    else
                        *name8 = '\0';

                    lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1;
                    name_ptr = fs_name->shrt_name;      // put 8.3 into shrt_name
                }
                /* We don't have a LFN, so put the short name in
                * fs_name->name */
                else {
                    fs_name->shrt_name[0] = '\0';
                    name_ptr = fs_name->name;   // put 8.3 into normal location
                }

                /* copy in the short name into the place specified above.
                * Skip spaces and put in the . */
                a = 0;
                for (b = 0; b < 8; b++) {
                    if ((dir->name[b] != 0) && (dir->name[b] != 0xff) &&
                        (dir->name[b] != 0x20)) {

                            if ((b == 0)
                                && (dir->name[0] == FATXXFS_SLOT_DELETED)) {
                                    name_ptr[a++] = '_';
                            }
                            else if ((dir->lowercase & FATXXFS_CASE_LOWER_BASE)
                                && (dir->name[b] >= 'A')
                                && (dir->name[b] <= 'Z')) {
                                    name_ptr[a++] = dir->name[b] + 32;
                            }
                            else {
                                name_ptr[a++] = dir->name[b];
                            }
                    }
                }

                for (b = 0; b < 3; b++) {
                    if ((dir->ext[b] != 0) && (dir->ext[b] != 0xff) &&
                        (dir->ext[b] != 0x20)) {
                            if (b == 0)
                                name_ptr[a++] = '.';
                            if ((dir->lowercase & FATXXFS_CASE_LOWER_EXT) &&
                                (dir->ext[b] >= 'A') && (dir->ext[b] <= 'Z'))
                                name_ptr[a++] = dir->ext[b] + 32;
                            else
                                name_ptr[a++] = dir->ext[b];
                    }
                }
                name_ptr[a] = '\0';

                // make sure that only ASCII is in the short name
                fatfs_cleanup_ascii(name_ptr);
            }

            /* file type: FAT only knows DIR and FILE */
            if ((dir->attrib & FATFS_ATTR_DIRECTORY) ==
                FATFS_ATTR_DIRECTORY)
                fs_name->type = TSK_FS_NAME_TYPE_DIR;
            else
                fs_name->type = TSK_FS_NAME_TYPE_REG;

            /* set the inode */
            fs_name->meta_addr = inode;
            inode = 0;  // so that we don't use it anymore -- use only fs_name->meta_addr

            /* Handle the . and .. entries specially
            * The current inode 'address' they have is for the current
            * slot in the cluster, but it needs to refer to the original
            * slot
            */
            if (TSK_FS_ISDOT(fs_name->name)
                    && (fs_name->type == TSK_FS_NAME_TYPE_DIR)
                    && idx < 2) {
                if (fs_name->name[1] == '\0') {
                    /* Current directory - "." */
                    fs_name->meta_addr =
                        a_fs_dir->fs_file->meta->addr;
                }
                /* for the parent directory, look up in the list that
                * is maintained in fafs_info */
                else if (fs_name->name[1] == '.') {
                    /* Parent directory - ".." */
                    uint8_t dir_found = 0;

                    if (fatfs_dir_buf_get(fatfs, a_fs_dir->fs_file->meta->addr, &(fs_name->meta_addr)) == 0)  {
                        dir_found = 1;
                    }

                    if ((dir_found == 0)
                        && (addrs[0] == fatfs->firstdatasect)) {
                            /* if we are currently in the root directory, we aren't going to find
                            * a parent.  This shouldn't happen, but could result in an infinite loop. */
                            fs_name->meta_addr = 0;
                            dir_found = 1;
                    }
                    if (dir_found == 0) {
                        if (tsk_verbose)
                            fprintf(stderr,
                            "fatfs_dent_parse_buf: Walking directory to find parent\n");

                        /* The parent directory is not in the list.  We are going to walk
                        * the directory until we hit this directory. This process will
                        * populate the buffer table and we will then rescan it */
                        if (tsk_fs_dir_walk(fs, fs->root_inum,
                            (TSK_FS_DIR_WALK_FLAG_ENUM)(TSK_FS_DIR_WALK_FLAG_ALLOC |
                            TSK_FS_DIR_WALK_FLAG_UNALLOC |
                            TSK_FS_DIR_WALK_FLAG_RECURSE),
                            fatfs_find_parent_act,
                            (void *) &a_fs_dir->fs_file->meta->addr)) {
                                return TSK_OK;
                        }

                        if (tsk_verbose)
                            fprintf(stderr,
                            "fatfs_dent_parse_buf: Finished walking directory to find parent\n");

                        if (fatfs_dir_buf_get(fatfs, a_fs_dir->fs_file->meta->addr, &(fs_name->meta_addr)) == 0) {
                            dir_found = 1;
                        }

                        // if we did not find it, then it was probably
                        // from the orphan directory...
                        if (dir_found == 0)
                            fs_name->meta_addr = TSK_FS_ORPHANDIR_INUM(fs);
                    }
                }
            }
            else {
                /* Save the (non-. or ..) directory to parent directory info to local
                * structures so that we can later fill into the inode
                * info for '..' entries */
                if (fs_name->type == TSK_FS_NAME_TYPE_DIR) {
                    if (fatfs_dir_buf_add(fatfs,
                        a_fs_dir->fs_file->meta->addr, fs_name->meta_addr))
                        return TSK_ERR;
                }
            }


            /* The allocation status of an entry is based on the allocation
            * status of the sector it is in and the flag.  Deleted directories
            * do not always clear the flags of each entry
            */
            if (sectalloc == 1) {
				if(FATXXFS_IS_DELETED(dep->name, fatfs)){
						fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC;
				}
				else{
					fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
				}
            }
            else {
                fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC;
            }

            tsk_fs_dir_add(a_fs_dir, fs_name);
        }
    }
    tsk_fs_name_free(fs_name);

    return TSK_OK;
}
Exemplo n.º 13
0
TSK_RETVAL_ENUM
fatfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
    TSK_INUM_T a_addr)
{
    TSK_OFF_T size, len;
    FATFS_INFO *fatfs = (FATFS_INFO *) a_fs;
    char *dirbuf;
    TSK_DADDR_T *addrbuf;
    FATFS_LOAD_DIR load;
    int retval;

    TSK_FS_DIR *fs_dir;

    if ((a_addr < a_fs->first_inum) || (a_addr > a_fs->last_inum)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("fatfs_dir_open_meta: invalid a_addr value: %"
            PRIuINUM "\n", a_addr);
        return TSK_ERR;
    }
    else if (a_fs_dir == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("fatfs_dir_open_meta: NULL fs_attr argument given");
        return TSK_ERR;
    }

    fs_dir = *a_fs_dir;
    if (fs_dir) {
        tsk_fs_dir_reset(fs_dir);
    }
    else {
        if ((*a_fs_dir = fs_dir =
                tsk_fs_dir_alloc(a_fs, a_addr, 128)) == NULL) {
            return TSK_ERR;
        }
    }

    //  handle the orphan directory if its contents were requested
    if (a_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) {
        return tsk_fs_dir_find_orphans(a_fs, fs_dir);
    }

    fs_dir->fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr);
    if (fs_dir->fs_file == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_INODE_NUM);
        tsk_error_set_errstr("fatfs_dir_open_meta: %" PRIuINUM
            " is not a valid inode", a_addr);
        return TSK_COR;
    }

    size = fs_dir->fs_file->meta->size;
    len = roundup(size, fatfs->ssize);

    if (tsk_verbose)
        tsk_fprintf(stderr,
            "fatfs_dir_open_meta: Processing directory %" PRIuINUM "\n",
            a_addr);

    if (size == 0) {
        if (tsk_verbose)
            tsk_fprintf(stderr,
                "fatfs_dir_open_meta: directory has 0 size\n");
        return TSK_OK;
    }

    /* Make a copy of the directory contents using file_walk */
    if ((dirbuf = tsk_malloc((size_t) len)) == NULL) {
        return TSK_ERR;
    }
    load.curdirptr = dirbuf;
    load.dirleft = (size_t) size;

    /* We are going to save the address of each sector in the directory
     * in a stack - they are needed to determine the inode address.
     */
    load.addrsize = (size_t) (len / fatfs->ssize);
    addrbuf =
        (TSK_DADDR_T *) tsk_malloc(load.addrsize * sizeof(TSK_DADDR_T));
    if (addrbuf == NULL) {
        free(dirbuf);
        return TSK_ERR;
    }

    /* Set the variables that are used during the copy */
    load.addridx = 0;
    load.addrbuf = addrbuf;

    /* save the directory contents into dirbuf */
    if (tsk_fs_file_walk(fs_dir->fs_file,
            TSK_FS_FILE_WALK_FLAG_SLACK,
            fatfs_dent_action, (void *) &load)) {
        tsk_error_errstr2_concat("- fatfs_dir_open_meta");
        free(dirbuf);
        free(addrbuf);
        return TSK_COR;
    }

    /* We did not copy the entire directory, which occurs if an error occured */
    if (load.dirleft > 0) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_FWALK);
        tsk_error_set_errstr
            ("fatfs_dir_open_meta: Error reading directory %" PRIuINUM,
            a_addr);

        /* Free the local buffers */
        free(dirbuf);
        free(addrbuf);
        return TSK_COR;
    }

    if (tsk_verbose)
        fprintf(stderr,
            "fatfs_dir_open_meta: Parsing directory %" PRIuINUM "\n",
            a_addr);

    retval = fatfs_dent_parse_buf(fatfs, fs_dir, dirbuf, len, addrbuf);

    free(dirbuf);
    free(addrbuf);

    // if we are listing the root directory, add the Orphan directory and special FAT file entries
    if (a_addr == a_fs->root_inum) {
        TSK_FS_NAME *fs_name = tsk_fs_name_alloc(256, 0);
        if (fs_name == NULL)
            return TSK_ERR;

        // MBR Entry
        strncpy(fs_name->name, FATFS_MBRNAME, fs_name->name_size);
        fs_name->meta_addr = FATFS_MBRINO(a_fs);
        fs_name->type = TSK_FS_NAME_TYPE_VIRT;
        fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
        if (tsk_fs_dir_add(fs_dir, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }

        // FAT1 Entry
        strncpy(fs_name->name, FATFS_FAT1NAME, fs_name->name_size);
        fs_name->meta_addr = FATFS_FAT1INO(a_fs);
        fs_name->type = TSK_FS_NAME_TYPE_VIRT;
        fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
        if (tsk_fs_dir_add(fs_dir, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }

        // FAT2 Entry
        strncpy(fs_name->name, FATFS_FAT2NAME, fs_name->name_size);
        fs_name->meta_addr = FATFS_FAT2INO(a_fs);
        fs_name->type = TSK_FS_NAME_TYPE_VIRT;
        fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
        if (tsk_fs_dir_add(fs_dir, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }

        // orphan directory
        if (tsk_fs_dir_make_orphan_dir_name(a_fs, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }
        if (tsk_fs_dir_add(fs_dir, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }
        tsk_fs_name_free(fs_name);
    }

    return retval;
}
Exemplo n.º 14
0
/**
 * \internal
 * Searches an exFAT file system for its volume label directory entry, which 
 * should be in the root directory of the file system. If the entry is found, 
 * its metadata is copied into the TSK_FS_META object of a TSK_FS_FILE object.
 *
 * @param [in] a_fatfs Generic FAT file system info structure.
 * @param [out] a_fatfs Generic file system file structure.
 * @return 0 on success, 1 otherwise, per TSK convention.
 */
static uint8_t
exfatfs_find_volume_label_dentry(FATFS_INFO *a_fatfs, TSK_FS_FILE *a_fs_file)
{
    const char *func_name = "exfatfs_find_volume_label_dentry";
    TSK_FS_INFO *fs = (TSK_FS_INFO *)a_fatfs;
    TSK_DADDR_T current_sector = 0;
    TSK_DADDR_T last_sector_of_data_area = 0;
    char *sector_buf = NULL;
    ssize_t bytes_read = 0;
    TSK_INUM_T current_inum = 0;
    FATFS_DENTRY *dentry = NULL;
    uint64_t i = 0;

    assert(a_fatfs != NULL);
    assert(a_fs_file != NULL);

    tsk_error_reset();
    if (fatfs_ptr_arg_is_null(a_fatfs, "a_fatfs", func_name) ||
        fatfs_ptr_arg_is_null(a_fs_file, "a_fs_file", func_name)) {
        return FATFS_FAIL; 
    }

    /* Allocate or reset the TSK_FS_META object. */
    if (a_fs_file->meta == NULL) {
        if ((a_fs_file->meta =
                tsk_fs_meta_alloc(FATFS_FILE_CONTENT_LEN)) == NULL) {
            return FATFS_FAIL;
        }
    }
    else {
        tsk_fs_meta_reset(a_fs_file->meta);
    }

    /* Allocate a buffer for reading in sector-size chunks of the image. */
    if ((sector_buf = (char*)tsk_malloc(a_fatfs->ssize)) == NULL) {
        return FATFS_FAIL;
    }

    current_sector = a_fatfs->rootsect;
    last_sector_of_data_area = a_fatfs->firstdatasect + (a_fatfs->clustcnt * a_fatfs->csize) - 1;
    while (current_sector < last_sector_of_data_area) {
        int8_t sector_is_alloc = 0;

        /* Read in a sector from the root directory. The volume label
         * directory entry will probably be near the beginning of the 
         * directory, probably in the first sector. */
        bytes_read = tsk_fs_read_block(fs, current_sector, sector_buf, a_fatfs->ssize);
        if (bytes_read != a_fatfs->ssize) {
            if (bytes_read >= 0) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_READ);
            }
            tsk_error_set_errstr2("%s: error reading sector: %" PRIuDADDR, func_name, current_sector);
            free(sector_buf);
            return FATFS_FAIL;
        }

        /* Get the allocation status of the sector (yes, it should be allocated). */
        sector_is_alloc = fatfs_is_sectalloc(a_fatfs, current_sector);
        if (sector_is_alloc == -1) {
            return FATFS_FAIL;
        }

        /* Get the inode address of the first directory entry of the sector. */
        current_inum = FATFS_SECT_2_INODE(a_fatfs, current_sector);

        /* Loop through the putative directory entries in the sector, 
         * until the volume label entry is found.  */
        for (i = 0; i < a_fatfs->ssize; i += sizeof(FATFS_DENTRY)) {
            dentry = (FATFS_DENTRY*)&(sector_buf[i]); 

            /* The type of the directory entry is encoded in the first byte 
             * of the entry. See EXFATFS_DIR_ENTRY_TYPE_ENUM. */ 
            if (exfatfs_get_enum_from_type(dentry->data[0]) == EXFATFS_DIR_ENTRY_TYPE_VOLUME_LABEL) {
                if (!exfatfs_is_vol_label_dentry(dentry, FATFS_DATA_UNIT_ALLOC_STATUS_UNKNOWN)) {
                    continue;
                }

                /* Found it, save it to the TSK_FS_META object of the 
                 * TSK_FS_FILE object and exit. */ 
                if (exfatfs_dinode_copy(a_fatfs, current_inum, dentry, 
                    sector_is_alloc, a_fs_file) == TSK_OK) {
                        return FATFS_OK;
                }
                else {
                    return FATFS_FAIL;
                }
            }
        }
    }

    free(sector_buf);
    return FATFS_OK;
}
Exemplo n.º 15
0
/**
 * \internal
 * Searches the root directory of an exFAT file system for an allocation bitmap
 * directory entry. If the entry is found, data from the entry is saved to a
 * FATFS_INFO object.
 *
 * @param [in, out] a_fatfs Generic FAT file system info structure.
 * @return 0 on success, 1 otherwise, per TSK convention.
 */
static uint8_t
exfatfs_get_alloc_bitmap(FATFS_INFO *a_fatfs)
{
    const char *func_name = "exfatfs_get_alloc_bitmap";
    TSK_FS_INFO *fs = &(a_fatfs->fs_info);
    TSK_DADDR_T current_sector = 0;
    TSK_DADDR_T last_sector_of_data_area = 0;
    char *sector_buf = NULL;
    EXFATFS_ALLOC_BITMAP_DIR_ENTRY *dentry = NULL;
    uint64_t i = 0;
    uint64_t first_sector_of_alloc_bitmap = 0;
    uint64_t alloc_bitmap_length_in_bytes = 0;
    uint64_t last_sector_of_alloc_bitmap = 0;

    assert(a_fatfs != NULL);
    
    if ((sector_buf = (char*)tsk_malloc(a_fatfs->ssize)) == NULL) {
        return FATFS_FAIL;
    }

    last_sector_of_data_area = a_fatfs->firstdatasect + (a_fatfs->clustcnt * a_fatfs->csize) - 1;
    for (current_sector = a_fatfs->rootsect; current_sector < last_sector_of_data_area; current_sector++) {
        ssize_t bytes_read = 0;

        /* Read in a sector from the root directory. The allocation bitmap
         * directory entries will probably be near the beginning of the 
         * directory, probably in the first sector. */
        bytes_read = tsk_fs_read_block(fs, current_sector, sector_buf, a_fatfs->ssize);
        if (bytes_read != a_fatfs->ssize) {
            if (bytes_read >= 0) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_READ);
            }
            tsk_error_set_errstr2("%s: sector: %" PRIuDADDR, func_name, current_sector);
            free(sector_buf);
            return FATFS_FAIL;
        }

        /* Read the directory entries in the sector, looking for allocation
         * bitmap entries. There will be one entry unless the file system is 
         * TexFAT (transactional exFAT), in which case there will be two. */
        for (i = 0; i < a_fatfs->ssize; i += sizeof(FATFS_DENTRY)) {
            dentry = (EXFATFS_ALLOC_BITMAP_DIR_ENTRY*)&(sector_buf[i]); 

            /* The type of the directory entry is encoded in the first byte 
             * of the entry. See EXFATFS_DIR_ENTRY_TYPE_ENUM. */ 
            if (exfatfs_get_enum_from_type(dentry->entry_type) == EXFATFS_DIR_ENTRY_TYPE_ALLOC_BITMAP) {
                /* Do an in-depth test. */
                if (!exfatfs_is_alloc_bitmap_dentry((FATFS_DENTRY*)dentry, FATFS_DATA_UNIT_ALLOC_STATUS_UNKNOWN, a_fatfs)) {
                    continue;
                }

                /* The first bit of the flags byte is 0 for the first 
                 * allocation bitmap directory entry and 1 for the second 
                 * bitmap directory entry. If TexFAT is in use and there are
                 * two allocation bitmaps, the first bitmap should be the
                 * stable copy of the last known good allocation bitmap. 
                 * Therefore, the SleuthKit will use the first bitmap to 
                 * determine which clusters are allocated. */
                if (~(dentry->flags & 0x01)) {
                    first_sector_of_alloc_bitmap = FATFS_CLUST_2_SECT(a_fatfs, tsk_getu32(fs->endian, dentry->first_cluster_of_bitmap));
                    alloc_bitmap_length_in_bytes = tsk_getu64(fs->endian, dentry->length_of_alloc_bitmap_in_bytes);
                    last_sector_of_alloc_bitmap = first_sector_of_alloc_bitmap + (roundup(alloc_bitmap_length_in_bytes, a_fatfs->ssize) / a_fatfs->ssize) - 1;

                    /* The allocation bitmap must lie within the boundaries of the data area. 
                     * It also must be big enough for the number of clusters reported in the VBR. */
                    if ((first_sector_of_alloc_bitmap >= a_fatfs->firstdatasect) &&
                        (last_sector_of_alloc_bitmap <= last_sector_of_data_area) &&
                        (alloc_bitmap_length_in_bytes >= (a_fatfs->clustcnt + 7) / 8))
                    {
                        a_fatfs->EXFATFS_INFO.first_sector_of_alloc_bitmap = first_sector_of_alloc_bitmap; 
                        a_fatfs->EXFATFS_INFO.length_of_alloc_bitmap_in_bytes = alloc_bitmap_length_in_bytes;
                        free(sector_buf);
                        return FATFS_OK;
                    }
                }
            }
        }
    }
    free(sector_buf);

    return FATFS_FAIL;
}
Exemplo n.º 16
0
/**
 * \internal
 * Parses the MBR of an exFAT file system to obtain file system layout 
 * information to add to a FATFS_INFO object.
 *
 * @param [in, out] a_fatfs Generic FAT file system info structure.
 * @return 0 on success, 1 otherwise, per TSK convention.
 */
static uint8_t 
exfatfs_get_fs_layout(FATFS_INFO *a_fatfs)
{
    const char *func_name = "exfatfs_get_fs_layout";
    TSK_FS_INFO *fs = &(a_fatfs->fs_info);
    EXFATFS_MASTER_BOOT_REC *exfatbs = NULL;
    uint64_t vol_len_in_sectors = 0;
    uint64_t last_sector_of_cluster_heap = 0;

    assert(a_fatfs != NULL);
    
    /* Get the size of the volume. It should be non-zero. */
    exfatbs = (EXFATFS_MASTER_BOOT_REC*)(&a_fatfs->boot_sector_buffer);
    vol_len_in_sectors = tsk_getu64(fs->endian, exfatbs->vol_len_in_sectors);
    if (vol_len_in_sectors == 0) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr("Not an exFAT file system (invalid volume length)");
        if (tsk_verbose) {
            fprintf(stderr, "%s: Invalid volume length in sectors (%" PRIu64 ")\n", func_name, vol_len_in_sectors);
        }
        return FATFS_FAIL;
    }

    /* Get the number of FATs. There will be one FAT for regular exFAT and two 
     * FATs for TexFAT (transactional exFAT). */
    a_fatfs->numfat = exfatbs->num_fats;
    if ((a_fatfs->numfat != 1) && (a_fatfs->numfat != 2)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr("Not an exFAT file system (number of FATs)");
        if (tsk_verbose) {
            fprintf(stderr, "%s: Invalid number of FATs (%d)\n", func_name, a_fatfs->numfat);
        }
        return FATFS_FAIL;
    }

    /* Get the sector address of the first FAT (FAT0). 
     * It should be non-zero and within the boundaries of the volume.
     * Note that if the file system is TexFAT, FAT1 will be the working copy
     * of the FAT and FAT0 will be the stable copy of the last known good FAT. 
     * Therefore, the Sleuthkit should use FAT0. */
    a_fatfs->firstfatsect = tsk_getu32(fs->endian, exfatbs->fat_offset);
    if ((a_fatfs->firstfatsect == 0) || ((uint64_t)a_fatfs->firstfatsect >= vol_len_in_sectors)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("Not an exFAT file system (invalid first FAT sector)");
        if (tsk_verbose) {
            fprintf(stderr, "%s: Invalid first FAT sector (%" PRIuDADDR ")\n", func_name, a_fatfs->firstfatsect);
        }
        return FATFS_FAIL;
    }

    /* Get the sector address of the cluster heap (data area). It should be 
     * after the FATs and within the boundaries of the volume. */
    a_fatfs->firstdatasect = tsk_getu32(fs->endian, exfatbs->cluster_heap_offset);  
    if ((a_fatfs->firstdatasect <= (a_fatfs->firstfatsect + (a_fatfs->sectperfat * a_fatfs->numfat) - 1)) ||
        ((uint64_t)a_fatfs->firstdatasect >= vol_len_in_sectors)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("Not an exFAT file system (invalid first data sector");
        if (tsk_verbose) {
            fprintf(stderr, "%s: Invalid first data sector (%" PRIuDADDR ")\n", func_name, a_fatfs->firstdatasect);
        }
        return FATFS_FAIL;
    }

    /* Unlike FAT12 and FAT16, but like FAT32, the sector address of the first
     * cluster (cluster #2, there is no cluster #0 or cluster #1) is the same
     * as the sector address of the cluster heap (data area). */
    a_fatfs->firstclustsect = a_fatfs->firstdatasect;

    /* Get the total number of clusters. It should be non-zero, and should 
     * define a cluster heap (data area) that is within the boundaries of the
     * volume. */
    a_fatfs->clustcnt = tsk_getu32(fs->endian, exfatbs->cluster_cnt);
    last_sector_of_cluster_heap = a_fatfs->firstdatasect + (a_fatfs->clustcnt * a_fatfs->csize) - 1;
    if ((a_fatfs->clustcnt == 0) || 
        (last_sector_of_cluster_heap >= vol_len_in_sectors)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("Not an exFAT file system (invalid cluster count)");
        if (tsk_verbose) {
            fprintf(stderr, "%s: Invalid cluster count (%" PRIuDADDR ")\n", func_name, a_fatfs->clustcnt);
        }
        return FATFS_FAIL;
    }

    /* The first cluster is #2, so the final cluster is: */
     a_fatfs->lastclust = 1 + a_fatfs->clustcnt;

     /* This bit mask is required to make the FATFS_CLUST_2_SECT macro work
      * for exFAT. It is the same as the FAT32 mask. */
     a_fatfs->mask = EXFATFS_MASK;

    /* Get the sector address of the root directory. It should be within the
     * cluster heap (data area). */
    a_fatfs->rootsect = FATFS_CLUST_2_SECT(a_fatfs, tsk_getu32(fs->endian, exfatbs->root_dir_cluster));
    if ((a_fatfs->rootsect < a_fatfs->firstdatasect) ||
        ((uint64_t)a_fatfs->rootsect > last_sector_of_cluster_heap)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("Not an exFAT file system (invalid root directory sector address)");
        if (tsk_verbose) {
            fprintf(stderr, "%s: Invalid root directory sector address (%"PRIuDADDR")\n", func_name, a_fatfs->rootsect);
        }
        return FATFS_FAIL;
    }

    /* The number of directory entries in the root directory is not specified
     * in the exFAT boot sector. */
    a_fatfs->numroot = 0;

    return FATFS_OK;
}
Exemplo n.º 17
0
/* convert HFS+'s UTF16 to UTF8
 * replaces null characters with another character (0xfffd)
 * replaces slashes (permitted by HFS+ but causes problems with TSK)
 *   with colons (generally not allowed by Mac OS X)
 * note that at least one directory on HFS+ volumes begins with
 *   four nulls, so we do need to handle nulls; also, Apple chooses
 *   to encode nulls as UTF8 \xC0\x80, which is not a valid UTF8 sequence
 *
 *   @param fs  the file system
 *   @param uni  the UTF16 string as a sequence of bytes
 *   @param ulen  then length of the UTF16 string in characters
 *   @param asc   a buffer to hold the UTF8 result
 *   @param alen  the length of that buffer
 *   @param flags  control some aspects of the conversion
 *   @return 0 on success, 1 on failure; sets up to error string 1
 *
 *   HFS_U16U8_FLAG_REPLACE_SLASH  if this flag is set, then slashes will be replaced
 *   by colons.  Otherwise, they will not be replaced.
 *
 *   HFS_U16U8_FLAG_REPLACE_CONTROL if this flag is set, then all control characters
 *   will be replaced by the UTF16_NULL_REPLACE character. N.B., always replaces
 *   null characters regardless of this flag.
 */
uint8_t
hfs_UTF16toUTF8(TSK_FS_INFO * fs, uint8_t * uni, int ulen, char *asc,
                int alen, uint32_t flags)
{
    UTF8 *ptr8;
    uint8_t *uniclean;
    UTF16 *ptr16;
    int i;
    TSKConversionResult r;

    // remove nulls from the Unicode string
    // convert / to :
    uniclean = (uint8_t *) tsk_malloc(ulen * 2);
    if (!uniclean)
        return 1;

    memcpy(uniclean, uni, ulen * 2);

    for (i = 0; i < ulen; ++i) {
        uint16_t uc = tsk_getu16(fs->endian, uniclean + i * 2);


        int changed = 0;
        if (uc == UTF16_NULL) {
            uc = UTF16_NULL_REPLACE;
            changed = 1;
        }
        else if ((flags & HFS_U16U8_FLAG_REPLACE_SLASH)
                 && uc == UTF16_SLASH) {
            uc = UTF16_COLON;
            changed = 1;
        }

        else if ((flags & HFS_U16U8_FLAG_REPLACE_CONTROL)
                 && uc < UTF16_LEAST_PRINTABLE) {
            uc = (uint16_t) UTF16_NULL_REPLACE;
            changed = 1;
        }

        if (changed)
            *((uint16_t *) (uniclean + i * 2)) =
                tsk_getu16(fs->endian, (uint8_t *) & uc);
    }

    // convert to UTF-8
    memset(asc, 0, alen);

    ptr8 = (UTF8 *) asc;
    ptr16 = (UTF16 *) uniclean;
    r = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &ptr16,
                        (const UTF16 *) (&uniclean[ulen * 2]), &ptr8,
                        (UTF8 *) & asc[alen], TSKstrictConversion);

    free(uniclean);
    if (r != TSKconversionOK) {
        tsk_error_set_errno(TSK_ERR_FS_UNICODE);
        tsk_error_set_errstr
        ("hfs_UTF16toUTF8: unicode conversion failed (%d)", (int) r);
        return 1;
    }

    return 0;
}
Exemplo n.º 18
0
/** \internal
* Process a directory and load up FS_DIR with the entries. If a pointer to
* an already allocated FS_DIR struture is given, it will be cleared.  If no existing
* FS_DIR structure is passed (i.e. NULL), then a new one will be created. If the return
* value is error or corruption, then the FS_DIR structure could
* have entries (depending on when the error occured).
*
* @param a_fs File system to analyze
* @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated
* structure or a new structure.
* @param a_addr Address of directory to process.
* @returns error, corruption, ok etc.
*/
TSK_RETVAL_ENUM
hfs_dir_open_meta(TSK_FS_INFO * fs, TSK_FS_DIR ** a_fs_dir,
                  TSK_INUM_T a_addr)
{
    HFS_INFO *hfs = (HFS_INFO *) fs;
    uint32_t cnid;              /* catalog node ID of the entry (= inum) */
    TSK_FS_DIR *fs_dir;
    TSK_FS_NAME *fs_name;
    HFS_DIR_OPEN_META_INFO info;


    tsk_error_reset();

    cnid = (uint32_t) a_addr;

    if (tsk_verbose)
        fprintf(stderr,
                "hfs_dir_open_meta: called for directory %" PRIu32 "\n", cnid);

    if (a_addr < fs->first_inum || a_addr > fs->last_inum) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("hfs_dir_open_meta: Invalid inode value: %"
                             PRIuINUM, a_addr);
        return TSK_ERR;
    }
    else if (a_fs_dir == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
        ("hfs_dir_open_meta: NULL fs_dir argument given");
        return TSK_ERR;
    }

    if (tsk_verbose)
        tsk_fprintf(stderr,
                    "hfs_dir_open_meta: Processing directory %" PRIuINUM "\n",
                    a_addr);

    fs_dir = *a_fs_dir;
    if (fs_dir) {
        tsk_fs_dir_reset(fs_dir);
        fs_dir->addr = a_addr;
    }
    else if ((*a_fs_dir = fs_dir =
                              tsk_fs_dir_alloc(fs, a_addr, 128)) == NULL) {
        return TSK_ERR;
    }

    if ((fs_name = tsk_fs_name_alloc(HFS_MAXNAMLEN, 0)) == NULL) {
        return TSK_ERR;
    }
    info.fs_dir = fs_dir;
    info.fs_name = fs_name;

    if ((fs_dir->fs_file =
                tsk_fs_file_open_meta(fs, NULL, a_addr)) == NULL) {
        tsk_error_errstr2_concat(" - hfs_dir_open_meta");
        tsk_fs_name_free(fs_name);
        return TSK_ERR;
    }

    // if we are listing the root directory, add the Orphan directory and special HFS file entries
    if (a_addr == fs->root_inum) {
        int i;
        for (i = 0; i < 6; i++) {
            switch (i) {
            case 0:
                if (!hfs->has_extents_file)
                    continue;
                strncpy(fs_name->name, HFS_EXTENTS_FILE_NAME,
                        fs_name->name_size);
                fs_name->meta_addr = HFS_EXTENTS_FILE_ID;
                break;
            case 1:
                strncpy(fs_name->name, HFS_CATALOG_FILE_NAME,
                        fs_name->name_size);
                fs_name->meta_addr = HFS_CATALOG_FILE_ID;
                break;
            case 2:
                // Note: the Extents file and the BadBlocks file are really the same.
                if (!hfs->has_extents_file)
                    continue;
                strncpy(fs_name->name, HFS_BAD_BLOCK_FILE_NAME,
                        fs_name->name_size);
                fs_name->meta_addr = HFS_BAD_BLOCK_FILE_ID;
                break;
            case 3:
                strncpy(fs_name->name, HFS_ALLOCATION_FILE_NAME,
                        fs_name->name_size);
                fs_name->meta_addr = HFS_ALLOCATION_FILE_ID;
                break;
            case 4:
                if (!hfs->has_startup_file)
                    continue;
                strncpy(fs_name->name, HFS_STARTUP_FILE_NAME,
                        fs_name->name_size);
                fs_name->meta_addr = HFS_STARTUP_FILE_ID;
                break;
            case 5:
                if (!hfs->has_attributes_file)
                    continue;
                strncpy(fs_name->name, HFS_ATTRIBUTES_FILE_NAME,
                        fs_name->name_size);
                fs_name->meta_addr = HFS_ATTRIBUTES_FILE_ID;
                break;
                /*
                   case 6:
                   strncpy(fs_name->name, HFS_REPAIR_CATALOG_FILE_NAME, fs_name->name_size);
                   fs_name->meta_addr = HFS_REPAIR_CATALOG_FILE_ID;
                   break;
                   case 7:
                   strncpy(fs_name->name, HFS_BOGUS_EXTENT_FILE_NAME, fs_name->name_size);
                   fs_name->meta_addr = HFS_BOGUS_EXTENT_FILE_ID;
                   break;
                 */
            }
            fs_name->type = TSK_FS_NAME_TYPE_REG;
            fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
            if (tsk_fs_dir_add(fs_dir, fs_name)) {
                tsk_fs_name_free(fs_name);
                return TSK_ERR;
            }
        }
    }

    if (hfs_cat_traverse(hfs, &cnid, hfs_dir_open_meta_cb, &info)) {
        tsk_fs_name_free(fs_name);
        return TSK_ERR;
    }

    tsk_fs_name_free(fs_name);
    return TSK_OK;
}
Exemplo n.º 19
0
static uint8_t
hfs_dir_open_meta_cb(HFS_INFO * hfs, int8_t level_type,
                     const void *targ_data, const hfs_btree_key_cat * cur_key,
                     TSK_OFF_T key_off, void *ptr)
{
    uint32_t *cnid_p = (uint32_t *) targ_data;
    HFS_DIR_OPEN_META_INFO *info = (HFS_DIR_OPEN_META_INFO *) ptr;
    TSK_FS_INFO *fs = &hfs->fs_info;

    if (tsk_verbose)
        fprintf(stderr,
                "hfs_dir_open_meta_cb: want %" PRIu32 " vs got %" PRIu32
                " (%s node)\n", *cnid_p, tsk_getu32(hfs->fs_info.endian,
                        cur_key->parent_cnid),
                (level_type == HFS_BT_NODE_TYPE_IDX) ? "Index" : "Leaf");

    if (level_type == HFS_BT_NODE_TYPE_IDX) {
        if (tsk_getu32(hfs->fs_info.endian,
                       cur_key->parent_cnid) < *cnid_p) {
            return HFS_BTREE_CB_IDX_LT;
        }
        else {
            return HFS_BTREE_CB_IDX_EQGT;
        }
    }
    else {
        uint8_t *rec_buf = (uint8_t *) cur_key;
        uint16_t rec_type;
        size_t rec_off2;

        if (tsk_getu32(hfs->fs_info.endian,
                       cur_key->parent_cnid) < *cnid_p) {
            return HFS_BTREE_CB_LEAF_GO;
        }
        else if (tsk_getu32(hfs->fs_info.endian,
                            cur_key->parent_cnid) > *cnid_p) {
            return HFS_BTREE_CB_LEAF_STOP;
        }
        rec_off2 = 2 + tsk_getu16(hfs->fs_info.endian, cur_key->key_len);
        // @@@ NEED TO REPLACE THIS SOMEHOW, but need to figure out the max length
        /*
           if (rec_off2 > nodesize) {
           tsk_error_set_errno(TSK_ERR_FS_GENFS);
           tsk_error_set_errstr(
           "hfs_dir_open_meta: offset of record+keylen %d in leaf node %d too large (%zu vs %"
           PRIu16 ")", rec, cur_node, rec_off2, nodesize);
           tsk_fs_name_free(fs_name);
           free(node);
           return TSK_COR;
           }
         */
        rec_type = tsk_getu16(hfs->fs_info.endian, &rec_buf[rec_off2]);

        // Catalog entry is for a file
        if (rec_type == HFS_FILE_THREAD) {
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
            tsk_error_set_errstr("hfs_dir_open_meta: Entry"
                                 " is a file, not a folder");
            return HFS_BTREE_CB_ERR;
        }

        /* This will link the folder to its parent, which is the ".." entry */
        else if (rec_type == HFS_FOLDER_THREAD) {
            hfs_thread *thread = (hfs_thread *) & rec_buf[rec_off2];
            strcpy(info->fs_name->name, "..");
            info->fs_name->meta_addr =
                tsk_getu32(hfs->fs_info.endian, thread->parent_cnid);
            info->fs_name->type = TSK_FS_NAME_TYPE_DIR;
            info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
        }

        /* This is a folder in the folder */
        else if (rec_type == HFS_FOLDER_RECORD) {
            hfs_folder *folder = (hfs_folder *) & rec_buf[rec_off2];

            info->fs_name->meta_addr =
                tsk_getu32(hfs->fs_info.endian, folder->std.cnid);
            info->fs_name->type = TSK_FS_NAME_TYPE_DIR;
            info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;


            if (hfs_UTF16toUTF8(fs, (uint8_t *) cur_key->name.unicode,
                                tsk_getu16(hfs->fs_info.endian, cur_key->name.length),
                                info->fs_name->name, HFS_MAXNAMLEN + 1,
                                HFS_U16U8_FLAG_REPLACE_SLASH)) {
                return HFS_BTREE_CB_ERR;
            }
        }

        /* This is a normal file in the folder */
        else if (rec_type == HFS_FILE_RECORD) {
            hfs_file *file = (hfs_file *) & rec_buf[rec_off2];
            // This could be a hard link.  We need to test this CNID, and follow it if necessary.
            unsigned char is_err;
            TSK_INUM_T file_cnid =
                tsk_getu32(hfs->fs_info.endian, file->std.cnid);
            TSK_INUM_T target_cnid =
                hfs_follow_hard_link(hfs, file, &is_err);
            if (is_err > 1) {
                error_returned
                ("hfs_dir_open_meta_cb: trying to follow a possible hard link in the directory");
                return HFS_BTREE_CB_ERR;
            }
            if (target_cnid != file_cnid) {
                HFS_ENTRY entry;
                uint8_t lkup;   // lookup result

                // This is a hard link.  We need to fill in the name->type and name->meta_addr from the target
                info->fs_name->meta_addr = target_cnid;
                // get the Catalog entry for the target CNID

                lkup = hfs_cat_file_lookup(hfs, target_cnid, &entry,
                                           FALSE);
                if (lkup != 0) {
                    error_returned
                    ("hfs_dir_open_meta_cb: retrieving the catalog entry for the target of a hard link");
                    return HFS_BTREE_CB_ERR;
                }
                info->fs_name->type =
                    hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian,
                                                   entry.cat.std.perm.mode));
            }
            else {
                // This is NOT a hard link.
                info->fs_name->meta_addr =
                    tsk_getu32(hfs->fs_info.endian, file->std.cnid);
                info->fs_name->type =
                    hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian,
                                                   file->std.perm.mode));
            }
            info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
            if (hfs_UTF16toUTF8(fs, (uint8_t *) cur_key->name.unicode,
                                tsk_getu16(hfs->fs_info.endian, cur_key->name.length),
                                info->fs_name->name, HFS_MAXNAMLEN + 1,
                                HFS_U16U8_FLAG_REPLACE_SLASH)) {
                return HFS_BTREE_CB_ERR;
            }
        }
        else {
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
            // @@@ MAY NEED TO IMPROVE BELOW MESSAGE
            tsk_error_set_errstr
            ("hfs_dir_open_meta: Unknown record type %d in leaf node",
             rec_type);
            return HFS_BTREE_CB_ERR;
        }

        if (tsk_fs_dir_add(info->fs_dir, info->fs_name)) {
            return HFS_BTREE_CB_ERR;
        }
        return HFS_BTREE_CB_LEAF_GO;
    }
}
Exemplo n.º 20
0
/** \internal
 *
 * return 1 on error and 0 on success
 */
uint8_t
tsk_fs_nofs_block_walk(TSK_FS_INFO * fs, TSK_DADDR_T a_start_blk,
    TSK_DADDR_T a_end_blk, TSK_FS_BLOCK_WALK_FLAG_ENUM a_flags,
    TSK_FS_BLOCK_WALK_CB a_action, void *a_ptr)
{
    TSK_FS_BLOCK *fs_block;
    TSK_DADDR_T addr;

    // clean up any error messages that are lying around
    tsk_error_reset();

    /*
     * Sanity checks.
     */
    if (a_start_blk < fs->first_block || a_start_blk > fs->last_block) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("nofs_block_walk: Start block number: %"
            PRIuDADDR, a_start_blk);
        return 1;
    }

    if (a_end_blk < fs->first_block || a_end_blk > fs->last_block
        || a_end_blk < a_start_blk) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("nofs_block_walk: Last block number: %"
            PRIuDADDR, a_end_blk);
        return 1;
    }

    /* Sanity check on a_flags -- make sure at least one ALLOC is set */
    if (((a_flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC) == 0) &&
        ((a_flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC) == 0)) {
        a_flags |=
            (TSK_FS_BLOCK_WALK_FLAG_ALLOC |
            TSK_FS_BLOCK_WALK_FLAG_UNALLOC);
    }

    /* All swap has is allocated blocks... exit if not wanted */
    if (!(a_flags & TSK_FS_BLOCK_FLAG_ALLOC)) {
        return 0;
    }

    if ((fs_block = tsk_fs_block_alloc(fs)) == NULL) {
        return 1;
    }

    for (addr = a_start_blk; addr <= a_end_blk; addr++) {
        int retval;

        if (tsk_fs_block_get(fs, fs_block, addr) == NULL) {
            tsk_error_set_errstr2("nofs_block_walk: Block %" PRIuDADDR,
                addr);
            tsk_fs_block_free(fs_block);
            return 1;
        }

        retval = a_action(fs_block, a_ptr);
        if (retval == TSK_WALK_STOP) {
            break;
        }
        else if (retval == TSK_WALK_ERROR) {
            tsk_fs_block_free(fs_block);
            return 1;
        }
    }

    /*
     * Cleanup.
     */
    tsk_fs_block_free(fs_block);
    return 0;
}
Exemplo n.º 21
0
Arquivo: ewf.c Projeto: 0xkasun/OpenDF
TSK_IMG_INFO *
ewf_open(int a_num_img,
    const TSK_TCHAR * const a_images[], unsigned int a_ssize)
{
#if defined( HAVE_LIBEWF_V2_API )
    char error_string[TSK_EWF_ERROR_STRING_SIZE];

    libewf_error_t *ewf_error = NULL;
    int result = 0;
#elif !defined( LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 )
    uint8_t md5_hash[16];
#endif

    IMG_EWF_INFO *ewf_info = NULL;
    TSK_IMG_INFO *img_info = NULL;

#if !defined( HAVE_LIBEWF_V2_API)
    if (tsk_verbose)
        libewf_set_notify_values(stderr, 1);
#endif

    if ((ewf_info =
            (IMG_EWF_INFO *) tsk_img_malloc(sizeof(IMG_EWF_INFO))) ==
        NULL) {
        return NULL;
    }
    img_info = (TSK_IMG_INFO *) ewf_info;

    // See if they specified only the first of the set...
    ewf_info->used_ewf_glob = 0;
    if (a_num_img == 1) {
#if defined( HAVE_LIBEWF_V2_API)
#ifdef TSK_WIN32
        if (libewf_glob_wide(a_images[0], TSTRLEN(a_images[0]),
                LIBEWF_FORMAT_UNKNOWN, &ewf_info->images,
                &ewf_info->num_imgs, &ewf_error) == -1) {
#else
        if (libewf_glob(a_images[0], TSTRLEN(a_images[0]),
                LIBEWF_FORMAT_UNKNOWN, &ewf_info->images,
                &ewf_info->num_imgs, &ewf_error) == -1) {
#endif
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_IMG_MAGIC);

            getError(ewf_error, error_string);
            tsk_error_set_errstr("ewf_open: Not an E01 glob name (%s)",
                error_string);
            libewf_error_free(&ewf_error);
            tsk_img_free(ewf_info);
            return NULL;
        }

#else                           //use v1

#ifdef TSK_WIN32
        ewf_info->num_imgs =
            libewf_glob_wide(a_images[0], TSTRLEN(a_images[0]),
            LIBEWF_FORMAT_UNKNOWN, &ewf_info->images);
#else
        ewf_info->num_imgs =
            libewf_glob(a_images[0], TSTRLEN(a_images[0]),
            LIBEWF_FORMAT_UNKNOWN, &ewf_info->images);
#endif
        if (ewf_info->num_imgs <= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_IMG_MAGIC);
            tsk_error_set_errstr("ewf_open: Not an E01 glob name");

            tsk_img_free(ewf_info);
            return NULL;
        }
#endif                          // end v1

        ewf_info->used_ewf_glob = 1;
        if (tsk_verbose)
            tsk_fprintf(stderr,
                "ewf_open: found %d segment files via libewf_glob\n",
                ewf_info->num_imgs);
    }
    else {
        int i;
        ewf_info->num_imgs = a_num_img;
        if ((ewf_info->images =
                (TSK_TCHAR **) tsk_malloc(a_num_img *
                    sizeof(TSK_TCHAR *))) == NULL) {
            tsk_img_free(ewf_info);
            return NULL;
        }
        for (i = 0; i < a_num_img; i++) {
            if ((ewf_info->images[i] =
                    (TSK_TCHAR *) tsk_malloc((TSTRLEN(a_images[i]) +
                            1) * sizeof(TSK_TCHAR))) == NULL) {
                tsk_img_free(ewf_info);
                return NULL;
            }
            TSTRNCPY(ewf_info->images[i], a_images[i],
                TSTRLEN(a_images[i]) + 1);
        }
    }


#if defined( HAVE_LIBEWF_V2_API )

    // Check the file signature before we call the library open
#if defined( TSK_WIN32 )
    if (libewf_check_file_signature_wide(a_images[0], &ewf_error) != 1)
#else
    if (libewf_check_file_signature(a_images[0], &ewf_error) != 1)
#endif
    {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_MAGIC);

        getError(ewf_error, error_string);
        tsk_error_set_errstr("ewf_open: Not an EWF file (%s)",
            error_string);
        libewf_error_free(&ewf_error);

        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Not an EWF file\n");
        }
        return (NULL);
    }

    if (libewf_handle_initialize(&(ewf_info->handle), &ewf_error) != 1) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);

        getError(ewf_error, error_string);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error initializing handle (%s)", a_images[0], error_string);
        libewf_error_free(&ewf_error);

        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Unable to create EWF handle\n");
        }
        return (NULL);
    }
#if defined( TSK_WIN32 )
    if (libewf_handle_open_wide(ewf_info->handle,
            (wchar_t * const *) ewf_info->images,
            ewf_info->num_imgs, LIBEWF_OPEN_READ, &ewf_error) != 1)
#else
    if (libewf_handle_open(ewf_info->handle,
            (char *const *) ewf_info->images,
            ewf_info->num_imgs, LIBEWF_OPEN_READ, &ewf_error) != 1)
#endif
    {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);

        getError(ewf_error, error_string);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error opening (%s)", a_images[0], error_string);
        libewf_error_free(&ewf_error);

        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Error opening EWF file\n");
        }
        return (NULL);
    }
    if (libewf_handle_get_media_size(ewf_info->handle,
            (size64_t *) & (img_info->size), &ewf_error) != 1) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);

        getError(ewf_error, error_string);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error getting size of image (%s)", a_images[0],
            error_string);
        libewf_error_free(&ewf_error);

        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Error getting size of EWF file\n");
        }
        return (NULL);
    }
    result = libewf_handle_get_utf8_hash_value_md5(ewf_info->handle,
        (uint8_t *) ewf_info->md5hash, 33, &ewf_error);

    if (result == -1) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);

        getError(ewf_error, error_string);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error getting MD5 of image (%s)", a_images[0],
            error_string);
        libewf_error_free(&ewf_error);

        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Error getting size of EWF file\n");
        }
        return (NULL);
    }
    ewf_info->md5hash_isset = result;

#else                           // V1 API

    // Check the file signature before we call the library open
#if defined( TSK_WIN32 )
    if (libewf_check_file_signature_wide(a_images[0]) != 1)
#else
    if (libewf_check_file_signature(a_images[0]) != 1)
#endif
    {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_MAGIC);
        tsk_error_set_errstr("ewf_open: Not an EWF file");
        tsk_img_free(ewf_info);
        if (tsk_verbose)
            tsk_fprintf(stderr, "Not an EWF file\n");

        return NULL;
    }

#if defined( TSK_WIN32 )
    ewf_info->handle = libewf_open_wide(
        (wchar_t * const *) ewf_info->images, ewf_info->num_imgs,
        LIBEWF_OPEN_READ);
#else
    ewf_info->handle = libewf_open(
        (char *const *) ewf_info->images, ewf_info->num_imgs,
        LIBEWF_OPEN_READ);
#endif
    if (ewf_info->handle == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error opening", ewf_info->images[0]);
        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Error opening EWF file\n");
        }
        return (NULL);
    }
#if defined( LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 )
    // 2007 version
    img_info->size = libewf_get_media_size(ewf_info->handle);

    ewf_info->md5hash_isset = libewf_get_stored_md5_hash(ewf_info->handle,
        ewf_info->md5hash, LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5);
#else
    // libewf-20080322 version
    if (libewf_get_media_size(ewf_info->handle,
            (size64_t *) & (img_info->size)) != 1) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error getting size of image", ewf_info->images[0]);
        tsk_img_free(ewf_info);
        if (tsk_verbose) {
            tsk_fprintf(stderr, "Error getting size of EWF file\n");
        }
        return (NULL);
    }
    if (libewf_get_md5_hash(ewf_info->handle, md5_hash, 16) == 1) {
        int md5_string_iterator = 0;
        int md5_hash_iterator = 0;

        for (md5_hash_iterator = 0;
            md5_hash_iterator < 16; md5_hash_iterator++) {
            int digit = md5_hash[md5_hash_iterator] / 16;

            if (digit <= 9) {
                ewf_info->md5hash[md5_string_iterator++] =
                    '0' + (char) digit;
            }
            else {
                ewf_info->md5hash[md5_string_iterator++] =
                    'a' + (char) (digit - 10);
            }
            digit = md5_hash[md5_hash_iterator] % 16;

            if (digit <= 9) {
                ewf_info->md5hash[md5_string_iterator++] =
                    '0' + (char) digit;
            }
            else {
                ewf_info->md5hash[md5_string_iterator++] =
                    'a' + (char) (digit - 10);
            }
        }
        ewf_info->md5hash_isset = 1;
    }
#endif                          /* defined( LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 ) */
#endif                          /* defined( HAVE_LIBEWF_V2_API ) */
    if (a_ssize != 0) {
        img_info->sector_size = a_ssize;
    }
    else {
        img_info->sector_size = 512;
    }
    img_info->itype = TSK_IMG_TYPE_EWF_EWF;
    img_info->read = &ewf_image_read;
    img_info->close = &ewf_image_close;
    img_info->imgstat = &ewf_image_imgstat;

    // initialize the read lock
    tsk_init_lock(&(ewf_info->read_lock));

    return (img_info);
}
Exemplo n.º 22
0
/**
 * \ingroup fslib
 * Read the contents of a given attribute using a typical read() type interface.
 * 0s are returned for missing runs. 
 * 
 * @param a_fs_attr The attribute to read.
 * @param a_offset The byte offset to start reading from.
 * @param a_buf The buffer to read the data into.
 * @param a_len The number of bytes to read from the file.
 * @param a_flags Flags to use while reading
 * @returns The number of bytes read or -1 on error (incl if offset is past end of file).
 */
ssize_t
tsk_fs_attr_read(const TSK_FS_ATTR * a_fs_attr, TSK_OFF_T a_offset,
    char *a_buf, size_t a_len, TSK_FS_FILE_READ_FLAG_ENUM a_flags)
{
    TSK_FS_INFO *fs;

    if ((a_fs_attr == NULL) || (a_fs_attr->fs_file == NULL)
        || (a_fs_attr->fs_file->fs_info == NULL)) {
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_attr_read: Attribute has null pointers.");
        return -1;
    }
    fs = a_fs_attr->fs_file->fs_info;

    /* for compressed data, call the specialized function */
    if (a_fs_attr->flags & TSK_FS_ATTR_COMP) {
        if (a_fs_attr->r == NULL) {
            tsk_error_set_errno(TSK_ERR_FS_ARG);
            tsk_error_set_errstr
                ("tsk_fs_attr_read: Attribute has compressed type set, but no compressed read function defined");
            return -1;
        }
        return a_fs_attr->r(a_fs_attr, a_offset, a_buf, a_len);
    }

    /* For resident data, copy data from the local buffer */
    else if (a_fs_attr->flags & TSK_FS_ATTR_RES) {
        size_t len_toread;

        if (a_offset >= a_fs_attr->size) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_READ_OFF);
            tsk_error_set_errstr("tsk_fs_attr_read - %" PRIuOFF, a_offset);
            return -1;
        }

        len_toread = a_len;
        if (a_offset + a_len > a_fs_attr->size) {
            len_toread = (size_t) (a_fs_attr->size - a_offset);
            memset(&a_buf[len_toread], 0, a_len - len_toread);
        }

        memcpy(a_buf, &a_fs_attr->rd.buf[a_offset], len_toread);

        return (ssize_t) len_toread;
    }

    /* For non-resident data, load the needed block and copy the data */
    else if (a_fs_attr->flags & TSK_FS_ATTR_NONRES) {
        TSK_FS_ATTR_RUN *data_run_cur;
        TSK_DADDR_T blkoffset_toread;   // block offset of where we want to start reading from
        size_t byteoffset_toread;       // byte offset in blkoffset_toread of where we want to start reading from
        size_t len_remain;      // length remaining to copy
        size_t len_toread;      // length total to copy

        if (((a_flags & TSK_FS_FILE_READ_FLAG_SLACK)
                && (a_offset >= a_fs_attr->nrd.allocsize))
            || (!(a_flags & TSK_FS_FILE_READ_FLAG_SLACK)
                && (a_offset >= a_fs_attr->size))) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_READ_OFF);
            tsk_error_set_errstr("tsk_fs_attr_read - %" PRIuOFF, a_offset);
            return -1;
        }

        blkoffset_toread = a_offset / fs->block_size;
        byteoffset_toread = (size_t) (a_offset % fs->block_size);

        // determine how many bytes we can copy
        len_toread = a_len;
        if (a_flags & TSK_FS_FILE_READ_FLAG_SLACK) {
            if (a_offset + a_len > a_fs_attr->nrd.allocsize)
                len_toread =
                    (size_t) (a_fs_attr->nrd.allocsize - a_offset);
        }
        else {
            if (a_offset + a_len > a_fs_attr->size)
                len_toread = (size_t) (a_fs_attr->size - a_offset);
        }
        // wipe the buffer we won't read into
        if (len_toread < a_len)
            memset(&a_buf[len_toread], 0, a_len - len_toread);

        len_remain = len_toread;

        // cycle through the run until we find where we can start to process the clusters
        for (data_run_cur = a_fs_attr->nrd.run; data_run_cur;
            data_run_cur = data_run_cur->next) {
            TSK_DADDR_T blkoffset_inrun;
            size_t len_inrun;

            // we are done
            if (len_remain <= 0)
                break;

            // See if this run contains the starting offset they requested
            if (data_run_cur->offset + data_run_cur->len <=
                blkoffset_toread)
                continue;

            // block offset into this run
            if (data_run_cur->offset < blkoffset_toread)
                blkoffset_inrun = blkoffset_toread - data_run_cur->offset;
            else
                blkoffset_inrun = 0;

            // see if we need to read the rest of this run and into the next or if it is all here
            len_inrun = len_remain;
            if ((data_run_cur->len - blkoffset_inrun) * fs->block_size -
                byteoffset_toread < len_remain)
                len_inrun =
                    (size_t) ((data_run_cur->len -
                        blkoffset_inrun) * fs->block_size -
                    byteoffset_toread);

            /* sparse files/runs just get 0s */
            if (data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE) {
                memset(&a_buf[len_toread - len_remain], 0, len_inrun);
            }
            /* FILLER entries exist when the source file system can store run
             * info out of order and we did not get all of the run info.  We
             * return 0s if data is read from this type of run. */
            else if (data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) {
                memset(&a_buf[len_toread - len_remain], 0, len_inrun);
                if (tsk_verbose)
                    fprintf(stderr,
                        "tsk_fs_attr_read_type: File %" PRIuINUM
                        " has FILLER entry, using 0s\n",
                        (a_fs_attr->fs_file->meta) ? a_fs_attr->fs_file->
                        meta->addr : 0);
            }
            // we return 0s for reads past the initsize (unless they want slack space)
            else if (((TSK_OFF_T) ((data_run_cur->offset +
                            blkoffset_inrun) * fs->block_size +
                        byteoffset_toread) >= a_fs_attr->nrd.initsize)
                && ((a_flags & TSK_FS_FILE_READ_FLAG_SLACK) == 0)) {
                memset(&a_buf[len_toread - len_remain], 0, len_inrun);
                if (tsk_verbose)
                    fprintf(stderr,
                        "tsk_fs_attr_read: Returning 0s for read past end of initsize (%"
                        PRIuINUM ")\n", ((a_fs_attr->fs_file)
                            && (a_fs_attr->fs_file->meta)) ? a_fs_attr->
                        fs_file->meta->addr : 0);
            }
            else {
                TSK_OFF_T fs_offset_b;
                ssize_t cnt;

                // calcuate the byte offset in the file system
                fs_offset_b =
                    (data_run_cur->addr +
                    blkoffset_inrun) * fs->block_size;

                // add the byte offset in the block
                fs_offset_b += byteoffset_toread;

                // reset this in case we need to also read from the next run 
                byteoffset_toread = 0;

                cnt =
                    tsk_fs_read(fs, fs_offset_b,
                    &a_buf[len_toread - len_remain], len_inrun);
                if (cnt != len_inrun) {
                    if (cnt >= 0) {
                        tsk_error_reset();
                        tsk_error_set_errno(TSK_ERR_FS_READ);
                    }
                    tsk_error_set_errstr2
                        ("tsk_fs_attr_read_type: offset: %" PRIuOFF
                        "  Len: %" PRIuSIZE "", fs_offset_b, len_inrun);
                    return cnt;
                }

                // see if part of the data is in the non-initialized space
                if (((TSK_OFF_T) ((data_run_cur->offset +
                                blkoffset_inrun) * fs->block_size +
                            byteoffset_toread + len_inrun) >
                        a_fs_attr->nrd.initsize)
                    && ((a_flags & TSK_FS_FILE_READ_FLAG_SLACK) == 0)) {

                    size_t uninit_off = a_fs_attr->nrd.initsize -
                        ((data_run_cur->offset +
                            blkoffset_inrun) * fs->block_size +
                        byteoffset_toread);

                    memset(&a_buf[len_toread - len_remain + uninit_off], 0,
                        len_inrun - uninit_off);
                }

            }
            len_remain -= len_inrun;
        }
        return (ssize_t) (len_toread - len_remain);
    }

    tsk_error_set_errno(TSK_ERR_FS_ARG);
    tsk_error_set_errstr("tsk_fs_attr_read: Unknown attribute type: %x",
        a_fs_attr->flags);
    return -1;
}
Exemplo n.º 23
0
/**
 * Process the database to create a sorted index of it. Consecutive
 * entries with the same hash value are not added to the index, but
 * will be found during lookup.
 *
 * @param hdb_info Hash database to make index of
 * @param dbtype Text of database type (should always be TSK_HDB_DBTYPE_HK_STR)
 *
 * @return 1 on error and 0 on success.
 */
uint8_t
hk_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype)
{
    int i;
    size_t len = 0;
    char buf[TSK_HDB_MAXLEN];
    char *hash = NULL, phash[TSK_HDB_HTYPE_MD5_LEN + 1];
    TSK_OFF_T offset = 0;
    int db_cnt = 0, idx_cnt = 0, ig_cnt = 0;

    if (tsk_hdb_idxinitialize(hdb_info, dbtype)) {
        tsk_error_set_errstr2( "hk_makeindex");
        return 1;
    }
    fseek(hdb_info->hDb, 0, SEEK_SET);

    /* Status */
    if (tsk_verbose)
        TFPRINTF(stderr, _TSK_T("Extracting Data from Database (%s)\n"),
                 hdb_info->db_fname);

    /* Allocate a buffer to hold the previous hash values */
    memset(phash, '0', TSK_HDB_HTYPE_MD5_LEN + 1);

    /* read each line of the file */
    fseek(hdb_info->hDb, 0, SEEK_SET);
    for (i = 0; NULL != fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb);
         offset += (TSK_OFF_T) len, i++) {

        len = strlen(buf);

        /* Parse each line to get the MD5 value */
        if (hk_parse_md5(buf, &hash, NULL, 0, NULL, 0)) {
            ig_cnt++;
            continue;
        }
        db_cnt++;

        /* If this entry is for the same hash value as the last entry,
         * the skip it -- we'll look for it during lookup */
        if (memcmp(hash, phash, TSK_HDB_HTYPE_MD5_LEN) == 0) {
            continue;
        }

        /* Add the entry to the index */
        if (tsk_hdb_idxaddentry(hdb_info, hash, offset)) {
            tsk_error_set_errstr2( "hk_makeindex");
            return 1;
        }

        idx_cnt++;

        /* Set the previous hash value */
        strncpy(phash, hash, TSK_HDB_HTYPE_MD5_LEN + 1);
    }

    if (idx_cnt > 0) {
        if (tsk_verbose) {
            fprintf(stderr, "  Valid Database Entries: %d\n", db_cnt);
            fprintf(stderr,
                    "  Invalid Database Entries (headers or errors): %d\n",
                    ig_cnt);
            fprintf(stderr, "  Index File Entries %s: %d\n",
                    (idx_cnt == db_cnt) ? "" : "(optimized)", idx_cnt);
        }

        /* Finish the index making process */
        if (tsk_hdb_idxfinalize(hdb_info)) {
            tsk_error_set_errstr2( "hk_makeindex");
            return 1;
        }
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
        tsk_error_set_errstr(
                 "hk_makeindex: No valid entries found in database");
        return 1;
    }

    return 0;
}
Exemplo n.º 24
0
/**
 * Process the database to create a sorted index of it. Consecutive
 * entries with the same hash value are not added to the index, but
 * will be found during lookup.
 *
 * @param hdb_info Hash database to make index of.
 * @param dbtype Type of database 
 *
 * @return 1 on error and 0 on success.
 */
uint8_t
nsrl_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype)
{
    size_t i, len;
    char buf[TSK_HDB_MAXLEN];
    char *hash = NULL, phash[TSK_HDB_HTYPE_SHA1_LEN + 1];
    TSK_OFF_T offset = 0;
    int ver = 0;
    int db_cnt = 0, idx_cnt = 0, ig_cnt = 0;

    if (tsk_hdb_idxinitialize(hdb_info, dbtype)) {
        tsk_error_set_errstr2( "nsrl_makeindex");
        return 1;
    }

    /* Status */
    if (tsk_verbose)
        TFPRINTF(stderr, _TSK_T("Extracting Data from Database (%s)\n"),
                 hdb_info->db_fname);

    /* Allocate a buffer for the previous hash value */
    memset(phash, '0', TSK_HDB_HTYPE_SHA1_LEN + 1);

    /* read the file */
    fseek(hdb_info->hDb, 0, SEEK_SET);
    for (i = 0; NULL != fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb);
         offset += len, i++) {

        len = strlen(buf);

        /* Get the version of the database on the first time around */
        if (i == 0) {
            if ((ver = get_format_ver(buf)) == -1) {
                return 1;
            }
            ig_cnt++;
            continue;
        }

        /* Parse the line */
        if (hdb_info->hash_type & TSK_HDB_HTYPE_SHA1_ID) {
            if (nsrl_parse_sha1(buf, &hash, NULL, ver)) {
                ig_cnt++;
                continue;
            }
        }
        else if (hdb_info->hash_type & TSK_HDB_HTYPE_MD5_ID) {
            if (nsrl_parse_md5(buf, &hash, NULL, ver)) {
                ig_cnt++;
                continue;
            }
        }

        db_cnt++;

        /* We only want to add one of each hash to the index */
        if (memcmp(hash, phash, hdb_info->hash_len) == 0) {
            continue;
        }

        /* Add the entry to the index */
        if (tsk_hdb_idxaddentry(hdb_info, hash, offset)) {
            tsk_error_set_errstr2( "nsrl_makeindex");
            return 1;
        }

        idx_cnt++;

        /* Set the previous has value */
        strncpy(phash, hash, hdb_info->hash_len + 1);
    }

    if (idx_cnt > 0) {
        if (tsk_verbose) {
            fprintf(stderr, "  Valid Database Entries: %d\n", db_cnt);
            fprintf(stderr,
                    "  Invalid Database Entries (headers or errors): %d\n",
                    ig_cnt);
            fprintf(stderr, "  Index File Entries %s: %d\n",
                    (idx_cnt == db_cnt) ? "" : "(optimized)", idx_cnt);
        }

        /* Close and sort the index */
        if (tsk_hdb_idxfinalize(hdb_info)) {
            tsk_error_set_errstr2( "nsrl_makeindex");
            return 1;
        }
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
        tsk_error_set_errstr(
                 "nsrl_makeindex: No valid entries found in database");
        return 1;
    }

    return 0;
}
Exemplo n.º 25
0
TSK_IMG_INFO *
aff_open(const TSK_TCHAR * const images[], unsigned int a_ssize)
{
    IMG_AFF_INFO *aff_info;
    TSK_IMG_INFO *img_info;
    int type;
    char *image;

#ifdef TSK_WIN32
    // convert wchar_t* image path to char* to conform to
    // the AFFLIB API
    UTF16 *utf16 = (UTF16 *)images[0];
    size_t ilen = wcslen(utf16);
    size_t olen = ilen*4 + 1;
    UTF8 *utf8 = (UTF8 *) tsk_malloc(olen);

    image = (char *) utf8;
    if ( image == NULL )
        return NULL;
    TSKConversionResult retval =
    tsk_UTF16toUTF8_lclorder( (const UTF16 **) &utf16,
        &utf16[ilen], &utf8,
        &utf8[olen], TSKlenientConversion );
    *utf8 = '\0';
    if (retval != TSKconversionOK) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_UNICODE);
        tsk_error_set_errstr("aff_open file: %" PRIttocTSK
            ": Error converting path to UTF-8 %d\n",
            images[0], retval);
        free(image);
        return NULL;
    }
    utf8 = (UTF8 *) image;
    while ( *utf8 ) {
        if ( *utf8 > 127 ) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_UNICODE);
            tsk_error_set_errstr("aff_open file: %" PRIttocTSK
                ": Non-Latin paths are not supported for AFF images\n",
                images[0]);
            free(image);
            return NULL;
        }
        utf8++;
    }
#else
    image = (char *) tsk_malloc( strlen(images[0])+1 );
    if ( image == NULL )
        return NULL;
    strncpy(image, images[0], strlen(images[0])+1 );
#endif

    if ((aff_info =
            (IMG_AFF_INFO *) tsk_img_malloc(sizeof(IMG_AFF_INFO))) ==
        NULL) {
        free(image);
        return NULL;
    }

    img_info = (TSK_IMG_INFO *) aff_info;
    img_info->read = aff_read;
    img_info->close = aff_close;
    img_info->imgstat = aff_imgstat;

    img_info->sector_size = 512;
    if (a_ssize)
        img_info->sector_size = a_ssize;

    type = af_identify_file_type(image, 1);
    if ((type == AF_IDENTIFY_ERR) || (type == AF_IDENTIFY_NOEXIST)) {
        if (tsk_verbose) {
            tsk_fprintf(stderr,
                "aff_open: Error determining type of file: %" PRIttocTSK
                "\n", images[0]);
            perror("aff_open");
        }
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);
        tsk_error_set_errstr("aff_open file: %" PRIttocTSK
            ": Error checking type", images[0]);
        tsk_img_free(aff_info);
        free(image);
        return NULL;
    }
    else if (type == AF_IDENTIFY_AFF) {
        img_info->itype = TSK_IMG_TYPE_AFF_AFF;
    }
    else if (type == AF_IDENTIFY_AFD) {
        img_info->itype = TSK_IMG_TYPE_AFF_AFD;
    }
    else if (type == AF_IDENTIFY_AFM) {
        img_info->itype = TSK_IMG_TYPE_AFF_AFM;
    }
    else {
        img_info->itype = TSK_IMG_TYPE_AFF_ANY;
    }

    aff_info->af_file = af_open(image, O_RDONLY | O_BINARY, 0);
    if (!aff_info->af_file) {
        // @@@ Need to check here if the open failed because of an incorrect password. 
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);
        tsk_error_set_errstr("aff_open file: %" PRIttocTSK
            ": Error opening - %s", images[0], strerror(errno));
        tsk_img_free(aff_info);
        if (tsk_verbose) {
            tsk_fprintf(stderr, "Error opening AFF/AFD/AFM file\n");
            perror("aff_open");
        }
        free(image);
        return NULL;
    }
    // verify that a password was given and we can read encrypted data. 
    if (af_cannot_decrypt(aff_info->af_file)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_PASSWD);
        tsk_error_set_errstr("aff_open file: %" PRIttocTSK, images[0]);
        tsk_img_free(aff_info);
        if (tsk_verbose) {
            tsk_fprintf(stderr,
                "Error opening AFF/AFD/AFM file (incorrect password)\n");
        }
        free(image);
        return NULL;
    }

    aff_info->type = type;

    img_info->size = af_imagesize(aff_info->af_file);

    af_seek(aff_info->af_file, 0, SEEK_SET);
    aff_info->seek_pos = 0;
    free(image);
    return img_info;
}
Exemplo n.º 26
0
/**
 * \internal
 * Set the needed fields along with an initial run list for a data attribute.  To add more 
 * runs, use ...._add_run().
 *
 * @param a_fs File system the run comes from.
 * @param a_fs_attr The data attribute to initialize and add the run to
 * @param a_data_run_new The set of runs to add (can be NULL).
 * @param name Name of the attribute (can be NULL)
 * @param type Type of attribute to add run to
 * @param id Id of attribute to add run to
 * @param size Total size of the attribute (can be larger than length of initial run being added) 
 * @param init_size Number of bytes in attribute that have been initialized (less then or equal to size)
 * (note that this sets the initialized size for the attribute and it will not be updated as more runs are added).
 * @param alloc_size Allocated size of the attribute (>= size).  Identifies the slack space. 
 * (note that this sets the allocated size for the attribute and it will not be updated as more runs are added).
 * @param flags Flags about compression, sparse etc. of data
 * @param compsize Compression unit size (in case it needs to be created)
 *
 * @returns 1 on error and 0 on success
 */
uint8_t
tsk_fs_attr_set_run(TSK_FS_FILE * a_fs_file, TSK_FS_ATTR * a_fs_attr,
    TSK_FS_ATTR_RUN * a_data_run_new, const char *name,
    TSK_FS_ATTR_TYPE_ENUM type, uint16_t id, TSK_OFF_T size,
    TSK_OFF_T init_size, TSK_OFF_T alloc_size,
    TSK_FS_ATTR_FLAG_ENUM flags, uint32_t compsize)
{
    if ((a_fs_file == NULL) || (a_fs_file->meta == NULL)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("Null fs_file in tsk_fs_attr_set_run");
        return 1;
    }
    if (a_fs_attr == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("Null fs_attr in tsk_fs_attr_set_run");
        return 1;
    }

    if (alloc_size < size) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("tsk_fs_attr_set_run: alloc_size (%" PRIuOFF
            ") is less than size (%" PRIuOFF ")", alloc_size, size);
        return 1;
    }

    a_fs_attr->fs_file = a_fs_file;
    a_fs_attr->flags = (TSK_FS_ATTR_INUSE | TSK_FS_ATTR_NONRES | flags);
    a_fs_attr->type = type;
    a_fs_attr->id = id;
    a_fs_attr->size = size;
    a_fs_attr->nrd.allocsize = alloc_size;
    a_fs_attr->nrd.initsize = init_size;
    a_fs_attr->nrd.compsize = compsize;

    if (fs_attr_put_name(a_fs_attr, name)) {
        return 1;
    }

    /* Add the a_data_run_new to the attribute. */

    /* We support the ODD case where the run is NULL.  In this case, 
     * we set the attribute size info, but set everything else to NULL.
     */
    if (a_data_run_new == NULL) {
        a_fs_attr->nrd.run = NULL;
        a_fs_attr->nrd.run_end = NULL;
        return 0;
    }


    /*
     * If this is not in the begining, then we need to make a filler 
     * to account for the cluster numbers we haven't seen yet
     *
     * This commonly happens when we process an MFT entry that
     * is not a base entry and it is referenced in an $ATTR_LIST
     *
     * The $DATA attribute in the non-base have a non-zero
     * a_data_run_new->offset.  
     */
    if (a_data_run_new->offset != 0) {
        TSK_FS_ATTR_RUN *fill_run = tsk_fs_attr_run_alloc();
        fill_run->flags = TSK_FS_ATTR_RUN_FLAG_FILLER;
        fill_run->offset = 0;
        fill_run->addr = 0;
        fill_run->len = a_data_run_new->offset;
        fill_run->next = a_data_run_new;
        a_data_run_new = fill_run;
    }

    a_fs_attr->nrd.run = a_data_run_new;

    // update the pointer to the end of the list
    a_fs_attr->nrd.run_end = a_data_run_new;
    while (a_fs_attr->nrd.run_end->next) {
        a_fs_attr->nrd.run_end = a_fs_attr->nrd.run_end->next;
    }

    return 0;
}
Exemplo n.º 27
0
/* 
 * Process the partition table at the sector address 
 * 
 * It is loaded into the internal sorted list 
 */
static uint8_t
gpt_load_table(TSK_VS_INFO * vs)
{
    gpt_head *head;
    gpt_entry *ent;
    dos_sect *dos_part;
    unsigned int i, a;
    uint32_t ent_size;
    char *safe_str, *head_str, *tab_str, *ent_buf;
    ssize_t cnt;
    char *sect_buf;
    TSK_DADDR_T taddr = vs->offset / vs->block_size + GPT_PART_SOFFSET;
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector

    if (tsk_verbose)
        tsk_fprintf(stderr, "gpt_load_table: Sector: %" PRIuDADDR "\n",
            taddr);

    if ((sect_buf = tsk_malloc(vs->block_size)) == NULL)
        return 1;
    dos_part = (dos_sect *) sect_buf;

    cnt = tsk_vs_read_block
        (vs, GPT_PART_SOFFSET, sect_buf, vs->block_size);
    /* if -1, then tsk_errno is already set */
    if (cnt != vs->block_size) {
        if (cnt >= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_READ);
        }
        tsk_error_set_errstr2
            ("Error reading DOS safety partition table in Sector: %"
            PRIuDADDR, taddr);
        free(sect_buf);
        return 1;
    }

    /* Sanity Check */
    if (tsk_vs_guessu16(vs, dos_part->magic, DOS_MAGIC)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr
            ("Missing DOS safety partition (invalid magic) (Sector: %"
            PRIuDADDR ")", taddr);
        free(sect_buf);
        return 1;
    }

    if (dos_part->ptable[0].ptype != GPT_DOS_TYPE) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr
            ("Missing DOS safety partition (invalid type in table: %d)",
            dos_part->ptable[0].ptype);
        free(sect_buf);
        return 1;
    }

    /* Read the GPT header */
    head = (gpt_head *) sect_buf;
    cnt = tsk_vs_read_block
        (vs, GPT_PART_SOFFSET + 1, sect_buf, vs->block_size);
    if (cnt != vs->block_size) {
        if (cnt >= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_READ);
        }
        tsk_error_set_errstr2("GPT Header structure in Sector: %"
            PRIuDADDR, taddr + 1);
        free(sect_buf);
        return 1;
    }

    if (tsk_getu64(vs->endian, &head->signature) != GPT_HEAD_SIG) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr("GPT Header: %" PRIx64, tsk_getu64(vs->endian,
                &head->signature));
        free(sect_buf);
        return 1;
    }

    // now that we checked the sig, lets make the meta  entries
    if ((safe_str = tsk_malloc(16)) == NULL) {
        free(sect_buf);
        return 1;
    }

    snprintf(safe_str, 16, "Safety Table");
    if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 0, (TSK_DADDR_T) 1,
            TSK_VS_PART_FLAG_META, safe_str, -1, -1)) {
        free(sect_buf);
        return 1;
    }


    if ((head_str = tsk_malloc(16)) == NULL) {
        free(sect_buf);
        return 1;
    }

    snprintf(head_str, 16, "GPT Header");
    if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 1,
            (TSK_DADDR_T) ((tsk_getu32(vs->endian,
                        &head->head_size_b) + (vs->block_size-1)) / vs->block_size),
            TSK_VS_PART_FLAG_META, head_str, -1, -1)) {
        free(sect_buf);
        return 1;
    }

    /* Allocate a buffer for each table entry */
    ent_size = tsk_getu32(vs->endian, &head->tab_size_b);
    if (ent_size < sizeof(gpt_entry)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr("Header reports partition entry size of %"
            PRIu32 " and not %" PRIuSIZE "", ent_size, sizeof(gpt_entry));
        free(sect_buf);
        return 1;
    }

    if ((tab_str = tsk_malloc(20)) == NULL) {
        free(sect_buf);
        return 1;
    }

    snprintf(tab_str, 20, "Partition Table");
    if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) tsk_getu64(vs->endian,
                &head->tab_start_lba),
            (TSK_DADDR_T) ((ent_size * tsk_getu32(vs->endian,
                        &head->tab_num_ent) + (vs->block_size-1)) / vs->block_size),
            TSK_VS_PART_FLAG_META, tab_str, -1, -1)) {
        free(sect_buf);
        return 1;
    }


    /* Process the partition table */
    if ((ent_buf = tsk_malloc(vs->block_size)) == NULL) {
        free(sect_buf);
        return 1;
    }

    i = 0;
    for (a = 0; i < tsk_getu32(vs->endian, &head->tab_num_ent); a++) {
        char *name;

        /* Read a sector */
        cnt = tsk_vs_read_block(vs,
            tsk_getu64(vs->endian, &head->tab_start_lba) + a,
            ent_buf, vs->block_size);
        if (cnt != vs->block_size) {
            if (cnt >= 0) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_VS_READ);
            }
            tsk_error_set_errstr2
                ("Error reading GPT partition table sector : %" PRIuDADDR,
                tsk_getu64(vs->endian, &head->tab_start_lba) + a);
            free(ent_buf);
            free(sect_buf);
            return 1;
        }

        /* Process the sector */
        ent = (gpt_entry *) ent_buf;
        for (; (uintptr_t) ent < (uintptr_t) ent_buf + vs->block_size &&
            i < tsk_getu32(vs->endian, &head->tab_num_ent); i++) {

            UTF16 *name16;
            UTF8 *name8;
            int retVal;

            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "gpt_load: %d  Starting Sector: %" PRIu64
                    "  End: %" PRIu64 " Flag: %" PRIx64 "\n", i,
                    tsk_getu64(vs->endian, ent->start_lba),
                    tsk_getu64(vs->endian, ent->end_lba),
                    tsk_getu64(vs->endian, ent->flags));


            if (tsk_getu64(vs->endian, ent->start_lba) == 0) {
                ent++;
                continue;
            }

            // make sure the first couple are in the image bounds
            if ((i < 2)
                && (tsk_getu64(vs->endian, ent->start_lba) > max_addr)) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
                tsk_error_set_errstr
                    ("gpt_load_table: Starting sector too large for image");
                free(sect_buf);
                free(ent_buf);
                return 1;
            }


            if ((name = tsk_malloc(256)) == NULL) {
                free(sect_buf);
                free(ent_buf);
                return 1;
            }

            name16 = (UTF16 *) ((uintptr_t) ent->name);
            name8 = (UTF8 *) name;

            retVal =
                tsk_UTF16toUTF8(vs->endian, (const UTF16 **) &name16,
                (UTF16 *) ((uintptr_t) name16 + sizeof(ent->name)),
                &name8,
                (UTF8 *) ((uintptr_t) name8 + 256), TSKlenientConversion);

            if (retVal != TSKconversionOK) {
                if (tsk_verbose)
                    tsk_fprintf(stderr,
                        "gpt_load_table: Error converting name to UTF8: %d\n",
                        retVal);
                *name = '\0';
            }

            if (NULL == tsk_vs_part_add(vs,
                    (TSK_DADDR_T) tsk_getu64(vs->endian, ent->start_lba),
                    (TSK_DADDR_T) (tsk_getu64(vs->endian,
                            ent->end_lba) - tsk_getu64(vs->endian,
                            ent->start_lba) + 1), TSK_VS_PART_FLAG_ALLOC,
                    name, -1, i)) {
                free(sect_buf);
                free(ent_buf);
                return 1;
            }

            ent++;
        }
    }

    free(sect_buf);
    free(ent_buf);
    return 0;
}
Exemplo n.º 28
0
/**
 * \internal
 * Add a set of consecutive runs to an attribute. This will add and remove FILLER entries
 * as needed and update internal variables. 
 *
 * @param a_fs File system run is from
 * @param fs_attr Attribute to add run to
 * @param a_data_run_new The set of runs to add.  
 *
 * @returns 1 on error and 0 on succes
 */
uint8_t
tsk_fs_attr_add_run(TSK_FS_INFO * a_fs, TSK_FS_ATTR * a_fs_attr,
    TSK_FS_ATTR_RUN * a_data_run_new)
{
    TSK_FS_ATTR_RUN *data_run_cur, *data_run_prev;
    TSK_DADDR_T run_len;

    tsk_error_reset();

    if (a_fs_attr == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_attr_add_run: Error, a_fs_attr is NULL");
        return 1;
    }

    // we only support the case of a null run if it is the only run...
    if (a_data_run_new == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_attr_add_run: Error, a_data_run_new is NULL (%"
            PRIuINUM ")", a_fs_attr->fs_file->meta->addr);
        return 1;
    }

    run_len = 0;
    data_run_cur = a_data_run_new;
    while (data_run_cur) {
        run_len += data_run_cur->len;
        data_run_cur = data_run_cur->next;
    }

    /* First thing, is to check if we can just add it to the end */
    if ((a_fs_attr->nrd.run_end)
        && (a_fs_attr->nrd.run_end->offset + a_fs_attr->nrd.run_end->len ==
            a_data_run_new->offset)) {

        a_fs_attr->nrd.run_end->next = a_data_run_new;
        // update the pointer to the end of the list
        while (a_fs_attr->nrd.run_end->next)
            a_fs_attr->nrd.run_end = a_fs_attr->nrd.run_end->next;

        /* return head of a_fs_attr list */
        return 0;
    }

    // cycle through existing runs and see if we can add this into a filler spot
    data_run_cur = a_fs_attr->nrd.run;
    data_run_prev = NULL;
    while (data_run_cur) {

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "tsk_fs_attr_add: %" PRIuOFF "@%" PRIuOFF
                " (Filler: %s)\n", data_run_cur->offset, data_run_cur->len,
                (data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) ? "Yes"
                : "No");

        /* Do we replace this filler spot? */
        if (data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) {

            /* This should never happen because we always add 
             * the filler to start from VCN 0 */
            if (data_run_cur->offset > a_data_run_new->offset) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_GENFS);
                tsk_error_set_errstr
                    ("tsk_fs_attr_add_run: could not add data_run b.c. offset (%"
                    PRIuOFF ") is larger than FILLER (%" PRIuOFF ") (%"
                    PRIuINUM ")", a_data_run_new->offset,
                    data_run_cur->offset, a_fs_attr->fs_file->meta->addr);
                dump_attr(a_fs_attr);
                return 1;
            }

            /* Check if the new run starts inside of this filler. */
            if (data_run_cur->offset + data_run_cur->len >
                a_data_run_new->offset) {
                TSK_FS_ATTR_RUN *endrun;

                /* if the new starts at the same as the filler, 
                 * replace the pointer */
                if (data_run_cur->offset == a_data_run_new->offset) {
                    if (data_run_prev)
                        data_run_prev->next = a_data_run_new;
                    else
                        a_fs_attr->nrd.run = a_data_run_new;
                }

                /* The new run does not start at the begining of
                 * the filler, so make a new start filler
                 */
                else {
                    TSK_FS_ATTR_RUN *newfill = tsk_fs_attr_run_alloc();
                    if (newfill == NULL)
                        return 1;

                    if (data_run_prev)
                        data_run_prev->next = newfill;
                    else
                        a_fs_attr->nrd.run = newfill;

                    newfill->next = a_data_run_new;
                    newfill->len =
                        a_data_run_new->offset - data_run_cur->offset;
                    newfill->offset = data_run_cur->offset;
                    newfill->flags = TSK_FS_ATTR_RUN_FLAG_FILLER;

                    data_run_cur->len -= newfill->len;
                }

                /* get to the end of the run that we are trying to add */
                endrun = a_data_run_new;
                while (endrun->next)
                    endrun = endrun->next;

                /* if the filler is the same size as the
                 * new one, replace it 
                 */
                if (run_len == data_run_cur->len) {
                    endrun->next = data_run_cur->next;

                    // update the pointer to the end of the list (if we are the end)
                    if (endrun->next == NULL)
                        a_fs_attr->nrd.run_end = endrun;

                    free(data_run_cur);
                }
                /* else adjust the last filler entry */
                else {
                    endrun->next = data_run_cur;
                    data_run_cur->len -= run_len;
                    data_run_cur->offset =
                        a_data_run_new->offset + a_data_run_new->len;
                }

                return 0;
            }
        }

        data_run_prev = data_run_cur;
        data_run_cur = data_run_cur->next;
    }


    /* 
     * There is no filler holding the location of this run, so
     * we will add it to the end of the list 
     * 
     * we got here because it did not fit in the current list or
     * because the current list is NULL
     *
     * At this point data_run_prev is the end of the existing list or
     * 0 if there is no list
     */
    /* This is an error condition.  
     * It means that we cycled through the existing runs,
     * ended at a VCN that is larger than what we are adding,
     * and never found a filler entry to insert it into... 
     */
    if ((data_run_prev)
        && (data_run_prev->offset + data_run_prev->len >
            a_data_run_new->offset)) {

        /* MAYBE this is because of a duplicate entry .. */
        if ((data_run_prev->addr == a_data_run_new->addr) &&
            (data_run_prev->len == a_data_run_new->len)) {
            // @@@ Sould be we freeing this....?  What if the caller tries to write to it?
            tsk_fs_attr_run_free(a_data_run_new);
            return 0;
        }

        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_GENFS);
        tsk_error_set_errstr
            ("fs_attr_add_run: error adding additional run (%" PRIuINUM
            "): No filler entry for %" PRIuDADDR ". Final: %" PRIuDADDR,
            a_fs_attr->fs_file->meta->addr, a_data_run_new->offset,
            data_run_prev->offset + data_run_prev->len);
        dump_attr(a_fs_attr);
        return 1;
    }

    /* we should add it right here */
    else if (((data_run_prev)
            && (data_run_prev->offset + data_run_prev->len ==
                a_data_run_new->offset))
        || (a_data_run_new->offset == 0)) {
        if (data_run_prev)
            data_run_prev->next = a_data_run_new;
        else
            a_fs_attr->nrd.run = a_data_run_new;
    }
    /* we need to make a filler before it */
    else {
        TSK_FS_ATTR_RUN *tmprun = tsk_fs_attr_run_alloc();
        if (tmprun == NULL)
            return 1;

        if (data_run_prev) {
            data_run_prev->next = tmprun;
            tmprun->offset = data_run_prev->offset + data_run_prev->len;
        }
        else {
            a_fs_attr->nrd.run = tmprun;
        }

        tmprun->len = a_data_run_new->offset - tmprun->offset;
        tmprun->flags = TSK_FS_ATTR_RUN_FLAG_FILLER;
        tmprun->next = a_data_run_new;
    }

    // update the pointer to the end of the list
    a_fs_attr->nrd.run_end = a_data_run_new;
    while (a_fs_attr->nrd.run_end->next)
        a_fs_attr->nrd.run_end = a_fs_attr->nrd.run_end->next;

    return 0;
}
Exemplo n.º 29
0
static uint8_t
ffs_dent_copy(FFS_INFO * ffs, char *ffs_dent, TSK_FS_NAME * fs_name)
{
    TSK_FS_INFO *a_fs = &(ffs->fs_info);

    /* this one has the type field */
    if ((a_fs->ftype == TSK_FS_TYPE_FFS1)
            || (a_fs->ftype == TSK_FS_TYPE_FFS2)) {
        ffs_dentry1 *dir = (ffs_dentry1 *) ffs_dent;

        fs_name->meta_addr = tsk_getu32(a_fs->endian, dir->d_ino);

        if (fs_name->name_size != FFS_MAXNAMLEN) {
            if (tsk_fs_name_realloc(fs_name, FFS_MAXNAMLEN))
                return 1;
        }

        /* ffs null terminates so we can strncpy */
        strncpy(fs_name->name, dir->d_name, fs_name->name_size);

        switch (dir->d_type) {
        case FFS_DT_REG:
            fs_name->type = TSK_FS_NAME_TYPE_REG;
            break;
        case FFS_DT_DIR:
            fs_name->type = TSK_FS_NAME_TYPE_DIR;
            break;
        case FFS_DT_CHR:
            fs_name->type = TSK_FS_NAME_TYPE_CHR;
            break;
        case FFS_DT_BLK:
            fs_name->type = TSK_FS_NAME_TYPE_BLK;
            break;
        case FFS_DT_FIFO:
            fs_name->type = TSK_FS_NAME_TYPE_FIFO;
            break;
        case FFS_DT_SOCK:
            fs_name->type = TSK_FS_NAME_TYPE_SOCK;
            break;
        case FFS_DT_LNK:
            fs_name->type = TSK_FS_NAME_TYPE_LNK;
            break;
        case FFS_DT_WHT:
            fs_name->type = TSK_FS_NAME_TYPE_WHT;
            break;
        case FFS_DT_UNKNOWN:
        default:
            fs_name->type = TSK_FS_NAME_TYPE_UNDEF;
            break;
        }
    }
    else if (a_fs->ftype == TSK_FS_TYPE_FFS1B) {
        ffs_dentry2 *dir = (ffs_dentry2 *) ffs_dent;

        fs_name->meta_addr = tsk_getu32(a_fs->endian, dir->d_ino);

        if (fs_name->name_size != FFS_MAXNAMLEN) {
            if (tsk_fs_name_realloc(fs_name, FFS_MAXNAMLEN))
                return 1;
        }

        /* ffs null terminates so we can strncpy */
        strncpy(fs_name->name, dir->d_name, fs_name->name_size);

        fs_name->type = TSK_FS_NAME_TYPE_UNDEF;
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("ffs_dent_copy: Unknown FS type");
        return 1;
    }

    fs_name->flags = 0;
    return 0;
}
Exemplo n.º 30
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;
}