/* load a sparc disk label, this is called from the general * sun_load_table */ static uint8_t sun_load_table_sparc(TSK_VS_INFO * vs, sun_dlabel_sparc * dlabel_sp) { uint32_t idx = 0; uint32_t cyl_conv; TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector /* The value to convert cylinders to sectors */ cyl_conv = tsk_getu16(vs->endian, dlabel_sp->sec_per_tr) * tsk_getu16(vs->endian, dlabel_sp->num_head); if (tsk_verbose) tsk_fprintf(stderr, "load_table_sparc: Number of partitions: %d\n", tsk_getu16(vs->endian, dlabel_sp->num_parts)); /* Cycle through the partitions, there are either 8 or 16 */ for (idx = 0; idx < tsk_getu16(vs->endian, dlabel_sp->num_parts); idx++) { TSK_VS_PART_FLAG_ENUM ptype = TSK_VS_PART_FLAG_ALLOC; uint32_t part_start = cyl_conv * tsk_getu32(vs->endian, dlabel_sp->part_layout[idx].start_cyl); uint32_t part_size = tsk_getu32(vs->endian, dlabel_sp->part_layout[idx].size_blk); if (tsk_verbose) tsk_fprintf(stderr, "load_table_sparc: %" PRIu32 " Starting Sector: %" PRIu32 " Size: %" PRIu32 " Type: %" PRIu16 "\n", idx, part_start, part_size, tsk_getu16(vs->endian, dlabel_sp->part_meta[idx].type)); if (part_size == 0) continue; // make sure the first couple are in the image bounds if ((idx < 2) && (part_start > max_addr)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_BLK_NUM); tsk_error_set_errstr ("sun_load_sparc: Starting sector too large for image"); return 1; } // set the entry that covers the entire disk image as DESC if ((tsk_getu16(vs->endian, dlabel_sp->part_meta[idx].type) == 5) && (part_start == 0)) ptype = TSK_VS_PART_FLAG_META; /* Add the partition to the internal sorted list */ if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start, (TSK_DADDR_T) part_size, ptype, sun_get_desc(tsk_getu16(vs->endian, dlabel_sp->part_meta[idx].type)), -1, idx)) return 1; } return 0; }
/* * Parse a V 2.0 USN record. * Returns 0 on success, 1 otherwise */ static uint8_t parse_v2_record(const unsigned char *buf, TSK_USN_RECORD_HEADER *header, TSK_USN_RECORD_V2 *record, TSK_ENDIAN_ENUM endian) { uint64_t timestamp = 0; uint16_t name_offset = 0, name_length = 0; record->refnum = tsk_getu48(endian, &buf[8]); record->refnum_seq = tsk_getu16(endian, &buf[14]); record->parent_refnum = tsk_getu48(endian, &buf[16]); record->parent_refnum_seq = tsk_getu16(endian, &buf[22]); record->usn = tsk_getu64(endian, &buf[24]); /* Convert NT timestamp into Unix */ timestamp = tsk_getu64(endian, &buf[32]); record->time_sec = nt2unixtime(timestamp); record->time_nsec = nt2nano(timestamp); record->reason = tsk_getu32(endian, &buf[40]); record->source_info = tsk_getu32(endian, &buf[44]); record->security = tsk_getu32(endian, &buf[48]); record->attributes = tsk_getu32(endian, &buf[52]); /* Extract file name */ name_length = tsk_getu16(endian, &buf[56]); name_offset = tsk_getu16(endian, &buf[58]); return parse_fname(&buf[name_offset], name_length, record, endian); }
static void parse_record_header(const unsigned char *buf, TSK_USN_RECORD_HEADER *header, TSK_ENDIAN_ENUM endian) { header->length = tsk_getu32(endian, &buf[0]); header->major_version = tsk_getu16(endian, &buf[4]); header->minor_version = tsk_getu16(endian, &buf[6]); }
/** * \internal * Parses the MBR of an exFAT file system to obtain file system size * information - bytes per sector, sectors per cluster, and sectors per FAT - * to add to a FATFS_INFO object. * * @param [in, out] a_fatfs Generic FAT file system info structure. * @return 0 on success, 1 otherwise, per TSK convention. */ static uint8_t exfatfs_get_fs_size_params(FATFS_INFO *a_fatfs) { const char *func_name = "exfatfs_get_fs_size_params"; TSK_FS_INFO *fs = &(a_fatfs->fs_info); EXFATFS_MASTER_BOOT_REC *exfatbs = NULL; assert(a_fatfs != NULL); exfatbs = (EXFATFS_MASTER_BOOT_REC*)(&a_fatfs->boot_sector_buffer); /* Get bytes per sector. * Bytes per sector is a base 2 logarithm, defining a range of sizes with * a min of 512 bytes and a max of 4096 bytes. */ a_fatfs->ssize_sh = (uint16_t)exfatbs->bytes_per_sector; if ((a_fatfs->ssize_sh < 9) || (a_fatfs->ssize_sh > 12)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr("Not an exFAT file system (invalid sector size)"); if (tsk_verbose) { fprintf(stderr, "%s: Invalid sector size base 2 logarithm (%d), not in range (9 - 12)\n", func_name, a_fatfs->ssize); } return FATFS_FAIL; } a_fatfs->ssize = (1 << a_fatfs->ssize_sh); /* Get sectors per cluster. * Sectors per cluster is a base 2 logarithm. The max cluster size is * 32 MiB, so the sum of the bytes per sector and sectors per cluster * logs cannot exceed 25. */ if ((a_fatfs->ssize_sh + exfatbs->sectors_per_cluster) > 25) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr("Not an exFAT file system (invalid cluster size)"); if (tsk_verbose) { fprintf(stderr, "%s: Invalid cluster size (%d)\n", func_name, exfatbs->sectors_per_cluster); } return FATFS_FAIL; } a_fatfs->csize = (1 << exfatbs->sectors_per_cluster); /* Get sectors per FAT. * It will at least be non-zero. */ a_fatfs->sectperfat = tsk_getu32(fs->endian, exfatbs->fat_len_in_sectors); if (a_fatfs->sectperfat == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr("Not an exFAT file system (invalid sectors per FAT)"); if (tsk_verbose) { fprintf(stderr, "%s: Invalid number of sectors per FAT (%d)\n", func_name, a_fatfs->sectperfat); } return FATFS_FAIL; } return FATFS_OK; }
static uint8_t sun_load_table_i386(TSK_VS_INFO * vs, sun_dlabel_i386 * dlabel_x86) { uint32_t idx = 0; TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector if (tsk_verbose) tsk_fprintf(stderr, "load_table_i386: Number of partitions: %d\n", tsk_getu16(vs->endian, dlabel_x86->num_parts)); /* Cycle through the partitions, there are either 8 or 16 */ for (idx = 0; idx < tsk_getu16(vs->endian, dlabel_x86->num_parts); idx++) { TSK_VS_PART_FLAG_ENUM ptype = TSK_VS_PART_FLAG_ALLOC; if (tsk_verbose) tsk_fprintf(stderr, "load_table_i386: %" PRIu32 " Starting Sector: %" PRIu32 " Size: %" PRIu32 " Type: %" PRIu16 "\n", idx, tsk_getu32(vs->endian, dlabel_x86->part[idx].start_sec), tsk_getu32(vs->endian, dlabel_x86->part[idx].size_sec), tsk_getu16(vs->endian, dlabel_x86->part[idx].type)); if (tsk_getu32(vs->endian, dlabel_x86->part[idx].size_sec) == 0) continue; // make sure the first couple are in the image bounds if ((idx < 2) && (tsk_getu32(vs->endian, dlabel_x86->part[idx].start_sec) > max_addr)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_BLK_NUM); tsk_error_set_errstr ("sun_load_i386: Starting sector too large for image"); return 1; } // set the entry that covers the entire disk image as DESC if ((tsk_getu16(vs->endian, dlabel_x86->part[idx].type) == 5) && (tsk_getu32(vs->endian, dlabel_x86->part[idx].start_sec) == 0)) ptype = TSK_VS_PART_FLAG_META; /* Add the partition to the internal sorted list */ if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) tsk_getu32(vs->endian, dlabel_x86->part[idx].start_sec), (TSK_DADDR_T) tsk_getu32(vs->endian, dlabel_x86->part[idx].size_sec), ptype, sun_get_desc(tsk_getu16(vs->endian, dlabel_x86->part[idx].type)), -1, idx)) { return 1; } } return 0; }
static uint8_t ext2fs_dent_copy(EXT2FS_INFO * ext2fs, char *ext2_dent, TSK_FS_NAME * fs_name) { TSK_FS_INFO *fs = &(ext2fs->fs_info); if (ext2fs->deentry_type == EXT2_DE_V1) { ext2fs_dentry1 *dir = (ext2fs_dentry1 *) ext2_dent; fs_name->meta_addr = tsk_getu32(fs->endian, dir->inode); /* ext2 does not null terminate */ if (tsk_getu16(fs->endian, dir->name_len) >= fs_name->name_size) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr ("ext2fs_dent_copy: Name Space too Small %d %" PRIuSIZE "", tsk_getu16(fs->endian, dir->name_len), fs_name->name_size); return 1; } /* Copy and Null Terminate */ strncpy(fs_name->name, dir->name, tsk_getu16(fs->endian, dir->name_len)); fs_name->name[tsk_getu16(fs->endian, dir->name_len)] = '\0'; fs_name->type = TSK_FS_NAME_TYPE_UNDEF; } else { ext2fs_dentry2 *dir = (ext2fs_dentry2 *) ext2_dent; fs_name->meta_addr = tsk_getu32(fs->endian, dir->inode); /* ext2 does not null terminate */ if (dir->name_len >= fs_name->name_size) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr ("ext2_dent_copy: Name Space too Small %d %" PRIuSIZE "", dir->name_len, fs_name->name_size); return 1; } /* Copy and Null Terminate */ strncpy(fs_name->name, dir->name, dir->name_len); fs_name->name[dir->name_len] = '\0'; switch (dir->type) { case EXT2_DE_REG: fs_name->type = TSK_FS_NAME_TYPE_REG; break; case EXT2_DE_DIR: fs_name->type = TSK_FS_NAME_TYPE_DIR; break; case EXT2_DE_CHR: fs_name->type = TSK_FS_NAME_TYPE_CHR; break; case EXT2_DE_BLK: fs_name->type = TSK_FS_NAME_TYPE_BLK; break; case EXT2_DE_FIFO: fs_name->type = TSK_FS_NAME_TYPE_FIFO; break; case EXT2_DE_SOCK: fs_name->type = TSK_FS_NAME_TYPE_SOCK; break; case EXT2_DE_LNK: fs_name->type = TSK_FS_NAME_TYPE_LNK; break; case EXT2_DE_UNKNOWN: default: fs_name->type = TSK_FS_NAME_TYPE_UNDEF; break; } } fs_name->flags = 0; return 0; }
/* * Load an extended partition table into the structure in TSK_VS_INFO. * * sect_cur: The sector where the extended table is located * sect_ext_base: The sector of the primary extended table (this does * not change for recursive calls) * table: a counter that identifies the table depth * (increases by 1 for each recursive call) * * For the primary extended table, sect_cur == sect_ext_base * * Return 1 on error and 0 on success * */ static uint8_t dos_load_ext_table(TSK_VS_INFO * vs, TSK_DADDR_T sect_cur, TSK_DADDR_T sect_ext_base, int table) { dos_sect *sect; char *sect_buf; int i; char *table_str; ssize_t cnt; TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector if (tsk_verbose) tsk_fprintf(stderr, "dos_load_ext: Table Sector: %" PRIuDADDR ", Primary Base Sector: %" PRIuDADDR "\n", sect_cur, sect_ext_base); if ((sect_buf = tsk_malloc(vs->block_size)) == NULL) return 1; sect = (dos_sect *) sect_buf; /* Read the partition table sector */ cnt = tsk_vs_read_block(vs, sect_cur, sect_buf, vs->block_size); if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2("Extended DOS table sector %" PRIuDADDR, sect_cur); free(sect_buf); return 1; } /* Sanity Check */ if (tsk_getu16(vs->endian, sect->magic) != DOS_MAGIC) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr("Extended DOS partition table in sector %" PRIuDADDR, sect_cur); free(sect_buf); return 1; } /* Add an entry of 1 length for the table to the internal structure */ if ((table_str = tsk_malloc(32)) == NULL) { free(sect_buf); return 1; } snprintf(table_str, 32, "Extended Table (#%d)", table); if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) sect_cur, (TSK_DADDR_T) 1, TSK_VS_PART_FLAG_META, table_str, table, -1)) { free(sect_buf); return 1; } /* Cycle through the four partitions in the table * * When another extended partition is found, it is processed * inside of the loop */ for (i = 0; i < 4; i++) { dos_part *part = §->ptable[i]; /* Get the starting sector and size, we currently * ignore CHS */ uint32_t part_start = tsk_getu32(vs->endian, part->start_sec); uint32_t part_size = tsk_getu32(vs->endian, part->size_sec); if (tsk_verbose) tsk_fprintf(stderr, "load_ext: %d:%d Start: %" PRIu32 " Size: %" PRIu32 " Type: %d\n", table, i, part_start, part_size, part->ptype); if (part_size == 0) continue; /* partitions are addressed differently * in extended partitions */ if (dos_is_ext(part->ptype)) { /* part start is added to the start of the * first extended partition (the primary * extended partition) */ if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) (sect_ext_base + part_start), (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_META, dos_get_desc(part->ptype), table, i)) { free(sect_buf); return 1; } if (sect_ext_base + part_start > max_addr) { if (tsk_verbose) tsk_fprintf(stderr, "Starting sector %" PRIuDADDR " of extended partition too large for image\n", sect_ext_base + part_start); } /* Process the extended partition */ else if (dos_load_ext_table(vs, sect_ext_base + part_start, sect_ext_base, table + 1)) { free(sect_buf); return 1; } } else { /* part_start is added to the start of the * current partition for the actual * starting location */ // we ignore the max_addr checks on extended partitions... if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) (sect_cur + part_start), (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC, dos_get_desc(part->ptype), table, i)) { free(sect_buf); return 1; } } } free(sect_buf); return 0; }
/* * @param a_is_del Set to 1 if block is from a deleted directory. */ static TSK_RETVAL_ENUM ffs_dent_parse_block(FFS_INFO * ffs, TSK_FS_DIR * fs_dir, uint8_t a_is_del, char *buf, unsigned int len) { unsigned int idx; unsigned int inode = 0, dellen = 0, reclen = 0; unsigned int minreclen = 4; TSK_FS_INFO *fs = &(ffs->fs_info); char *dirPtr; TSK_FS_NAME *fs_name; if ((fs_name = tsk_fs_name_alloc(FFS_MAXNAMLEN + 1, 0)) == NULL) return TSK_ERR; /* update each time by the actual length instead of the ** recorded length so we can view the deleted entries */ for (idx = 0; idx <= len - FFS_DIRSIZ_lcl(1); idx += minreclen) { unsigned int namelen = 0; dirPtr = (char *) &buf[idx]; /* copy to local variables */ if ((fs->ftype == TSK_FS_TYPE_FFS1) || (fs->ftype == TSK_FS_TYPE_FFS2)) { ffs_dentry1 *dir = (ffs_dentry1 *) dirPtr; inode = tsk_getu32(fs->endian, dir->d_ino); namelen = dir->d_namlen; reclen = tsk_getu16(fs->endian, dir->d_reclen); } /* TSK_FS_TYPE_FFS1B */ else if (fs->ftype == TSK_FS_TYPE_FFS1B) { ffs_dentry2 *dir = (ffs_dentry2 *) dirPtr; inode = tsk_getu32(fs->endian, dir->d_ino); namelen = tsk_getu16(fs->endian, dir->d_namlen); reclen = tsk_getu16(fs->endian, dir->d_reclen); } /* what is the minimum size needed for this entry */ minreclen = FFS_DIRSIZ_lcl(namelen); /* Perform a couple sanity checks ** OpenBSD never zeros the inode number, but solaris ** does. These checks will hopefully catch all non ** entries */ if ((inode > fs->last_inum) || // inode is unsigned (namelen > FFS_MAXNAMLEN) || // namelen is unsigned (namelen == 0) || (reclen < minreclen) || (reclen % 4) || (idx + reclen > len)) { /* we don't have a valid entry, so skip ahead 4 */ minreclen = 4; if (dellen > 0) dellen -= 4; continue; } /* Before we process an entry in unallocated space, make * sure that it also ends in the unalloc space */ if ((dellen) && (dellen < minreclen)) { minreclen = 4; dellen -= 4; continue; } /* the entry is valid */ if (ffs_dent_copy(ffs, dirPtr, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } /* Do we have a deleted entry? (are we in a deleted space) */ if ((dellen > 0) || (inode == 0) || (a_is_del)) { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; if (dellen) dellen -= minreclen; } else { fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } if (tsk_fs_dir_add(fs_dir, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } /* If we have some slack and an entry could exist in it, the set dellen */ if (dellen <= 0) { if (reclen - minreclen >= FFS_DIRSIZ_lcl(1)) dellen = reclen - minreclen; else minreclen = reclen; } } tsk_fs_name_free(fs_name); return TSK_OK; } /* end ffs_dent_parse_block */
/* * * NoTe that this does not set the flag value. * * return 1 on error and 0 on success */ static uint8_t ext2fs_dent_copy(EXT2FS_INFO * ext2fs, EXT2FS_DINFO * dinfo, char *ext2_dent, TSK_FS_DENT * fs_dent) { TSK_FS_INFO *fs = &(ext2fs->fs_info); int i; if (ext2fs->deentry_type == EXT2_DE_V1) { ext2fs_dentry1 *dir = (ext2fs_dentry1 *) ext2_dent; fs_dent->inode = tsk_getu32(fs->endian, dir->inode); /* ext2 does not null terminate */ if (tsk_getu16(fs->endian, dir->name_len) >= fs_dent->name_max) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ext2fs_dent_copy: Name Space too Small %d %lu", tsk_getu16(fs->endian, dir->name_len), fs_dent->name_max); return 1; } /* Copy and Null Terminate */ strncpy(fs_dent->name, dir->name, tsk_getu16(fs->endian, dir->name_len)); fs_dent->name[tsk_getu16(fs->endian, dir->name_len)] = '\0'; fs_dent->ent_type = TSK_FS_DENT_TYPE_UNDEF; } else { ext2fs_dentry2 *dir = (ext2fs_dentry2 *) ext2_dent; fs_dent->inode = tsk_getu32(fs->endian, dir->inode); /* ext2 does not null terminate */ if (dir->name_len >= fs_dent->name_max) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ext2_dent_copy: Name Space too Small %d %lu", dir->name_len, fs_dent->name_max); return 1; } /* Copy and Null Terminate */ strncpy(fs_dent->name, dir->name, dir->name_len); fs_dent->name[dir->name_len] = '\0'; switch (dir->type) { case EXT2_DE_REG_FILE: fs_dent->ent_type = TSK_FS_DENT_TYPE_REG; break; case EXT2_DE_DIR: fs_dent->ent_type = TSK_FS_DENT_TYPE_DIR; break; case EXT2_DE_CHRDEV: fs_dent->ent_type = TSK_FS_DENT_TYPE_CHR; break; case EXT2_DE_BLKDEV: fs_dent->ent_type = TSK_FS_DENT_TYPE_BLK; break; case EXT2_DE_FIFO: fs_dent->ent_type = TSK_FS_DENT_TYPE_FIFO; break; case EXT2_DE_SOCK: fs_dent->ent_type = TSK_FS_DENT_TYPE_SOCK; break; case EXT2_DE_SYMLINK: fs_dent->ent_type = TSK_FS_DENT_TYPE_LNK; break; case EXT2_DE_UNKNOWN: default: fs_dent->ent_type = TSK_FS_DENT_TYPE_UNDEF; break; } } /* Clean up name */ i = 0; while (fs_dent->name[i] != '\0') { if (TSK_IS_CNTRL(fs_dent->name[i])) fs_dent->name[i] = '^'; i++; } fs_dent->path = dinfo->dirs; fs_dent->pathdepth = dinfo->depth; if ((fs != NULL) && (fs_dent->inode) && (fs_dent->inode <= fs->last_inum)) { /* Get inode */ if (fs_dent->fsi) tsk_fs_inode_free(fs_dent->fsi); if ((fs_dent->fsi = fs->inode_lookup(fs, fs_dent->inode)) == NULL) { strncat(tsk_errstr2, " - ext2fs_dent_copy", TSK_ERRSTR_L - strlen(tsk_errstr2)); return 1; } } else { if (fs_dent->fsi) tsk_fs_inode_free(fs_dent->fsi); fs_dent->fsi = NULL; } fs_dent->flags = 0; return 0; }
/** \internal * Process a directory and load up FS_DIR with the entries. If a pointer to * an already allocated FS_DIR struture is given, it will be cleared. If no existing * FS_DIR structure is passed (i.e. NULL), then a new one will be created. If the return * value is error or corruption, then the FS_DIR structure could * have entries (depending on when the error occured). * * @param a_fs File system to analyze * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated * structure or a new structure. * @param a_addr Address of directory to process. * @returns error, corruption, ok etc. */ TSK_RETVAL_ENUM ntfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr) { NTFS_INFO *ntfs = (NTFS_INFO *) a_fs; TSK_FS_DIR *fs_dir; const TSK_FS_ATTR *fs_attr_root = NULL; const TSK_FS_ATTR *fs_attr_idx; char *idxalloc; ntfs_idxentry *idxe; ntfs_idxroot *idxroot; ntfs_idxelist *idxelist; ntfs_idxrec *idxrec_p, *idxrec; int off; TSK_OFF_T idxalloc_len; TSK_FS_LOAD_FILE load_file; NTFS_PAR_MAP *map; /* In this function, we will return immediately if we get an error. * If we get corruption though, we will record that in 'retval_final' * and continue processing. */ TSK_RETVAL_ENUM retval_final = TSK_OK; TSK_RETVAL_ENUM retval_tmp; /* sanity check */ if (a_addr < a_fs->first_inum || a_addr > a_fs->last_inum) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_WALK_RNG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_dir_open_meta: inode value: %" PRIuINUM "\n", a_addr); return TSK_ERR; } else if (a_fs_dir == NULL) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_dir_open_meta: NULL fs_attr argument given"); return TSK_ERR; } if (tsk_verbose) tsk_fprintf(stderr, "ntfs_open_dir: Processing directory %" PRIuINUM "\n", a_addr); fs_dir = *a_fs_dir; if (fs_dir) { tsk_fs_dir_reset(fs_dir); } else { if ((*a_fs_dir = fs_dir = tsk_fs_dir_alloc(a_fs, 128)) == NULL) { return TSK_ERR; } } // handle the orphan directory if its contents were requested if (a_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) { return tsk_fs_dir_find_orphans(a_fs, fs_dir); } /* Get the inode and verify it has attributes */ if ((fs_dir->fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr)) == NULL) { strncat(tsk_errstr2, " - ntfs_dir_open_meta", TSK_ERRSTR_L - strlen(tsk_errstr2)); return TSK_COR; } if (!(fs_dir->fs_file->meta->attr)) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "dent_walk: Error: Directory address %" PRIuINUM " has no attributes", a_addr); return TSK_COR; } /* * Read the Index Root Attribute -- we do some sanity checking here * to report errors before we start to make up data for the "." and ".." * entries */ fs_attr_root = tsk_fs_attrlist_get(fs_dir->fs_file->meta->attr, NTFS_ATYPE_IDXROOT); if (!fs_attr_root) { strncat(tsk_errstr2, " - dent_walk: $IDX_ROOT not found", TSK_ERRSTR_L - strlen(tsk_errstr2)); return TSK_COR; } if (fs_attr_root->flags & TSK_FS_ATTR_NONRES) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "dent_walk: $IDX_ROOT is not resident - it should be"); return TSK_COR; } idxroot = (ntfs_idxroot *) fs_attr_root->rd.buf; /* Verify that the attribute type is $FILE_NAME */ if (tsk_getu32(a_fs->endian, idxroot->type) == 0) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "dent_walk: Attribute type in index root is 0"); return TSK_COR; } else if (tsk_getu32(a_fs->endian, idxroot->type) != NTFS_ATYPE_FNAME) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "ERROR: Directory index is sorted by type: %" PRIu32 ".\nOnly $FNAME is currently supported", tsk_getu32(a_fs->endian, idxroot->type)); return TSK_COR; } /* Get the header of the index entry list */ idxelist = &idxroot->list; /* Get the offset to the start of the index entry list */ idxe = (ntfs_idxentry *) ((uintptr_t) idxelist + tsk_getu32(a_fs->endian, idxelist->begin_off)); /* * NTFS does not have "." and ".." entries in the index trees * (except for a "." entry in the root directory) * * So, we'll make 'em up by making a TSK_FS_NAME structure for * a '.' and '..' entry and call the action */ if (a_addr != a_fs->root_inum) { // && (flags & TSK_FS_NAME_FLAG_ALLOC)) { TSK_FS_NAME *fs_name; TSK_FS_META_NAME_LIST *fs_name_list; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dir_open_meta: Creating . and .. entries\n"); if ((fs_name = tsk_fs_name_alloc(16, 0)) == NULL) { return TSK_ERR; } /* * "." */ fs_name->meta_addr = a_addr; fs_name->meta_seq = fs_dir->fs_file->meta->seq; fs_name->type = TSK_FS_NAME_TYPE_DIR; strcpy(fs_name->name, "."); fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (tsk_fs_dir_add(fs_dir, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } /* * ".." */ strcpy(fs_name->name, ".."); fs_name->type = TSK_FS_NAME_TYPE_DIR; /* The fs_name structure holds the parent inode value, so we * just cycle using those */ for (fs_name_list = fs_dir->fs_file->meta->name2; fs_name_list != NULL; fs_name_list = fs_name_list->next) { fs_name->meta_addr = fs_name_list->par_inode; fs_name->meta_seq = fs_name_list->par_seq; if (tsk_fs_dir_add(fs_dir, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } } tsk_fs_name_free(fs_name); fs_name = NULL; } /* Now we return to processing the Index Root Attribute */ if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dir_open_meta: Processing $IDX_ROOT of inum %" PRIuINUM "\n", a_addr); /* Verify the offset pointers */ if ((tsk_getu32(a_fs->endian, idxelist->seqend_off) < tsk_getu32(a_fs->endian, idxelist->begin_off)) || (tsk_getu32(a_fs->endian, idxelist->bufend_off) < tsk_getu32(a_fs->endian, idxelist->seqend_off)) || (((uintptr_t) idxe + tsk_getu32(a_fs->endian, idxelist->bufend_off)) > ((uintptr_t) fs_attr_root->rd.buf + fs_attr_root->rd.buf_size))) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error: Index list offsets are invalid on entry: %" PRIuINUM, fs_dir->fs_file->meta->addr); return TSK_COR; } retval_tmp = ntfs_proc_idxentry(ntfs, fs_dir, (fs_dir->fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC) ? 1 : 0, idxe, tsk_getu32(a_fs->endian, idxelist->bufend_off) - tsk_getu32(a_fs->endian, idxelist->begin_off), tsk_getu32(a_fs->endian, idxelist->seqend_off) - tsk_getu32(a_fs->endian, idxelist->begin_off)); // stop if we get an error, continue if we got corruption if (retval_tmp == TSK_ERR) { return TSK_ERR; } else if (retval_tmp == TSK_COR) { retval_final = TSK_COR; } /* * get the index allocation attribute if it exists (it doesn't for * small directories */ fs_attr_idx = tsk_fs_attrlist_get(fs_dir->fs_file->meta->attr, NTFS_ATYPE_IDXALLOC); /* if we don't have an index alloc then return, we have processed * all of the entries */ if (!fs_attr_idx) { if (tsk_getu32(a_fs->endian, idxelist->flags) & NTFS_IDXELIST_CHILD) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error: $IDX_ROOT says there should be children, but there isn't"); return TSK_COR; } } else { if (fs_attr_idx->flags & TSK_FS_ATTR_RES) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "$IDX_ALLOC is Resident - it shouldn't be"); return TSK_COR; } /* * Copy the index allocation run into a big buffer */ idxalloc_len = fs_attr_idx->nrd.allocsize; if ((idxalloc = tsk_malloc((size_t) idxalloc_len)) == NULL) { return TSK_ERR; } /* Fill in the loading data structure */ load_file.total = load_file.left = (size_t) idxalloc_len; load_file.cur = load_file.base = idxalloc; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dir_open_meta: Copying $IDX_ALLOC into buffer\n"); if (tsk_fs_attr_walk(fs_attr_idx, TSK_FS_FILE_WALK_FLAG_SLACK, tsk_fs_load_file_action, (void *) &load_file)) { free(idxalloc); strncat(tsk_errstr2, " - ntfs_dir_open_meta", TSK_ERRSTR_L - strlen(tsk_errstr2)); return TSK_COR; // this could be an error though } /* Not all of the directory was copied, so we exit */ if (load_file.left > 0) { free(idxalloc); tsk_error_reset(); tsk_errno = TSK_ERR_FS_FWALK; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error reading directory contents: %" PRIuINUM "\n", a_addr); return TSK_COR; } /* * The idxalloc is a big buffer that contains one or more * idx buffer structures. Each idxrec is a node in the B-Tree. * We do not process the tree as a tree because then we could * not find the deleted file names. * * Therefore, we scan the big buffer looking for the index record * structures. We save a pointer to the known beginning (idxrec_p). * Then we scan for the beginning of the next one (idxrec) and process * everything in the middle as an ntfs_idxrec. We can't use the * size given because then we wouldn't see the deleted names */ /* Set the previous pointer to NULL */ idxrec_p = idxrec = NULL; /* Loop by cluster size */ for (off = 0; off < idxalloc_len; off += ntfs->csize_b) { uint32_t list_len, rec_len; idxrec = (ntfs_idxrec *) & idxalloc[off]; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dir_open_meta: Index Buffer Offset: %d Magic: %" PRIx32 "\n", off, tsk_getu32(a_fs->endian, idxrec->magic)); /* Is this the begining of an index record? */ if (tsk_getu32(a_fs->endian, idxrec->magic) != NTFS_IDXREC_MAGIC) continue; /* idxrec_p is only NULL for the first time * Set it and start again to find the next one */ if (idxrec_p == NULL) { idxrec_p = idxrec; continue; } /* Process the previous structure */ /* idxrec points to the next idxrec structure, idxrec_p * points to the one we are going to process */ rec_len = (uint32_t) ((uintptr_t) idxrec - (uintptr_t) idxrec_p); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dir_open_meta: Processing previous index record (len: %" PRIu32 ")\n", rec_len); /* remove the update sequence in the index record */ if (ntfs_fix_idxrec(ntfs, idxrec_p, rec_len)) { free(idxalloc); return TSK_COR; } /* Locate the start of the index entry list */ idxelist = &idxrec_p->list; idxe = (ntfs_idxentry *) ((uintptr_t) idxelist + tsk_getu32(a_fs->endian, idxelist->begin_off)); /* the length from the start of the next record to where our * list starts. * This should be the same as bufend_off in idxelist, but we don't * trust it. */ list_len = (uint32_t) ((uintptr_t) idxrec - (uintptr_t) idxe); /* Verify the offset pointers */ if (((uintptr_t) idxe > (uintptr_t) idxrec) || ((uintptr_t) idxelist + tsk_getu32(a_fs->endian, idxelist->seqend_off) > (uintptr_t) idxrec)) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error: Index list offsets are invalid on entry: %" PRIuINUM, fs_dir->fs_file->meta->addr); free(idxalloc); return TSK_COR; } /* process the list of index entries */ retval_tmp = ntfs_proc_idxentry(ntfs, fs_dir, (fs_dir->fs_file-> meta->flags & TSK_FS_META_FLAG_UNALLOC) ? 1 : 0, idxe, list_len, tsk_getu32(a_fs->endian, idxelist->seqend_off) - tsk_getu32(a_fs->endian, idxelist->begin_off)); // stop if we get an error, record if we get corruption if (retval_tmp == TSK_ERR) { free(idxalloc); return TSK_ERR; } else if (retval_tmp == TSK_COR) { retval_final = TSK_COR; } /* reset the pointer to the next record */ idxrec_p = idxrec; } /* end of cluster loop */ /* Process the final record */ if (idxrec_p) { uint32_t list_len, rec_len; /* Length from end of attribute to start of this */ rec_len = (uint32_t) (idxalloc_len - (uintptr_t) idxrec_p - (uintptr_t) idxalloc); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dir_open_meta: Processing final index record (len: %" PRIu32 ")\n", rec_len); /* remove the update sequence */ if (ntfs_fix_idxrec(ntfs, idxrec_p, rec_len)) { free(idxalloc); return TSK_COR; } idxelist = &idxrec_p->list; idxe = (ntfs_idxentry *) ((uintptr_t) idxelist + tsk_getu32(a_fs->endian, idxelist->begin_off)); /* This is the length of the idx entries */ list_len = (uint32_t) ((uintptr_t) idxalloc + idxalloc_len) - (uintptr_t) idxe; /* Verify the offset pointers */ if ((list_len > rec_len) || ((uintptr_t) idxelist + tsk_getu32(a_fs->endian, idxelist->seqend_off) > (uintptr_t) idxalloc + idxalloc_len)) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error: Index list offsets are invalid on entry: %" PRIuINUM, fs_dir->fs_file->meta->addr); free(idxalloc); return TSK_COR; } /* process the list of index entries */ retval_tmp = ntfs_proc_idxentry(ntfs, fs_dir, (fs_dir->fs_file-> meta->flags & TSK_FS_META_FLAG_UNALLOC) ? 1 : 0, idxe, list_len, tsk_getu32(a_fs->endian, idxelist->seqend_off) - tsk_getu32(a_fs->endian, idxelist->begin_off)); // stop if we get an error, record if we get corruption if (retval_tmp == TSK_ERR) { free(idxalloc); return TSK_ERR; } else if (retval_tmp == TSK_COR) { retval_final = TSK_COR; } } free(idxalloc); } // get the orphan files // load and cache the map if it has not already been done if (ntfs->orphan_map == NULL) { if (a_fs->inode_walk(a_fs, a_fs->first_inum, a_fs->last_inum, TSK_FS_META_FLAG_UNALLOC, ntfs_orphan_act, NULL)) { return TSK_ERR; } } // see if there are any entries for this dir map = ntfs_orphan_map_get(ntfs, a_addr); if (map != NULL) { int a; TSK_FS_NAME *fs_name; TSK_FS_FILE *fs_file_orp = NULL; if ((fs_name = tsk_fs_name_alloc(256, 0)) == NULL) return TSK_ERR; fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; fs_name->type = TSK_FS_NAME_TYPE_UNDEF; for (a = 0; a < map->used_cnt; a++) { /* Fill in the basics of the fs_name entry * so we can print in the fls formats */ fs_name->meta_addr = map->addrs[a]; // lookup the file to get its name (we did not cache that) fs_file_orp = tsk_fs_file_open_meta(a_fs, fs_file_orp, map->addrs[a]); if ((fs_file_orp) && (fs_file_orp->meta) && (fs_file_orp->meta->name2)) { TSK_FS_META_NAME_LIST *n2 = fs_file_orp->meta->name2; while (n2) { if (n2->par_inode == a_addr) { strncpy(fs_name->name, n2->name, fs_name->name_size); tsk_fs_dir_add(fs_dir, fs_name); } n2 = n2->next; } } } tsk_fs_name_free(fs_name); } // if we are listing the root directory, add the Orphan directory entry if (a_addr == a_fs->root_inum) { TSK_FS_NAME *fs_name; if ((fs_name = tsk_fs_name_alloc(256, 0)) == NULL) return TSK_ERR; if (tsk_fs_dir_make_orphan_dir_name(a_fs, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } if (tsk_fs_dir_add(fs_dir, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } tsk_fs_name_free(fs_name); } return retval_final; }
/** * \internal * Parses the MBR of an exFAT file system to obtain file system layout * information to add to a FATFS_INFO object. * * @param [in, out] a_fatfs Generic FAT file system info structure. * @return 0 on success, 1 otherwise, per TSK convention. */ static uint8_t exfatfs_get_fs_layout(FATFS_INFO *a_fatfs) { const char *func_name = "exfatfs_get_fs_layout"; TSK_FS_INFO *fs = &(a_fatfs->fs_info); EXFATFS_MASTER_BOOT_REC *exfatbs = NULL; uint64_t vol_len_in_sectors = 0; uint64_t last_sector_of_cluster_heap = 0; assert(a_fatfs != NULL); /* Get the size of the volume. It should be non-zero. */ exfatbs = (EXFATFS_MASTER_BOOT_REC*)(&a_fatfs->boot_sector_buffer); vol_len_in_sectors = tsk_getu64(fs->endian, exfatbs->vol_len_in_sectors); if (vol_len_in_sectors == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr("Not an exFAT file system (invalid volume length)"); if (tsk_verbose) { fprintf(stderr, "%s: Invalid volume length in sectors (%" PRIu64 ")\n", func_name, vol_len_in_sectors); } return FATFS_FAIL; } /* Get the number of FATs. There will be one FAT for regular exFAT and two * FATs for TexFAT (transactional exFAT). */ a_fatfs->numfat = exfatbs->num_fats; if ((a_fatfs->numfat != 1) && (a_fatfs->numfat != 2)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr("Not an exFAT file system (number of FATs)"); if (tsk_verbose) { fprintf(stderr, "%s: Invalid number of FATs (%d)\n", func_name, a_fatfs->numfat); } return FATFS_FAIL; } /* Get the sector address of the first FAT (FAT0). * It should be non-zero and within the boundaries of the volume. * Note that if the file system is TexFAT, FAT1 will be the working copy * of the FAT and FAT0 will be the stable copy of the last known good FAT. * Therefore, the Sleuthkit should use FAT0. */ a_fatfs->firstfatsect = tsk_getu32(fs->endian, exfatbs->fat_offset); if ((a_fatfs->firstfatsect == 0) || ((uint64_t)a_fatfs->firstfatsect >= vol_len_in_sectors)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); tsk_error_set_errstr("Not an exFAT file system (invalid first FAT sector)"); if (tsk_verbose) { fprintf(stderr, "%s: Invalid first FAT sector (%" PRIuDADDR ")\n", func_name, a_fatfs->firstfatsect); } return FATFS_FAIL; } /* Get the sector address of the cluster heap (data area). It should be * after the FATs and within the boundaries of the volume. */ a_fatfs->firstdatasect = tsk_getu32(fs->endian, exfatbs->cluster_heap_offset); if ((a_fatfs->firstdatasect <= (a_fatfs->firstfatsect + (a_fatfs->sectperfat * a_fatfs->numfat) - 1)) || ((uint64_t)a_fatfs->firstdatasect >= vol_len_in_sectors)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); tsk_error_set_errstr("Not an exFAT file system (invalid first data sector"); if (tsk_verbose) { fprintf(stderr, "%s: Invalid first data sector (%" PRIuDADDR ")\n", func_name, a_fatfs->firstdatasect); } return FATFS_FAIL; } /* Unlike FAT12 and FAT16, but like FAT32, the sector address of the first * cluster (cluster #2, there is no cluster #0 or cluster #1) is the same * as the sector address of the cluster heap (data area). */ a_fatfs->firstclustsect = a_fatfs->firstdatasect; /* Get the total number of clusters. It should be non-zero, and should * define a cluster heap (data area) that is within the boundaries of the * volume. */ a_fatfs->clustcnt = tsk_getu32(fs->endian, exfatbs->cluster_cnt); last_sector_of_cluster_heap = a_fatfs->firstdatasect + (a_fatfs->clustcnt * a_fatfs->csize) - 1; if ((a_fatfs->clustcnt == 0) || (last_sector_of_cluster_heap >= vol_len_in_sectors)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); tsk_error_set_errstr("Not an exFAT file system (invalid cluster count)"); if (tsk_verbose) { fprintf(stderr, "%s: Invalid cluster count (%" PRIuDADDR ")\n", func_name, a_fatfs->clustcnt); } return FATFS_FAIL; } /* The first cluster is #2, so the final cluster is: */ a_fatfs->lastclust = 1 + a_fatfs->clustcnt; /* This bit mask is required to make the FATFS_CLUST_2_SECT macro work * for exFAT. It is the same as the FAT32 mask. */ a_fatfs->mask = EXFATFS_MASK; /* Get the sector address of the root directory. It should be within the * cluster heap (data area). */ a_fatfs->rootsect = FATFS_CLUST_2_SECT(a_fatfs, tsk_getu32(fs->endian, exfatbs->root_dir_cluster)); if ((a_fatfs->rootsect < a_fatfs->firstdatasect) || ((uint64_t)a_fatfs->rootsect > last_sector_of_cluster_heap)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); tsk_error_set_errstr("Not an exFAT file system (invalid root directory sector address)"); if (tsk_verbose) { fprintf(stderr, "%s: Invalid root directory sector address (%"PRIuDADDR")\n", func_name, a_fatfs->rootsect); } return FATFS_FAIL; } /* The number of directory entries in the root directory is not specified * in the exFAT boot sector. */ a_fatfs->numroot = 0; return FATFS_OK; }
static uint8_t ntfs_dent_walk_lcl(TSK_FS_INFO * fs, NTFS_DINFO * dinfo, TSK_LIST ** list_seen, INUM_T inum, TSK_FS_DENT_FLAG_ENUM flags, TSK_FS_DENT_TYPE_WALK_CB action, void *ptr) { NTFS_INFO *ntfs = (NTFS_INFO *) fs; TSK_FS_INODE *fs_inode; TSK_FS_DATA *fs_data_root, *tsk_fs_data_alloc; char *idxalloc; ntfs_idxentry *idxe; ntfs_idxroot *idxroot; ntfs_idxelist *idxelist; ntfs_idxrec *idxrec_p, *idxrec; int off; OFF_T idxalloc_len; TSK_FS_LOAD_FILE load_file; int retval; /* sanity check */ if (inum < fs->first_inum || inum > fs->last_inum) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_WALK_RNG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_dent_walk: inode value: %" PRIuINUM "\n", inum); return 1; } if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_walk: Processing directory %" PRIuINUM " with flags %x\n", inum, flags); /* Get the inode and verify it has attributes */ fs_inode = fs->inode_lookup(fs, inum); if (!fs_inode) { strncat(tsk_errstr2, " - ntfs_dent_walk", TSK_ERRSTR_L - strlen(tsk_errstr2)); return 1; } if (!fs_inode->attr) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; snprintf(tsk_errstr, TSK_ERRSTR_L, "dent_walk: Error: Directory address %" PRIuINUM " has no attributes", inum); return 1; } /* * Read the Index Root Attribute -- we do some sanity checking here * to report errors before we start to make up data for the "." and ".." * entries */ fs_data_root = tsk_fs_data_lookup_noid(fs_inode->attr, NTFS_ATYPE_IDXROOT); if (!fs_data_root) { strncat(tsk_errstr2, " - dent_walk: $IDX_ROOT not found", TSK_ERRSTR_L - strlen(tsk_errstr2)); tsk_fs_inode_free(fs_inode); return 1; } if (fs_data_root->flags & TSK_FS_DATA_NONRES) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; snprintf(tsk_errstr, TSK_ERRSTR_L, "dent_walk: $IDX_ROOT is not resident - it should be"); tsk_fs_inode_free(fs_inode); return 1; } idxroot = (ntfs_idxroot *) fs_data_root->buf; /* Verify that the attribute type is $FILE_NAME */ if (tsk_getu32(fs->endian, idxroot->type) == 0) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; snprintf(tsk_errstr, TSK_ERRSTR_L, "dent_walk: Attribute type in index root is 0"); tsk_fs_inode_free(fs_inode); return 1; } else if (tsk_getu32(fs->endian, idxroot->type) != NTFS_ATYPE_FNAME) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; snprintf(tsk_errstr, TSK_ERRSTR_L, "ERROR: Directory index is sorted by type: %" PRIu32 ".\nOnly $FNAME is currently supported", tsk_getu32(fs->endian, idxroot->type)); return 1; } /* Get the header of the index entry list */ idxelist = &idxroot->list; /* Get the offset to the start of the index entry list */ idxe = (ntfs_idxentry *) ((uintptr_t) idxelist + tsk_getu32(fs->endian, idxelist->begin_off)); /* * NTFS does not have "." and ".." entries in the index trees * (except for a "." entry in the root directory) * * So, we'll make 'em up by making a TSK_FS_DENT structure for * a '.' and '..' entry and call the action */ if ((inum != fs->root_inum) && (flags & TSK_FS_DENT_FLAG_ALLOC)) { TSK_FS_DENT *fs_dent; TSK_FS_INODE_NAME_LIST *fs_name; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_walk: Creating . and .. entries\n"); if ((fs_dent = tsk_fs_dent_alloc(16, 0)) == NULL) { tsk_fs_inode_free(fs_inode); return 1; } /* * "." */ fs_dent->inode = inum; strcpy(fs_dent->name, "."); /* copy the path data */ fs_dent->path = dinfo->dirs; fs_dent->pathdepth = dinfo->depth; fs_dent->flags = TSK_FS_DENT_FLAG_ALLOC; /* this is probably a waste, but just in case the action mucks * with it ... */ fs_dent->fsi = fs->inode_lookup(fs, fs_dent->inode); if (fs_dent->fsi != NULL) { fs_dent->ent_type = TSK_FS_DENT_TYPE_DIR; retval = action(fs, fs_dent, ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dent_free(fs_dent); tsk_fs_inode_free(fs_inode); return 0; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dent_free(fs_dent); tsk_fs_inode_free(fs_inode); return 1; } } else { if (tsk_verbose) tsk_fprintf(stderr, "Error reading . entry: %" PRIuINUM, fs_dent->inode); } /* * ".." */ strcpy(fs_dent->name, ".."); fs_dent->ent_type = TSK_FS_DENT_TYPE_DIR; /* The fs_name structure holds the parent inode value, so we * just cycle using those */ for (fs_name = fs_inode->name; fs_name != NULL; fs_name = fs_name->next) { if (fs_dent->fsi) { tsk_fs_inode_free(fs_dent->fsi); fs_dent->fsi = NULL; } fs_dent->inode = fs_name->par_inode; fs_dent->fsi = fs->inode_lookup(fs, fs_dent->inode); if (fs_dent->fsi) { retval = action(fs, fs_dent, ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dent_free(fs_dent); tsk_fs_inode_free(fs_inode); return 0; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dent_free(fs_dent); tsk_fs_inode_free(fs_inode); return 1; } } else { if (tsk_verbose) tsk_fprintf(stderr, "dent_walk: Error reading .. inode: %" PRIuINUM, fs_dent->inode); } } tsk_fs_dent_free(fs_dent); fs_dent = NULL; } /* Now we return to processing the Index Root Attribute */ if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_walk: Processing $IDX_ROOT of inum %" PRIuINUM "\n", inum); /* Verify the offset pointers */ if ((tsk_getu32(fs->endian, idxelist->seqend_off) < tsk_getu32(fs->endian, idxelist->begin_off)) || (tsk_getu32(fs->endian, idxelist->bufend_off) < tsk_getu32(fs->endian, idxelist->seqend_off)) || (((uintptr_t) idxe + tsk_getu32(fs->endian, idxelist->bufend_off)) > ((uintptr_t) fs_data_root->buf + fs_data_root->buflen))) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error: Index list offsets are invalid on entry: %" PRIuINUM, fs_inode->addr); tsk_fs_inode_free(fs_inode); return 1; } retval = ntfs_dent_idxentry(ntfs, dinfo, list_seen, idxe, tsk_getu32(fs->endian, idxelist->bufend_off) - tsk_getu32(fs->endian, idxelist->begin_off), tsk_getu32(fs->endian, idxelist->seqend_off) - tsk_getu32(fs->endian, idxelist->begin_off), flags, action, ptr); if (retval != 0) { tsk_fs_inode_free(fs_inode); return (retval == -1) ? 1 : 0; } /* * get the index allocation attribute if it exists (it doesn't for * small directories */ tsk_fs_data_alloc = tsk_fs_data_lookup_noid(fs_inode->attr, NTFS_ATYPE_IDXALLOC); /* if we don't have an index alloc then return, we have processed * all of the entries */ if (!tsk_fs_data_alloc) { int retval; if (tsk_getu32(fs->endian, idxelist->flags) & NTFS_IDXELIST_CHILD) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error: $IDX_ROOT says there should be children, but there isn't"); retval = 1; } else { retval = 0; } tsk_fs_inode_free(fs_inode); return retval; } if (tsk_fs_data_alloc->flags & TSK_FS_DATA_RES) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; snprintf(tsk_errstr, TSK_ERRSTR_L, "$IDX_ALLOC is Resident - it shouldn't be"); tsk_fs_inode_free(fs_inode); return 1; } /* * Copy the index allocation run into a big buffer */ idxalloc_len = tsk_fs_data_alloc->allocsize; if ((idxalloc = tsk_malloc((size_t) idxalloc_len)) == NULL) { tsk_fs_inode_free(fs_inode); return 1; } /* Fill in the loading data structure */ load_file.total = load_file.left = (size_t) idxalloc_len; load_file.cur = load_file.base = idxalloc; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_walk: Copying $IDX_ALLOC into buffer\n"); if (ntfs_data_walk(ntfs, fs_inode->addr, tsk_fs_data_alloc, TSK_FS_FILE_FLAG_SLACK, tsk_fs_load_file_action, (void *) &load_file)) { free(idxalloc); tsk_fs_inode_free(fs_inode); strncat(tsk_errstr2, " - ntfs_dent_walk", TSK_ERRSTR_L - strlen(tsk_errstr2)); return 1; } /* Not all of the directory was copied, so we exit */ if (load_file.left > 0) { free(idxalloc); tsk_fs_inode_free(fs_inode); tsk_error_reset(); tsk_errno = TSK_ERR_FS_FWALK; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error reading directory contents: %" PRIuINUM "\n", inum); return 1; } /* * The idxalloc is a big buffer that contains one or more * idx buffer structures. Each idxrec is a node in the B-Tree. * We do not process the tree as a tree because then we could * not find the deleted file names. * * Therefore, we scan the big buffer looking for the index record * structures. We save a pointer to the known beginning (idxrec_p). * Then we scan for the beginning of the next one (idxrec) and process * everything in the middle as an ntfs_idxrec. We can't use the * size given because then we wouldn't see the deleted names */ /* Set the previous pointer to NULL */ idxrec_p = idxrec = NULL; /* Loop by cluster size */ for (off = 0; off < idxalloc_len; off += ntfs->csize_b) { uint32_t list_len, rec_len; idxrec = (ntfs_idxrec *) & idxalloc[off]; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_walk: Index Buffer Offset: %d Magic: %" PRIx32 "\n", off, tsk_getu32(fs->endian, idxrec->magic)); /* Is this the begining of an index record? */ if (tsk_getu32(fs->endian, idxrec->magic) != NTFS_IDXREC_MAGIC) continue; /* idxrec_p is only NULL for the first time * Set it and start again to find the next one */ if (idxrec_p == NULL) { idxrec_p = idxrec; continue; } /* Process the previous structure */ /* idxrec points to the next idxrec structure, idxrec_p * points to the one we are going to process */ rec_len = (uint32_t) ((uintptr_t) idxrec - (uintptr_t) idxrec_p); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_walk: Processing previous index record (len: %" PRIu32 ")\n", rec_len); /* remove the update sequence in the index record */ if (ntfs_fix_idxrec(ntfs, idxrec_p, rec_len)) { free(idxalloc); tsk_fs_inode_free(fs_inode); return 1; } /* Locate the start of the index entry list */ idxelist = &idxrec_p->list; idxe = (ntfs_idxentry *) ((uintptr_t) idxelist + tsk_getu32(fs->endian, idxelist->begin_off)); /* the length from the start of the next record to where our * list starts. * This should be the same as bufend_off in idxelist, but we don't * trust it. */ list_len = (uint32_t) ((uintptr_t) idxrec - (uintptr_t) idxe); /* Verify the offset pointers */ if (((uintptr_t) idxe > (uintptr_t) idxrec) || ((uintptr_t) idxelist + tsk_getu32(fs->endian, idxelist->seqend_off) > (uintptr_t) idxrec)) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error: Index list offsets are invalid on entry: %" PRIuINUM, fs_inode->addr); tsk_fs_inode_free(fs_inode); free(idxalloc); return 1; } /* process the list of index entries */ retval = ntfs_dent_idxentry(ntfs, dinfo, list_seen, idxe, list_len, tsk_getu32(fs->endian, idxelist->seqend_off) - tsk_getu32(fs->endian, idxelist->begin_off), flags, action, ptr); if (retval != 0) { tsk_fs_inode_free(fs_inode); free(idxalloc); return (retval == -1) ? 1 : 0; } /* reset the pointer to the next record */ idxrec_p = idxrec; } /* end of cluster loop */ /* Process the final record */ if (idxrec_p) { uint32_t list_len, rec_len; /* Length from end of attribute to start of this */ rec_len = (uint32_t) (idxalloc_len - (uintptr_t) idxrec_p - (uintptr_t) idxalloc); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_walk: Processing final index record (len: %" PRIu32 ")\n", rec_len); /* remove the update sequence */ if (ntfs_fix_idxrec(ntfs, idxrec_p, rec_len)) { tsk_fs_inode_free(fs_inode); free(idxalloc); return 1; } idxelist = &idxrec_p->list; idxe = (ntfs_idxentry *) ((uintptr_t) idxelist + tsk_getu32(fs->endian, idxelist->begin_off)); /* This is the length of the idx entries */ list_len = (uint32_t) ((uintptr_t) idxalloc + idxalloc_len) - (uintptr_t) idxe; /* Verify the offset pointers */ if ((list_len > rec_len) || ((uintptr_t) idxelist + tsk_getu32(fs->endian, idxelist->seqend_off) > (uintptr_t) idxalloc + idxalloc_len)) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error: Index list offsets are invalid on entry: %" PRIuINUM, fs_inode->addr); tsk_fs_inode_free(fs_inode); free(idxalloc); return 1; } /* process the list of index entries */ retval = ntfs_dent_idxentry(ntfs, dinfo, list_seen, idxe, list_len, tsk_getu32(fs->endian, idxelist->seqend_off) - tsk_getu32(fs->endian, idxelist->begin_off), flags, action, ptr); if (retval != 0) { tsk_fs_inode_free(fs_inode); free(idxalloc); return (retval == -1) ? 1 : 0; } } tsk_fs_inode_free(fs_inode); free(idxalloc); return 0; } /* end of dent_walk */
static uint8_t hfs_dir_open_meta_cb(HFS_INFO * hfs, int8_t level_type, const void *targ_data, const hfs_btree_key_cat * cur_key, TSK_OFF_T key_off, void *ptr) { uint32_t *cnid_p = (uint32_t *) targ_data; HFS_DIR_OPEN_META_INFO *info = (HFS_DIR_OPEN_META_INFO *) ptr; TSK_FS_INFO *fs = &hfs->fs_info; if (tsk_verbose) fprintf(stderr, "hfs_dir_open_meta_cb: want %" PRIu32 " vs got %" PRIu32 " (%s node)\n", *cnid_p, tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid), (level_type == HFS_BT_NODE_TYPE_IDX) ? "Index" : "Leaf"); if (level_type == HFS_BT_NODE_TYPE_IDX) { if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) < *cnid_p) return HFS_BTREE_CB_IDX_LT; else return HFS_BTREE_CB_IDX_EQGT; } else { uint8_t *rec_buf = (uint8_t *) cur_key; uint16_t rec_type; size_t rec_off2; if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) < *cnid_p) return HFS_BTREE_CB_LEAF_GO; else if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) > *cnid_p) return HFS_BTREE_CB_LEAF_STOP; rec_off2 = 2 + tsk_getu16(hfs->fs_info.endian, cur_key->key_len); // @@@ NEED TO REPLACE THIS SOMEHOW, but need to figure out the max length /* if (rec_off2 > nodesize) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, "hfs_dir_open_meta: offset of record+keylen %d in leaf node %d too large (%zu vs %" PRIu16 ")", rec, cur_node, rec_off2, nodesize); tsk_fs_name_free(fs_name); free(node); return TSK_COR; } */ rec_type = tsk_getu16(hfs->fs_info.endian, &rec_buf[rec_off2]); // Catalog entry is for a file if (rec_type == HFS_FILE_THREAD) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, "hfs_dir_open_meta: Entry" " is a file, not a folder"); return HFS_BTREE_CB_ERR; } /* This will link the folder to its parent, which is the ".." entry */ else if (rec_type == HFS_FOLDER_THREAD) { hfs_thread *thread = (hfs_thread *) & rec_buf[rec_off2]; strcpy(info->fs_name->name, ".."); info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, thread->parent_cnid); info->fs_name->type = TSK_FS_NAME_TYPE_DIR; info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } /* This is a folder in the folder */ else if (rec_type == HFS_FOLDER_RECORD) { hfs_folder *folder = (hfs_folder *) & rec_buf[rec_off2]; info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, folder->std.cnid); info->fs_name->type = TSK_FS_NAME_TYPE_DIR; info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (hfs_uni2ascii(fs, (uint8_t *) cur_key->name.unicode, tsk_getu16(hfs->fs_info.endian, cur_key->name.length), info->fs_name->name, HFS_MAXNAMLEN + 1)) { return HFS_BTREE_CB_ERR; } } /* This is a normal file in the folder */ else if (rec_type == HFS_FILE_RECORD) { hfs_file *file = (hfs_file *) & rec_buf[rec_off2]; info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, file->std.cnid); info->fs_name->type = hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian, file->std.perm.mode)); info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (hfs_uni2ascii(fs, (uint8_t *) cur_key->name.unicode, tsk_getu16(hfs->fs_info.endian, cur_key->name.length), info->fs_name->name, HFS_MAXNAMLEN + 1)) { return HFS_BTREE_CB_ERR; } } else { tsk_errno = TSK_ERR_FS_GENFS; // @@@ MAY NEED TO IMPROVE BELOW MESSAGE snprintf(tsk_errstr, TSK_ERRSTR_L, "hfs_dir_open_meta: Unknown record type %d in leaf node", rec_type); return HFS_BTREE_CB_ERR; } if (tsk_fs_dir_add(info->fs_dir, info->fs_name)) { return HFS_BTREE_CB_ERR; } return HFS_BTREE_CB_LEAF_GO; } }
/* * Load the primary partition table (MBR) into the internal * data structures in TSK_VS_INFO * * This will automatically call load_ext_table for extended * partitions * * sect_cur is the address of the table to load * * 0 is returned if the load is successful and 1 if error */ static uint8_t dos_load_prim_table(TSK_VS_INFO * vs, uint8_t test) { dos_sect *sect; char *sect_buf; int i, added = 0; char *table_str; ssize_t cnt; TSK_DADDR_T taddr = vs->offset / vs->block_size + DOS_PART_SOFFSET; TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim: Table Sector: %" PRIuDADDR "\n", taddr); if ((sect_buf = tsk_malloc(vs->block_size)) == NULL) return 1; sect = (dos_sect *) sect_buf; /* Read the table */ cnt = tsk_vs_read_block (vs, DOS_PART_SOFFSET, sect_buf, vs->block_size); if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2("Primary DOS table sector %" PRIuDADDR, taddr); free(sect_buf); return 1; } /* Sanity Check */ if (tsk_vs_guessu16(vs, sect->magic, DOS_MAGIC)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("File is not a DOS partition (invalid primary magic) (Sector: %" PRIuDADDR ")", taddr); if (tsk_verbose) fprintf(stderr, "File is not a DOS partition (invalid primary magic) (Sector: %" PRIuDADDR ")", taddr); free(sect_buf); return 1; } /* Because FAT and NTFS use the same magic - check for a * standard MS OEM name and sizes. Not a great check, but we can't * really test the table entries. */ if (test) { if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim_table: Testing FAT/NTFS conditions\n"); if (strncmp("MSDOS", sect->oemname, 5) == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("dos_load_prim_table: MSDOS OEM name exists"); if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim_table: MSDOS OEM name exists\n"); free(sect_buf); return 1; } else if (strncmp("MSWIN", sect->oemname, 5) == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("dos_load_prim_table: MSWIN OEM name exists"); if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim_table: MSWIN OEM name exists\n"); free(sect_buf); return 1; } else if (strncmp("NTFS", sect->oemname, 4) == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("dos_load_prim_table: NTFS OEM name exists"); if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim_table: NTFS OEM name exists\n"); free(sect_buf); return 1; } else if (strncmp("FAT", sect->oemname, 4) == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("dos_load_prim_table: FAT OEM name exists"); if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim_table: FAT OEM name exists\n"); free(sect_buf); return 1; } } /* Add an entry of 1 sector for the table to the internal structure */ if ((table_str = tsk_malloc(32)) == NULL) { free(sect_buf); return 1; } snprintf(table_str, 32, "Primary Table (#0)"); if (NULL == tsk_vs_part_add(vs, DOS_PART_SOFFSET, (TSK_DADDR_T) 1, TSK_VS_PART_FLAG_META, table_str, -1, -1)) { free(sect_buf); return 1; } /* Cycle through the partition table */ for (i = 0; i < 4; i++) { dos_part *part = §->ptable[i]; /* We currently ignore CHS */ uint32_t part_start = tsk_getu32(vs->endian, part->start_sec); uint32_t part_size = tsk_getu32(vs->endian, part->size_sec); if (tsk_verbose) tsk_fprintf(stderr, "load_pri:0:%d Start: %" PRIu32 " Size: %" PRIu32 " Type: %d\n", i, part_start, part_size, part->ptype); if (part_size == 0) continue; // make sure the first couple are in the image bounds if ((i < 2) && (part_start > max_addr)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_BLK_NUM); tsk_error_set_errstr ("dos_load_prim_table: Starting sector too large for image"); if (tsk_verbose) tsk_fprintf(stderr, "Starting sector %" PRIu32 " too large for image\n", part_start); free(sect_buf); return 1; } #if 0 // I'm not sure if this is too strict ... else if ((part_start + part_size) > max_addr) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_BLK_NUM); tsk_error_set_errstr ("dos_load_prim_table: Partition ends after image"); return 1; } #endif added = 1; /* Add the partition to the internal structure * If it is an extended partition, process it now */ if (dos_is_ext(part->ptype)) { if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start, (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_META, dos_get_desc(part->ptype), 0, i)) { free(sect_buf); return 1; } if (dos_load_ext_table(vs, part_start, part_start, 1)) { if (tsk_verbose) { fprintf(stderr, "Error loading extended table, moving on"); tsk_error_print(stderr); } tsk_error_reset(); } } else { if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start, (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC, dos_get_desc(part->ptype), 0, i)) { free(sect_buf); return 1; } } } free(sect_buf); if (added == 0) { if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim: No valid entries\n"); tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("dos_load_prim_table: No valid entries in primary table"); return 1; } return 0; }
/** \internal * Read an indirect block and process the contents to make a runlist from the pointers. * * @param fs File system to analyze * @param fs_attr Structure to save run data into * @param fs_attr_indir Structure to save addresses of indirect block pointers in * @param buf Buffers to read block data into (0 is block sized, 1+ are DADDR_T arrays based on FS type) * @param level Indirection level that this will process at (1+) * @param addr Address of block to read * @param length Length of file remaining * * @returns the number of bytes processed during call and -1 if an error occurred */ static TSK_OFF_T unix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr, TSK_FS_ATTR * fs_attr_indir, char *buf[], int level, TSK_DADDR_T addr, TSK_OFF_T length) { char *myname = "unix_make_data_run_indirect"; size_t addr_cnt = 0; TSK_DADDR_T *myaddrs = (TSK_DADDR_T *) buf[level]; TSK_OFF_T length_remain = length; TSK_OFF_T retval; size_t fs_bufsize; size_t fs_blen; TSK_FS_ATTR_RUN *data_run; if (tsk_verbose) tsk_fprintf(stderr, "%s: level %d block %" PRIuDADDR "\n", myname, level, addr); // block_size is a fragment size in UFS, so we need to maintain length in fragments if (TSK_FS_TYPE_ISFFS(fs->ftype)) { FFS_INFO *ffs = (FFS_INFO *) fs; fs_blen = ffs->ffsbsize_f; fs_bufsize = ffs->ffsbsize_b; } else { fs_blen = 1; fs_bufsize = fs->block_size; } if (addr > fs->last_block) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_INODE_COR); tsk_error_set_errstr("unix: Indirect block address too large: %" PRIuDADDR "", addr); return -1; } // make a non-resident run data_run = tsk_fs_attr_run_alloc(); if (data_run == NULL) return -1; data_run->addr = addr; data_run->len = fs_blen; /* * Read a block of disk addresses. */ // sparse if (addr == 0) { memset(buf[0], 0, fs_bufsize); data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE; } else { ssize_t cnt; // read the data into the scratch buffer cnt = tsk_fs_read_block(fs, addr, buf[0], fs_bufsize); if (cnt != fs_bufsize) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_READ); } tsk_error_set_errstr2("unix_make_data_run_indir: Block %" PRIuDADDR, addr); return -1; } } // save the run tsk_fs_attr_append_run(fs, fs_attr_indir, data_run); // convert the raw addresses to the correct endian ordering if ((fs->ftype == TSK_FS_TYPE_FFS1) || (fs->ftype == TSK_FS_TYPE_FFS1B) || (TSK_FS_TYPE_ISEXT(fs->ftype))) { size_t n; uint32_t *iaddr = (uint32_t *) buf[0]; addr_cnt = fs_bufsize / sizeof(*iaddr); for (n = 0; n < addr_cnt; n++) { myaddrs[n] = tsk_getu32(fs->endian, (uint8_t *) & iaddr[n]); } } else if (fs->ftype == TSK_FS_TYPE_FFS2) { size_t n; uint64_t *iaddr = (uint64_t *) buf[0]; addr_cnt = fs_bufsize / sizeof(*iaddr); for (n = 0; n < addr_cnt; n++) { myaddrs[n] = tsk_getu64(fs->endian, (uint8_t *) & iaddr[n]); } } // pass the addresses to the next level if (level == 1) { retval = unix_make_data_run_direct(fs, fs_attr, myaddrs, addr_cnt, length_remain); if (retval != -1) { length_remain -= retval; } } else { size_t i; retval = 0; for (i = 0; i < addr_cnt && retval != -1; i++) { retval = unix_make_data_run_indirect(fs, fs_attr, fs_attr_indir, buf, level - 1, myaddrs[i], length_remain); if (retval == -1) { break; } else { length_remain -= retval; } } } if (retval == -1) return -1; else return length - length_remain; }
static uint8_t hfs_dir_open_meta_cb(HFS_INFO * hfs, int8_t level_type, const void *targ_data, const hfs_btree_key_cat * cur_key, TSK_OFF_T key_off, void *ptr) { uint32_t *cnid_p = (uint32_t *) targ_data; HFS_DIR_OPEN_META_INFO *info = (HFS_DIR_OPEN_META_INFO *) ptr; TSK_FS_INFO *fs = &hfs->fs_info; if (tsk_verbose) fprintf(stderr, "hfs_dir_open_meta_cb: want %" PRIu32 " vs got %" PRIu32 " (%s node)\n", *cnid_p, tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid), (level_type == HFS_BT_NODE_TYPE_IDX) ? "Index" : "Leaf"); if (level_type == HFS_BT_NODE_TYPE_IDX) { if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) < *cnid_p) { return HFS_BTREE_CB_IDX_LT; } else { return HFS_BTREE_CB_IDX_EQGT; } } else { uint8_t *rec_buf = (uint8_t *) cur_key; uint16_t rec_type; size_t rec_off2; if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) < *cnid_p) { return HFS_BTREE_CB_LEAF_GO; } else if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) > *cnid_p) { return HFS_BTREE_CB_LEAF_STOP; } rec_off2 = 2 + tsk_getu16(hfs->fs_info.endian, cur_key->key_len); // @@@ NEED TO REPLACE THIS SOMEHOW, but need to figure out the max length /* if (rec_off2 > nodesize) { tsk_error_set_errno(TSK_ERR_FS_GENFS); tsk_error_set_errstr( "hfs_dir_open_meta: offset of record+keylen %d in leaf node %d too large (%zu vs %" PRIu16 ")", rec, cur_node, rec_off2, nodesize); tsk_fs_name_free(fs_name); free(node); return TSK_COR; } */ rec_type = tsk_getu16(hfs->fs_info.endian, &rec_buf[rec_off2]); // Catalog entry is for a file if (rec_type == HFS_FILE_THREAD) { tsk_error_set_errno(TSK_ERR_FS_GENFS); tsk_error_set_errstr("hfs_dir_open_meta: Entry" " is a file, not a folder"); return HFS_BTREE_CB_ERR; } /* This will link the folder to its parent, which is the ".." entry */ else if (rec_type == HFS_FOLDER_THREAD) { hfs_thread *thread = (hfs_thread *) & rec_buf[rec_off2]; strcpy(info->fs_name->name, ".."); info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, thread->parent_cnid); info->fs_name->type = TSK_FS_NAME_TYPE_DIR; info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } /* This is a folder in the folder */ else if (rec_type == HFS_FOLDER_RECORD) { hfs_folder *folder = (hfs_folder *) & rec_buf[rec_off2]; info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, folder->std.cnid); info->fs_name->type = TSK_FS_NAME_TYPE_DIR; info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (hfs_UTF16toUTF8(fs, (uint8_t *) cur_key->name.unicode, tsk_getu16(hfs->fs_info.endian, cur_key->name.length), info->fs_name->name, HFS_MAXNAMLEN + 1, HFS_U16U8_FLAG_REPLACE_SLASH)) { return HFS_BTREE_CB_ERR; } } /* This is a normal file in the folder */ else if (rec_type == HFS_FILE_RECORD) { hfs_file *file = (hfs_file *) & rec_buf[rec_off2]; // This could be a hard link. We need to test this CNID, and follow it if necessary. unsigned char is_err; TSK_INUM_T file_cnid = tsk_getu32(hfs->fs_info.endian, file->std.cnid); TSK_INUM_T target_cnid = hfs_follow_hard_link(hfs, file, &is_err); if (is_err > 1) { error_returned ("hfs_dir_open_meta_cb: trying to follow a possible hard link in the directory"); return HFS_BTREE_CB_ERR; } if (target_cnid != file_cnid) { HFS_ENTRY entry; uint8_t lkup; // lookup result // This is a hard link. We need to fill in the name->type and name->meta_addr from the target info->fs_name->meta_addr = target_cnid; // get the Catalog entry for the target CNID lkup = hfs_cat_file_lookup(hfs, target_cnid, &entry, FALSE); if (lkup != 0) { error_returned ("hfs_dir_open_meta_cb: retrieving the catalog entry for the target of a hard link"); return HFS_BTREE_CB_ERR; } info->fs_name->type = hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian, entry.cat.std.perm.mode)); } else { // This is NOT a hard link. info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, file->std.cnid); info->fs_name->type = hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian, file->std.perm.mode)); } info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (hfs_UTF16toUTF8(fs, (uint8_t *) cur_key->name.unicode, tsk_getu16(hfs->fs_info.endian, cur_key->name.length), info->fs_name->name, HFS_MAXNAMLEN + 1, HFS_U16U8_FLAG_REPLACE_SLASH)) { return HFS_BTREE_CB_ERR; } } else { tsk_error_set_errno(TSK_ERR_FS_GENFS); // @@@ MAY NEED TO IMPROVE BELOW MESSAGE tsk_error_set_errstr ("hfs_dir_open_meta: Unknown record type %d in leaf node", rec_type); return HFS_BTREE_CB_ERR; } if (tsk_fs_dir_add(info->fs_dir, info->fs_name)) { return HFS_BTREE_CB_ERR; } return HFS_BTREE_CB_LEAF_GO; } }
/* * Process the partition table at the sector address * * This method just finds out if it is sparc or Intel and then * calls the appropriate method * * Return 0 on success and 1 on error */ static uint8_t sun_load_table(TSK_VS_INFO * vs) { sun_dlabel_sparc *dlabel_sp; sun_dlabel_i386 *dlabel_x86; char *buf; ssize_t cnt; TSK_DADDR_T taddr = vs->offset / vs->block_size + SUN_SPARC_PART_SOFFSET; int result = 0; /* Sanity check in case label sizes change */ if ((sizeof(*dlabel_sp) > vs->block_size) || (sizeof(*dlabel_x86) > vs->block_size)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_BUF); tsk_error_set_errstr ("sun_load_table: disk labels bigger than block size"); return 1; } if (tsk_verbose) tsk_fprintf(stderr, "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr); if ((buf = tsk_malloc(vs->block_size)) == NULL) { goto on_error; } /* Try the given offset */ cnt = tsk_vs_read_block (vs, SUN_SPARC_PART_SOFFSET, buf, vs->block_size); /* If -1 is returned, tsk_errno is already set */ if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2("SUN Disk Label in Sector: %" PRIuDADDR, taddr); goto on_error; } /* Check the magic value * Both intel and sparc have the magic value in the same location * * We try both in case someone specifies the exact location of the * intel disk label. * */ dlabel_sp = (sun_dlabel_sparc *) buf; dlabel_x86 = (sun_dlabel_i386 *) buf; if (tsk_vs_guessu16(vs, dlabel_sp->magic, SUN_MAGIC) == 0) { if (tsk_getu32(vs->endian, dlabel_sp->sanity) == SUN_SANITY) { result = sun_load_table_sparc(vs, dlabel_sp); // TODO: I assume based on the existing free that the previous function // does not take ownership of buf. free(buf); return result; } else if (tsk_getu32(vs->endian, dlabel_x86->sanity) == SUN_SANITY) { result = sun_load_table_i386(vs, dlabel_x86); // TODO: I assume based on the existing free that the previous function // does not take ownership of buf. free(buf); return result; } } /* Now try the next sector, which is where the intel * could be stored */ taddr = vs->offset / vs->block_size / SUN_I386_PART_SOFFSET; if (tsk_verbose) tsk_fprintf(stderr, "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr + 1); cnt = tsk_vs_read_block (vs, SUN_I386_PART_SOFFSET, buf, vs->block_size); if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2("SUN (Intel) Disk Label in Sector: %" PRIuDADDR, taddr); goto on_error; } dlabel_x86 = (sun_dlabel_i386 *) buf; if (tsk_vs_guessu16(vs, dlabel_x86->magic, SUN_MAGIC)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr("SUN (intel) partition table (Sector: %" PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian, dlabel_sp->magic)); goto on_error; } if (tsk_getu32(vs->endian, dlabel_x86->sanity) != SUN_SANITY) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr("SUN (intel) sanity value (Sector: %" PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian, dlabel_sp->magic)); goto on_error; } result = sun_load_table_i386(vs, dlabel_x86); // TODO: I assume based on the existing free that the previous function // does not take ownership of buf. free(buf); return result; on_error: if( buf != NULL ) { free( buf ); } return 1; }
/** * \internal * Searches the root directory of an exFAT file system for an allocation bitmap * directory entry. If the entry is found, data from the entry is saved to a * FATFS_INFO object. * * @param [in, out] a_fatfs Generic FAT file system info structure. * @return 0 on success, 1 otherwise, per TSK convention. */ static uint8_t exfatfs_get_alloc_bitmap(FATFS_INFO *a_fatfs) { const char *func_name = "exfatfs_get_alloc_bitmap"; TSK_FS_INFO *fs = &(a_fatfs->fs_info); TSK_DADDR_T current_sector = 0; TSK_DADDR_T last_sector_of_data_area = 0; char *sector_buf = NULL; EXFATFS_ALLOC_BITMAP_DIR_ENTRY *dentry = NULL; uint64_t i = 0; uint64_t first_sector_of_alloc_bitmap = 0; uint64_t alloc_bitmap_length_in_bytes = 0; uint64_t last_sector_of_alloc_bitmap = 0; assert(a_fatfs != NULL); if ((sector_buf = (char*)tsk_malloc(a_fatfs->ssize)) == NULL) { return FATFS_FAIL; } last_sector_of_data_area = a_fatfs->firstdatasect + (a_fatfs->clustcnt * a_fatfs->csize) - 1; for (current_sector = a_fatfs->rootsect; current_sector < last_sector_of_data_area; current_sector++) { ssize_t bytes_read = 0; /* Read in a sector from the root directory. The allocation bitmap * directory entries will probably be near the beginning of the * directory, probably in the first sector. */ bytes_read = tsk_fs_read_block(fs, current_sector, sector_buf, a_fatfs->ssize); if (bytes_read != a_fatfs->ssize) { if (bytes_read >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_READ); } tsk_error_set_errstr2("%s: sector: %" PRIuDADDR, func_name, current_sector); free(sector_buf); return FATFS_FAIL; } /* Read the directory entries in the sector, looking for allocation * bitmap entries. There will be one entry unless the file system is * TexFAT (transactional exFAT), in which case there will be two. */ for (i = 0; i < a_fatfs->ssize; i += sizeof(FATFS_DENTRY)) { dentry = (EXFATFS_ALLOC_BITMAP_DIR_ENTRY*)&(sector_buf[i]); /* The type of the directory entry is encoded in the first byte * of the entry. See EXFATFS_DIR_ENTRY_TYPE_ENUM. */ if (exfatfs_get_enum_from_type(dentry->entry_type) == EXFATFS_DIR_ENTRY_TYPE_ALLOC_BITMAP) { /* Do an in-depth test. */ if (!exfatfs_is_alloc_bitmap_dentry((FATFS_DENTRY*)dentry, FATFS_DATA_UNIT_ALLOC_STATUS_UNKNOWN, a_fatfs)) { continue; } /* The first bit of the flags byte is 0 for the first * allocation bitmap directory entry and 1 for the second * bitmap directory entry. If TexFAT is in use and there are * two allocation bitmaps, the first bitmap should be the * stable copy of the last known good allocation bitmap. * Therefore, the SleuthKit will use the first bitmap to * determine which clusters are allocated. */ if (~(dentry->flags & 0x01)) { first_sector_of_alloc_bitmap = FATFS_CLUST_2_SECT(a_fatfs, tsk_getu32(fs->endian, dentry->first_cluster_of_bitmap)); alloc_bitmap_length_in_bytes = tsk_getu64(fs->endian, dentry->length_of_alloc_bitmap_in_bytes); last_sector_of_alloc_bitmap = first_sector_of_alloc_bitmap + (roundup(alloc_bitmap_length_in_bytes, a_fatfs->ssize) / a_fatfs->ssize) - 1; /* The allocation bitmap must lie within the boundaries of the data area. * It also must be big enough for the number of clusters reported in the VBR. */ if ((first_sector_of_alloc_bitmap >= a_fatfs->firstdatasect) && (last_sector_of_alloc_bitmap <= last_sector_of_data_area) && (alloc_bitmap_length_in_bytes >= (a_fatfs->clustcnt + 7) / 8)) { a_fatfs->EXFATFS_INFO.first_sector_of_alloc_bitmap = first_sector_of_alloc_bitmap; a_fatfs->EXFATFS_INFO.length_of_alloc_bitmap_in_bytes = alloc_bitmap_length_in_bytes; free(sector_buf); return FATFS_OK; } } } } } free(sector_buf); return FATFS_FAIL; }
/** \internal * process the data from inside of a directory and load the corresponding * file data into a TSK_FS_DIR structure. * * @param a_fs File system * @param a_fs_dir Structore to store file names into * @param buf Buffer that contains the directory content * @param a_length Number of bytes in buffer * @param a_addr The metadata address for the directory being processed * @param a_dir_addr The block offset where this directory starts * @returns TSK_ERR on error and TSK_OK otherwise */ static uint8_t iso9660_proc_dir(TSK_FS_INFO * a_fs, TSK_FS_DIR * a_fs_dir, char *buf, size_t a_length, TSK_INUM_T a_addr, TSK_OFF_T a_dir_addr) { ISO_INFO *iso = (ISO_INFO *) a_fs; TSK_FS_NAME *fs_name; size_t buf_idx; iso9660_dentry *dd; /* directory descriptor */ iso9660_inode_node *in; TSK_OFF_T dir_offs = a_dir_addr * a_fs->block_size; if ((fs_name = tsk_fs_name_alloc(ISO9660_MAXNAMLEN + 1, 0)) == NULL) return TSK_ERR; buf_idx = 0; dd = (iso9660_dentry *) & buf[buf_idx]; /* handle "." entry */ fs_name->meta_addr = a_addr; strcpy(fs_name->name, "."); fs_name->type = TSK_FS_NAME_TYPE_DIR; fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; tsk_fs_dir_add(a_fs_dir, fs_name); buf_idx += dd->entry_len; if (buf_idx > a_length - sizeof(iso9660_dentry)) { free(buf); tsk_fs_name_free(fs_name); return TSK_OK; } dd = (iso9660_dentry *) & buf[buf_idx]; /* handle ".." entry */ in = iso->in_list; while (in && (tsk_getu32(a_fs->endian, in->inode.dr.ext_loc_m) != tsk_getu32(a_fs->endian, dd->ext_loc_m))) in = in->next; if (in) { fs_name->meta_addr = in->inum; strcpy(fs_name->name, ".."); fs_name->type = TSK_FS_NAME_TYPE_DIR; fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; tsk_fs_dir_add(a_fs_dir, fs_name); } buf_idx += dd->entry_len; // process the rest of the entries in the directory while (buf_idx < a_length - sizeof(iso9660_dentry)) { dd = (iso9660_dentry *) & buf[buf_idx]; // process the entry (if it has a defined and valid length) if ((dd->entry_len) && (buf_idx + dd->entry_len < a_length)) { /* We need to find the data in the pre-processed list because that * contains the meta data address that TSK assigned to this file. * We find the entry by looking for one that was stored at the same * byte offset that we now are. We used to use the extent location, but * we found an image * that had a file with 0 bytes with the same starting block as another * file. */ for (in = iso->in_list; in; in = in->next) { if (in->dentry_offset == dir_offs + buf_idx) break; } // we may have not found it because we are reading corrupt data... if (!in) { buf_idx++; continue; } // copy the data in fs_name for loading fs_name->meta_addr = in->inum; strncpy(fs_name->name, in->inode.fn, ISO9660_MAXNAMLEN); if (dd->flags & ISO9660_FLAG_DIR) fs_name->type = TSK_FS_NAME_TYPE_DIR; else fs_name->type = TSK_FS_NAME_TYPE_REG; fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; tsk_fs_dir_add(a_fs_dir, fs_name); buf_idx += dd->entry_len; } /* If the length was not defined, we are probably in a hole in the * directory. The contents are block aligned. So, we * scan ahead until we get either a non-zero entry or the block boundary */ else { buf_idx++; for (; buf_idx < a_length - sizeof(iso9660_dentry); buf_idx++) { if (buf[buf_idx] != 0) { dd = (iso9660_dentry *) & buf[buf_idx]; if ((dd->entry_len) && (buf_idx + dd->entry_len < a_length)) break; } if (buf_idx % a_fs->block_size == 0) break; } } } free(buf); tsk_fs_name_free(fs_name); return TSK_OK; }
/* * 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; }
uint8_t fatxxfs_open(FATFS_INFO *fatfs) { const char *func_name = "fatxxfs_open"; TSK_FS_INFO *fs = &(fatfs->fs_info); FATXXFS_SB *fatsb = (FATXXFS_SB*)(&fatfs->boot_sector_buffer); int i = 0; TSK_DADDR_T sectors = 0; TSK_FS_DIR * test_dir1; // Directories used to try opening the root directory // clean up any error messages that are lying around tsk_error_reset(); /* Calculate block sizes and layout info */ // sector size fatfs->ssize = tsk_getu16(fs->endian, fatsb->ssize); if (fatfs->ssize == 512) { fatfs->ssize_sh = 9; } else if (fatfs->ssize == 1024) { fatfs->ssize_sh = 10; } else if (fatfs->ssize == 2048) { fatfs->ssize_sh = 11; } else if (fatfs->ssize == 4096) { fatfs->ssize_sh = 12; } else { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr ("Error: sector size (%d) is not a multiple of device size (%d)\nDo you have a disk image instead of a partition image?", fatfs->ssize, fs->dev_bsize); if (tsk_verbose) fprintf(stderr, "%s: Invalid sector size (%d)\n", func_name, fatfs->ssize); return 1; } // cluster size fatfs->csize = fatsb->csize; if ((fatfs->csize != 0x01) && (fatfs->csize != 0x02) && (fatfs->csize != 0x04) && (fatfs->csize != 0x08) && (fatfs->csize != 0x10) && (fatfs->csize != 0x20) && (fatfs->csize != 0x40) && (fatfs->csize != 0x80)) { if (tsk_verbose) fprintf(stderr, "%s: Invalid cluster size (%d)\n", func_name, fatfs->csize); tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr("Not a FATXX file system (cluster size)"); return 1; } // number of FAT tables fatfs->numfat = fatsb->numfat; if ((fatfs->numfat == 0) || (fatfs->numfat > 8)) { if (tsk_verbose) fprintf(stderr, "%s: Invalid number of FATS (%d)\n", func_name, fatfs->numfat); tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr("Not a FATXX file system (number of FATs)"); return 1; } /* We can't do a sanity check on this b.c. TSK_FS_TYPE_FAT32 has a value of 0 */ /* num of root entries */ fatfs->numroot = tsk_getu16(fs->endian, fatsb->numroot); /* if sectors16 is 0, then the number of sectors is stored in sectors32 */ if (0 == (sectors = tsk_getu16(fs->endian, fatsb->sectors16))) sectors = tsk_getu32(fs->endian, fatsb->sectors32); /* if secperfat16 is 0, then read sectperfat32 */ if (0 == (fatfs->sectperfat = tsk_getu16(fs->endian, fatsb->sectperfat16))) fatfs->sectperfat = tsk_getu32(fs->endian, fatsb->a.f32.sectperfat32); if (fatfs->sectperfat == 0) { if (tsk_verbose) fprintf(stderr, "%s: Invalid number of sectors per FAT (%d)\n", func_name, fatfs->sectperfat); tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr ("Not a FATXX file system (invalid sectors per FAT)"); return 1; } fatfs->firstfatsect = tsk_getu16(fs->endian, fatsb->reserved); if ((fatfs->firstfatsect == 0) || (fatfs->firstfatsect > sectors)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); tsk_error_set_errstr ("Not a FATXX file system (invalid first FAT sector %" PRIuDADDR ")", fatfs->firstfatsect); if (tsk_verbose) fprintf(stderr, "%s: Invalid first FAT (%" PRIuDADDR ")\n", func_name, fatfs->firstfatsect); return 1; } /* Calculate the block info * * The sector of the beginning of the data area - which is * after all of the FATs * * For TSK_FS_TYPE_FAT12 and TSK_FS_TYPE_FAT16, the data area starts with the root * directory entries and then the first cluster. For TSK_FS_TYPE_FAT32, * the data area starts with clusters and the root directory * is somewhere in the data area */ fatfs->firstdatasect = fatfs->firstfatsect + fatfs->sectperfat * fatfs->numfat; /* The sector where the first cluster is located. It will be used * to translate cluster addresses to sector addresses * * For TSK_FS_TYPE_FAT32, the first cluster is the start of the data area and * it is after the root directory for TSK_FS_TYPE_FAT12 and TSK_FS_TYPE_FAT16. At this * point in the program, numroot is set to 0 for TSK_FS_TYPE_FAT32 */ fatfs->firstclustsect = fatfs->firstdatasect + ((fatfs->numroot * 32 + fatfs->ssize - 1) / fatfs->ssize); /* total number of clusters */ fatfs->clustcnt = (sectors - fatfs->firstclustsect) / fatfs->csize; /* the first cluster is #2, so the final cluster is: */ fatfs->lastclust = 1 + fatfs->clustcnt; /* identify the FAT type by the total number of data clusters * this calculation is from the MS FAT Overview Doc * * A FAT file system made by another OS could use different values */ if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT_DETECT) { if (fatfs->clustcnt < 4085) { fatfs->fs_info.ftype = TSK_FS_TYPE_FAT12; } else if (fatfs->clustcnt < 65525) { fatfs->fs_info.ftype = TSK_FS_TYPE_FAT16; } else { fatfs->fs_info.ftype = TSK_FS_TYPE_FAT32; } fatfs->fs_info.ftype = fatfs->fs_info.ftype; } /* Some sanity checks */ else { if ((fatfs->fs_info.ftype == TSK_FS_TYPE_FAT12) && (fatfs->clustcnt >= 4085)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr ("Too many sectors for TSK_FS_TYPE_FAT12: try auto-detect mode"); if (tsk_verbose) fprintf(stderr, "%s: Too many sectors for FAT12\n", func_name); return 1; } } if ((fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) && (fatfs->numroot != 0)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr ("Invalid TSK_FS_TYPE_FAT32 image (numroot != 0)"); if (tsk_verbose) fprintf(stderr, "%s: numroom != 0 for FAT32\n", func_name); return 1; } if ((fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) && (fatfs->numroot == 0)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr ("Invalid FAT image (numroot == 0, and not TSK_FS_TYPE_FAT32)"); if (tsk_verbose) fprintf(stderr, "%s: numroom == 0 and not FAT32\n", func_name); return 1; } /* additional sanity checks if we think we are using the backup boot sector. * The scenario to prevent here is if fat_open is called 6 sectors before the real start * of the file system, then we want to detect that it was not a backup that we saw. */ if (fatfs->using_backup_boot_sector) { // only FAT32 has backup boot sectors.. if (fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr ("Invalid FAT image (Used what we thought was a backup boot sector, but it is not TSK_FS_TYPE_FAT32)"); if (tsk_verbose) fprintf(stderr, "%s: Had to use backup boot sector, but this isn't FAT32\n", func_name); return 1; } if (fatfs->numroot > 1) { uint8_t buf1[512]; uint8_t buf2[512]; int i2; int numDiffs; ssize_t cnt = 0; cnt = tsk_fs_read(fs, fatfs->firstfatsect * fatfs->ssize, (char *) buf1, 512); if (cnt != 512) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_READ); } tsk_error_set_errstr2("%s: FAT1", func_name); fs->tag = 0; return 1; } cnt = tsk_fs_read(fs, (fatfs->firstfatsect + fatfs->sectperfat) * fatfs->ssize, (char *) buf2, 512); if (cnt != 512) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_READ); } tsk_error_set_errstr2("%s: FAT2", func_name); fs->tag = 0; return 1; } numDiffs = 0; for (i2 = 0; i2 < 512; i2++) { if (buf1[i2] != buf2[i2]) { numDiffs++; } } if (numDiffs > 25) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_MAGIC); tsk_error_set_errstr ("Invalid FAT image (Too many differences between FATS from guessing (%d diffs))", numDiffs); if (tsk_verbose) fprintf(stderr, "%s: Too many differences in FAT from guessing (%d diffs)\n", func_name, numDiffs); return 1; } } } /* Set the mask to use on the cluster values */ if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT12) { fatfs->mask = FATFS_12_MASK; } else if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT16) { fatfs->mask = FATFS_16_MASK; } else if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) { fatfs->mask = FATFS_32_MASK; } else { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("Unknown FAT type in %s: %d\n", func_name, fatfs->fs_info.ftype); return 1; } fs->duname = "Sector"; /* the root directories are always after the FAT for TSK_FS_TYPE_FAT12 and TSK_FS_TYPE_FAT16, * but are dynamically located for TSK_FS_TYPE_FAT32 */ if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) fatfs->rootsect = FATFS_CLUST_2_SECT(fatfs, tsk_getu32(fs->endian, fatsb->a.f32.rootclust)); else fatfs->rootsect = fatfs->firstdatasect; for (i = 0; i < FATFS_FAT_CACHE_N; i++) { fatfs->fatc_addr[i] = 0; fatfs->fatc_ttl[i] = 0; } /* * block calculations : although there are no blocks in fat, we will * use these fields for sector calculations */ fs->first_block = 0; fs->block_count = sectors; fs->last_block = fs->last_block_act = fs->block_count - 1; fs->block_size = fatfs->ssize; // determine the last block we have in this image if ((TSK_DADDR_T) ((fatfs->fs_info.img_info->size - fatfs->fs_info.offset) / fs->block_size) < fs->block_count) fs->last_block_act = (fatfs->fs_info.img_info->size - fatfs->fs_info.offset) / fs->block_size - 1; /* * inode calculations */ /* maximum number of dentries in a sector & cluster */ fatfs->dentry_cnt_se = fatfs->ssize / sizeof(FATXXFS_DENTRY); fatfs->dentry_cnt_cl = fatfs->dentry_cnt_se * fatfs->csize; fs->root_inum = FATFS_ROOTINO; fs->first_inum = FATFS_FIRSTINO; /* Calculate inode addresses for the virtual files (MBR, one or two FATS) * and the virtual orphan files directory. */ fs->last_inum = (FATFS_SECT_2_INODE(fatfs, fs->last_block_act + 1) - 1) + FATFS_NUM_VIRT_FILES(fatfs); fatfs->mbr_virt_inum = fs->last_inum - FATFS_NUM_VIRT_FILES(fatfs) + 1; fatfs->fat1_virt_inum = fatfs->mbr_virt_inum + 1; if (fatfs->numfat == 2) { fatfs->fat2_virt_inum = fatfs->fat1_virt_inum + 1; } else { fatfs->fat2_virt_inum = fatfs->fat1_virt_inum; } /* Calculate the total number of inodes. */ fs->inum_count = fs->last_inum - fs->first_inum + 1; /* Volume ID */ for (fs->fs_id_used = 0; fs->fs_id_used < 4; fs->fs_id_used++) { if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) fs->fs_id[fs->fs_id_used] = fatsb->a.f32.vol_id[fs->fs_id_used]; else fs->fs_id[fs->fs_id_used] = fatsb->a.f16.vol_id[fs->fs_id_used]; } /* * Set the function pointers */ fs->block_walk = fatfs_block_walk; fs->block_getflags = fatfs_block_getflags; fs->inode_walk = fatfs_inode_walk; fs->istat = fatfs_istat; fs->file_add_meta = fatfs_inode_lookup; fs->get_default_attr_type = fatfs_get_default_attr_type; fs->load_attrs = fatfs_make_data_runs; fs->dir_open_meta = fatfs_dir_open_meta; fs->name_cmp = fatfs_name_cmp; fs->fsstat = fatxxfs_fsstat; fs->fscheck = fatfs_fscheck; fs->close = fatfs_close; fs->jblk_walk = fatfs_jblk_walk; fs->jentry_walk = fatfs_jentry_walk; fs->jopen = fatfs_jopen; fatfs->is_cluster_alloc = fatxxfs_is_cluster_alloc; fatfs->is_dentry = fatxxfs_is_dentry; fatfs->dinode_copy = fatxxfs_dinode_copy; fatfs->inode_lookup = fatxxfs_inode_lookup; fatfs->inode_walk_should_skip_dentry = fatxxfs_inode_walk_should_skip_dentry; fatfs->istat_attr_flags = fatxxfs_istat_attr_flags; fatfs->dent_parse_buf = fatxxfs_dent_parse_buf; // initialize the caches tsk_init_lock(&fatfs->cache_lock); tsk_init_lock(&fatfs->dir_lock); fatfs->inum2par = NULL; // Test to see if this is the odd Android case where the FAT entries have no short name // // If there are no entries found with the normal short name // and we find more entries by removing the short name test for allocated directories, then assume // this is the case where we have no short names fatfs->subtype = TSK_FATFS_SUBTYPE_SPEC; test_dir1 = tsk_fs_dir_open_meta(fs, fs->root_inum); if (test_dir1 != NULL && test_dir1->names_used <= 4){ // At most four automatic directories ($MBR, $FAT1, $FAT1, $OrphanFiles) TSK_FS_DIR * test_dir2; // to see if it's the Android FAT version fatfs->subtype = TSK_FATFS_SUBTYPE_ANDROID_1; test_dir2 = tsk_fs_dir_open_meta(fs, fs->root_inum); if (test_dir2 != NULL && test_dir2->names_used > test_dir1->names_used){ fatfs->subtype = TSK_FATFS_SUBTYPE_ANDROID_1; } else{ fatfs->subtype = TSK_FATFS_SUBTYPE_SPEC; } tsk_fs_dir_close(test_dir2); } tsk_fs_dir_close(test_dir1); return 0; }
/* ** ** Read contents of directory block ** ** if entry is active call action with myflags set to TSK_FS_DENT_FLAG_ALLOC, if ** it is deleted then call action with TSK_FS_DENT_FLAG_UNALLOC. ** len is the size of buf ** ** return 1 to stop, 0 on success, and -1 on error */ static int ext2fs_dent_parse_block(EXT2FS_INFO * ext2fs, EXT2FS_DINFO * dinfo, TSK_LIST ** list_seen, char *buf, int len, int flags, TSK_FS_DENT_TYPE_WALK_CB action, void *ptr) { TSK_FS_INFO *fs = &(ext2fs->fs_info); int dellen = 0; int idx; uint16_t reclen; uint32_t inode; char *dirPtr; TSK_FS_DENT *fs_dent; int minreclen = 4; if ((fs_dent = tsk_fs_dent_alloc(EXT2FS_MAXNAMLEN + 1, 0)) == NULL) return -1; /* update each time by the actual length instead of the ** recorded length so we can view the deleted entries */ for (idx = 0; idx <= len - EXT2FS_DIRSIZ_lcl(1); idx += minreclen) { unsigned int namelen; dirPtr = &buf[idx]; if (ext2fs->deentry_type == EXT2_DE_V1) { ext2fs_dentry1 *dir = (ext2fs_dentry1 *) dirPtr; inode = tsk_getu32(fs->endian, dir->inode); namelen = tsk_getu16(fs->endian, dir->name_len); reclen = tsk_getu16(fs->endian, dir->rec_len); } else { ext2fs_dentry2 *dir = (ext2fs_dentry2 *) dirPtr; inode = tsk_getu32(fs->endian, dir->inode); namelen = dir->name_len; reclen = tsk_getu16(fs->endian, dir->rec_len); } minreclen = EXT2FS_DIRSIZ_lcl(namelen); /* ** Check if we may have a valid directory entry. If we don't, ** then increment to the next word and try again. */ if ((inode > fs->last_inum) || (inode < 0) || (namelen > EXT2FS_MAXNAMLEN) || (namelen <= 0) || (reclen < minreclen) || (reclen % 4) || (idx + reclen > len)) { minreclen = 4; if (dellen > 0) dellen -= 4; continue; } /* Before we process an entry in unallocated space, make * sure that it also ends in the unalloc space */ if ((dellen) && (dellen < minreclen)) { minreclen = 4; if (dellen > 0) dellen -= 4; continue; } if (ext2fs_dent_copy(ext2fs, dinfo, dirPtr, fs_dent)) { tsk_fs_dent_free(fs_dent); return -1; } /* Do we have a deleted entry? */ if ((dellen > 0) || (inode == 0)) { fs_dent->flags = TSK_FS_DENT_FLAG_UNALLOC; if (dellen > 0) dellen -= minreclen; if (flags & TSK_FS_DENT_FLAG_UNALLOC) { int retval; retval = action(fs, fs_dent, ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dent_free(fs_dent); return 1; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dent_free(fs_dent); return -1; } } } /* We have a non-deleted entry */ else { fs_dent->flags = TSK_FS_DENT_FLAG_ALLOC; if (flags & TSK_FS_DENT_FLAG_ALLOC) { int retval; retval = action(fs, fs_dent, ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dent_free(fs_dent); return 1; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dent_free(fs_dent); return -1; } } } /* If the actual length is shorter then the ** recorded length, then the next entry(ies) have been ** deleted. Set dellen to the length of data that ** has been deleted ** ** Because we aren't guaranteed with Ext2FS that the next ** entry begins right after this one, we will check to ** see if the difference is less than a possible entry ** before we waste time searching it */ if ((reclen - minreclen >= EXT2FS_DIRSIZ_lcl(1)) && (dellen <= 0)) dellen = reclen - minreclen; /* we will be recursing directories */ if ((fs_dent->flags & TSK_FS_DENT_FLAG_ALLOC) && (flags & TSK_FS_DENT_FLAG_RECURSE) && (!TSK_FS_ISDOT(fs_dent->name)) && ((fs_dent->fsi->mode & TSK_FS_INODE_MODE_FMT) == TSK_FS_INODE_MODE_DIR)) { int depth_added = 0; /* Make sure we do not get into an infinite loop */ if (0 == tsk_list_find(*list_seen, fs_dent->inode)) { if (tsk_list_add(list_seen, fs_dent->inode)) { tsk_fs_dent_free(fs_dent); return -1; } if ((dinfo->depth < MAX_DEPTH) && (DIR_STRSZ > strlen(dinfo->dirs) + strlen(fs_dent->name))) { dinfo->didx[dinfo->depth] = &dinfo->dirs[strlen(dinfo->dirs)]; strncpy(dinfo->didx[dinfo->depth], fs_dent->name, DIR_STRSZ - strlen(dinfo->dirs)); strncat(dinfo->dirs, "/", DIR_STRSZ); depth_added = 1; } dinfo->depth++; if (ext2fs_dent_walk_lcl(&(ext2fs->fs_info), dinfo, list_seen, fs_dent->inode, flags, action, ptr)) { /* If this fails because the directory could not be * loaded, then we still continue */ if (tsk_verbose) { tsk_fprintf(stderr, "ffs_dent_parse_block: error reading directory: %" PRIuINUM "\n", fs_dent->inode); tsk_error_print(stderr); } tsk_error_reset(); } dinfo->depth--; if (depth_added) *dinfo->didx[dinfo->depth] = '\0'; } } } tsk_fs_dent_free(fs_dent); return 0; } /* end ext2fs_dent_parse_block() */
/** * Print details about the file system to a file handle. * * @param fs File system to print details on * @param hFile File handle to print text to * * @returns 1 on error and 0 on success */ static uint8_t fatxxfs_fsstat(TSK_FS_INFO * fs, FILE * hFile) { unsigned int i; TSK_DADDR_T next, snext, sstart, send; FATFS_INFO *fatfs = (FATFS_INFO *) fs; FATXXFS_SB *sb = (FATXXFS_SB*)fatfs->boot_sector_buffer; char *data_buf; FATXXFS_DENTRY *vol_label_dentry = NULL; ssize_t cnt; // clean up any error messages that are lying around tsk_error_reset(); if ((data_buf = (char *) tsk_malloc(fs->block_size)) == NULL) { return 1; } /* Read the root directory sector so that we can get the volume * label from it */ cnt = tsk_fs_read_block(fs, fatfs->rootsect, data_buf, fs->block_size); if (cnt != fs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_READ); } tsk_error_set_errstr2("fatxxfs_fsstat: root directory: %" PRIuDADDR, fatfs->rootsect); free(data_buf); return 1; } /* Find the dentry that is set as the volume label */ vol_label_dentry = NULL; if (fatfs->ssize <= fs->block_size) { FATXXFS_DENTRY *current_entry = (FATXXFS_DENTRY *) data_buf; for (i = 0; i < fatfs->ssize; i += sizeof(*current_entry)) { if (current_entry->attrib == FATFS_ATTR_VOLUME) { vol_label_dentry = current_entry; break; } current_entry++; } } /* Print the general file system information */ tsk_fprintf(hFile, "FILE SYSTEM INFORMATION\n"); tsk_fprintf(hFile, "--------------------------------------------\n"); tsk_fprintf(hFile, "File System Type: FAT"); if (fs->ftype == TSK_FS_TYPE_FAT12) tsk_fprintf(hFile, "12\n"); else if (fs->ftype == TSK_FS_TYPE_FAT16) tsk_fprintf(hFile, "16\n"); else if (fs->ftype == TSK_FS_TYPE_FAT32) tsk_fprintf(hFile, "32\n"); else tsk_fprintf(hFile, "\n"); tsk_fprintf(hFile, "\nOEM Name: %c%c%c%c%c%c%c%c\n", sb->oemname[0], sb->oemname[1], sb->oemname[2], sb->oemname[3], sb->oemname[4], sb->oemname[5], sb->oemname[6], sb->oemname[7]); if (fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) { tsk_fprintf(hFile, "Volume ID: 0x%" PRIx32 "\n", tsk_getu32(fs->endian, sb->a.f16.vol_id)); tsk_fprintf(hFile, "Volume Label (Boot Sector): %c%c%c%c%c%c%c%c%c%c%c\n", sb->a.f16.vol_lab[0], sb->a.f16.vol_lab[1], sb->a.f16.vol_lab[2], sb->a.f16.vol_lab[3], sb->a.f16.vol_lab[4], sb->a.f16.vol_lab[5], sb->a.f16.vol_lab[6], sb->a.f16.vol_lab[7], sb->a.f16.vol_lab[8], sb->a.f16.vol_lab[9], sb->a.f16.vol_lab[10]); if ((vol_label_dentry) && (vol_label_dentry->name[0])) { tsk_fprintf(hFile, "Volume Label (Root Directory): %c%c%c%c%c%c%c%c%c%c%c\n", vol_label_dentry->name[0], vol_label_dentry->name[1], vol_label_dentry->name[2], vol_label_dentry->name[3], vol_label_dentry->name[4], vol_label_dentry->name[5], vol_label_dentry->name[6], vol_label_dentry->name[7], vol_label_dentry->ext[0], vol_label_dentry->ext[1], vol_label_dentry->ext[2]); } else { tsk_fprintf(hFile, "Volume Label (Root Directory):\n"); } tsk_fprintf(hFile, "File System Type Label: %c%c%c%c%c%c%c%c\n", sb->a.f16.fs_type[0], sb->a.f16.fs_type[1], sb->a.f16.fs_type[2], sb->a.f16.fs_type[3], sb->a.f16.fs_type[4], sb->a.f16.fs_type[5], sb->a.f16.fs_type[6], sb->a.f16.fs_type[7]); } else { char *fat_fsinfo_buf; if ((fat_fsinfo_buf = (char *) tsk_malloc(sizeof(FATXXFS_FSINFO))) == NULL) { free(data_buf); return 1; } tsk_fprintf(hFile, "Volume ID: 0x%" PRIx32 "\n", tsk_getu32(fs->endian, sb->a.f32.vol_id)); tsk_fprintf(hFile, "Volume Label (Boot Sector): %c%c%c%c%c%c%c%c%c%c%c\n", sb->a.f32.vol_lab[0], sb->a.f32.vol_lab[1], sb->a.f32.vol_lab[2], sb->a.f32.vol_lab[3], sb->a.f32.vol_lab[4], sb->a.f32.vol_lab[5], sb->a.f32.vol_lab[6], sb->a.f32.vol_lab[7], sb->a.f32.vol_lab[8], sb->a.f32.vol_lab[9], sb->a.f32.vol_lab[10]); if ((vol_label_dentry) && (vol_label_dentry->name[0])) { tsk_fprintf(hFile, "Volume Label (Root Directory): %c%c%c%c%c%c%c%c%c%c%c\n", vol_label_dentry->name[0], vol_label_dentry->name[1], vol_label_dentry->name[2], vol_label_dentry->name[3], vol_label_dentry->name[4], vol_label_dentry->name[5], vol_label_dentry->name[6], vol_label_dentry->name[7], vol_label_dentry->ext[0], vol_label_dentry->ext[1], vol_label_dentry->ext[2]); } else { tsk_fprintf(hFile, "Volume Label (Root Directory):\n"); } tsk_fprintf(hFile, "File System Type Label: %c%c%c%c%c%c%c%c\n", sb->a.f32.fs_type[0], sb->a.f32.fs_type[1], sb->a.f32.fs_type[2], sb->a.f32.fs_type[3], sb->a.f32.fs_type[4], sb->a.f32.fs_type[5], sb->a.f32.fs_type[6], sb->a.f32.fs_type[7]); /* Process the FS info */ if (tsk_getu16(fs->endian, sb->a.f32.fsinfo)) { FATXXFS_FSINFO *fat_info; cnt = tsk_fs_read(fs, (TSK_DADDR_T) tsk_getu16(fs->endian, sb->a.f32.fsinfo) * fs->block_size, fat_fsinfo_buf, sizeof(FATXXFS_FSINFO)); if (cnt != sizeof(FATXXFS_FSINFO)) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_READ); } tsk_error_set_errstr2 ("fatxxfs_fsstat: TSK_FS_TYPE_FAT32 FSINFO block: %" PRIuDADDR, (TSK_DADDR_T) tsk_getu16(fs->endian, sb->a.f32.fsinfo)); free(data_buf); free(fat_fsinfo_buf); return 1; } fat_info = (FATXXFS_FSINFO *) fat_fsinfo_buf; tsk_fprintf(hFile, "Next Free Sector (FS Info): %" PRIuDADDR "\n", FATFS_CLUST_2_SECT(fatfs, tsk_getu32(fs->endian, fat_info->nextfree))); tsk_fprintf(hFile, "Free Sector Count (FS Info): %" PRIu32 "\n", (tsk_getu32(fs->endian, fat_info->freecnt) * fatfs->csize)); free(fat_fsinfo_buf); } } free(data_buf); tsk_fprintf(hFile, "\nSectors before file system: %" PRIu32 "\n", tsk_getu32(fs->endian, sb->prevsect)); tsk_fprintf(hFile, "\nFile System Layout (in sectors)\n"); tsk_fprintf(hFile, "Total Range: %" PRIuDADDR " - %" PRIuDADDR "\n", fs->first_block, fs->last_block); if (fs->last_block != fs->last_block_act) tsk_fprintf(hFile, "Total Range in Image: %" PRIuDADDR " - %" PRIuDADDR "\n", fs->first_block, fs->last_block_act); tsk_fprintf(hFile, "* Reserved: 0 - %" PRIuDADDR "\n", fatfs->firstfatsect - 1); tsk_fprintf(hFile, "** Boot Sector: 0\n"); if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) { tsk_fprintf(hFile, "** FS Info Sector: %" PRIu16 "\n", tsk_getu16(fs->endian, sb->a.f32.fsinfo)); tsk_fprintf(hFile, "** Backup Boot Sector: %" PRIu16 "\n", tsk_getu16(fs->endian, sb->a.f32.bs_backup)); } for (i = 0; i < fatfs->numfat; i++) { TSK_DADDR_T base = fatfs->firstfatsect + i * (fatfs->sectperfat); tsk_fprintf(hFile, "* FAT %d: %" PRIuDADDR " - %" PRIuDADDR "\n", i, base, (base + fatfs->sectperfat - 1)); } tsk_fprintf(hFile, "* Data Area: %" PRIuDADDR " - %" PRIuDADDR "\n", fatfs->firstdatasect, fs->last_block); if (fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) { TSK_DADDR_T x = fatfs->csize * fatfs->clustcnt; tsk_fprintf(hFile, "** Root Directory: %" PRIuDADDR " - %" PRIuDADDR "\n", fatfs->firstdatasect, fatfs->firstclustsect - 1); tsk_fprintf(hFile, "** Cluster Area: %" PRIuDADDR " - %" PRIuDADDR "\n", fatfs->firstclustsect, (fatfs->firstclustsect + x - 1)); if ((fatfs->firstclustsect + x - 1) != fs->last_block) { tsk_fprintf(hFile, "** Non-clustered: %" PRIuDADDR " - %" PRIuDADDR "\n", (fatfs->firstclustsect + x), fs->last_block); } } else { TSK_LIST *list_seen = NULL; TSK_DADDR_T x = fatfs->csize * (fatfs->lastclust - 1); TSK_DADDR_T clust, clust_p; tsk_fprintf(hFile, "** Cluster Area: %" PRIuDADDR " - %" PRIuDADDR "\n", fatfs->firstclustsect, (fatfs->firstclustsect + x - 1)); clust_p = fatfs->rootsect; clust = FATFS_SECT_2_CLUST(fatfs, fatfs->rootsect); while ((clust) && (0 == FATFS_ISEOF(clust, FATFS_32_MASK))) { TSK_DADDR_T nxt; clust_p = clust; /* Make sure we do not get into an infinite loop */ if (tsk_list_find(list_seen, clust)) { if (tsk_verbose) tsk_fprintf(stderr, "Loop found while determining root directory size\n"); break; } if (tsk_list_add(&list_seen, clust)) { tsk_list_free(list_seen); list_seen = NULL; return 1; } if (fatfs_getFAT(fatfs, clust, &nxt)) break; clust = nxt; } tsk_list_free(list_seen); list_seen = NULL; tsk_fprintf(hFile, "*** Root Directory: %" PRIuDADDR " - %" PRIuDADDR "\n", fatfs->rootsect, (FATFS_CLUST_2_SECT(fatfs, clust_p + 1) - 1)); if ((fatfs->firstclustsect + x - 1) != fs->last_block) { tsk_fprintf(hFile, "** Non-clustered: %" PRIuDADDR " - %" PRIuDADDR "\n", (fatfs->firstclustsect + x), fs->last_block); } } tsk_fprintf(hFile, "\nMETADATA INFORMATION\n"); tsk_fprintf(hFile, "--------------------------------------------\n"); tsk_fprintf(hFile, "Range: %" PRIuINUM " - %" PRIuINUM "\n", fs->first_inum, fs->last_inum); tsk_fprintf(hFile, "Root Directory: %" PRIuINUM "\n", fs->root_inum); tsk_fprintf(hFile, "\nCONTENT INFORMATION\n"); tsk_fprintf(hFile, "--------------------------------------------\n"); tsk_fprintf(hFile, "Sector Size: %" PRIu16 "\n", fatfs->ssize); tsk_fprintf(hFile, "Cluster Size: %" PRIu32 "\n", (uint32_t) fatfs->csize << fatfs->ssize_sh); tsk_fprintf(hFile, "Total Cluster Range: 2 - %" PRIuDADDR "\n", fatfs->lastclust); /* cycle via cluster and look at each cluster in the FAT * for clusters marked as bad */ cnt = 0; for (i = 2; i <= fatfs->lastclust; i++) { TSK_DADDR_T entry; TSK_DADDR_T sect; unsigned int a; /* Get the FAT table entry */ if (fatfs_getFAT(fatfs, i, &entry)) break; if (FATFS_ISBAD(entry, fatfs->mask) == 0) { continue; } if (cnt == 0) tsk_fprintf(hFile, "Bad Sectors: "); sect = FATFS_CLUST_2_SECT(fatfs, i); for (a = 0; a < fatfs->csize; a++) { tsk_fprintf(hFile, "%" PRIuDADDR " ", sect + a); if ((++cnt % 8) == 0) tsk_fprintf(hFile, "\n"); } } if ((cnt > 0) && ((cnt % 8) != 0)) tsk_fprintf(hFile, "\n"); /* Display the FAT Table */ tsk_fprintf(hFile, "\nFAT CONTENTS (in sectors)\n"); tsk_fprintf(hFile, "--------------------------------------------\n"); /* 'sstart' marks the first sector of the current run to print */ sstart = fatfs->firstclustsect; /* cycle via cluster and look at each cluster in the FAT to make runs */ for (i = 2; i <= fatfs->lastclust; i++) { /* 'send' marks the end sector of the current run, which will extend * when the current cluster continues to the next */ send = FATFS_CLUST_2_SECT(fatfs, i + 1) - 1; /* get the next cluster */ if (fatfs_getFAT(fatfs, i, &next)) break; snext = FATFS_CLUST_2_SECT(fatfs, next); /* we are also using the next sector (clust) */ if ((next & fatfs->mask) == (i + 1)) { continue; } /* The next clust is either further away or the clust is available, * print it if is further away */ else if ((next & fatfs->mask)) { if (FATFS_ISEOF(next, fatfs->mask)) tsk_fprintf(hFile, "%" PRIuDADDR "-%" PRIuDADDR " (%" PRIuDADDR ") -> EOF\n", sstart, send, send - sstart + 1); else if (FATFS_ISBAD(next, fatfs->mask)) tsk_fprintf(hFile, "%" PRIuDADDR "-%" PRIuDADDR " (%" PRIuDADDR ") -> BAD\n", sstart, send, send - sstart + 1); else tsk_fprintf(hFile, "%" PRIuDADDR "-%" PRIuDADDR " (%" PRIuDADDR ") -> %" PRIuDADDR "\n", sstart, send, send - sstart + 1, snext); } /* reset the starting counter */ sstart = send + 1; } return 0; }
/* * 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; }
/* * @param a_is_del Set to 1 if block is from a deleted directory. */ static TSK_RETVAL_ENUM ext2fs_dent_parse_block(EXT2FS_INFO * ext2fs, TSK_FS_DIR * a_fs_dir, uint8_t a_is_del, TSK_LIST ** list_seen, char *buf, int len) { TSK_FS_INFO *fs = &(ext2fs->fs_info); int dellen = 0; int idx; uint16_t reclen; uint32_t inode; char *dirPtr; TSK_FS_NAME *fs_name; int minreclen = 4; if ((fs_name = tsk_fs_name_alloc(EXT2FS_MAXNAMLEN + 1, 0)) == NULL) return TSK_ERR; /* update each time by the actual length instead of the ** recorded length so we can view the deleted entries */ for (idx = 0; idx <= len - EXT2FS_DIRSIZ_lcl(1); idx += minreclen) { unsigned int namelen; dirPtr = &buf[idx]; if (ext2fs->deentry_type == EXT2_DE_V1) { ext2fs_dentry1 *dir = (ext2fs_dentry1 *) dirPtr; inode = tsk_getu32(fs->endian, dir->inode); namelen = tsk_getu16(fs->endian, dir->name_len); reclen = tsk_getu16(fs->endian, dir->rec_len); } else { ext2fs_dentry2 *dir = (ext2fs_dentry2 *) dirPtr; inode = tsk_getu32(fs->endian, dir->inode); namelen = dir->name_len; reclen = tsk_getu16(fs->endian, dir->rec_len); } minreclen = EXT2FS_DIRSIZ_lcl(namelen); /* ** Check if we may have a valid directory entry. If we don't, ** then increment to the next word and try again. */ if ((inode > fs->last_inum) || // inode is unsigned (namelen > EXT2FS_MAXNAMLEN) || (namelen == 0) || // namelen is unsigned (reclen < minreclen) || (reclen % 4) || (idx + reclen > len)) { minreclen = 4; if (dellen > 0) dellen -= 4; continue; } /* Before we process an entry in unallocated space, make * sure that it also ends in the unalloc space */ if ((dellen) && (dellen < minreclen)) { minreclen = 4; dellen -= 4; continue; } if (ext2fs_dent_copy(ext2fs, dirPtr, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } /* Do we have a deleted entry? */ if ((dellen > 0) || (inode == 0) || (a_is_del)) { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; if (dellen > 0) dellen -= minreclen; } /* We have a non-deleted entry */ else { fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } if (tsk_fs_dir_add(a_fs_dir, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } /* If the actual length is shorter then the ** recorded length, then the next entry(ies) have been ** deleted. Set dellen to the length of data that ** has been deleted ** ** Because we aren't guaranteed with Ext2FS that the next ** entry begins right after this one, we will check to ** see if the difference is less than a possible entry ** before we waste time searching it */ if (dellen <= 0) { if (reclen - minreclen >= EXT2FS_DIRSIZ_lcl(1)) dellen = reclen - minreclen; else minreclen = reclen; } } tsk_fs_name_free(fs_name); return TSK_OK; }
static uint8_t ffs_dent_copy(FFS_INFO * ffs, char *ffs_dent, TSK_FS_NAME * fs_name) { TSK_FS_INFO *a_fs = &(ffs->fs_info); /* this one has the type field */ if ((a_fs->ftype == TSK_FS_TYPE_FFS1) || (a_fs->ftype == TSK_FS_TYPE_FFS2)) { ffs_dentry1 *dir = (ffs_dentry1 *) ffs_dent; fs_name->meta_addr = tsk_getu32(a_fs->endian, dir->d_ino); if (fs_name->name_size != FFS_MAXNAMLEN) { if (tsk_fs_name_realloc(fs_name, FFS_MAXNAMLEN)) return 1; } /* ffs null terminates so we can strncpy */ strncpy(fs_name->name, dir->d_name, fs_name->name_size); switch (dir->d_type) { case FFS_DT_REG: fs_name->type = TSK_FS_NAME_TYPE_REG; break; case FFS_DT_DIR: fs_name->type = TSK_FS_NAME_TYPE_DIR; break; case FFS_DT_CHR: fs_name->type = TSK_FS_NAME_TYPE_CHR; break; case FFS_DT_BLK: fs_name->type = TSK_FS_NAME_TYPE_BLK; break; case FFS_DT_FIFO: fs_name->type = TSK_FS_NAME_TYPE_FIFO; break; case FFS_DT_SOCK: fs_name->type = TSK_FS_NAME_TYPE_SOCK; break; case FFS_DT_LNK: fs_name->type = TSK_FS_NAME_TYPE_LNK; break; case FFS_DT_WHT: fs_name->type = TSK_FS_NAME_TYPE_WHT; break; case FFS_DT_UNKNOWN: default: fs_name->type = TSK_FS_NAME_TYPE_UNDEF; break; } } else if (a_fs->ftype == TSK_FS_TYPE_FFS1B) { ffs_dentry2 *dir = (ffs_dentry2 *) ffs_dent; fs_name->meta_addr = tsk_getu32(a_fs->endian, dir->d_ino); if (fs_name->name_size != FFS_MAXNAMLEN) { if (tsk_fs_name_realloc(fs_name, FFS_MAXNAMLEN)) return 1; } /* ffs null terminates so we can strncpy */ strncpy(fs_name->name, dir->d_name, fs_name->name_size); fs_name->type = TSK_FS_NAME_TYPE_UNDEF; } else { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("ffs_dent_copy: Unknown FS type"); return 1; } fs_name->flags = 0; return 0; }
/* * Process the partition table at the sector address * * It is loaded into the internal sorted list * * Return 1 on error and 0 on success */ static uint8_t mac_load_table(TSK_MM_INFO * mm) { mac_part part; char *table_str; uint32_t idx, max_part; TSK_DADDR_T taddr = mm->offset / mm->block_size + MAC_PART_SOFFSET; TSK_DADDR_T max_addr = (mm->img_info->size - mm->offset) / mm->block_size; // max sector if (tsk_verbose) tsk_fprintf(stderr, "mac_load_table: Sector: %" PRIuDADDR "\n", taddr); /* The table can be variable length, so we loop on it * The idx variable shows which round it is * Each structure is 512-bytes each */ max_part = 1; /* set it to 1 and it will be set in the first loop */ for (idx = 0; idx < max_part; idx++) { uint32_t part_start; uint32_t part_size; char *str; ssize_t cnt; /* Read the entry */ cnt = tsk_mm_read_block_nobuf (mm, (char *) &part, sizeof(part), MAC_PART_SOFFSET + idx); /* If -1, then tsk_errno is already set */ if (cnt != sizeof(part)) { if (cnt >= 0) { tsk_error_reset(); tsk_errno = TSK_ERR_MM_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, "MAC Partition entry %" PRIuDADDR, taddr + idx); return 1; } /* Sanity Check */ if (idx == 0) { /* Set the endian ordering the first time around */ if (tsk_mm_guessu16(mm, part.magic, MAC_MAGIC)) { tsk_error_reset(); tsk_errno = TSK_ERR_MM_MAGIC; snprintf(tsk_errstr, TSK_ERRSTR_L, "Mac partition table entry (Sector: %" PRIuDADDR ") %" PRIx16, (taddr + idx), tsk_getu16(mm->endian, part.magic)); return 1; } /* Get the number of partitions */ max_part = tsk_getu32(mm->endian, part.pmap_size); } else if (tsk_getu16(mm->endian, part.magic) != MAC_MAGIC) { tsk_error_reset(); tsk_errno = TSK_ERR_MM_MAGIC; snprintf(tsk_errstr, TSK_ERRSTR_L, "Mac partition table entry (Sector: %" PRIuDADDR ") %" PRIx16, (taddr + idx), tsk_getu16(mm->endian, part.magic)); return 1; } part_start = tsk_getu32(mm->endian, part.start_sec); part_size = tsk_getu32(mm->endian, part.size_sec); if (tsk_verbose) tsk_fprintf(stderr, "mac_load: %" PRIu32 " Starting Sector: %" PRIu32 " Size: %" PRIu32 " Type: %s\n", idx, part_start, part_size, part.type); if (part_size == 0) continue; if (part_start > max_addr) { tsk_error_reset(); tsk_errno = TSK_ERR_MM_BLK_NUM; snprintf(tsk_errstr, TSK_ERRSTR_L, "mac_load_table: Starting sector too large for image"); return 1; } if ((str = talloc_size(NULL, sizeof(part.name))) == NULL) return 1; strncpy(str, (char *) part.type, sizeof(part.name)); if (NULL == tsk_mm_part_add(mm, (TSK_DADDR_T) part_start, (TSK_DADDR_T) part_size, TSK_MM_PART_TYPE_VOL, str, -1, idx)) { talloc_free(str); return 1; } talloc_free(str); } /* Add an entry for the table length */ if ((table_str = talloc_size(NULL, 16)) == NULL) return 1; snprintf(table_str, 16, "Table"); if (NULL == tsk_mm_part_add(mm, taddr, max_part, TSK_MM_PART_TYPE_DESC, table_str, -1, -1)) { talloc_free(table_str); return 1; } talloc_free(table_str); return 0; }