Example #1
0
/*
 * Convert the record file name from UTF16 to UTF8.
 * Returns 0 on success, 1 otherwise
 */
static uint8_t
parse_fname(const unsigned char *buf, uint16_t nlen,
            TSK_USN_RECORD_V2 *record, TSK_ENDIAN_ENUM endian)
{
    int ret = 0;
    UTF8 *temp_name = NULL;
    size_t src_len = (size_t) nlen, dst_len = (size_t) nlen * 2;

    record->fname = tsk_malloc(dst_len + 1);
    if (record->fname == NULL)
        return 1;

    temp_name = (UTF8*)record->fname;

    ret = tsk_UTF16toUTF8(endian,
                          (const UTF16**)&buf, (UTF16*)&buf[src_len],
                          (UTF8**)&temp_name, (UTF8*)&temp_name[dst_len],
                          TSKlenientConversion);

    if (ret != TSKconversionOK) {
        if (tsk_verbose)
            tsk_fprintf(
                stderr, "parse_v2_record: USN name to UTF8 conversion error.");

        record->fname = '\0';
    }
    else
        record->fname[dst_len] = '\0';

    return 0;
}
Example #2
0
static uint8_t
ntfs_dent_copy(NTFS_INFO * ntfs, ntfs_idxentry * idxe,
    TSK_FS_NAME * fs_name)
{
    ntfs_attr_fname *fname = (ntfs_attr_fname *) & idxe->stream;
    TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info;
    UTF16 *name16;
    UTF8 *name8;
    int retVal;
    int i;

    fs_name->meta_addr = tsk_getu48(fs->endian, idxe->file_ref);
    fs_name->meta_seq = tsk_getu16(fs->endian, idxe->seq_num);

    name16 = (UTF16 *) & fname->name;
    name8 = (UTF8 *) fs_name->name;

    retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16,
        (UTF16 *) ((uintptr_t) name16 +
            fname->nlen * 2), &name8,
        (UTF8 *) ((uintptr_t) name8 +
            fs_name->name_size), TSKlenientConversion);

    if (retVal != TSKconversionOK) {
        *name8 = '\0';
        if (tsk_verbose)
            tsk_fprintf(stderr,
                "Error converting NTFS name to UTF8: %d %" PRIuINUM,
                retVal, fs_name->meta_addr);
    }

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

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

    if (tsk_getu64(fs->endian, fname->flags) & NTFS_FNAME_FLAGS_DIR)
        fs_name->type = TSK_FS_NAME_TYPE_DIR;
    else
        fs_name->type = TSK_FS_NAME_TYPE_REG;

    fs_name->flags = 0;

    return 0;
}
Example #3
0
/* convert HFS+'s UTF16 to UTF8
 * replaces null characters with another character (0xfffd)
 * replaces slashes (permitted by HFS+ but causes problems with TSK)
 *   with colons (generally not allowed by Mac OS X)
 * note that at least one directory on HFS+ volumes begins with
 *   four nulls, so we do need to handle nulls; also, Apple chooses
 *   to encode nulls as UTF8 \xC0\x80, which is not a valid UTF8 sequence
 * returns 0 on success, 1 on failure; sets up to error string 1 */
uint8_t
hfs_uni2ascii(TSK_FS_INFO * fs, uint8_t * uni, int ulen, char *asc,
    int alen)
{
    char *aptr;
    uint8_t *uniclean;
    uint8_t *uptr;
    int i;
    TSKConversionResult r;

    // remove nulls from the Unicode string
    // convert / to :
    uniclean = (uint8_t *) tsk_malloc(ulen * 2);
    memcpy(uniclean, uni, ulen * 2);
    for (i = 0; i < ulen; ++i) {
        uint16_t uc = tsk_getu16(fs->endian, uniclean + i * 2);
        int changed = 0;
        if (uc == UTF16_NULL) {
            uc = UTF16_NULL_REPLACE;
            changed = 1;
        }
        else if (uc == UTF16_SLASH) {
            uc = UTF16_COLON;
            changed = 1;
        }
        if (changed)
            *((uint16_t *) (uniclean + i * 2)) =
                tsk_getu16(fs->endian, (uint8_t *) & uc);
    }

    memset(asc, 0, alen);
    aptr = asc;
    uptr = uniclean;
    r = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &uptr,
        (const UTF16 *) (uptr + ulen * 2), (UTF8 **) & aptr,
        (UTF8 *) aptr + alen - 1, TSKstrictConversion);

    if (r != TSKconversionOK) {
        tsk_errno = TSK_ERR_FS_UNICODE;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "hfs_uni2ascii: unicode conversion failed (%d)", (int)r);
        free(uniclean);
        return 1;
    }

    free(uniclean);
    return 0;
}
static int convert(TSK_TCHAR *OPTARG, char **_opt_arg)
{
		char *opt_arg=*_opt_arg;
		char *temp = NULL;
		int arg_len = TSTRLEN(OPTARG);
		int ret_val = 0;

		opt_arg=(char *)tsk_malloc(TSTRLEN(OPTARG)+2);
		temp=opt_arg;
		ret_val = 
			tsk_UTF16toUTF8(TSK_LIT_ENDIAN,
			(const UTF16 **) &OPTARG, (UTF16 *)(OPTARG+arg_len+1),
			(UTF8 **)&temp, (UTF8 *)(temp+arg_len+2), TSKlenientConversion);
		if (ret_val)
		{
			printf("Conversion Error ret_val: %d\n", ret_val);
			return ret_val;
		}
		*_opt_arg=opt_arg;
		printf("opt_arg: %s\n",opt_arg);
		return 0;
}
Example #5
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;
}
/**
 * /internal
 * Parse a buffer containing the contents of a directory and add TSK_FS_NAME 
 * objects for each named file found to the TSK_FS_DIR representation of the 
 * directory.
 *
 * @param fatfs File system information structure for file system that
 * contains the directory.
 * @param a_fs_dir Directory structure into to which parsed file metadata will
 * be added.
 * @param buf Buffer that contains the directory contents.
 * @param len Length of buffer in bytes (must be a multiple of sector
*  size).
 * @param addrs Array where each element is the original address of
 * the corresponding sector in a_buf (size of array is number of sectors in
 * the directory).
 * @return TSK_RETVAL_ENUM
*/
TSK_RETVAL_ENUM
fatxxfs_dent_parse_buf(FATFS_INFO *fatfs, TSK_FS_DIR *a_fs_dir, char *buf,
    TSK_OFF_T len, TSK_DADDR_T *addrs)
{
    char *func_name = "fatxxfs_dent_parse_buf";
    unsigned int idx = 0; 
    unsigned int sidx = 0;
    int a = 0;
    int b = 0;
    TSK_INUM_T ibase = 0;
    FATXXFS_DENTRY *dep = NULL;
    TSK_FS_INFO *fs = (TSK_FS_INFO*)&fatfs->fs_info;
    int sectalloc = 0;
    TSK_FS_NAME *fs_name = NULL;
    FATXXFS_LFN lfninfo;
    int entrySeenCount = 0;
    int entryInvalidCount = 0;
    uint8_t isCorruptDir = 0;

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

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

    dep = (FATXXFS_DENTRY*)buf;

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

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

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

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

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

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

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

            entrySeenCount++;

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

            dir = dep;

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

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

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

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

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

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

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

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

                    /* @@@ Check the checksum */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

    return TSK_OK;
}
Example #7
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 #8
0
/* Return -1 for error, 0 if found, and 1 if not found */
int8_t
tsk_fs_ifind_path(TSK_FS_INFO * fs, uint8_t lclflags, TSK_TCHAR * tpath,
                  INUM_T * result)
{
    char *cpath;
    IFIND_PATH_DATA ipd;


    localflags = lclflags;


#ifdef TSK_WIN32
    {
        size_t clen;
        UTF8 *ptr8;
        UTF16 *ptr16;
        int retval;

        clen = TSTRLEN(tpath) * 4;
        cpath = (char *) tsk_malloc(clen);
        if (cpath == NULL) {
            return -1;
        }
        ptr8 = (UTF8 *) cpath;
        ptr16 = (UTF16 *) tpath;

        retval =
            tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &ptr16, (UTF16 *)
                            & ptr16[TSTRLEN(tpath) + 1], &ptr8,
                            (UTF8 *) ((uintptr_t) ptr8 + clen), TSKlenientConversion);
        if (retval != TSKconversionOK) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_FS_UNICODE;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                     "tsk_fs_ifind_path: Error converting path to UTF-8: %d",
                     retval);
            free(cpath);
            return -1;
        }
    }
#else
    cpath = tpath;
#endif

    ipd.id = IFIND_PATH_DATA_ID;
    ipd.found = 0;
    ipd.badpath = 0;
    ipd.cur_dir = (char *) strtok_r(cpath, "/", &ipd.strtok_last);
    ipd.cur_attr = NULL;

    /* If there is no token, then only a '/' was given */
    if (!(ipd.cur_dir)) {
#ifdef TSK_WIN32
        free(cpath);
#endif
        *result = fs->root_inum;
        return 0;
    }

    /* If this is NTFS, ensure that we take out the attribute */
    if (((fs->ftype & TSK_FS_INFO_TYPE_FS_MASK) ==
            TSK_FS_INFO_TYPE_NTFS_TYPE)
            && ((ipd.cur_attr = strchr(ipd.cur_dir, ':')) != NULL)) {
        *(ipd.cur_attr) = '\0';
        ipd.cur_attr++;
    }

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

    if (fs->dent_walk(fs, fs->root_inum,
                      TSK_FS_DENT_FLAG_ALLOC | TSK_FS_DENT_FLAG_UNALLOC,
                      ifind_path_act, (void *) &ipd)) {
        /* If we found files before the error was encountered, then
         * ignore it */
        if (ipd.found == 0) {
#ifdef TSK_WIN32
            free(cpath);
#endif
            return -1;
        }
        else {
            tsk_error_reset();
        }
    }


#ifdef TSK_WIN32
    free(cpath);
#endif

    if (1 == ipd.badpath) {
        if (tsk_verbose)
            tsk_fprintf(stderr, "Invalid path (%s is a file)\n",
                        fs_dent->name);
        *result = 0;
        return 1;
    }
    else if (0 == ipd.found) {
        if (tsk_verbose)
            tsk_printf("File not found: %s\n", ipd.cur_dir);
        *result = 0;
        return 1;
    }

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

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

    memcpy(uniclean, uni, ulen * 2);

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


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

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

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

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

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

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

    return 0;
}
Example #10
0
/* 
 * Process the contents of a directory and add them to FS_DIR. 
 * 
 * @param fatfs File system information structure
 * @param a_fs_dir Structure to store the files in. 
 * @param list_seen List of directory inodes that have been seen thus far in
 * directory walking (can be a pointer to a NULL pointer on first call). 
 * @param buf Buffer that contains the directory contents. 
 * @param len Length of buffer in bytes (must be a multiple of sector size)
 * @param addrs Array where each element is the original address of the 
 * corresponding block in buf (size of array is number of blocks in directory).
 *
 * @return -1 on error, 0 on success, and 1 to stop
 */
static TSK_RETVAL_ENUM
fatfs_dent_parse_buf(FATFS_INFO * fatfs, TSK_FS_DIR * a_fs_dir, char *buf,
    TSK_OFF_T len, TSK_DADDR_T * addrs)
{
    unsigned int idx, sidx;
    int a, b;
    TSK_INUM_T inode, ibase;
    fatfs_dentry *dep;
    TSK_FS_INFO *fs = (TSK_FS_INFO *) & fatfs->fs_info;
    int sectalloc;
    TSK_FS_NAME *fs_name;
    FATFS_LFN lfninfo;

    if (buf == NULL) {
        tsk_error_reset();
        tsk_errno = TSK_ERR_FS_ARG;
        snprintf(tsk_errstr, TSK_ERRSTR_L,
            "fatfs_dent_parse_buf: buffer is NULL");
        return TSK_ERR;
    }

    dep = (fatfs_dentry *) buf;

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

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

    for (sidx = 0; sidx < (unsigned int) (len / fatfs->ssize); sidx++) {

        /* Get the base inode for this sector */
        ibase = FATFS_SECT_2_INODE(fatfs, addrs[sidx]);

        if (ibase > fs->last_inum) {
            tsk_error_reset();
            tsk_errno = TSK_ERR_FS_ARG;
            snprintf(tsk_errstr, TSK_ERRSTR_L,
                "fatfs_parse: inode address is too large");
            tsk_fs_name_free(fs_name);
            return TSK_COR;
        }

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "fatfs_dent_parse_buf: Parsing sector %" PRIuDADDR
                "\n", addrs[sidx]);

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

        /* cycle through the directory entries */
        for (idx = 0; idx < fatfs->dentry_cnt_se; idx++, dep++) {
            fatfs_dentry *dir;
            int i;

            /* is it a valid dentry? */
            if (0 == fatfs_isdentry(fatfs, dep)) {
                if (tsk_verbose)
                    tsk_fprintf(stderr,
                        "fatfs_dent_parse_buf: Entry %u is invalid\n",
                        idx);
                continue;
            }

            /* Copy the directory entry into the TSK_FS_NAME structure */
            dir = (fatfs_dentry *) dep;

            inode = ibase + idx;

            /* Take care of the name 
             * Copy a long name to a buffer and take action if it
             * is a small name */
            if ((dir->attrib & FATFS_ATTR_LFN) == FATFS_ATTR_LFN) {
                fatfs_dentry_lfn *dirl = (fatfs_dentry_lfn *) dir;

                /* Store the name in dinfo until we get the 8.3 name 
                 * Use the checksum to identify a new sequence 
                 * */
                if (((dirl->seq & FATFS_LFN_SEQ_FIRST)
                        && (dirl->seq != FATFS_SLOT_DELETED))
                    || (dirl->chksum != lfninfo.chk)) {
                    // @@@ Do a partial output here


                    /* Reset the values */
                    lfninfo.seq = dirl->seq & FATFS_LFN_SEQ_MASK;
                    lfninfo.chk = dirl->chksum;
                    lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1;

                }
                else if (dirl->seq != lfninfo.seq - 1) {
                    // @@@ Check the sequence number - the checksum is correct though...

                }

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

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

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

                fs_name->name[a] = '\0';
                /* Append a string to show it is a label */
                if (a + 22 < FATFS_MAXNAMLEN_UTF8) {
                    char *volstr = " (Volume Label Entry)";
                    strncat(fs_name->name, volstr,
                        FATFS_MAXNAMLEN_UTF8 - a);
                }
            }

            /* A short (8.3) entry */
            else {
                char *name_ptr; // The dest location for the short name

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

                    /* @@@ Check the checksum */

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

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

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

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

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

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


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

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

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

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

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

            /* Get inode */
            fs_name->meta_addr = inode;

            /* Handle the . and .. entries specially
             * The current inode 'address' they have is for the current
             * slot in the cluster, but it needs to refer to the original
             * slot 
             */
            if (TSK_FS_ISDOT(fs_name->name)) {
                if (fs_name->name[1] == '\0') {
                    inode = fs_name->meta_addr =
                        a_fs_dir->fs_file->meta->addr;
                }
                /* for the parent directory, look up in the list that 
                 * is maintained in fafs_info */
                else if (fs_name->name[1] == '.') {
                    size_t q;
                    uint8_t dir_found = 0;
                    for (q = 0; q < fatfs->dir_buf_next; q++) {
                        if (fatfs->dir_buf[q] ==
                            a_fs_dir->fs_file->meta->addr) {
                            inode = fs_name->meta_addr = fatfs->par_buf[q];
                            dir_found = 1;
                            break;
                        }
                    }

                    if ((dir_found == 0) && (fs->isOrphanHunting)) {
                        /* if we are currently scanning the fs to determine the orphan files,
                         * then we do not care about the value of '..' and this can only cause
                         * infinite loop problems */
                        inode = fs_name->meta_addr = 0;
                        dir_found = 1;
                    }
                    if ((dir_found == 0)
                        && (addrs[0] == fatfs->firstdatasect)) {
                        /* if we are currently in the root directory, we aren't going to find
                         * a parent.  This shouldn't happen, but could result in an infinite loop. */
                        inode = fs_name->meta_addr = 0;
                        dir_found = 1;
                    }
                    if (dir_found == 0) {
                        /* The parent directory is not in the list.  We are going to walk
                         * the directory until we hit this directory. This process will
                         * populate the buffer table and we will then rescan it */
                        if (tsk_fs_dir_walk(fs, fs->root_inum,
                                TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | 
                                TSK_FS_DIR_WALK_FLAG_RECURSE,
                                find_parent_act,
                                (void *) &a_fs_dir->fs_file->meta->addr)) {
                            return 0;
                        }

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


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

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

    return TSK_OK;
}
Example #11
0
/*
 * copy the index (directory) entry into the generic structure
 *
 * uses the global variables 'dirs' and 'depth'
 *
 * Returns 1 on eror and 0 on success
 */
static uint8_t
ntfs_dent_copy(NTFS_INFO * ntfs, NTFS_DINFO * dinfo, ntfs_idxentry * idxe,
               TSK_FS_DENT * fs_dent)
{
    ntfs_attr_fname *fname = (ntfs_attr_fname *) & idxe->stream;
    TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info;
    UTF16 *name16;
    UTF8 *name8;
    int retVal;
    int i;

    fs_dent->inode = tsk_getu48(fs->endian, idxe->file_ref);

    name16 = (UTF16 *) & fname->name;
    name8 = (UTF8 *) fs_dent->name;

    retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16,
                             (UTF16 *) ((uintptr_t) name16 +
                                        fname->nlen * 2), &name8,
                             (UTF8 *) ((uintptr_t) name8 +
                                       fs_dent->name_max), TSKlenientConversion);

    if (retVal != TSKconversionOK) {
        *name8 = '\0';
        if (tsk_verbose)
            tsk_fprintf(stderr,
                        "Error converting NTFS name to UTF8: %d %" PRIuINUM,
                        retVal, fs_dent->inode);
    }

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

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

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

    /* Get the actual inode */
    if (fs_dent->fsi != NULL)
        tsk_fs_inode_free(fs_dent->fsi);

    if (NULL == (fs_dent->fsi = fs->inode_lookup(fs, fs_dent->inode))) {
        if (tsk_verbose) {
            tsk_fprintf(stderr,
                        "ntfs_dent_copy: error looking up inode: %" PRIuINUM "\n",
                        fs_dent->inode);
            tsk_error_print(stderr);
            tsk_error_reset();
        }
    }

    if (tsk_getu64(fs->endian, fname->flags) & NTFS_FNAME_FLAGS_DIR)
        fs_dent->ent_type = TSK_FS_DENT_TYPE_DIR;
    else
        fs_dent->ent_type = TSK_FS_DENT_TYPE_REG;

    fs_dent->flags = 0;

    return 0;
}