Esempio n. 1
0
/* tsk_fs_malloc - init lock after tsk_malloc 
 * This is for fs module and all it's inheritances
 */
TSK_FS_INFO *
tsk_fs_malloc(size_t a_len)
{
    TSK_FS_INFO *fs_info;
    if ((fs_info = (TSK_FS_INFO *) tsk_malloc(a_len)) == NULL)
        return NULL;
    tsk_init_lock(&fs_info->list_inum_named_lock);
    tsk_init_lock(&fs_info->orphan_dir_lock);

    fs_info->list_inum_named = NULL;

    return fs_info;
}
Esempio n. 2
0
/**
 * \internal
 * Initializes the data structures used to cache the cluster addresses that 
 * make up FAT chains in an exFAT file system, and the lock used to make the
 * data structures thread-safe. 
 *
 * @param [in, out] a_fatfs Generic FAT file system info structure.
 */
static void 
exfatfs_init_fat_cache(FATFS_INFO *a_fatfs)
{
    uint32_t i = 0;

    assert(a_fatfs != NULL);

    for (i = 0; i < FATFS_FAT_CACHE_N; i++) {
        a_fatfs->fatc_addr[i] = 0;
        a_fatfs->fatc_ttl[i] = 0;
    }

    tsk_init_lock(&a_fatfs->cache_lock);
    tsk_init_lock(&a_fatfs->dir_lock);
    a_fatfs->inum2par = NULL;
}
Esempio n. 3
0
/**
 * \internal
 * Initializes the data structure used to map inode addresses to parent inode
 * addresses in an exFAT file system, and the lock used to make the data 
 * structure thread-safe. 
 *
 * @param [in, out] a_fatfs Generic FAT file system info structure.
 */
static void 
exfatfs_init_inums_map(FATFS_INFO *a_fatfs)
{
    assert(a_fatfs != NULL);

    tsk_init_lock(&a_fatfs->dir_lock);
    a_fatfs->inum2par = NULL;
}
Esempio n. 4
0
/* tsk_img_malloc - init lock after tsk_malloc 
 * This is for img module and all its inheritances
 */
void *
tsk_img_malloc(size_t a_len)
{
    TSK_IMG_INFO *imgInfo;
    if ((imgInfo = (TSK_IMG_INFO *) tsk_malloc(a_len)) == NULL)
        return NULL;
    //init lock
    tsk_init_lock(&(imgInfo->cache_lock));
    imgInfo->tag = TSK_IMG_INFO_TAG;

    return (void *) imgInfo;
}
Esempio n. 5
0
/**
* \ingroup hashdblib
* \internal
* Initializes TSK_HDB_INFO struct with "base class" method pointers and basic
* setup of values.  
* @param hdb_info Allocated struct to initialize.
* @param db_path 
* @return 0 on success, 1 on failure.
*/
uint8_t 
    hdb_info_base_open(TSK_HDB_INFO *hdb_info, const TSK_TCHAR *db_path)
{
    // copy the database path into the struct
    size_t path_len = TSTRLEN(db_path); 
    hdb_info->db_fname = (TSK_TCHAR*)tsk_malloc((path_len + 1) * sizeof(TSK_TCHAR));
    if (!hdb_info->db_fname) {
        return 1;
    }
    TSTRNCPY(hdb_info->db_fname, db_path, path_len);

    // set the name based on path
    hdb_base_db_name_from_path(hdb_info);

    hdb_info->db_type = TSK_HDB_DBTYPE_INVALID_ID;
    tsk_init_lock(&hdb_info->lock);

    hdb_info->transaction_in_progress = 0;

    hdb_info->get_db_path = hdb_base_get_db_path;
    hdb_info->get_display_name = hdb_base_get_display_name;
    hdb_info->uses_external_indexes = hdb_base_uses_external_indexes;
    hdb_info->get_index_path = hdb_base_get_index_path;
    hdb_info->has_index = hdb_base_has_index; 
    hdb_info->make_index = hdb_base_make_index;
    hdb_info->open_index = hdb_base_open_index;
    hdb_info->lookup_str = hdb_base_lookup_str;
    hdb_info->lookup_raw = hdb_base_lookup_bin;
    hdb_info->lookup_verbose_str = hdb_base_lookup_verbose_str;
    hdb_info->accepts_updates = hdb_base_accepts_updates;
    hdb_info->add_entry = hdb_base_add_entry;
    hdb_info->begin_transaction = hdb_base_begin_transaction;
    hdb_info->commit_transaction = hdb_base_commit_transaction;
    hdb_info->rollback_transaction = hdb_base_rollback_transaction;
    hdb_info->close_db = hdb_info_base_close;

    return 0;
}
Esempio n. 6
0
File: ewf.c Progetto: 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);
}
Esempio n. 7
0
/**
    Originally we used tsk_img_open_sing(), but that leads to calling ewf_open(),
    which in turn will fail if the L01 file has an incorrect filename extension.
    This function is a simpler version of ewf_open() which will not fail if the
    filename extension is wrong.
*/
TSK_IMG_INFO * TskL01Extract::openEwfSimple()
{
    const int a_num_img = 1;
    unsigned int a_ssize = 512;
    int result = 0;
    TSK_IMG_INFO *img_info = NULL;
    ewf::libewf_error_t *ewfError = NULL;
    ewf::IMG_EWF_INFO *ewf_info = NULL;

    try
    {
        // Make an absolute path (if it's relative) so that libewf doesn't cause 
        // an error when it tries to make it absolute.
        Poco::Path tempPath(TskUtilities::toUTF8(m_archivePath));
        tempPath.makeAbsolute();
        // We convert to unicode here because that is what the TSK_IMG_INFO structure requires.
        std::wstring ewfArchivePath = TskUtilities::toUTF16(tempPath.toString());

        if ((ewf_info = (ewf::IMG_EWF_INFO *) tsk_img_malloc(sizeof(ewf::IMG_EWF_INFO))) == NULL)
        {
            throw TskException("tsk_img_malloc");
        }
        img_info = (TSK_IMG_INFO *) ewf_info;

        if (ewf::libewf_handle_initialize(&(ewf_info->handle), &ewfError) != 1)
        {
            throw TskException("libewf_handle_initialize");
        }

        //int i;
        ewf_info->num_imgs = a_num_img;
        if ((ewf_info->images = (TSK_TCHAR **) tsk_malloc(a_num_img * sizeof(TSK_TCHAR *))) == NULL)
        {
            throw TskException("tsk_malloc");
        }

        if ((ewf_info->images[0] =
            (TSK_TCHAR *) tsk_malloc((TSTRLEN(ewfArchivePath.c_str()) + 1) * sizeof(TSK_TCHAR))) == NULL)
        {
            throw TskException("tsk_malloc 2");
        }
        TSTRNCPY(ewf_info->images[0], ewfArchivePath.c_str(), TSTRLEN(ewfArchivePath.c_str()) + 1);

        ///NOTE: libewf_handle_open_wide() will not open the file if the filename length is < 4 chars long.
        ewfError = NULL;
    #if defined( TSK_WIN32 )
        if (ewf::libewf_handle_open_wide(ewf_info->handle, (TSK_TCHAR * const *) ewf_info->images,
            ewf_info->num_imgs, ewf::LIBEWF_ACCESS_FLAG_READ, &ewfError) != 1)
    #else
        if (ewf::libewf_handle_open(ewf_info->handle,
                (char *const *) ewf_info->images,
                ewf_info->num_imgs, ewf::LIBEWF_OPEN_READ, &ewfError) != 1)
    #endif
        {
            throw TskException("libewf_handle_open_wide");
        }

        ewfError = NULL;
        if (ewf::libewf_handle_get_media_size(ewf_info->handle,
                (ewf::size64_t *) & (img_info->size), &ewfError) != 1)
        {
            throw TskException("libewf_handle_get_media_size");
        }

        ewfError = NULL;
        result = ewf::libewf_handle_get_utf8_hash_value_md5(ewf_info->handle,
            (uint8_t *) ewf_info->md5hash, 33, &ewfError);

        if (result == -1)
        {
            throw TskException("libewf_handle_get_utf8_hash_value_md5");
        }
        ewf_info->md5hash_isset = result;

        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->close   = ewf_image_close;
        img_info->read    = null_read;
        img_info->imgstat = null_imgstat;

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

        return img_info;
    }
    catch (TskException &ex)
    {
        std::ostringstream msg;
        msg << "openEwfSimple: TskException: " << ex.message();
        if (ewfError)
        {
            char errorString[512];
            errorString[0] = '\0';
            ewf::libewf_error_backtrace_sprint(ewfError, errorString, 512);
            msg << " - libewf error: " << errorString << std::endl;
        }
        LOGERROR(msg.str());
        free(ewf_info);
        return NULL;
    }
}
Esempio n. 8
0
uint8_t
fatxxfs_open(FATFS_INFO *fatfs)
{
    const char *func_name = "fatxxfs_open";
	TSK_FS_INFO *fs = &(fatfs->fs_info);
	FATXXFS_SB *fatsb = (FATXXFS_SB*)(&fatfs->boot_sector_buffer);
	int i = 0;
    TSK_DADDR_T sectors = 0;
	TSK_FS_DIR * test_dir1; // Directories used to try opening the root directory

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

    /* Calculate block sizes and layout info */
    // sector size
    fatfs->ssize = tsk_getu16(fs->endian, fatsb->ssize);
    if (fatfs->ssize == 512) {
        fatfs->ssize_sh = 9;
    }
    else if (fatfs->ssize == 1024) {
        fatfs->ssize_sh = 10;
    }
    else if (fatfs->ssize == 2048) {
        fatfs->ssize_sh = 11;
    }
    else if (fatfs->ssize == 4096) {
        fatfs->ssize_sh = 12;
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr
            ("Error: sector size (%d) is not a multiple of device size (%d)\nDo you have a disk image instead of a partition image?",
            fatfs->ssize, fs->dev_bsize);
        if (tsk_verbose)
            fprintf(stderr, "%s: Invalid sector size (%d)\n",
                func_name, fatfs->ssize);
        return 1;
    }

    // cluster size 
    fatfs->csize = fatsb->csize;
    if ((fatfs->csize != 0x01) &&
        (fatfs->csize != 0x02) &&
        (fatfs->csize != 0x04) &&
        (fatfs->csize != 0x08) &&
        (fatfs->csize != 0x10) &&
        (fatfs->csize != 0x20) &&
        (fatfs->csize != 0x40) && (fatfs->csize != 0x80)) {
        if (tsk_verbose)
            fprintf(stderr, "%s: Invalid cluster size (%d)\n",
                func_name, fatfs->csize);
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr("Not a FATXX file system (cluster size)");
        return 1;
    }

    // number of FAT tables
    fatfs->numfat = fatsb->numfat;
    if ((fatfs->numfat == 0) || (fatfs->numfat > 8)) {
        if (tsk_verbose)
            fprintf(stderr, "%s: Invalid number of FATS (%d)\n",
                func_name, fatfs->numfat);
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr("Not a FATXX file system (number of FATs)");
        return 1;
    }

    /* We can't do a sanity check on this b.c. TSK_FS_TYPE_FAT32 has a value of 0 */
    /* num of root entries */
    fatfs->numroot = tsk_getu16(fs->endian, fatsb->numroot);

    /* if sectors16 is 0, then the number of sectors is stored in sectors32 */
    if (0 == (sectors = tsk_getu16(fs->endian, fatsb->sectors16)))
        sectors = tsk_getu32(fs->endian, fatsb->sectors32);

    /* if secperfat16 is 0, then read sectperfat32 */
    if (0 == (fatfs->sectperfat =
            tsk_getu16(fs->endian, fatsb->sectperfat16)))
        fatfs->sectperfat =
            tsk_getu32(fs->endian, fatsb->a.f32.sectperfat32);

    if (fatfs->sectperfat == 0) {
        if (tsk_verbose)
            fprintf(stderr,
                "%s: Invalid number of sectors per FAT (%d)\n",
                func_name, fatfs->sectperfat);
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr
            ("Not a FATXX file system (invalid sectors per FAT)");
        return 1;
    }

    fatfs->firstfatsect = tsk_getu16(fs->endian, fatsb->reserved);
    if ((fatfs->firstfatsect == 0) || (fatfs->firstfatsect > sectors)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr
            ("Not a FATXX file system (invalid first FAT sector %"
            PRIuDADDR ")", fatfs->firstfatsect);
        if (tsk_verbose)
            fprintf(stderr,
                "%s: Invalid first FAT (%" PRIuDADDR ")\n",
                func_name, fatfs->firstfatsect);
        return 1;
    }

    /* Calculate the block info
     * 
     * The sector of the beginning of the data area  - which is 
     * after all of the FATs
     *
     * For TSK_FS_TYPE_FAT12 and TSK_FS_TYPE_FAT16, the data area starts with the root
     * directory entries and then the first cluster.  For TSK_FS_TYPE_FAT32,
     * the data area starts with clusters and the root directory
     * is somewhere in the data area
     */
    fatfs->firstdatasect = fatfs->firstfatsect +
        fatfs->sectperfat * fatfs->numfat;

    /* The sector where the first cluster is located.  It will be used
     * to translate cluster addresses to sector addresses 
     *
     * For TSK_FS_TYPE_FAT32, the first cluster is the start of the data area and
     * it is after the root directory for TSK_FS_TYPE_FAT12 and TSK_FS_TYPE_FAT16.  At this
     * point in the program, numroot is set to 0 for TSK_FS_TYPE_FAT32
     */
    fatfs->firstclustsect = fatfs->firstdatasect +
        ((fatfs->numroot * 32 + fatfs->ssize - 1) / fatfs->ssize);

    /* total number of clusters */
    fatfs->clustcnt = (sectors - fatfs->firstclustsect) / fatfs->csize;

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


    /* identify the FAT type by the total number of data clusters
     * this calculation is from the MS FAT Overview Doc
     *
     * A FAT file system made by another OS could use different values
     */
    if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT_DETECT) {

        if (fatfs->clustcnt < 4085) {
            fatfs->fs_info.ftype = TSK_FS_TYPE_FAT12;
        }
        else if (fatfs->clustcnt < 65525) {
            fatfs->fs_info.ftype = TSK_FS_TYPE_FAT16;
        }
        else {
            fatfs->fs_info.ftype = TSK_FS_TYPE_FAT32;
        }

        fatfs->fs_info.ftype = fatfs->fs_info.ftype;
    }

    /* Some sanity checks */
    else {
        if ((fatfs->fs_info.ftype == TSK_FS_TYPE_FAT12)
            && (fatfs->clustcnt >= 4085)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_MAGIC);
            tsk_error_set_errstr
                ("Too many sectors for TSK_FS_TYPE_FAT12: try auto-detect mode");
            if (tsk_verbose)
                fprintf(stderr,
                    "%s: Too many sectors for FAT12\n", func_name);
            return 1;
        }
    }

    if ((fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) && (fatfs->numroot != 0)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr
            ("Invalid TSK_FS_TYPE_FAT32 image (numroot != 0)");
        if (tsk_verbose)
            fprintf(stderr, "%s: numroom != 0 for FAT32\n", func_name);
        return 1;
    }

    if ((fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) && (fatfs->numroot == 0)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr
            ("Invalid FAT image (numroot == 0, and not TSK_FS_TYPE_FAT32)");
        if (tsk_verbose)
            fprintf(stderr, "%s: numroom == 0 and not FAT32\n", func_name);
        return 1;
    }

    /* additional sanity checks if we think we are using the backup boot sector.
     * The scenario to prevent here is if fat_open is called 6 sectors before the real start
     * of the file system, then we want to detect that it was not a backup that we saw.  
     */
    if (fatfs->using_backup_boot_sector) {
        // only FAT32 has backup boot sectors..
        if (fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_MAGIC);
            tsk_error_set_errstr
                ("Invalid FAT image (Used what we thought was a backup boot sector, but it is not TSK_FS_TYPE_FAT32)");
            if (tsk_verbose)
                fprintf(stderr,
                    "%s: Had to use backup boot sector, but this isn't FAT32\n", func_name);
            return 1;
        }
        if (fatfs->numroot > 1) {
            uint8_t buf1[512];
            uint8_t buf2[512];
            int i2;
            int numDiffs;
	        ssize_t cnt = 0;

            cnt =
                tsk_fs_read(fs, fatfs->firstfatsect * fatfs->ssize,
                (char *) buf1, 512);
            if (cnt != 512) {
                if (cnt >= 0) {
                    tsk_error_reset();
                    tsk_error_set_errno(TSK_ERR_FS_READ);
                }
                tsk_error_set_errstr2("%s: FAT1", func_name);
                fs->tag = 0;
                return 1;
            }

            cnt =
                tsk_fs_read(fs,
                (fatfs->firstfatsect + fatfs->sectperfat) * fatfs->ssize,
                (char *) buf2, 512);
            if (cnt != 512) {
                if (cnt >= 0) {
                    tsk_error_reset();
                    tsk_error_set_errno(TSK_ERR_FS_READ);
                }
                tsk_error_set_errstr2("%s: FAT2", func_name);
                fs->tag = 0;
                return 1;
            }

            numDiffs = 0;
            for (i2 = 0; i2 < 512; i2++) {
                if (buf1[i2] != buf2[i2]) {
                    numDiffs++;
                }
            }
            if (numDiffs > 25) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_MAGIC);
                tsk_error_set_errstr
                    ("Invalid FAT image (Too many differences between FATS from guessing (%d diffs))",
                    numDiffs);
                if (tsk_verbose)
                    fprintf(stderr,
                        "%s: Too many differences in FAT from guessing (%d diffs)\n",
                        func_name, numDiffs);
                return 1;
            }
        }
    }

    /* Set the mask to use on the cluster values */
    if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT12) {
        fatfs->mask = FATFS_12_MASK;
    }
    else if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT16) {
        fatfs->mask = FATFS_16_MASK;
    }
    else if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) {
        fatfs->mask = FATFS_32_MASK;
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("Unknown FAT type in %s: %d\n",
            func_name, fatfs->fs_info.ftype);
        return 1;
    }
    fs->duname = "Sector";

    /* the root directories are always after the FAT for TSK_FS_TYPE_FAT12 and TSK_FS_TYPE_FAT16,
     * but are dynamically located for TSK_FS_TYPE_FAT32
     */
    if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32)
        fatfs->rootsect = FATFS_CLUST_2_SECT(fatfs,
            tsk_getu32(fs->endian, fatsb->a.f32.rootclust));
    else
        fatfs->rootsect = fatfs->firstdatasect;

    for (i = 0; i < FATFS_FAT_CACHE_N; i++) {
        fatfs->fatc_addr[i] = 0;
        fatfs->fatc_ttl[i] = 0;
    }

    /*
     * block calculations : although there are no blocks in fat, we will
     * use these fields for sector calculations
     */
    fs->first_block = 0;
    fs->block_count = sectors;
    fs->last_block = fs->last_block_act = fs->block_count - 1;
    fs->block_size = fatfs->ssize;

    // determine the last block we have in this image
    if ((TSK_DADDR_T) ((fatfs->fs_info.img_info->size - fatfs->fs_info.offset) / fs->block_size) <
        fs->block_count)
        fs->last_block_act =
            (fatfs->fs_info.img_info->size - fatfs->fs_info.offset) / fs->block_size - 1;

    /*
     * inode calculations
     */

    /* maximum number of dentries in a sector & cluster */
    fatfs->dentry_cnt_se = fatfs->ssize / sizeof(FATXXFS_DENTRY);
    fatfs->dentry_cnt_cl = fatfs->dentry_cnt_se * fatfs->csize;

    fs->root_inum = FATFS_ROOTINO;
    fs->first_inum = FATFS_FIRSTINO;

    /* Calculate inode addresses for the virtual files (MBR, one or two FATS) 
     * and the virtual orphan files directory. */
    fs->last_inum = (FATFS_SECT_2_INODE(fatfs, fs->last_block_act + 1) - 1) + FATFS_NUM_VIRT_FILES(fatfs);
    fatfs->mbr_virt_inum = fs->last_inum - FATFS_NUM_VIRT_FILES(fatfs) + 1;
    fatfs->fat1_virt_inum = fatfs->mbr_virt_inum + 1;
    if (fatfs->numfat == 2) {
        fatfs->fat2_virt_inum = fatfs->fat1_virt_inum + 1;
    }
    else {
        fatfs->fat2_virt_inum = fatfs->fat1_virt_inum;
    }

    /* Calculate the total number of inodes. */
    fs->inum_count = fs->last_inum - fs->first_inum + 1;

    /* Volume ID */
    for (fs->fs_id_used = 0; fs->fs_id_used < 4; fs->fs_id_used++) {
        if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32)
            fs->fs_id[fs->fs_id_used] =
                fatsb->a.f32.vol_id[fs->fs_id_used];
        else
            fs->fs_id[fs->fs_id_used] =
                fatsb->a.f16.vol_id[fs->fs_id_used];
    }

    /*
     * Set the function pointers  
     */

    fs->block_walk = fatfs_block_walk;
    fs->block_getflags = fatfs_block_getflags;

    fs->inode_walk = fatfs_inode_walk;
    fs->istat = fatfs_istat;
    fs->file_add_meta = fatfs_inode_lookup;

    fs->get_default_attr_type = fatfs_get_default_attr_type;
    fs->load_attrs = fatfs_make_data_runs;

    fs->dir_open_meta = fatfs_dir_open_meta;
    fs->name_cmp = fatfs_name_cmp;

    fs->fsstat = fatxxfs_fsstat;
    fs->fscheck = fatfs_fscheck;

    fs->close = fatfs_close;

    fs->jblk_walk = fatfs_jblk_walk;
    fs->jentry_walk = fatfs_jentry_walk;
    fs->jopen = fatfs_jopen;

    fatfs->is_cluster_alloc = fatxxfs_is_cluster_alloc;
    fatfs->is_dentry = fatxxfs_is_dentry;
    fatfs->dinode_copy =  fatxxfs_dinode_copy;
    fatfs->inode_lookup = fatxxfs_inode_lookup;
    fatfs->inode_walk_should_skip_dentry = fatxxfs_inode_walk_should_skip_dentry;
    fatfs->istat_attr_flags = fatxxfs_istat_attr_flags;
    fatfs->dent_parse_buf = fatxxfs_dent_parse_buf;

    // initialize the caches
    tsk_init_lock(&fatfs->cache_lock);
    tsk_init_lock(&fatfs->dir_lock);
    fatfs->inum2par = NULL;

	// Test to see if this is the odd Android case where the FAT entries have no short name
	//
	// If there are no entries found with the normal short name
	// and we find more entries by removing the short name test for allocated directories, then assume
	// this is the case where we have no short names
	fatfs->subtype = TSK_FATFS_SUBTYPE_SPEC;
	test_dir1 = tsk_fs_dir_open_meta(fs, fs->root_inum);

	if (test_dir1 != NULL && test_dir1->names_used <= 4){ // At most four automatic directories ($MBR, $FAT1, $FAT1, $OrphanFiles)
	    TSK_FS_DIR * test_dir2; //  to see if it's the Android FAT version

		fatfs->subtype = TSK_FATFS_SUBTYPE_ANDROID_1;
		test_dir2 = tsk_fs_dir_open_meta(fs, fs->root_inum);

		if (test_dir2 != NULL && test_dir2->names_used > test_dir1->names_used){
			fatfs->subtype = TSK_FATFS_SUBTYPE_ANDROID_1;
		}
		else{
			fatfs->subtype = TSK_FATFS_SUBTYPE_SPEC;
		}
		tsk_fs_dir_close(test_dir2);
	}
	tsk_fs_dir_close(test_dir1);

    return 0;
}