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