/* load a sparc disk label, this is called from the general
 * sun_load_table
 */
static uint8_t
sun_load_table_sparc(TSK_VS_INFO * vs, sun_dlabel_sparc * dlabel_sp)
{
    uint32_t idx = 0;
    uint32_t cyl_conv;
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector

    /* The value to convert cylinders to sectors */
    cyl_conv = tsk_getu16(vs->endian, dlabel_sp->sec_per_tr) *
        tsk_getu16(vs->endian, dlabel_sp->num_head);

    if (tsk_verbose)
        tsk_fprintf(stderr, "load_table_sparc: Number of partitions: %d\n",
            tsk_getu16(vs->endian, dlabel_sp->num_parts));

    /* Cycle through the partitions, there are either 8 or 16 */
    for (idx = 0; idx < tsk_getu16(vs->endian, dlabel_sp->num_parts);
        idx++) {
        TSK_VS_PART_FLAG_ENUM ptype = TSK_VS_PART_FLAG_ALLOC;
        uint32_t part_start = cyl_conv * tsk_getu32(vs->endian,
            dlabel_sp->part_layout[idx].start_cyl);

        uint32_t part_size = tsk_getu32(vs->endian,
            dlabel_sp->part_layout[idx].size_blk);

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "load_table_sparc: %" PRIu32
                "  Starting Sector: %" PRIu32 "  Size: %" PRIu32
                "  Type: %" PRIu16 "\n", idx, part_start, part_size,
                tsk_getu16(vs->endian, dlabel_sp->part_meta[idx].type));

        if (part_size == 0)
            continue;

        // make sure the first couple are in the image bounds
        if ((idx < 2) && (part_start > max_addr)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
            tsk_error_set_errstr
                ("sun_load_sparc: Starting sector too large for image");
            return 1;
        }

        // set the entry that covers the entire disk image as DESC
        if ((tsk_getu16(vs->endian, dlabel_sp->part_meta[idx].type) == 5)
            && (part_start == 0))
            ptype = TSK_VS_PART_FLAG_META;

        /* Add the partition to the internal sorted list */
        if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
                (TSK_DADDR_T) part_size, ptype,
                sun_get_desc(tsk_getu16(vs->endian,
                        dlabel_sp->part_meta[idx].type)), -1, idx))
            return 1;

    }

    return 0;
}
Example #2
0
/*
 * Parse a V 2.0 USN record.
 * Returns 0 on success, 1 otherwise
 */
static uint8_t
parse_v2_record(const unsigned char *buf, TSK_USN_RECORD_HEADER *header,
                TSK_USN_RECORD_V2 *record, TSK_ENDIAN_ENUM endian)
{
    uint64_t timestamp = 0;
    uint16_t name_offset = 0, name_length = 0;

    record->refnum = tsk_getu48(endian, &buf[8]);
    record->refnum_seq = tsk_getu16(endian, &buf[14]);
    record->parent_refnum = tsk_getu48(endian, &buf[16]);
    record->parent_refnum_seq = tsk_getu16(endian, &buf[22]);
    record->usn = tsk_getu64(endian, &buf[24]);

    /* Convert NT timestamp into Unix */
    timestamp = tsk_getu64(endian, &buf[32]);
    record->time_sec = nt2unixtime(timestamp);
    record->time_nsec = nt2nano(timestamp);

    record->reason = tsk_getu32(endian, &buf[40]);
    record->source_info = tsk_getu32(endian, &buf[44]);
    record->security = tsk_getu32(endian, &buf[48]);
    record->attributes = tsk_getu32(endian, &buf[52]);

    /* Extract file name */
    name_length = tsk_getu16(endian, &buf[56]);
    name_offset = tsk_getu16(endian, &buf[58]);

    return parse_fname(&buf[name_offset], name_length, record, endian);
}
Example #3
0
static void
parse_record_header(const unsigned char *buf, TSK_USN_RECORD_HEADER *header,
                    TSK_ENDIAN_ENUM endian)
{
    header->length = tsk_getu32(endian, &buf[0]);
    header->major_version = tsk_getu16(endian, &buf[4]);
    header->minor_version = tsk_getu16(endian, &buf[6]);
}
Example #4
0
/**
 * \internal
 * Parses the MBR of an exFAT file system to obtain file system size 
 * information - bytes per sector, sectors per cluster, and sectors per FAT -
 * 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_size_params(FATFS_INFO *a_fatfs)
{
    const char *func_name = "exfatfs_get_fs_size_params";
    TSK_FS_INFO *fs = &(a_fatfs->fs_info);
    EXFATFS_MASTER_BOOT_REC *exfatbs = NULL;

    assert(a_fatfs != NULL);
    
    exfatbs = (EXFATFS_MASTER_BOOT_REC*)(&a_fatfs->boot_sector_buffer);

    /* Get bytes per sector.
     * Bytes per sector is a base 2 logarithm, defining a range of sizes with 
     * a min of 512 bytes and a max of 4096 bytes. */ 
    a_fatfs->ssize_sh = (uint16_t)exfatbs->bytes_per_sector;
    if ((a_fatfs->ssize_sh < 9) || (a_fatfs->ssize_sh > 12))
    {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr("Not an exFAT file system (invalid sector size)");
        if (tsk_verbose) {
            fprintf(stderr, "%s: Invalid sector size base 2 logarithm (%d), not in range (9 - 12)\n", func_name, a_fatfs->ssize);
        }
        return FATFS_FAIL;
    }
    a_fatfs->ssize = (1 << a_fatfs->ssize_sh);

    /* Get sectors per cluster. 
     * Sectors per cluster is a base 2 logarithm. The max cluster size is 
     * 32 MiB, so the sum of the bytes per sector and sectors per cluster
     * logs cannot exceed 25. */
    if ((a_fatfs->ssize_sh + exfatbs->sectors_per_cluster) > 25) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr("Not an exFAT file system (invalid cluster size)");
        if (tsk_verbose) {
            fprintf(stderr, "%s: Invalid cluster size (%d)\n", func_name, exfatbs->sectors_per_cluster);
        }
        return FATFS_FAIL;
    }
    a_fatfs->csize = (1 << exfatbs->sectors_per_cluster);

    /* Get sectors per FAT. 
     * It will at least be non-zero. */
    a_fatfs->sectperfat = tsk_getu32(fs->endian, exfatbs->fat_len_in_sectors);
    if (a_fatfs->sectperfat == 0) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr("Not an exFAT file system (invalid sectors per FAT)");
        if (tsk_verbose) {
            fprintf(stderr, "%s: Invalid number of sectors per FAT (%d)\n", func_name, a_fatfs->sectperfat);
        }
        return FATFS_FAIL;
    }

    return FATFS_OK;
}
static uint8_t
sun_load_table_i386(TSK_VS_INFO * vs, sun_dlabel_i386 * dlabel_x86)
{
    uint32_t idx = 0;
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector

    if (tsk_verbose)
        tsk_fprintf(stderr, "load_table_i386: Number of partitions: %d\n",
            tsk_getu16(vs->endian, dlabel_x86->num_parts));

    /* Cycle through the partitions, there are either 8 or 16 */
    for (idx = 0; idx < tsk_getu16(vs->endian, dlabel_x86->num_parts);
        idx++) {

        TSK_VS_PART_FLAG_ENUM ptype = TSK_VS_PART_FLAG_ALLOC;

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "load_table_i386: %" PRIu32
                "  Starting Sector: %" PRIu32 "  Size: %" PRIu32
                "  Type: %" PRIu16 "\n", idx, tsk_getu32(vs->endian,
                    dlabel_x86->part[idx].start_sec),
                tsk_getu32(vs->endian, dlabel_x86->part[idx].size_sec),
                tsk_getu16(vs->endian, dlabel_x86->part[idx].type));

        if (tsk_getu32(vs->endian, dlabel_x86->part[idx].size_sec) == 0)
            continue;

        // make sure the first couple are in the image bounds
        if ((idx < 2) && (tsk_getu32(vs->endian,
                    dlabel_x86->part[idx].start_sec) > max_addr)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
            tsk_error_set_errstr
                ("sun_load_i386: Starting sector too large for image");
            return 1;
        }

        // set the entry that covers the entire disk image as DESC
        if ((tsk_getu16(vs->endian, dlabel_x86->part[idx].type) == 5)
            && (tsk_getu32(vs->endian,
                    dlabel_x86->part[idx].start_sec) == 0))
            ptype = TSK_VS_PART_FLAG_META;

        /* Add the partition to the internal sorted list */
        if (NULL == tsk_vs_part_add(vs,
                (TSK_DADDR_T) tsk_getu32(vs->endian,
                    dlabel_x86->part[idx].start_sec),
                (TSK_DADDR_T) tsk_getu32(vs->endian,
                    dlabel_x86->part[idx].size_sec), ptype,
                sun_get_desc(tsk_getu16(vs->endian,
                        dlabel_x86->part[idx].type)), -1, idx)) {
            return 1;
        }
    }

    return 0;
}
Example #6
0
static uint8_t
ext2fs_dent_copy(EXT2FS_INFO * ext2fs,
    char *ext2_dent, TSK_FS_NAME * fs_name)
{
    TSK_FS_INFO *fs = &(ext2fs->fs_info);

    if (ext2fs->deentry_type == EXT2_DE_V1) {
        ext2fs_dentry1 *dir = (ext2fs_dentry1 *) ext2_dent;

        fs_name->meta_addr = tsk_getu32(fs->endian, dir->inode);

        /* ext2 does not null terminate */
        if (tsk_getu16(fs->endian, dir->name_len) >= fs_name->name_size) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_ARG);
            tsk_error_set_errstr
                ("ext2fs_dent_copy: Name Space too Small %d %" PRIuSIZE "",
                tsk_getu16(fs->endian, dir->name_len), fs_name->name_size);
            return 1;
        }

        /* Copy and Null Terminate */
        strncpy(fs_name->name, dir->name, tsk_getu16(fs->endian,
                dir->name_len));
        fs_name->name[tsk_getu16(fs->endian, dir->name_len)] = '\0';

        fs_name->type = TSK_FS_NAME_TYPE_UNDEF;
    }
    else {
        ext2fs_dentry2 *dir = (ext2fs_dentry2 *) ext2_dent;

        fs_name->meta_addr = tsk_getu32(fs->endian, dir->inode);

        /* ext2 does not null terminate */
        if (dir->name_len >= fs_name->name_size) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_ARG);
            tsk_error_set_errstr
                ("ext2_dent_copy: Name Space too Small %d %" PRIuSIZE "",
                dir->name_len, fs_name->name_size);
            return 1;
        }

        /* Copy and Null Terminate */
        strncpy(fs_name->name, dir->name, dir->name_len);
        fs_name->name[dir->name_len] = '\0';

        switch (dir->type) {
        case EXT2_DE_REG:
            fs_name->type = TSK_FS_NAME_TYPE_REG;
            break;
        case EXT2_DE_DIR:
            fs_name->type = TSK_FS_NAME_TYPE_DIR;
            break;
        case EXT2_DE_CHR:
            fs_name->type = TSK_FS_NAME_TYPE_CHR;
            break;
        case EXT2_DE_BLK:
            fs_name->type = TSK_FS_NAME_TYPE_BLK;
            break;
        case EXT2_DE_FIFO:
            fs_name->type = TSK_FS_NAME_TYPE_FIFO;
            break;
        case EXT2_DE_SOCK:
            fs_name->type = TSK_FS_NAME_TYPE_SOCK;
            break;
        case EXT2_DE_LNK:
            fs_name->type = TSK_FS_NAME_TYPE_LNK;
            break;
        case EXT2_DE_UNKNOWN:
        default:
            fs_name->type = TSK_FS_NAME_TYPE_UNDEF;
            break;
        }
    }

    fs_name->flags = 0;

    return 0;
}
Example #7
0
/*
 * Load an extended partition table into the structure in TSK_VS_INFO.
 *
 * sect_cur: The sector where the extended table is located
 * sect_ext_base: The sector of the primary extended table (this does
 *   not change for recursive calls)
 * table: a counter that identifies the table depth
 *   (increases by 1 for each recursive call)
 *
 * For the primary extended table, sect_cur == sect_ext_base
 *
 * Return 1 on error and 0 on success
 *
 */
static uint8_t
dos_load_ext_table(TSK_VS_INFO * vs, TSK_DADDR_T sect_cur,
    TSK_DADDR_T sect_ext_base, int table)
{
    dos_sect *sect;
    char *sect_buf;
    int i;
    char *table_str;
    ssize_t cnt;
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector

    if (tsk_verbose)
        tsk_fprintf(stderr,
            "dos_load_ext: Table Sector: %" PRIuDADDR
            ", Primary Base Sector: %" PRIuDADDR "\n", sect_cur,
            sect_ext_base);

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

    /* Read the partition table sector */
    cnt = tsk_vs_read_block(vs, sect_cur, 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("Extended DOS table sector %" PRIuDADDR,
            sect_cur);
        free(sect_buf);
        return 1;
    }

    /* Sanity Check */
    if (tsk_getu16(vs->endian, sect->magic) != DOS_MAGIC) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr("Extended DOS partition table in sector %"
            PRIuDADDR, sect_cur);
        free(sect_buf);
        return 1;
    }

    /* Add an entry of 1 length for the table  to the internal structure */
    if ((table_str = tsk_malloc(32)) == NULL) {
        free(sect_buf);
        return 1;
    }

    snprintf(table_str, 32, "Extended Table (#%d)", table);
    if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) sect_cur,
            (TSK_DADDR_T) 1, TSK_VS_PART_FLAG_META, table_str, table,
            -1)) {
        free(sect_buf);
        return 1;
    }

    /* Cycle through the four partitions in the table
     *
     * When another extended partition is found, it is processed
     * inside of the loop
     */
    for (i = 0; i < 4; i++) {
        dos_part *part = &sect->ptable[i];

        /* Get the starting sector and size, we currently
         * ignore CHS */
        uint32_t part_start = tsk_getu32(vs->endian, part->start_sec);
        uint32_t part_size = tsk_getu32(vs->endian, part->size_sec);

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "load_ext: %d:%d    Start: %" PRIu32 "   Size: %"
                PRIu32 "  Type: %d\n", table, i, part_start, part_size,
                part->ptype);

        if (part_size == 0)
            continue;

        /* partitions are addressed differently
         * in extended partitions */
        if (dos_is_ext(part->ptype)) {

            /* part start is added to the start of the
             * first extended partition (the primary
             * extended partition) */

            if (NULL == tsk_vs_part_add(vs,
                    (TSK_DADDR_T) (sect_ext_base + part_start),
                    (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_META,
                    dos_get_desc(part->ptype), table, i)) {
                free(sect_buf);
                return 1;
            }

            if (sect_ext_base + part_start > max_addr) {
                if (tsk_verbose)
                    tsk_fprintf(stderr,
                        "Starting sector %" PRIuDADDR
                        " of extended partition too large for image\n",
                        sect_ext_base + part_start);
            }
            /* Process the extended partition */
            else if (dos_load_ext_table(vs, sect_ext_base + part_start,
                    sect_ext_base, table + 1)) {
                free(sect_buf);
                return 1;
            }
        }

        else {
            /* part_start is added to the start of the
             * current partition for the actual
             * starting location */

            // we ignore the max_addr checks on extended partitions...

            if (NULL == tsk_vs_part_add(vs,
                    (TSK_DADDR_T) (sect_cur + part_start),
                    (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC,
                    dos_get_desc(part->ptype), table, i)) {
                free(sect_buf);
                return 1;
            }
        }
    }

    free(sect_buf);
    return 0;
}
Example #8
0
/*
 * @param a_is_del Set to 1 if block is from a deleted directory.
 */
static TSK_RETVAL_ENUM
ffs_dent_parse_block(FFS_INFO * ffs, TSK_FS_DIR * fs_dir, uint8_t a_is_del,
                     char *buf, unsigned int len)
{
    unsigned int idx;
    unsigned int inode = 0, dellen = 0, reclen = 0;
    unsigned int minreclen = 4;
    TSK_FS_INFO *fs = &(ffs->fs_info);

    char *dirPtr;
    TSK_FS_NAME *fs_name;

    if ((fs_name = tsk_fs_name_alloc(FFS_MAXNAMLEN + 1, 0)) == NULL)
        return TSK_ERR;

    /* update each time by the actual length instead of the
     ** recorded length so we can view the deleted entries
     */
    for (idx = 0; idx <= len - FFS_DIRSIZ_lcl(1); idx += minreclen) {
        unsigned int namelen = 0;

        dirPtr = (char *) &buf[idx];

        /* copy to local variables */
        if ((fs->ftype == TSK_FS_TYPE_FFS1)
                || (fs->ftype == TSK_FS_TYPE_FFS2)) {
            ffs_dentry1 *dir = (ffs_dentry1 *) dirPtr;
            inode = tsk_getu32(fs->endian, dir->d_ino);
            namelen = dir->d_namlen;
            reclen = tsk_getu16(fs->endian, dir->d_reclen);
        }
        /* TSK_FS_TYPE_FFS1B */
        else if (fs->ftype == TSK_FS_TYPE_FFS1B) {
            ffs_dentry2 *dir = (ffs_dentry2 *) dirPtr;
            inode = tsk_getu32(fs->endian, dir->d_ino);
            namelen = tsk_getu16(fs->endian, dir->d_namlen);
            reclen = tsk_getu16(fs->endian, dir->d_reclen);
        }

        /* what is the minimum size needed for this entry */
        minreclen = FFS_DIRSIZ_lcl(namelen);

        /* Perform a couple sanity checks
         ** OpenBSD never zeros the inode number, but solaris
         ** does.  These checks will hopefully catch all non
         ** entries
         */
        if ((inode > fs->last_inum) ||  // inode is unsigned
                (namelen > FFS_MAXNAMLEN) ||        // namelen is unsigned
                (namelen == 0) ||
                (reclen < minreclen) || (reclen % 4) || (idx + reclen > len)) {

            /* we don't have a valid entry, so skip ahead 4 */
            minreclen = 4;
            if (dellen > 0)
                dellen -= 4;
            continue;
        }

        /* Before we process an entry in unallocated space, make
         * sure that it also ends in the unalloc space */
        if ((dellen) && (dellen < minreclen)) {
            minreclen = 4;
            dellen -= 4;
            continue;
        }

        /* the entry is valid */
        if (ffs_dent_copy(ffs, dirPtr, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }


        /* Do we have a deleted entry? (are we in a deleted space) */
        if ((dellen > 0) || (inode == 0) || (a_is_del)) {
            fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC;
            if (dellen)
                dellen -= minreclen;
        }
        else {
            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 we have some slack and an entry could exist in it, the set dellen */
        if (dellen <= 0) {
            if (reclen - minreclen >= FFS_DIRSIZ_lcl(1))
                dellen = reclen - minreclen;
            else
                minreclen = reclen;
        }
    }

    tsk_fs_name_free(fs_name);
    return TSK_OK;
}                               /* end ffs_dent_parse_block */
Example #9
0
/* 
 *
 * NoTe that this does not set the flag value.
 *
 * return 1 on error and 0 on success */
static uint8_t
ext2fs_dent_copy(EXT2FS_INFO * ext2fs, EXT2FS_DINFO * dinfo,
    char *ext2_dent, TSK_FS_DENT * fs_dent)
{
    TSK_FS_INFO *fs = &(ext2fs->fs_info);
    int i;

    if (ext2fs->deentry_type == EXT2_DE_V1) {
        ext2fs_dentry1 *dir = (ext2fs_dentry1 *) ext2_dent;

        fs_dent->inode = tsk_getu32(fs->endian, dir->inode);

        /* ext2 does not null terminate */
        if (tsk_getu16(fs->endian, dir->name_len) >= fs_dent->name_max) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_FS_ARG;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                "ext2fs_dent_copy: Name Space too Small %d %lu",
                tsk_getu16(fs->endian, dir->name_len), fs_dent->name_max);
            return 1;
        }

        /* Copy and Null Terminate */
        strncpy(fs_dent->name, dir->name, tsk_getu16(fs->endian,
                dir->name_len));
        fs_dent->name[tsk_getu16(fs->endian, dir->name_len)] = '\0';

        fs_dent->ent_type = TSK_FS_DENT_TYPE_UNDEF;
    }
    else {
        ext2fs_dentry2 *dir = (ext2fs_dentry2 *) ext2_dent;

        fs_dent->inode = tsk_getu32(fs->endian, dir->inode);

        /* ext2 does not null terminate */
        if (dir->name_len >= fs_dent->name_max) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_FS_ARG;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                "ext2_dent_copy: Name Space too Small %d %lu",
                dir->name_len, fs_dent->name_max);
            return 1;
        }

        /* Copy and Null Terminate */
        strncpy(fs_dent->name, dir->name, dir->name_len);
        fs_dent->name[dir->name_len] = '\0';

        switch (dir->type) {
        case EXT2_DE_REG_FILE:
            fs_dent->ent_type = TSK_FS_DENT_TYPE_REG;
            break;
        case EXT2_DE_DIR:
            fs_dent->ent_type = TSK_FS_DENT_TYPE_DIR;
            break;
        case EXT2_DE_CHRDEV:
            fs_dent->ent_type = TSK_FS_DENT_TYPE_CHR;
            break;
        case EXT2_DE_BLKDEV:
            fs_dent->ent_type = TSK_FS_DENT_TYPE_BLK;
            break;
        case EXT2_DE_FIFO:
            fs_dent->ent_type = TSK_FS_DENT_TYPE_FIFO;
            break;
        case EXT2_DE_SOCK:
            fs_dent->ent_type = TSK_FS_DENT_TYPE_SOCK;
            break;
        case EXT2_DE_SYMLINK:
            fs_dent->ent_type = TSK_FS_DENT_TYPE_LNK;
            break;
        case EXT2_DE_UNKNOWN:
        default:
            fs_dent->ent_type = TSK_FS_DENT_TYPE_UNDEF;
            break;
        }
    }

    /* Clean up name */
    i = 0;
    while (fs_dent->name[i] != '\0') {
        if (TSK_IS_CNTRL(fs_dent->name[i]))
            fs_dent->name[i] = '^';
        i++;
    }

    fs_dent->path = dinfo->dirs;
    fs_dent->pathdepth = dinfo->depth;

    if ((fs != NULL) && (fs_dent->inode)
        && (fs_dent->inode <= fs->last_inum)) {
        /* Get inode */
        if (fs_dent->fsi)
            tsk_fs_inode_free(fs_dent->fsi);

        if ((fs_dent->fsi = fs->inode_lookup(fs, fs_dent->inode)) == NULL) {
            strncat(tsk_errstr2, " - ext2fs_dent_copy",
                TSK_ERRSTR_L - strlen(tsk_errstr2));
            return 1;
        }
    }
    else {
        if (fs_dent->fsi)
            tsk_fs_inode_free(fs_dent->fsi);
        fs_dent->fsi = NULL;
    }
    fs_dent->flags = 0;

    return 0;
}
Example #10
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
ntfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
    TSK_INUM_T a_addr)
{
    NTFS_INFO *ntfs = (NTFS_INFO *) a_fs;
    TSK_FS_DIR *fs_dir;
    const TSK_FS_ATTR *fs_attr_root = NULL;
    const TSK_FS_ATTR *fs_attr_idx;
    char *idxalloc;
    ntfs_idxentry *idxe;
    ntfs_idxroot *idxroot;
    ntfs_idxelist *idxelist;
    ntfs_idxrec *idxrec_p, *idxrec;
    int off;
    TSK_OFF_T idxalloc_len;
    TSK_FS_LOAD_FILE load_file;
    NTFS_PAR_MAP *map;

    /* In this function, we will return immediately if we get an error.
     * If we get corruption though, we will record that in 'retval_final'
     * and continue processing. 
     */
    TSK_RETVAL_ENUM retval_final = TSK_OK;
    TSK_RETVAL_ENUM retval_tmp;

    /* sanity check */
    if (a_addr < a_fs->first_inum || a_addr > a_fs->last_inum) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_WALK_RNG;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "ntfs_dir_open_meta: inode value: %" PRIuINUM "\n", a_addr);
        return TSK_ERR;
    }
    else if (a_fs_dir == NULL) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_ARG;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "ntfs_dir_open_meta: NULL fs_attr argument given");
        return TSK_ERR;
    }

    if (tsk_verbose)
        tsk_fprintf(stderr,
            "ntfs_open_dir: 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, 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);
    }

    /* Get the inode and verify it has attributes */
    if ((fs_dir->fs_file =
            tsk_fs_file_open_meta(a_fs, NULL, a_addr)) == NULL) {
        strncat(tsk_errstr2, " - ntfs_dir_open_meta",
            TSK_ERRSTR_L - strlen(tsk_errstr2));
        return TSK_COR;
    }

    if (!(fs_dir->fs_file->meta->attr)) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_COR;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "dent_walk: Error: Directory address %" PRIuINUM
            " has no attributes", a_addr);
        return TSK_COR;
    }


    /* 
     * Read the Index Root Attribute  -- we do some sanity checking here
     * to report errors before we start to make up data for the "." and ".."
     * entries
     */
    fs_attr_root =
        tsk_fs_attrlist_get(fs_dir->fs_file->meta->attr,
        NTFS_ATYPE_IDXROOT);
    if (!fs_attr_root) {
        strncat(tsk_errstr2, " - dent_walk: $IDX_ROOT not found",
            TSK_ERRSTR_L - strlen(tsk_errstr2));
        return TSK_COR;
    }

    if (fs_attr_root->flags & TSK_FS_ATTR_NONRES) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_COR;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "dent_walk: $IDX_ROOT is not resident - it should be");
        return TSK_COR;
    }
    idxroot = (ntfs_idxroot *) fs_attr_root->rd.buf;

    /* Verify that the attribute type is $FILE_NAME */
    if (tsk_getu32(a_fs->endian, idxroot->type) == 0) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_COR;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "dent_walk: Attribute type in index root is 0");
        return TSK_COR;
    }
    else if (tsk_getu32(a_fs->endian, idxroot->type) != NTFS_ATYPE_FNAME) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_COR;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "ERROR: Directory index is sorted by type: %" PRIu32
            ".\nOnly $FNAME is currently supported",
            tsk_getu32(a_fs->endian, idxroot->type));
        return TSK_COR;
    }

    /* Get the header of the index entry list */
    idxelist = &idxroot->list;

    /* Get the offset to the start of the index entry list */
    idxe = (ntfs_idxentry *) ((uintptr_t) idxelist +
        tsk_getu32(a_fs->endian, idxelist->begin_off));

    /* 
     * NTFS does not have "." and ".." entries in the index trees
     * (except for a "." entry in the root directory)
     * 
     * So, we'll make 'em up by making a TSK_FS_NAME structure for
     * a '.' and '..' entry and call the action
     */
    if (a_addr != a_fs->root_inum) {    // && (flags & TSK_FS_NAME_FLAG_ALLOC)) {
        TSK_FS_NAME *fs_name;
        TSK_FS_META_NAME_LIST *fs_name_list;

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "ntfs_dir_open_meta: Creating . and .. entries\n");

        if ((fs_name = tsk_fs_name_alloc(16, 0)) == NULL) {
            return TSK_ERR;
        }
        /* 
         * "." 
         */
        fs_name->meta_addr = a_addr;
        fs_name->meta_seq = fs_dir->fs_file->meta->seq;
        fs_name->type = TSK_FS_NAME_TYPE_DIR;
        strcpy(fs_name->name, ".");

        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;
        }


        /*
         * ".."
         */
        strcpy(fs_name->name, "..");
        fs_name->type = TSK_FS_NAME_TYPE_DIR;

        /* The fs_name structure holds the parent inode value, so we 
         * just cycle using those
         */
        for (fs_name_list = fs_dir->fs_file->meta->name2;
            fs_name_list != NULL; fs_name_list = fs_name_list->next) {
            fs_name->meta_addr = fs_name_list->par_inode;
            fs_name->meta_seq = fs_name_list->par_seq;
            if (tsk_fs_dir_add(fs_dir, fs_name)) {
                tsk_fs_name_free(fs_name);
                return TSK_ERR;
            }
        }

        tsk_fs_name_free(fs_name);
        fs_name = NULL;
    }

    /* Now we return to processing the Index Root Attribute */
    if (tsk_verbose)
        tsk_fprintf(stderr,
            "ntfs_dir_open_meta: Processing $IDX_ROOT of inum %" PRIuINUM
            "\n", a_addr);

    /* Verify the offset pointers */
    if ((tsk_getu32(a_fs->endian, idxelist->seqend_off) <
            tsk_getu32(a_fs->endian, idxelist->begin_off)) ||
        (tsk_getu32(a_fs->endian, idxelist->bufend_off) <
            tsk_getu32(a_fs->endian, idxelist->seqend_off)) ||
        (((uintptr_t) idxe + tsk_getu32(a_fs->endian,
                    idxelist->bufend_off)) >
            ((uintptr_t) fs_attr_root->rd.buf +
                fs_attr_root->rd.buf_size))) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_COR;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "Error: Index list offsets are invalid on entry: %" PRIuINUM,
            fs_dir->fs_file->meta->addr);
        return TSK_COR;
    }

    retval_tmp = ntfs_proc_idxentry(ntfs, fs_dir,
        (fs_dir->fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC) ? 1 : 0,
        idxe,
        tsk_getu32(a_fs->endian, idxelist->bufend_off) -
        tsk_getu32(a_fs->endian, idxelist->begin_off),
        tsk_getu32(a_fs->endian, idxelist->seqend_off) -
        tsk_getu32(a_fs->endian, idxelist->begin_off));

    // stop if we get an error, continue if we got corruption
    if (retval_tmp == TSK_ERR) {
        return TSK_ERR;
    }
    else if (retval_tmp == TSK_COR) {
        retval_final = TSK_COR;
    }

    /* 
     * get the index allocation attribute if it exists (it doesn't for 
     * small directories 
     */
    fs_attr_idx =
        tsk_fs_attrlist_get(fs_dir->fs_file->meta->attr,
        NTFS_ATYPE_IDXALLOC);


    /* if we don't have an index alloc then return, we have processed
     * all of the entries 
     */
    if (!fs_attr_idx) {
        if (tsk_getu32(a_fs->endian,
                idxelist->flags) & NTFS_IDXELIST_CHILD) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_FS_INODE_COR;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                "Error: $IDX_ROOT says there should be children, but there isn't");
            return TSK_COR;
        }
    }
    else {

        if (fs_attr_idx->flags & TSK_FS_ATTR_RES) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_FS_INODE_COR;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                "$IDX_ALLOC is Resident - it shouldn't be");
            return TSK_COR;
        }

        /* 
         * Copy the index allocation run into a big buffer
         */
        idxalloc_len = fs_attr_idx->nrd.allocsize;
        if ((idxalloc = tsk_malloc((size_t) idxalloc_len)) == NULL) {
            return TSK_ERR;
        }

        /* Fill in the loading data structure */
        load_file.total = load_file.left = (size_t) idxalloc_len;
        load_file.cur = load_file.base = idxalloc;

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "ntfs_dir_open_meta: Copying $IDX_ALLOC into buffer\n");

        if (tsk_fs_attr_walk(fs_attr_idx,
                TSK_FS_FILE_WALK_FLAG_SLACK, tsk_fs_load_file_action,
                (void *) &load_file)) {
            free(idxalloc);
            strncat(tsk_errstr2, " - ntfs_dir_open_meta",
                TSK_ERRSTR_L - strlen(tsk_errstr2));
            return TSK_COR;     // this could be an error though
        }

        /* Not all of the directory was copied, so we exit */
        if (load_file.left > 0) {
            free(idxalloc);

            tsk_error_reset();
            tsk_errno = TSK_ERR_FS_FWALK;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                "Error reading directory contents: %" PRIuINUM "\n",
                a_addr);
            return TSK_COR;
        }

        /*
         * The idxalloc is a big buffer that contains one or more
         * idx buffer structures.  Each idxrec is a node in the B-Tree.  
         * We do not process the tree as a tree because then we could
         * not find the deleted file names.
         *
         * Therefore, we scan the big buffer looking for the index record
         * structures.  We save a pointer to the known beginning (idxrec_p).
         * Then we scan for the beginning of the next one (idxrec) and process
         * everything in the middle as an ntfs_idxrec.  We can't use the
         * size given because then we wouldn't see the deleted names
         */

        /* Set the previous pointer to NULL */
        idxrec_p = idxrec = NULL;

        /* Loop by cluster size */
        for (off = 0; off < idxalloc_len; off += ntfs->csize_b) {
            uint32_t list_len, rec_len;

            idxrec = (ntfs_idxrec *) & idxalloc[off];

            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "ntfs_dir_open_meta: Index Buffer Offset: %d  Magic: %"
                    PRIx32 "\n", off, tsk_getu32(a_fs->endian,
                        idxrec->magic));

            /* Is this the begining of an index record? */
            if (tsk_getu32(a_fs->endian,
                    idxrec->magic) != NTFS_IDXREC_MAGIC)
                continue;


            /* idxrec_p is only NULL for the first time 
             * Set it and start again to find the next one */
            if (idxrec_p == NULL) {
                idxrec_p = idxrec;
                continue;
            }

            /* Process the previous structure */

            /* idxrec points to the next idxrec structure, idxrec_p
             * points to the one we are going to process
             */
            rec_len =
                (uint32_t) ((uintptr_t) idxrec - (uintptr_t) idxrec_p);

            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "ntfs_dir_open_meta: Processing previous index record (len: %"
                    PRIu32 ")\n", rec_len);

            /* remove the update sequence in the index record */
            if (ntfs_fix_idxrec(ntfs, idxrec_p, rec_len)) {
                free(idxalloc);
                return TSK_COR;
            }

            /* Locate the start of the index entry list */
            idxelist = &idxrec_p->list;
            idxe = (ntfs_idxentry *) ((uintptr_t) idxelist +
                tsk_getu32(a_fs->endian, idxelist->begin_off));

            /* the length from the start of the next record to where our
             * list starts.
             * This should be the same as bufend_off in idxelist, but we don't
             * trust it.
             */
            list_len = (uint32_t) ((uintptr_t) idxrec - (uintptr_t) idxe);

            /* Verify the offset pointers */
            if (((uintptr_t) idxe > (uintptr_t) idxrec) ||
                ((uintptr_t) idxelist +
                    tsk_getu32(a_fs->endian,
                        idxelist->seqend_off) > (uintptr_t) idxrec)) {
                tsk_error_reset();
                tsk_errno = TSK_ERR_FS_INODE_COR;
                snprintf(tsk_errstr, TSK_ERRSTR_L,
                    "Error: Index list offsets are invalid on entry: %"
                    PRIuINUM, fs_dir->fs_file->meta->addr);
                free(idxalloc);
                return TSK_COR;
            }


            /* process the list of index entries */
            retval_tmp = ntfs_proc_idxentry(ntfs, fs_dir,
                (fs_dir->fs_file->
                    meta->flags & TSK_FS_META_FLAG_UNALLOC) ? 1 : 0, idxe,
                list_len, tsk_getu32(a_fs->endian,
                    idxelist->seqend_off) - tsk_getu32(a_fs->endian,
                    idxelist->begin_off));
            // stop if we get an error, record if we get corruption
            if (retval_tmp == TSK_ERR) {
                free(idxalloc);
                return TSK_ERR;
            }
            else if (retval_tmp == TSK_COR) {
                retval_final = TSK_COR;
            }

            /* reset the pointer to the next record */
            idxrec_p = idxrec;

        }                       /* end of cluster loop */


        /* Process the final record */
        if (idxrec_p) {
            uint32_t list_len, rec_len;

            /* Length from end of attribute to start of this */
            rec_len =
                (uint32_t) (idxalloc_len - (uintptr_t) idxrec_p -
                (uintptr_t) idxalloc);

            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "ntfs_dir_open_meta: Processing final index record (len: %"
                    PRIu32 ")\n", rec_len);

            /* remove the update sequence */
            if (ntfs_fix_idxrec(ntfs, idxrec_p, rec_len)) {
                free(idxalloc);
                return TSK_COR;
            }

            idxelist = &idxrec_p->list;
            idxe = (ntfs_idxentry *) ((uintptr_t) idxelist +
                tsk_getu32(a_fs->endian, idxelist->begin_off));

            /* This is the length of the idx entries */
            list_len =
                (uint32_t) ((uintptr_t) idxalloc + idxalloc_len) -
                (uintptr_t) idxe;

            /* Verify the offset pointers */
            if ((list_len > rec_len) ||
                ((uintptr_t) idxelist +
                    tsk_getu32(a_fs->endian, idxelist->seqend_off) >
                    (uintptr_t) idxalloc + idxalloc_len)) {
                tsk_error_reset();
                tsk_errno = TSK_ERR_FS_INODE_COR;
                snprintf(tsk_errstr, TSK_ERRSTR_L,
                    "Error: Index list offsets are invalid on entry: %"
                    PRIuINUM, fs_dir->fs_file->meta->addr);
                free(idxalloc);
                return TSK_COR;
            }

            /* process the list of index entries */
            retval_tmp = ntfs_proc_idxentry(ntfs, fs_dir,
                (fs_dir->fs_file->
                    meta->flags & TSK_FS_META_FLAG_UNALLOC) ? 1 : 0, idxe,
                list_len, tsk_getu32(a_fs->endian,
                    idxelist->seqend_off) - tsk_getu32(a_fs->endian,
                    idxelist->begin_off));
            // stop if we get an error, record if we get corruption
            if (retval_tmp == TSK_ERR) {
                free(idxalloc);
                return TSK_ERR;
            }
            else if (retval_tmp == TSK_COR) {
                retval_final = TSK_COR;
            }
        }

        free(idxalloc);
    }


    // get the orphan files
    // load and cache the map if it has not already been done
    if (ntfs->orphan_map == NULL) {
        if (a_fs->inode_walk(a_fs, a_fs->first_inum, a_fs->last_inum,
                TSK_FS_META_FLAG_UNALLOC, ntfs_orphan_act, NULL)) {
            return TSK_ERR;
        }
    }

    // see if there are any entries for this dir
    map = ntfs_orphan_map_get(ntfs, a_addr);
    if (map != NULL) {
        int a;
        TSK_FS_NAME *fs_name;
        TSK_FS_FILE *fs_file_orp = NULL;

        if ((fs_name = tsk_fs_name_alloc(256, 0)) == NULL)
            return TSK_ERR;

        fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC;
        fs_name->type = TSK_FS_NAME_TYPE_UNDEF;

        for (a = 0; a < map->used_cnt; a++) {
            /* Fill in the basics of the fs_name entry 
             * so we can print in the fls formats */
            fs_name->meta_addr = map->addrs[a];

            // lookup the file to get its name (we did not cache that)
            fs_file_orp =
                tsk_fs_file_open_meta(a_fs, fs_file_orp, map->addrs[a]);
            if ((fs_file_orp) && (fs_file_orp->meta)
                && (fs_file_orp->meta->name2)) {
                TSK_FS_META_NAME_LIST *n2 = fs_file_orp->meta->name2;
                while (n2) {
                    if (n2->par_inode == a_addr) {
                        strncpy(fs_name->name, n2->name,
                            fs_name->name_size);
                        tsk_fs_dir_add(fs_dir, fs_name);
                    }
                    n2 = n2->next;
                }
            }
        }
        tsk_fs_name_free(fs_name);
    }

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

        if ((fs_name = tsk_fs_name_alloc(256, 0)) == 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;
}
Example #11
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;
}
Example #12
0
static uint8_t
ntfs_dent_walk_lcl(TSK_FS_INFO * fs, NTFS_DINFO * dinfo,
                   TSK_LIST ** list_seen, INUM_T inum, TSK_FS_DENT_FLAG_ENUM flags,
                   TSK_FS_DENT_TYPE_WALK_CB action, void *ptr)
{
    NTFS_INFO *ntfs = (NTFS_INFO *) fs;
    TSK_FS_INODE *fs_inode;
    TSK_FS_DATA *fs_data_root, *tsk_fs_data_alloc;
    char *idxalloc;
    ntfs_idxentry *idxe;
    ntfs_idxroot *idxroot;
    ntfs_idxelist *idxelist;
    ntfs_idxrec *idxrec_p, *idxrec;
    int off;
    OFF_T idxalloc_len;
    TSK_FS_LOAD_FILE load_file;
    int retval;

    /* sanity check */
    if (inum < fs->first_inum || inum > fs->last_inum) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_WALK_RNG;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
                 "ntfs_dent_walk: inode value: %" PRIuINUM "\n", inum);
        return 1;
    }

    if (tsk_verbose)
        tsk_fprintf(stderr,
                    "ntfs_dent_walk: Processing directory %" PRIuINUM
                    " with flags %x\n", inum, flags);

    /* Get the inode and verify it has attributes */
    fs_inode = fs->inode_lookup(fs, inum);
    if (!fs_inode) {
        strncat(tsk_errstr2, " - ntfs_dent_walk",
                TSK_ERRSTR_L - strlen(tsk_errstr2));
        return 1;
    }
    if (!fs_inode->attr) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_INT;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
                 "dent_walk: Error: Directory address %" PRIuINUM
                 " has no attributes", inum);
        return 1;
    }


    /*
     * Read the Index Root Attribute  -- we do some sanity checking here
     * to report errors before we start to make up data for the "." and ".."
     * entries
     */
    fs_data_root =
        tsk_fs_data_lookup_noid(fs_inode->attr, NTFS_ATYPE_IDXROOT);
    if (!fs_data_root) {
        strncat(tsk_errstr2, " - dent_walk: $IDX_ROOT not found",
                TSK_ERRSTR_L - strlen(tsk_errstr2));
        tsk_fs_inode_free(fs_inode);
        return 1;
    }

    if (fs_data_root->flags & TSK_FS_DATA_NONRES) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_INT;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
                 "dent_walk: $IDX_ROOT is not resident - it should be");
        tsk_fs_inode_free(fs_inode);
        return 1;
    }
    idxroot = (ntfs_idxroot *) fs_data_root->buf;

    /* Verify that the attribute type is $FILE_NAME */
    if (tsk_getu32(fs->endian, idxroot->type) == 0) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_INT;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
                 "dent_walk: Attribute type in index root is 0");
        tsk_fs_inode_free(fs_inode);
        return 1;
    }
    else if (tsk_getu32(fs->endian, idxroot->type) != NTFS_ATYPE_FNAME) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_INT;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
                 "ERROR: Directory index is sorted by type: %" PRIu32
                 ".\nOnly $FNAME is currently supported", tsk_getu32(fs->endian,
                         idxroot->type));
        return 1;
    }

    /* Get the header of the index entry list */
    idxelist = &idxroot->list;

    /* Get the offset to the start of the index entry list */
    idxe = (ntfs_idxentry *) ((uintptr_t) idxelist +
                              tsk_getu32(fs->endian, idxelist->begin_off));

    /*
     * NTFS does not have "." and ".." entries in the index trees
     * (except for a "." entry in the root directory)
     *
     * So, we'll make 'em up by making a TSK_FS_DENT structure for
     * a '.' and '..' entry and call the action
     */
    if ((inum != fs->root_inum) && (flags & TSK_FS_DENT_FLAG_ALLOC)) {
        TSK_FS_DENT *fs_dent;
        TSK_FS_INODE_NAME_LIST *fs_name;

        if (tsk_verbose)
            tsk_fprintf(stderr,
                        "ntfs_dent_walk: Creating . and .. entries\n");

        if ((fs_dent = tsk_fs_dent_alloc(16, 0)) == NULL) {
            tsk_fs_inode_free(fs_inode);
            return 1;
        }
        /*
         * "."
         */
        fs_dent->inode = inum;
        strcpy(fs_dent->name, ".");

        /* copy the path data */
        fs_dent->path = dinfo->dirs;
        fs_dent->pathdepth = dinfo->depth;

        fs_dent->flags = TSK_FS_DENT_FLAG_ALLOC;

        /* this is probably a waste, but just in case the action mucks
         * with it ...
         */
        fs_dent->fsi = fs->inode_lookup(fs, fs_dent->inode);
        if (fs_dent->fsi != NULL) {
            fs_dent->ent_type = TSK_FS_DENT_TYPE_DIR;

            retval = action(fs, fs_dent, ptr);
            if (retval == TSK_WALK_STOP) {
                tsk_fs_dent_free(fs_dent);
                tsk_fs_inode_free(fs_inode);
                return 0;
            }
            else if (retval == TSK_WALK_ERROR) {
                tsk_fs_dent_free(fs_dent);
                tsk_fs_inode_free(fs_inode);
                return 1;
            }
        }
        else {
            if (tsk_verbose)
                tsk_fprintf(stderr, "Error reading . entry: %" PRIuINUM,
                            fs_dent->inode);
        }


        /*
         * ".."
         */
        strcpy(fs_dent->name, "..");
        fs_dent->ent_type = TSK_FS_DENT_TYPE_DIR;

        /* The fs_name structure holds the parent inode value, so we
         * just cycle using those
         */
        for (fs_name = fs_inode->name; fs_name != NULL;
                fs_name = fs_name->next) {
            if (fs_dent->fsi) {
                tsk_fs_inode_free(fs_dent->fsi);
                fs_dent->fsi = NULL;
            }

            fs_dent->inode = fs_name->par_inode;
            fs_dent->fsi = fs->inode_lookup(fs, fs_dent->inode);
            if (fs_dent->fsi) {
                retval = action(fs, fs_dent, ptr);
                if (retval == TSK_WALK_STOP) {
                    tsk_fs_dent_free(fs_dent);
                    tsk_fs_inode_free(fs_inode);
                    return 0;
                }
                else if (retval == TSK_WALK_ERROR) {
                    tsk_fs_dent_free(fs_dent);
                    tsk_fs_inode_free(fs_inode);
                    return 1;
                }
            }
            else {
                if (tsk_verbose)
                    tsk_fprintf(stderr,
                                "dent_walk: Error reading .. inode: %"
                                PRIuINUM, fs_dent->inode);
            }

        }

        tsk_fs_dent_free(fs_dent);
        fs_dent = NULL;
    }

    /* Now we return to processing the Index Root Attribute */
    if (tsk_verbose)
        tsk_fprintf(stderr,
                    "ntfs_dent_walk: Processing $IDX_ROOT of inum %" PRIuINUM "\n",
                    inum);

    /* Verify the offset pointers */
    if ((tsk_getu32(fs->endian, idxelist->seqend_off) <
            tsk_getu32(fs->endian, idxelist->begin_off)) ||
            (tsk_getu32(fs->endian, idxelist->bufend_off) <
             tsk_getu32(fs->endian, idxelist->seqend_off)) ||
            (((uintptr_t) idxe + tsk_getu32(fs->endian,
                                            idxelist->bufend_off)) >
             ((uintptr_t) fs_data_root->buf + fs_data_root->buflen))) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_INT;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
                 "Error: Index list offsets are invalid on entry: %" PRIuINUM,
                 fs_inode->addr);
        tsk_fs_inode_free(fs_inode);
        return 1;
    }

    retval = ntfs_dent_idxentry(ntfs, dinfo, list_seen, idxe,
                                tsk_getu32(fs->endian, idxelist->bufend_off) -
                                tsk_getu32(fs->endian, idxelist->begin_off),
                                tsk_getu32(fs->endian, idxelist->seqend_off) -
                                tsk_getu32(fs->endian, idxelist->begin_off), flags, action, ptr);

    if (retval != 0) {
        tsk_fs_inode_free(fs_inode);
        return (retval == -1) ? 1 : 0;
    }

    /*
     * get the index allocation attribute if it exists (it doesn't for
     * small directories
     */
    tsk_fs_data_alloc =
        tsk_fs_data_lookup_noid(fs_inode->attr, NTFS_ATYPE_IDXALLOC);


    /* if we don't have an index alloc then return, we have processed
     * all of the entries
     */
    if (!tsk_fs_data_alloc) {
        int retval;
        if (tsk_getu32(fs->endian, idxelist->flags) & NTFS_IDXELIST_CHILD) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_FS_INODE_INT;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                     "Error: $IDX_ROOT says there should be children, but there isn't");
            retval = 1;
        }
        else {
            retval = 0;
        }
        tsk_fs_inode_free(fs_inode);
        return retval;
    }


    if (tsk_fs_data_alloc->flags & TSK_FS_DATA_RES) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_INODE_INT;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
                 "$IDX_ALLOC is Resident - it shouldn't be");
        tsk_fs_inode_free(fs_inode);
        return 1;
    }

    /*
     * Copy the index allocation run into a big buffer
     */
    idxalloc_len = tsk_fs_data_alloc->allocsize;
    if ((idxalloc = tsk_malloc((size_t) idxalloc_len)) == NULL) {
        tsk_fs_inode_free(fs_inode);
        return 1;
    }

    /* Fill in the loading data structure */
    load_file.total = load_file.left = (size_t) idxalloc_len;
    load_file.cur = load_file.base = idxalloc;

    if (tsk_verbose)
        tsk_fprintf(stderr,
                    "ntfs_dent_walk: Copying $IDX_ALLOC into buffer\n");

    if (ntfs_data_walk(ntfs, fs_inode->addr, tsk_fs_data_alloc,
                       TSK_FS_FILE_FLAG_SLACK, tsk_fs_load_file_action,
                       (void *) &load_file)) {
        free(idxalloc);
        tsk_fs_inode_free(fs_inode);
        strncat(tsk_errstr2, " - ntfs_dent_walk",
                TSK_ERRSTR_L - strlen(tsk_errstr2));
        return 1;
    }

    /* Not all of the directory was copied, so we exit */
    if (load_file.left > 0) {
        free(idxalloc);
        tsk_fs_inode_free(fs_inode);

        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_FWALK;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
                 "Error reading directory contents: %" PRIuINUM "\n", inum);
        return 1;
    }

    /*
     * The idxalloc is a big buffer that contains one or more
     * idx buffer structures.  Each idxrec is a node in the B-Tree.
     * We do not process the tree as a tree because then we could
     * not find the deleted file names.
     *
     * Therefore, we scan the big buffer looking for the index record
     * structures.  We save a pointer to the known beginning (idxrec_p).
     * Then we scan for the beginning of the next one (idxrec) and process
     * everything in the middle as an ntfs_idxrec.  We can't use the
     * size given because then we wouldn't see the deleted names
     */

    /* Set the previous pointer to NULL */
    idxrec_p = idxrec = NULL;

    /* Loop by cluster size */
    for (off = 0; off < idxalloc_len; off += ntfs->csize_b) {
        uint32_t list_len, rec_len;

        idxrec = (ntfs_idxrec *) & idxalloc[off];

        if (tsk_verbose)
            tsk_fprintf(stderr,
                        "ntfs_dent_walk: Index Buffer Offset: %d  Magic: %"
                        PRIx32 "\n", off, tsk_getu32(fs->endian, idxrec->magic));

        /* Is this the begining of an index record? */
        if (tsk_getu32(fs->endian, idxrec->magic) != NTFS_IDXREC_MAGIC)
            continue;


        /* idxrec_p is only NULL for the first time
         * Set it and start again to find the next one */
        if (idxrec_p == NULL) {
            idxrec_p = idxrec;
            continue;
        }

        /* Process the previous structure */

        /* idxrec points to the next idxrec structure, idxrec_p
         * points to the one we are going to process
         */
        rec_len = (uint32_t) ((uintptr_t) idxrec - (uintptr_t) idxrec_p);

        if (tsk_verbose)
            tsk_fprintf(stderr,
                        "ntfs_dent_walk: Processing previous index record (len: %"
                        PRIu32 ")\n", rec_len);

        /* remove the update sequence in the index record */
        if (ntfs_fix_idxrec(ntfs, idxrec_p, rec_len)) {
            free(idxalloc);
            tsk_fs_inode_free(fs_inode);
            return 1;
        }

        /* Locate the start of the index entry list */
        idxelist = &idxrec_p->list;
        idxe = (ntfs_idxentry *) ((uintptr_t) idxelist +
                                  tsk_getu32(fs->endian, idxelist->begin_off));

        /* the length from the start of the next record to where our
         * list starts.
         * This should be the same as bufend_off in idxelist, but we don't
         * trust it.
         */
        list_len = (uint32_t) ((uintptr_t) idxrec - (uintptr_t) idxe);

        /* Verify the offset pointers */
        if (((uintptr_t) idxe > (uintptr_t) idxrec) ||
                ((uintptr_t) idxelist +
                 tsk_getu32(fs->endian,
                            idxelist->seqend_off) > (uintptr_t) idxrec)) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_FS_INODE_INT;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                     "Error: Index list offsets are invalid on entry: %"
                     PRIuINUM, fs_inode->addr);
            tsk_fs_inode_free(fs_inode);
            free(idxalloc);
            return 1;
        }


        /* process the list of index entries */
        retval = ntfs_dent_idxentry(ntfs, dinfo, list_seen, idxe, list_len,
                                    tsk_getu32(fs->endian, idxelist->seqend_off) -
                                    tsk_getu32(fs->endian, idxelist->begin_off), flags, action,
                                    ptr);
        if (retval != 0) {
            tsk_fs_inode_free(fs_inode);
            free(idxalloc);
            return (retval == -1) ? 1 : 0;
        }

        /* reset the pointer to the next record */
        idxrec_p = idxrec;

    }                           /* end of cluster loop */


    /* Process the final record */
    if (idxrec_p) {
        uint32_t list_len, rec_len;

        /* Length from end of attribute to start of this */
        rec_len =
            (uint32_t) (idxalloc_len - (uintptr_t) idxrec_p -
                        (uintptr_t) idxalloc);

        if (tsk_verbose)
            tsk_fprintf(stderr,
                        "ntfs_dent_walk: Processing final index record (len: %"
                        PRIu32 ")\n", rec_len);

        /* remove the update sequence */
        if (ntfs_fix_idxrec(ntfs, idxrec_p, rec_len)) {
            tsk_fs_inode_free(fs_inode);
            free(idxalloc);
            return 1;
        }

        idxelist = &idxrec_p->list;
        idxe = (ntfs_idxentry *) ((uintptr_t) idxelist +
                                  tsk_getu32(fs->endian, idxelist->begin_off));

        /* This is the length of the idx entries */
        list_len =
            (uint32_t) ((uintptr_t) idxalloc + idxalloc_len) -
            (uintptr_t) idxe;

        /* Verify the offset pointers */
        if ((list_len > rec_len) ||
                ((uintptr_t) idxelist +
                 tsk_getu32(fs->endian, idxelist->seqend_off) >
                 (uintptr_t) idxalloc + idxalloc_len)) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_FS_INODE_INT;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                     "Error: Index list offsets are invalid on entry: %"
                     PRIuINUM, fs_inode->addr);
            tsk_fs_inode_free(fs_inode);
            free(idxalloc);
            return 1;
        }

        /* process the list of index entries */
        retval = ntfs_dent_idxentry(ntfs, dinfo, list_seen, idxe, list_len,
                                    tsk_getu32(fs->endian, idxelist->seqend_off) -
                                    tsk_getu32(fs->endian, idxelist->begin_off), flags, action,
                                    ptr);
        if (retval != 0) {
            tsk_fs_inode_free(fs_inode);
            free(idxalloc);
            return (retval == -1) ? 1 : 0;
        }
    }

    tsk_fs_inode_free(fs_inode);
    free(idxalloc);

    return 0;
}                               /* end of dent_walk */
Example #13
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_errno = TSK_ERR_FS_GENFS;
           snprintf(tsk_errstr, TSK_ERRSTR_L,
           "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_errno = TSK_ERR_FS_GENFS;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                "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_uni2ascii(fs, (uint8_t *) cur_key->name.unicode,
                    tsk_getu16(hfs->fs_info.endian, cur_key->name.length),
                    info->fs_name->name, HFS_MAXNAMLEN + 1)) {
                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];
            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_uni2ascii(fs, (uint8_t *) cur_key->name.unicode,
                    tsk_getu16(hfs->fs_info.endian, cur_key->name.length),
                    info->fs_name->name, HFS_MAXNAMLEN + 1)) {
                return HFS_BTREE_CB_ERR;
            }
        }
        else {
            tsk_errno = TSK_ERR_FS_GENFS;
            // @@@ MAY NEED TO IMPROVE BELOW MESSAGE
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                "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;
    }
}
Example #14
0
/*
 * Load the primary partition table (MBR) into the internal
 * data structures in TSK_VS_INFO
 *
 * This will automatically call load_ext_table for extended
 * partitions
 *
 * sect_cur is the address of the table to load
 *
 * 0 is returned if the load is successful and 1 if error
 */
static uint8_t
dos_load_prim_table(TSK_VS_INFO * vs, uint8_t test)
{
    dos_sect *sect;
    char *sect_buf;
    int i, added = 0;
    char *table_str;
    ssize_t cnt;
    TSK_DADDR_T taddr = vs->offset / vs->block_size + DOS_PART_SOFFSET;
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector

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

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

    /* Read the table */
    cnt = tsk_vs_read_block
        (vs, DOS_PART_SOFFSET, 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("Primary DOS table sector %" PRIuDADDR,
            taddr);
        free(sect_buf);
        return 1;
    }


    /* Sanity Check */
    if (tsk_vs_guessu16(vs, sect->magic, DOS_MAGIC)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr
            ("File is not a DOS partition (invalid primary magic) (Sector: %"
            PRIuDADDR ")", taddr);
        if (tsk_verbose)
            fprintf(stderr,
                "File is not a DOS partition (invalid primary magic) (Sector: %"
                PRIuDADDR ")", taddr);
        free(sect_buf);
        return 1;
    }

    /* Because FAT and NTFS use the same magic - check for a
     * standard MS OEM name and sizes.  Not a great check, but we can't
     * really test the table entries.
     */
    if (test) {
        if (tsk_verbose)
            tsk_fprintf(stderr,
                "dos_load_prim_table: Testing FAT/NTFS conditions\n");

        if (strncmp("MSDOS", sect->oemname, 5) == 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_MAGIC);
            tsk_error_set_errstr
                ("dos_load_prim_table: MSDOS OEM name exists");
            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "dos_load_prim_table: MSDOS OEM name exists\n");
            free(sect_buf);
            return 1;
        }
        else if (strncmp("MSWIN", sect->oemname, 5) == 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_MAGIC);
            tsk_error_set_errstr
                ("dos_load_prim_table: MSWIN OEM name exists");
            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "dos_load_prim_table: MSWIN OEM name exists\n");
            free(sect_buf);
            return 1;
        }
        else if (strncmp("NTFS", sect->oemname, 4) == 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_MAGIC);
            tsk_error_set_errstr
                ("dos_load_prim_table: NTFS OEM name exists");
            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "dos_load_prim_table: NTFS OEM name exists\n");
            free(sect_buf);
            return 1;
        }
        else if (strncmp("FAT", sect->oemname, 4) == 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_MAGIC);
            tsk_error_set_errstr
                ("dos_load_prim_table: FAT OEM name exists");
            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "dos_load_prim_table: FAT OEM name exists\n");
            free(sect_buf);
            return 1;
        }
    }

    /* Add an entry of 1 sector for the table  to the internal structure */
    if ((table_str = tsk_malloc(32)) == NULL) {
        free(sect_buf);
        return 1;
    }

    snprintf(table_str, 32, "Primary Table (#0)");
    if (NULL == tsk_vs_part_add(vs, DOS_PART_SOFFSET, (TSK_DADDR_T) 1,
            TSK_VS_PART_FLAG_META, table_str, -1, -1)) {
        free(sect_buf);
        return 1;
    }

    /* Cycle through the partition table */
    for (i = 0; i < 4; i++) {
        dos_part *part = &sect->ptable[i];

        /* We currently ignore CHS */
        uint32_t part_start = tsk_getu32(vs->endian, part->start_sec);
        uint32_t part_size = tsk_getu32(vs->endian, part->size_sec);

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "load_pri:0:%d    Start: %" PRIu32 "   Size: %" PRIu32
                "  Type: %d\n", i, part_start, part_size, part->ptype);

        if (part_size == 0)
            continue;

        // make sure the first couple are in the image bounds
        if ((i < 2) && (part_start > max_addr)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
            tsk_error_set_errstr
                ("dos_load_prim_table: Starting sector too large for image");
            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "Starting sector %" PRIu32 " too large for image\n",
                    part_start);
            free(sect_buf);
            return 1;
        }
#if 0
// I'm not sure if this is too strict ...
        else if ((part_start + part_size) > max_addr) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
            tsk_error_set_errstr
                ("dos_load_prim_table: Partition ends after image");
            return 1;
        }
#endif

        added = 1;

        /* Add the partition to the internal structure
         * If it is an extended partition, process it now */
        if (dos_is_ext(part->ptype)) {
            if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
                    (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_META,
                    dos_get_desc(part->ptype), 0, i)) {
                free(sect_buf);
                return 1;
            }

            if (dos_load_ext_table(vs, part_start, part_start, 1)) {
                if (tsk_verbose) {
                    fprintf(stderr,
                        "Error loading extended table, moving on");
                    tsk_error_print(stderr);
                }
                tsk_error_reset();
            }
        }
        else {
            if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
                    (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC,
                    dos_get_desc(part->ptype), 0, i)) {
                free(sect_buf);
                return 1;
            }
        }
    }
    free(sect_buf);

    if (added == 0) {
        if (tsk_verbose)
            tsk_fprintf(stderr, "dos_load_prim: No valid entries\n");

        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr
            ("dos_load_prim_table: No valid entries in primary table");
        return 1;
    }
    return 0;
}
Example #15
0
/** \internal
 * Read an indirect block and process the contents to make a runlist from the pointers. 
 *
 * @param fs File system to analyze
 * @param fs_attr Structure to save run data into
 * @param fs_attr_indir Structure to save addresses of indirect block pointers in
 * @param buf Buffers to read block data into (0 is block sized, 1+ are DADDR_T arrays based on FS type)
 * @param level Indirection level that this will process at (1+)
 * @param addr Address of block to read
 * @param length Length of file remaining
 *
 * @returns the number of bytes processed during call and -1 if an error occurred
 */
static TSK_OFF_T
unix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr,
    TSK_FS_ATTR * fs_attr_indir, char *buf[], int level, TSK_DADDR_T addr,
    TSK_OFF_T length)
{
    char *myname = "unix_make_data_run_indirect";
    size_t addr_cnt = 0;
    TSK_DADDR_T *myaddrs = (TSK_DADDR_T *) buf[level];
    TSK_OFF_T length_remain = length;
    TSK_OFF_T retval;
    size_t fs_bufsize;
    size_t fs_blen;
    TSK_FS_ATTR_RUN *data_run;

    if (tsk_verbose)
        tsk_fprintf(stderr, "%s: level %d block %" PRIuDADDR "\n", myname,
            level, addr);

    // block_size is a fragment size in UFS, so we need to maintain length in fragments
    if (TSK_FS_TYPE_ISFFS(fs->ftype)) {
        FFS_INFO *ffs = (FFS_INFO *) fs;
        fs_blen = ffs->ffsbsize_f;
        fs_bufsize = ffs->ffsbsize_b;
    }
    else {
        fs_blen = 1;
        fs_bufsize = fs->block_size;
    }

    if (addr > fs->last_block) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
        tsk_error_set_errstr("unix: Indirect block address too large: %"
            PRIuDADDR "", addr);
        return -1;
    }

    // make a non-resident run
    data_run = tsk_fs_attr_run_alloc();
    if (data_run == NULL)
        return -1;

    data_run->addr = addr;
    data_run->len = fs_blen;

    /*
     * Read a block of disk addresses.
     */
    // sparse
    if (addr == 0) {
        memset(buf[0], 0, fs_bufsize);
        data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE;
    }
    else {
        ssize_t cnt;
        // read the data into the scratch buffer
        cnt = tsk_fs_read_block(fs, addr, buf[0], fs_bufsize);
        if (cnt != fs_bufsize) {
            if (cnt >= 0) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_READ);
            }
            tsk_error_set_errstr2("unix_make_data_run_indir: Block %"
                PRIuDADDR, addr);
            return -1;
        }
    }

    // save the run
    tsk_fs_attr_append_run(fs, fs_attr_indir, data_run);

    // convert the raw addresses to the correct endian ordering
    if ((fs->ftype == TSK_FS_TYPE_FFS1)
        || (fs->ftype == TSK_FS_TYPE_FFS1B)
        || (TSK_FS_TYPE_ISEXT(fs->ftype))) {
        size_t n;
        uint32_t *iaddr = (uint32_t *) buf[0];
        addr_cnt = fs_bufsize / sizeof(*iaddr);
        for (n = 0; n < addr_cnt; n++) {
            myaddrs[n] = tsk_getu32(fs->endian, (uint8_t *) & iaddr[n]);
        }
    }
    else if (fs->ftype == TSK_FS_TYPE_FFS2) {
        size_t n;
        uint64_t *iaddr = (uint64_t *) buf[0];
        addr_cnt = fs_bufsize / sizeof(*iaddr);
        for (n = 0; n < addr_cnt; n++) {
            myaddrs[n] = tsk_getu64(fs->endian, (uint8_t *) & iaddr[n]);
        }
    }

    // pass the addresses to the next level
    if (level == 1) {
        retval =
            unix_make_data_run_direct(fs, fs_attr, myaddrs, addr_cnt,
            length_remain);
        if (retval != -1) {
            length_remain -= retval;
        }
    }
    else {
        size_t i;
        retval = 0;
        for (i = 0; i < addr_cnt && retval != -1; i++) {
            retval =
                unix_make_data_run_indirect(fs, fs_attr, fs_attr_indir,
                buf, level - 1, myaddrs[i], length_remain);
            if (retval == -1) {
                break;
            }
            else {
                length_remain -= retval;
            }
        }
    }

    if (retval == -1)
        return -1;
    else
        return length - length_remain;
}
Example #16
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;
    }
}
/* 
 * Process the partition table at the sector address 
 *
 * This method just finds out if it is sparc or Intel and then
 * calls the appropriate method
 *
 * Return 0 on success and 1 on error
 */
static uint8_t
sun_load_table(TSK_VS_INFO * vs)
{
    sun_dlabel_sparc *dlabel_sp;
    sun_dlabel_i386 *dlabel_x86;
    char *buf;
    ssize_t cnt;
    TSK_DADDR_T taddr =
        vs->offset / vs->block_size + SUN_SPARC_PART_SOFFSET;
    int result = 0;


    /* Sanity check in case label sizes change */
    if ((sizeof(*dlabel_sp) > vs->block_size) ||
        (sizeof(*dlabel_x86) > vs->block_size)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_BUF);
        tsk_error_set_errstr
            ("sun_load_table: disk labels bigger than block size");
        return 1;
    }

    if (tsk_verbose)
        tsk_fprintf(stderr,
            "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr);

    if ((buf = tsk_malloc(vs->block_size)) == NULL) {
        goto on_error;
    }

    /* Try the given offset */
    cnt = tsk_vs_read_block
        (vs, SUN_SPARC_PART_SOFFSET, buf, vs->block_size);

    /* If -1 is returned, 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("SUN Disk Label in Sector: %" PRIuDADDR,
            taddr);
        goto on_error;
    }


    /* Check the magic value 
     * Both intel and sparc have the magic value in the same location
     *
     * We try both in case someone specifies the exact location of the
     * intel disk label.
     * */
    dlabel_sp = (sun_dlabel_sparc *) buf;
    dlabel_x86 = (sun_dlabel_i386 *) buf;
    if (tsk_vs_guessu16(vs, dlabel_sp->magic, SUN_MAGIC) == 0) {
        if (tsk_getu32(vs->endian, dlabel_sp->sanity) == SUN_SANITY) {
            result = sun_load_table_sparc(vs, dlabel_sp);
            // TODO: I assume based on the existing free that the previous function
            // does not take ownership of buf.
            free(buf);
            return result;
        }
        else if (tsk_getu32(vs->endian, dlabel_x86->sanity) == SUN_SANITY) {
            result = sun_load_table_i386(vs, dlabel_x86);
            // TODO: I assume based on the existing free that the previous function
            // does not take ownership of buf.
            free(buf);
            return result;
        }
    }


    /* Now try the next sector, which is where the intel 
     * could be stored */

    taddr = vs->offset / vs->block_size / SUN_I386_PART_SOFFSET;
    if (tsk_verbose)
        tsk_fprintf(stderr,
            "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr + 1);

    cnt = tsk_vs_read_block
        (vs, SUN_I386_PART_SOFFSET, 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("SUN (Intel) Disk Label in Sector: %"
            PRIuDADDR, taddr);
        goto on_error;
    }

    dlabel_x86 = (sun_dlabel_i386 *) buf;
    if (tsk_vs_guessu16(vs, dlabel_x86->magic, SUN_MAGIC)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr("SUN (intel) partition table (Sector: %"
            PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian,
                dlabel_sp->magic));
        goto on_error;
    }

    if (tsk_getu32(vs->endian, dlabel_x86->sanity) != SUN_SANITY) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr("SUN (intel) sanity value (Sector: %"
            PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian,
                dlabel_sp->magic));
        goto on_error;
    }

    result = sun_load_table_i386(vs, dlabel_x86);
    // TODO: I assume based on the existing free that the previous function
    // does not take ownership of buf.
    free(buf);
    return result;

on_error:
    if( buf != NULL ) {
        free( buf );
    }
    return 1;
}
Example #18
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;
}
Example #19
0
/** \internal
 * process the data from inside of a directory and load the corresponding
 * file data into a TSK_FS_DIR structure.
 *
 * @param a_fs File system
 * @param a_fs_dir Structore to store file names into
 * @param buf Buffer that contains the directory content
 * @param a_length Number of bytes in buffer
 * @param a_addr The metadata address for the directory being processed
 * @param a_dir_addr The block offset where this directory starts
 * @returns TSK_ERR on error and TSK_OK otherwise
 */
static uint8_t
iso9660_proc_dir(TSK_FS_INFO * a_fs, TSK_FS_DIR * a_fs_dir, char *buf,
    size_t a_length, TSK_INUM_T a_addr, TSK_OFF_T a_dir_addr)
{
    ISO_INFO *iso = (ISO_INFO *) a_fs;
    TSK_FS_NAME *fs_name;
    size_t buf_idx;

    iso9660_dentry *dd;         /* directory descriptor */
    iso9660_inode_node *in;
    TSK_OFF_T dir_offs = a_dir_addr * a_fs->block_size;

    if ((fs_name = tsk_fs_name_alloc(ISO9660_MAXNAMLEN + 1, 0)) == NULL)
        return TSK_ERR;

    buf_idx = 0;
    dd = (iso9660_dentry *) & buf[buf_idx];

    /* handle "." entry */
    fs_name->meta_addr = a_addr;
    strcpy(fs_name->name, ".");
    fs_name->type = TSK_FS_NAME_TYPE_DIR;
    fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;

    tsk_fs_dir_add(a_fs_dir, fs_name);

    buf_idx += dd->entry_len;
    if (buf_idx > a_length - sizeof(iso9660_dentry)) {
        free(buf);
        tsk_fs_name_free(fs_name);
        return TSK_OK;
    }
    dd = (iso9660_dentry *) & buf[buf_idx];

    /* handle ".." entry */
    in = iso->in_list;
    while (in
        && (tsk_getu32(a_fs->endian, in->inode.dr.ext_loc_m) !=
            tsk_getu32(a_fs->endian, dd->ext_loc_m)))
        in = in->next;
    if (in) {
        fs_name->meta_addr = in->inum;
        strcpy(fs_name->name, "..");

        fs_name->type = TSK_FS_NAME_TYPE_DIR;
        fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;

        tsk_fs_dir_add(a_fs_dir, fs_name);
    }
    buf_idx += dd->entry_len;

    // process the rest of the entries in the directory
    while (buf_idx < a_length - sizeof(iso9660_dentry)) {
        dd = (iso9660_dentry *) & buf[buf_idx];

        // process the entry (if it has a defined and valid length)
        if ((dd->entry_len) && (buf_idx + dd->entry_len < a_length)) {

            /* We need to find the data in the pre-processed list because that
             * contains the meta data address that TSK assigned to this file.
             * We find the entry by looking for one that was stored at the same
             * byte offset that we now are.  We used to use the extent location, but
             * we found an image
             * that had a file with 0 bytes with the same starting block as another
             * file. */
            for (in = iso->in_list; in; in = in->next) {
                if (in->dentry_offset == dir_offs + buf_idx)
                    break;
            }

            // we may have not found it because we are reading corrupt data...
            if (!in) {
                buf_idx++;
                continue;
            }

            // copy the data in fs_name for loading
            fs_name->meta_addr = in->inum;
            strncpy(fs_name->name, in->inode.fn, ISO9660_MAXNAMLEN);

            if (dd->flags & ISO9660_FLAG_DIR)
                fs_name->type = TSK_FS_NAME_TYPE_DIR;
            else
                fs_name->type = TSK_FS_NAME_TYPE_REG;
            fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;

            tsk_fs_dir_add(a_fs_dir, fs_name);

            buf_idx += dd->entry_len;
        }
        /* If the length was not defined, we are probably in a hole in the
         * directory.  The contents are  block aligned. So, we
         * scan ahead until we get either a non-zero entry or the block boundary */
        else {
            buf_idx++;
            for (; buf_idx < a_length - sizeof(iso9660_dentry); buf_idx++) {
                if (buf[buf_idx] != 0) {
                    dd = (iso9660_dentry *) & buf[buf_idx];
                    if ((dd->entry_len)
                        && (buf_idx + dd->entry_len < a_length))
                        break;
                }

                if (buf_idx % a_fs->block_size == 0)
                    break;
            }
        }
    }

    free(buf);
    tsk_fs_name_free(fs_name);

    return TSK_OK;
}
Example #20
0
/* 
 * Process the partition table at the sector address 
 * 
 * It is loaded into the internal sorted list 
 */
static uint8_t
gpt_load_table(TSK_MM_INFO * mm)
{
    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;
    DADDR_T taddr = mm->offset / mm->block_size + GPT_PART_SOFFSET;
    DADDR_T max_addr = (mm->img_info->size - mm->offset) / mm->block_size;      // max sector

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

    cnt = tsk_mm_read_block_nobuf
        (mm, (char *) &dos_part, sizeof(dos_part), GPT_PART_SOFFSET);
    /* if -1, then tsk_errno is already set */
    if (cnt != sizeof(dos_part)) {
        if (cnt != -1) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_MM_READ;
        }
        snprintf(tsk_errstr2, TSK_ERRSTR_L,
            "Error reading DOS safety partition table in Sector: %"
            PRIuDADDR, taddr);
        return 1;
    }

    /* Sanity Check */
    if (tsk_mm_guessu16(mm, dos_part.magic, DOS_MAGIC)) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_MM_MAGIC;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "Missing DOS safety partition (invalid magic) (Sector: %"
            PRIuDADDR ")", taddr);
        return 1;
    }

    if (dos_part.ptable[0].ptype != GPT_DOS_TYPE) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_MM_MAGIC;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "Missing DOS safety partition (invalid type in table: %d)",
            dos_part.ptable[0].ptype);
        return 1;
    }

    if ((safe_str = tsk_malloc(16)) == NULL)
        return 1;

    snprintf(safe_str, 16, "Safety Table");
    if (NULL == tsk_mm_part_add(mm, (DADDR_T) 0, (DADDR_T) 1,
            TSK_MM_PART_TYPE_DESC, safe_str, -1, -1))
        return 1;


    /* Read the GPT header */
    cnt = tsk_mm_read_block_nobuf
        (mm, (char *) &head, sizeof(head), GPT_PART_SOFFSET + 1);
    if (cnt != sizeof(head)) {
        if (cnt != -1) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_MM_READ;
        }
        snprintf(tsk_errstr2, TSK_ERRSTR_L,
            "GPT Header structure in Sector: %" PRIuDADDR, taddr + 1);
        return 1;
    }


    if (tsk_getu64(mm->endian, &head.signature) != GPT_HEAD_SIG) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_MM_MAGIC;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "GPT Header: %" PRIx64, tsk_getu64(mm->endian,
                &head.signature));
        return 1;
    }

    if ((head_str = tsk_malloc(16)) == NULL)
        return 1;

    snprintf(head_str, 16, "GPT Header");
    if (NULL == tsk_mm_part_add(mm, (DADDR_T) 1,
            (DADDR_T) ((tsk_getu32(mm->endian,
                        &head.head_size_b) + 511) / 512),
            TSK_MM_PART_TYPE_DESC, head_str, -1, -1))
        return 1;

    /* Allocate a buffer for each table entry */
    ent_size = tsk_getu32(mm->endian, &head.tab_size_b);
    if (ent_size < sizeof(gpt_entry)) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_MM_MAGIC;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "Header reports partition entry size of %" PRIu32
            " and not %zu", ent_size, sizeof(gpt_entry));
        return 1;
    }

    if ((tab_str = tsk_malloc(20)) == NULL)
        return 1;

    snprintf(tab_str, 20, "Partition Table");
    if (NULL == tsk_mm_part_add(mm, (DADDR_T) tsk_getu64(mm->endian,
                &head.tab_start_lba),
            (DADDR_T) ((ent_size * tsk_getu32(mm->endian,
                        &head.tab_num_ent) + 511) / 512),
            TSK_MM_PART_TYPE_DESC, tab_str, -1, -1))
        return 1;


    /* Process the partition table */
    if ((ent_buf = tsk_malloc(mm->block_size)) == NULL)
        return 1;

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

        /* Read a sector */
        cnt = tsk_mm_read_block_nobuf(mm, ent_buf, mm->block_size,
            tsk_getu64(mm->endian, &head.tab_start_lba) + a);
        if (cnt != mm->block_size) {
            if (cnt != -1) {
                tsk_error_reset();
                tsk_errno = TSK_ERR_MM_READ;
            }
            snprintf(tsk_errstr2, TSK_ERRSTR_L,
                "Error reading GPT partition table sector : %"
                PRIuDADDR, tsk_getu64(mm->endian,
                    &head.tab_start_lba) + a);
            return 1;
        }

        /* Process the sector */
        ent = (gpt_entry *) ent_buf;
        for (; (uintptr_t) ent < (uintptr_t) ent_buf + mm->block_size &&
            i < tsk_getu32(mm->endian, &head.tab_num_ent); 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(mm->endian, ent->start_lba),
                    tsk_getu64(mm->endian, ent->end_lba),
                    tsk_getu64(mm->endian, ent->flags));


            if (tsk_getu64(mm->endian, ent->start_lba) == 0)
                continue;

            if (tsk_getu64(mm->endian, ent->start_lba) > max_addr) {
                tsk_error_reset();
                tsk_errno = TSK_ERR_MM_BLK_NUM;
                snprintf(tsk_errstr, TSK_ERRSTR_L,
                    "gpt_load_table: Starting sector too large for image");
                return 1;
            }


            if ((name = tsk_malloc(256)) == NULL)
                return 1;

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

            retVal =
                tsk_UTF16toUTF8(mm->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_mm_part_add(mm,
                    (DADDR_T) tsk_getu64(mm->endian, ent->start_lba),
                    (DADDR_T) (tsk_getu64(mm->endian,
                            ent->end_lba) - tsk_getu64(mm->endian,
                            ent->start_lba) + 1), TSK_MM_PART_TYPE_VOL,
                    name, -1, i))
                return 1;
        }
    }

    return 0;
}
Example #21
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;
}
Example #22
0
/* 
**
** Read contents of directory block
**
** if entry is active call action with myflags set to TSK_FS_DENT_FLAG_ALLOC, if 
** it is deleted then call action with TSK_FS_DENT_FLAG_UNALLOC.
** len is the size of buf
**
** return 1 to stop, 0 on success, and -1 on error
*/
static int
ext2fs_dent_parse_block(EXT2FS_INFO * ext2fs, EXT2FS_DINFO * dinfo,
    TSK_LIST ** list_seen, char *buf, int len, int flags,
    TSK_FS_DENT_TYPE_WALK_CB action, void *ptr)
{
    TSK_FS_INFO *fs = &(ext2fs->fs_info);

    int dellen = 0;
    int idx;
    uint16_t reclen;
    uint32_t inode;
    char *dirPtr;
    TSK_FS_DENT *fs_dent;
    int minreclen = 4;

    if ((fs_dent = tsk_fs_dent_alloc(EXT2FS_MAXNAMLEN + 1, 0)) == NULL)
        return -1;

    /* update each time by the actual length instead of the
     ** recorded length so we can view the deleted entries 
     */
    for (idx = 0; idx <= len - EXT2FS_DIRSIZ_lcl(1); idx += minreclen) {

        unsigned int namelen;
        dirPtr = &buf[idx];

        if (ext2fs->deentry_type == EXT2_DE_V1) {
            ext2fs_dentry1 *dir = (ext2fs_dentry1 *) dirPtr;
            inode = tsk_getu32(fs->endian, dir->inode);
            namelen = tsk_getu16(fs->endian, dir->name_len);
            reclen = tsk_getu16(fs->endian, dir->rec_len);
        }
        else {
            ext2fs_dentry2 *dir = (ext2fs_dentry2 *) dirPtr;
            inode = tsk_getu32(fs->endian, dir->inode);
            namelen = dir->name_len;
            reclen = tsk_getu16(fs->endian, dir->rec_len);
        }

        minreclen = EXT2FS_DIRSIZ_lcl(namelen);

        /* 
         ** Check if we may have a valid directory entry.  If we don't,
         ** then increment to the next word and try again.  
         */
        if ((inode > fs->last_inum) ||
            (inode < 0) ||
            (namelen > EXT2FS_MAXNAMLEN) ||
            (namelen <= 0) ||
            (reclen < minreclen) || (reclen % 4) || (idx + reclen > len)) {

            minreclen = 4;
            if (dellen > 0)
                dellen -= 4;
            continue;
        }

        /* Before we process an entry in unallocated space, make
         * sure that it also ends in the unalloc space */
        if ((dellen) && (dellen < minreclen)) {
            minreclen = 4;
            if (dellen > 0)
                dellen -= 4;
            continue;
        }

        if (ext2fs_dent_copy(ext2fs, dinfo, dirPtr, fs_dent)) {
            tsk_fs_dent_free(fs_dent);
            return -1;
        }


        /* Do we have a deleted entry? */
        if ((dellen > 0) || (inode == 0)) {
            fs_dent->flags = TSK_FS_DENT_FLAG_UNALLOC;
            if (dellen > 0)
                dellen -= minreclen;

            if (flags & TSK_FS_DENT_FLAG_UNALLOC) {
                int retval;
                retval = action(fs, fs_dent, ptr);
                if (retval == TSK_WALK_STOP) {
                    tsk_fs_dent_free(fs_dent);
                    return 1;
                }
                else if (retval == TSK_WALK_ERROR) {
                    tsk_fs_dent_free(fs_dent);
                    return -1;
                }
            }
        }
        /* We have a non-deleted entry */
        else {
            fs_dent->flags = TSK_FS_DENT_FLAG_ALLOC;
            if (flags & TSK_FS_DENT_FLAG_ALLOC) {
                int retval;

                retval = action(fs, fs_dent, ptr);
                if (retval == TSK_WALK_STOP) {
                    tsk_fs_dent_free(fs_dent);
                    return 1;
                }
                else if (retval == TSK_WALK_ERROR) {
                    tsk_fs_dent_free(fs_dent);
                    return -1;
                }
            }
        }

        /* If the actual length is shorter then the 
         ** recorded length, then the next entry(ies) have been 
         ** deleted.  Set dellen to the length of data that 
         ** has been deleted
         **
         ** Because we aren't guaranteed with Ext2FS that the next
         ** entry begins right after this one, we will check to
         ** see if the difference is less than a possible entry
         ** before we waste time searching it
         */
        if ((reclen - minreclen >= EXT2FS_DIRSIZ_lcl(1))
            && (dellen <= 0))
            dellen = reclen - minreclen;


        /* we will be recursing directories */
        if ((fs_dent->flags & TSK_FS_DENT_FLAG_ALLOC) &&
            (flags & TSK_FS_DENT_FLAG_RECURSE) &&
            (!TSK_FS_ISDOT(fs_dent->name)) &&
            ((fs_dent->fsi->mode & TSK_FS_INODE_MODE_FMT) ==
                TSK_FS_INODE_MODE_DIR)) {

            int depth_added = 0;

            /* Make sure we do not get into an infinite loop */
            if (0 == tsk_list_find(*list_seen, fs_dent->inode)) {
                if (tsk_list_add(list_seen, fs_dent->inode)) {
                    tsk_fs_dent_free(fs_dent);
                    return -1;
                }


                if ((dinfo->depth < MAX_DEPTH) &&
                    (DIR_STRSZ >
                        strlen(dinfo->dirs) + strlen(fs_dent->name))) {
                    dinfo->didx[dinfo->depth] =
                        &dinfo->dirs[strlen(dinfo->dirs)];
                    strncpy(dinfo->didx[dinfo->depth], fs_dent->name,
                        DIR_STRSZ - strlen(dinfo->dirs));
                    strncat(dinfo->dirs, "/", DIR_STRSZ);
                    depth_added = 1;
                }
                dinfo->depth++;
                if (ext2fs_dent_walk_lcl(&(ext2fs->fs_info), dinfo,
                        list_seen, fs_dent->inode, flags, action, ptr)) {
                    /* If this fails because the directory could not be 
                     * loaded, then we still continue */
                    if (tsk_verbose) {
                        tsk_fprintf(stderr,
                            "ffs_dent_parse_block: error reading directory: %"
                            PRIuINUM "\n", fs_dent->inode);
                        tsk_error_print(stderr);
                    }

                    tsk_error_reset();
                }


                dinfo->depth--;
                if (depth_added)
                    *dinfo->didx[dinfo->depth] = '\0';
            }
        }
    }

    tsk_fs_dent_free(fs_dent);
    return 0;
}                               /* end ext2fs_dent_parse_block() */
Example #23
0
/**
 * Print details about the file system to a file handle. 
 *
 * @param fs File system to print details on
 * @param hFile File handle to print text to
 * 
 * @returns 1 on error and 0 on success
 */
static uint8_t
fatxxfs_fsstat(TSK_FS_INFO * fs, FILE * hFile)
{
    unsigned int i;
    TSK_DADDR_T next, snext, sstart, send;
    FATFS_INFO *fatfs = (FATFS_INFO *) fs;
    FATXXFS_SB *sb = (FATXXFS_SB*)fatfs->boot_sector_buffer;
    char *data_buf;
    FATXXFS_DENTRY *vol_label_dentry = NULL;
    ssize_t cnt;

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

    if ((data_buf = (char *) tsk_malloc(fs->block_size)) == NULL) {
        return 1;
    }


    /* Read the root directory sector so that we can get the volume
     * label from it */
    cnt = tsk_fs_read_block(fs, fatfs->rootsect, data_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("fatxxfs_fsstat: root directory: %" PRIuDADDR,
            fatfs->rootsect);
        free(data_buf);
        return 1;
    }


    /* Find the dentry that is set as the volume label */
    vol_label_dentry = NULL;
    if (fatfs->ssize <= fs->block_size) {
        FATXXFS_DENTRY *current_entry = (FATXXFS_DENTRY *) data_buf;
        for (i = 0; i < fatfs->ssize; i += sizeof(*current_entry)) {
            if (current_entry->attrib == FATFS_ATTR_VOLUME) {
                vol_label_dentry = current_entry;
                break;
            }
            current_entry++;
        }
    }


    /* Print the general file system information */

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

    tsk_fprintf(hFile, "File System Type: FAT");
    if (fs->ftype == TSK_FS_TYPE_FAT12)
        tsk_fprintf(hFile, "12\n");
    else if (fs->ftype == TSK_FS_TYPE_FAT16)
        tsk_fprintf(hFile, "16\n");
    else if (fs->ftype == TSK_FS_TYPE_FAT32)
        tsk_fprintf(hFile, "32\n");
    else
        tsk_fprintf(hFile, "\n");

    tsk_fprintf(hFile, "\nOEM Name: %c%c%c%c%c%c%c%c\n", sb->oemname[0],
        sb->oemname[1], sb->oemname[2], sb->oemname[3], sb->oemname[4],
        sb->oemname[5], sb->oemname[6], sb->oemname[7]);


    if (fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) {
        tsk_fprintf(hFile, "Volume ID: 0x%" PRIx32 "\n",
            tsk_getu32(fs->endian, sb->a.f16.vol_id));

        tsk_fprintf(hFile,
            "Volume Label (Boot Sector): %c%c%c%c%c%c%c%c%c%c%c\n",
            sb->a.f16.vol_lab[0], sb->a.f16.vol_lab[1],
            sb->a.f16.vol_lab[2], sb->a.f16.vol_lab[3],
            sb->a.f16.vol_lab[4], sb->a.f16.vol_lab[5],
            sb->a.f16.vol_lab[6], sb->a.f16.vol_lab[7],
            sb->a.f16.vol_lab[8], sb->a.f16.vol_lab[9],
            sb->a.f16.vol_lab[10]);

        if ((vol_label_dentry) && (vol_label_dentry->name[0])) {
            tsk_fprintf(hFile,
                "Volume Label (Root Directory): %c%c%c%c%c%c%c%c%c%c%c\n",
                vol_label_dentry->name[0], vol_label_dentry->name[1], vol_label_dentry->name[2], vol_label_dentry->name[3],
                vol_label_dentry->name[4], vol_label_dentry->name[5], vol_label_dentry->name[6], vol_label_dentry->name[7],
                vol_label_dentry->ext[0], vol_label_dentry->ext[1], vol_label_dentry->ext[2]);
        }
        else {
            tsk_fprintf(hFile, "Volume Label (Root Directory):\n");
        }

        tsk_fprintf(hFile, "File System Type Label: %c%c%c%c%c%c%c%c\n",
            sb->a.f16.fs_type[0], sb->a.f16.fs_type[1],
            sb->a.f16.fs_type[2], sb->a.f16.fs_type[3],
            sb->a.f16.fs_type[4], sb->a.f16.fs_type[5],
            sb->a.f16.fs_type[6], sb->a.f16.fs_type[7]);
    }
    else {

        char *fat_fsinfo_buf;

        if ((fat_fsinfo_buf = (char *)
                tsk_malloc(sizeof(FATXXFS_FSINFO))) == NULL) {
            free(data_buf);
            return 1;
        }

        tsk_fprintf(hFile, "Volume ID: 0x%" PRIx32 "\n",
            tsk_getu32(fs->endian, sb->a.f32.vol_id));

        tsk_fprintf(hFile,
            "Volume Label (Boot Sector): %c%c%c%c%c%c%c%c%c%c%c\n",
            sb->a.f32.vol_lab[0], sb->a.f32.vol_lab[1],
            sb->a.f32.vol_lab[2], sb->a.f32.vol_lab[3],
            sb->a.f32.vol_lab[4], sb->a.f32.vol_lab[5],
            sb->a.f32.vol_lab[6], sb->a.f32.vol_lab[7],
            sb->a.f32.vol_lab[8], sb->a.f32.vol_lab[9],
            sb->a.f32.vol_lab[10]);

        if ((vol_label_dentry) && (vol_label_dentry->name[0])) {
            tsk_fprintf(hFile,
                "Volume Label (Root Directory): %c%c%c%c%c%c%c%c%c%c%c\n",
                vol_label_dentry->name[0], vol_label_dentry->name[1], vol_label_dentry->name[2], vol_label_dentry->name[3],
                vol_label_dentry->name[4], vol_label_dentry->name[5], vol_label_dentry->name[6], vol_label_dentry->name[7],
                vol_label_dentry->ext[0], vol_label_dentry->ext[1], vol_label_dentry->ext[2]);
        }
        else {
            tsk_fprintf(hFile, "Volume Label (Root Directory):\n");
        }

        tsk_fprintf(hFile, "File System Type Label: %c%c%c%c%c%c%c%c\n",
            sb->a.f32.fs_type[0], sb->a.f32.fs_type[1],
            sb->a.f32.fs_type[2], sb->a.f32.fs_type[3],
            sb->a.f32.fs_type[4], sb->a.f32.fs_type[5],
            sb->a.f32.fs_type[6], sb->a.f32.fs_type[7]);


        /* Process the FS info */
        if (tsk_getu16(fs->endian, sb->a.f32.fsinfo)) {
            FATXXFS_FSINFO *fat_info;
            cnt =
                tsk_fs_read(fs, 
                    (TSK_DADDR_T) tsk_getu16(fs->endian, sb->a.f32.fsinfo) * fs->block_size, 
                    fat_fsinfo_buf, sizeof(FATXXFS_FSINFO));

            if (cnt != sizeof(FATXXFS_FSINFO)) {
                if (cnt >= 0) {
                    tsk_error_reset();
                    tsk_error_set_errno(TSK_ERR_FS_READ);
                }
                tsk_error_set_errstr2
                    ("fatxxfs_fsstat: TSK_FS_TYPE_FAT32 FSINFO block: %"
                    PRIuDADDR, (TSK_DADDR_T) tsk_getu16(fs->endian,
                        sb->a.f32.fsinfo));
                free(data_buf);
                free(fat_fsinfo_buf);
                return 1;
            }


            fat_info = (FATXXFS_FSINFO *) fat_fsinfo_buf;
            tsk_fprintf(hFile,
                "Next Free Sector (FS Info): %" PRIuDADDR "\n",
                FATFS_CLUST_2_SECT(fatfs, tsk_getu32(fs->endian,
                        fat_info->nextfree)));

            tsk_fprintf(hFile,
                "Free Sector Count (FS Info): %" PRIu32 "\n",
                (tsk_getu32(fs->endian,
                        fat_info->freecnt) * fatfs->csize));

            free(fat_fsinfo_buf);
        }
    }

    free(data_buf);

    tsk_fprintf(hFile, "\nSectors before file system: %" PRIu32 "\n",
        tsk_getu32(fs->endian, sb->prevsect));

    tsk_fprintf(hFile, "\nFile System Layout (in sectors)\n");

    tsk_fprintf(hFile, "Total Range: %" PRIuDADDR " - %" PRIuDADDR "\n",
        fs->first_block, fs->last_block);

    if (fs->last_block != fs->last_block_act)
        tsk_fprintf(hFile,
            "Total Range in Image: %" PRIuDADDR " - %" PRIuDADDR "\n",
            fs->first_block, fs->last_block_act);

    tsk_fprintf(hFile, "* Reserved: 0 - %" PRIuDADDR "\n",
        fatfs->firstfatsect - 1);

    tsk_fprintf(hFile, "** Boot Sector: 0\n");

    if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) {
        tsk_fprintf(hFile, "** FS Info Sector: %" PRIu16 "\n",
            tsk_getu16(fs->endian, sb->a.f32.fsinfo));

        tsk_fprintf(hFile, "** Backup Boot Sector: %" PRIu16 "\n",
            tsk_getu16(fs->endian, sb->a.f32.bs_backup));
    }

    for (i = 0; i < fatfs->numfat; i++) {
        TSK_DADDR_T base = fatfs->firstfatsect + i * (fatfs->sectperfat);

        tsk_fprintf(hFile, "* FAT %d: %" PRIuDADDR " - %" PRIuDADDR "\n",
            i, base, (base + fatfs->sectperfat - 1));
    }

    tsk_fprintf(hFile, "* Data Area: %" PRIuDADDR " - %" PRIuDADDR "\n",
        fatfs->firstdatasect, fs->last_block);

    if (fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) {
        TSK_DADDR_T x = fatfs->csize * fatfs->clustcnt;

        tsk_fprintf(hFile,
            "** Root Directory: %" PRIuDADDR " - %" PRIuDADDR "\n",
            fatfs->firstdatasect, fatfs->firstclustsect - 1);

        tsk_fprintf(hFile,
            "** Cluster Area: %" PRIuDADDR " - %" PRIuDADDR "\n",
            fatfs->firstclustsect, (fatfs->firstclustsect + x - 1));

        if ((fatfs->firstclustsect + x - 1) != fs->last_block) {
            tsk_fprintf(hFile,
                "** Non-clustered: %" PRIuDADDR " - %" PRIuDADDR "\n",
                (fatfs->firstclustsect + x), fs->last_block);
        }
    }
    else {
        TSK_LIST *list_seen = NULL;
        TSK_DADDR_T x = fatfs->csize * (fatfs->lastclust - 1);
        TSK_DADDR_T clust, clust_p;

        tsk_fprintf(hFile,
            "** Cluster Area: %" PRIuDADDR " - %" PRIuDADDR "\n",
            fatfs->firstclustsect, (fatfs->firstclustsect + x - 1));


        clust_p = fatfs->rootsect;
        clust = FATFS_SECT_2_CLUST(fatfs, fatfs->rootsect);
        while ((clust) && (0 == FATFS_ISEOF(clust, FATFS_32_MASK))) {
            TSK_DADDR_T nxt;
            clust_p = clust;

            /* Make sure we do not get into an infinite loop */
            if (tsk_list_find(list_seen, clust)) {
                if (tsk_verbose)
                    tsk_fprintf(stderr,
                        "Loop found while determining root directory size\n");
                break;
            }
            if (tsk_list_add(&list_seen, clust)) {
                tsk_list_free(list_seen);
                list_seen = NULL;
                return 1;
            }

            if (fatfs_getFAT(fatfs, clust, &nxt))
                break;
            clust = nxt;
        }
        tsk_list_free(list_seen);
        list_seen = NULL;

        tsk_fprintf(hFile,
            "*** Root Directory: %" PRIuDADDR " - %" PRIuDADDR "\n",
            fatfs->rootsect, (FATFS_CLUST_2_SECT(fatfs, clust_p + 1) - 1));

        if ((fatfs->firstclustsect + x - 1) != fs->last_block) {
            tsk_fprintf(hFile,
                "** Non-clustered: %" PRIuDADDR " - %" PRIuDADDR "\n",
                (fatfs->firstclustsect + x), fs->last_block);
        }
    }


    tsk_fprintf(hFile, "\nMETADATA INFORMATION\n");
    tsk_fprintf(hFile, "--------------------------------------------\n");

    tsk_fprintf(hFile, "Range: %" PRIuINUM " - %" PRIuINUM "\n",
        fs->first_inum, fs->last_inum);
    tsk_fprintf(hFile, "Root Directory: %" PRIuINUM "\n", fs->root_inum);


    tsk_fprintf(hFile, "\nCONTENT INFORMATION\n");
    tsk_fprintf(hFile, "--------------------------------------------\n");
    tsk_fprintf(hFile, "Sector Size: %" PRIu16 "\n", fatfs->ssize);
    tsk_fprintf(hFile, "Cluster Size: %" PRIu32 "\n",
        (uint32_t) fatfs->csize << fatfs->ssize_sh);

    tsk_fprintf(hFile, "Total Cluster Range: 2 - %" PRIuDADDR "\n",
        fatfs->lastclust);


    /* cycle via cluster and look at each cluster in the FAT 
     * for clusters marked as bad */
    cnt = 0;
    for (i = 2; i <= fatfs->lastclust; i++) {
        TSK_DADDR_T entry;
        TSK_DADDR_T sect;
        unsigned int a;

        /* Get the FAT table entry */
        if (fatfs_getFAT(fatfs, i, &entry))
            break;

        if (FATFS_ISBAD(entry, fatfs->mask) == 0) {
            continue;
        }

        if (cnt == 0)
            tsk_fprintf(hFile, "Bad Sectors: ");

        sect = FATFS_CLUST_2_SECT(fatfs, i);
        for (a = 0; a < fatfs->csize; a++) {
            tsk_fprintf(hFile, "%" PRIuDADDR " ", sect + a);
            if ((++cnt % 8) == 0)
                tsk_fprintf(hFile, "\n");
        }
    }
    if ((cnt > 0) && ((cnt % 8) != 0))
        tsk_fprintf(hFile, "\n");

    /* Display the FAT Table */
    tsk_fprintf(hFile, "\nFAT CONTENTS (in sectors)\n");
    tsk_fprintf(hFile, "--------------------------------------------\n");

    /* 'sstart' marks the first sector of the current run to print */
    sstart = fatfs->firstclustsect;

    /* cycle via cluster and look at each cluster in the FAT  to make runs */
    for (i = 2; i <= fatfs->lastclust; i++) {

        /* 'send' marks the end sector of the current run, which will extend
         * when the current cluster continues to the next 
         */
        send = FATFS_CLUST_2_SECT(fatfs, i + 1) - 1;

        /* get the next cluster */
        if (fatfs_getFAT(fatfs, i, &next))
            break;

        snext = FATFS_CLUST_2_SECT(fatfs, next);

        /* we are also using the next sector (clust) */
        if ((next & fatfs->mask) == (i + 1)) {
            continue;
        }

        /* The next clust is either further away or the clust is available,
         * print it if is further away 
         */
        else if ((next & fatfs->mask)) {
            if (FATFS_ISEOF(next, fatfs->mask))
                tsk_fprintf(hFile,
                    "%" PRIuDADDR "-%" PRIuDADDR " (%" PRIuDADDR
                    ") -> EOF\n", sstart, send, send - sstart + 1);
            else if (FATFS_ISBAD(next, fatfs->mask))
                tsk_fprintf(hFile,
                    "%" PRIuDADDR "-%" PRIuDADDR " (%" PRIuDADDR
                    ") -> BAD\n", sstart, send, send - sstart + 1);
            else
                tsk_fprintf(hFile,
                    "%" PRIuDADDR "-%" PRIuDADDR " (%" PRIuDADDR
                    ") -> %" PRIuDADDR "\n", sstart, send,
                    send - sstart + 1, snext);
        }

        /* reset the starting counter */
        sstart = send + 1;
    }

    return 0;
}
Example #24
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;
}
Example #25
0
/*
 * @param a_is_del Set to 1 if block is from a deleted directory.
 */
static TSK_RETVAL_ENUM
ext2fs_dent_parse_block(EXT2FS_INFO * ext2fs, TSK_FS_DIR * a_fs_dir,
    uint8_t a_is_del, TSK_LIST ** list_seen, char *buf, int len)
{
    TSK_FS_INFO *fs = &(ext2fs->fs_info);

    int dellen = 0;
    int idx;
    uint16_t reclen;
    uint32_t inode;
    char *dirPtr;
    TSK_FS_NAME *fs_name;
    int minreclen = 4;

    if ((fs_name = tsk_fs_name_alloc(EXT2FS_MAXNAMLEN + 1, 0)) == NULL)
        return TSK_ERR;

    /* update each time by the actual length instead of the
     ** recorded length so we can view the deleted entries
     */
    for (idx = 0; idx <= len - EXT2FS_DIRSIZ_lcl(1); idx += minreclen) {

        unsigned int namelen;
        dirPtr = &buf[idx];

        if (ext2fs->deentry_type == EXT2_DE_V1) {
            ext2fs_dentry1 *dir = (ext2fs_dentry1 *) dirPtr;
            inode = tsk_getu32(fs->endian, dir->inode);
            namelen = tsk_getu16(fs->endian, dir->name_len);
            reclen = tsk_getu16(fs->endian, dir->rec_len);
        }
        else {
            ext2fs_dentry2 *dir = (ext2fs_dentry2 *) dirPtr;
            inode = tsk_getu32(fs->endian, dir->inode);
            namelen = dir->name_len;
            reclen = tsk_getu16(fs->endian, dir->rec_len);
        }

        minreclen = EXT2FS_DIRSIZ_lcl(namelen);

        /*
         ** Check if we may have a valid directory entry.  If we don't,
         ** then increment to the next word and try again.
         */
        if ((inode > fs->last_inum) ||  // inode is unsigned
            (namelen > EXT2FS_MAXNAMLEN) || (namelen == 0) ||   // namelen is unsigned
            (reclen < minreclen) || (reclen % 4) || (idx + reclen > len)) {

            minreclen = 4;
            if (dellen > 0)
                dellen -= 4;
            continue;
        }

        /* Before we process an entry in unallocated space, make
         * sure that it also ends in the unalloc space */
        if ((dellen) && (dellen < minreclen)) {
            minreclen = 4;
            dellen -= 4;
            continue;
        }

        if (ext2fs_dent_copy(ext2fs, dirPtr, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }

        /* Do we have a deleted entry? */
        if ((dellen > 0) || (inode == 0) || (a_is_del)) {
            fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC;
            if (dellen > 0)
                dellen -= minreclen;
        }
        /* We have a non-deleted entry */
        else {
            fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
        }
        if (tsk_fs_dir_add(a_fs_dir, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }

        /* If the actual length is shorter then the
         ** recorded length, then the next entry(ies) have been
         ** deleted.  Set dellen to the length of data that
         ** has been deleted
         **
         ** Because we aren't guaranteed with Ext2FS that the next
         ** entry begins right after this one, we will check to
         ** see if the difference is less than a possible entry
         ** before we waste time searching it
         */
        if (dellen <= 0) {
            if (reclen - minreclen >= EXT2FS_DIRSIZ_lcl(1))
                dellen = reclen - minreclen;
            else
                minreclen = reclen;
        }
    }

    tsk_fs_name_free(fs_name);
    return TSK_OK;
}
Example #26
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;
}
Example #27
0
/* 
 * Process the partition table at the sector address 
 * 
 * It is loaded into the internal sorted list 
 *
 * Return 1 on error and 0 on success
 */
static uint8_t
mac_load_table(TSK_MM_INFO * mm)
{
    mac_part part;
    char *table_str;
    uint32_t idx, max_part;
    TSK_DADDR_T taddr = mm->offset / mm->block_size + MAC_PART_SOFFSET;
    TSK_DADDR_T max_addr = (mm->img_info->size - mm->offset) / mm->block_size;      // max sector

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

    /* The table can be variable length, so we loop on it 
     * The idx variable shows which round it is
     * Each structure is 512-bytes each
     */

    max_part = 1;               /* set it to 1 and it will be set in the first loop */
    for (idx = 0; idx < max_part; idx++) {
        uint32_t part_start;
        uint32_t part_size;
        char *str;
        ssize_t cnt;


        /* Read the entry */
        cnt = tsk_mm_read_block_nobuf
            (mm, (char *) &part, sizeof(part), MAC_PART_SOFFSET + idx);

        /* If -1, then tsk_errno is already set */
        if (cnt != sizeof(part)) {
            if (cnt >= 0) {
                tsk_error_reset();
                tsk_errno = TSK_ERR_MM_READ;
            }
            snprintf(tsk_errstr2, TSK_ERRSTR_L,
                "MAC Partition entry %" PRIuDADDR, taddr + idx);
            return 1;
        }


        /* Sanity Check */
        if (idx == 0) {
            /* Set the endian ordering the first time around */
            if (tsk_mm_guessu16(mm, part.magic, MAC_MAGIC)) {
                tsk_error_reset();
                tsk_errno = TSK_ERR_MM_MAGIC;
                snprintf(tsk_errstr, TSK_ERRSTR_L,
                    "Mac partition table entry (Sector: %"
                    PRIuDADDR ") %" PRIx16,
                    (taddr + idx), tsk_getu16(mm->endian, part.magic));
                return 1;
            }

            /* Get the number of partitions */
            max_part = tsk_getu32(mm->endian, part.pmap_size);
        }
        else if (tsk_getu16(mm->endian, part.magic) != MAC_MAGIC) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_MM_MAGIC;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                "Mac partition table entry (Sector: %"
                PRIuDADDR ") %" PRIx16, (taddr + idx),
                tsk_getu16(mm->endian, part.magic));
            return 1;
        }


        part_start = tsk_getu32(mm->endian, part.start_sec);
        part_size = tsk_getu32(mm->endian, part.size_sec);

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "mac_load: %" PRIu32 "  Starting Sector: %" PRIu32
                "  Size: %" PRIu32 " Type: %s\n", idx, part_start,
                part_size, part.type);

        if (part_size == 0)
            continue;

        if (part_start > max_addr) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_MM_BLK_NUM;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                "mac_load_table: Starting sector too large for image");
            return 1;
        }


        if ((str = talloc_size(NULL, sizeof(part.name))) == NULL)
            return 1;

        strncpy(str, (char *) part.type, sizeof(part.name));

        if (NULL == tsk_mm_part_add(mm, (TSK_DADDR_T) part_start,
                (TSK_DADDR_T) part_size, TSK_MM_PART_TYPE_VOL, str, -1, idx)) {
            talloc_free(str);
            return 1;
        }
        talloc_free(str);
    }

    /* Add an entry for the table length */
    if ((table_str = talloc_size(NULL, 16)) == NULL)
        return 1;

    snprintf(table_str, 16, "Table");
    if (NULL == tsk_mm_part_add(mm, taddr, max_part, TSK_MM_PART_TYPE_DESC,
            table_str, -1, -1)) {
        talloc_free(table_str);
        return 1;
    }
    talloc_free(table_str);

    return 0;
}