/** * Identify regions in the partition list where there are unused sectors * and create new entries for them. * * @param a_vs Pointer to open volume system * @returns 1 on error and 0 on success */ uint8_t tsk_vs_part_unused(TSK_VS_INFO * a_vs) { TSK_VS_PART_INFO *part = a_vs->part_list; TSK_DADDR_T prev_end = 0; /* prev_ent is set to where the previous entry stopped plus 1 */ for (part = a_vs->part_list; part != NULL; part = part->next) { // ignore the META volume if (part->flags & TSK_VS_PART_FLAG_META) continue; // there is space before current and previous volume if (part->start > prev_end) { char *str; if ((str = tsk_malloc(12)) == NULL) return 1; snprintf(str, 12, "Unallocated"); if (NULL == tsk_vs_part_add(a_vs, prev_end, part->start - prev_end, TSK_VS_PART_FLAG_UNALLOC, str, -1, -1)) { free(str); return 1; } } prev_end = part->start + part->len; } /* Is there unallocated space at the end? */ if (prev_end < (TSK_DADDR_T) (a_vs->img_info->size / a_vs->block_size)) { char *str; if ((str = tsk_malloc(12)) == NULL) return 1; snprintf(str, 12, "Unallocated"); if (NULL == tsk_vs_part_add(a_vs, prev_end, a_vs->img_info->size / a_vs->block_size - prev_end, TSK_VS_PART_FLAG_UNALLOC, str, -1, -1)) { free(str); return 1; } } return 0; }
/* 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; }
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; }
/* * 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; }
/* * Given the path to the file, open it and load the internal * partition table structure * * offset is the byte offset to the start of the volume system * * If test is 1 then additional tests are performed to make sure * it isn't a FAT or NTFS file system. This is used when autodetection * is being used to detect the volume system type. */ TSK_VS_INFO * tsk_vs_xtaf_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset, uint8_t test) { TSK_VS_INFO *vs; ssize_t cnt = 0; char* xtaf_buffer[4]; unsigned int sector_size; /* Offsets and lengths are hard-coded, except for the user data partition length. */ /* Offsets are in bytes */ // TSK_DADDR_T known_xtaf_offsets[] = {0x80000, 0x80080000, 0x10C080000, 0x118EB0000, 0x120eb0000, 0x130eb0000}; TSK_DADDR_T known_xtaf_offsets[] = {1024, 4195328, 8782848, 9205120, 9467264, 9991552}; /* Lengths are in sectors */ TSK_DADDR_T known_xtaf_lengths[] = {4194304, 4587520, 422272 , 262144 , 524288 , 0}; /* Partition labels c/o the Free60 Wiki: http://free60.org/FATX */ char* known_xtaf_labels[] = { "XTAF (System Cache)", "XTAF (Game Cache)", "XTAF (System Extended)", "XTAF (System Extended 2)", "XTAF (Compatibility)", "XTAF (System)" }; //AJN: Recall that the label passed to tsk_vs_part_add must be malloc'ed. TSK_VS_PART_INFO* part; TSK_DADDR_T partition_offset; TSK_DADDR_T partition_length; int itor; char *part_label; int rc_verifysb; int partition_tally = 0; /* Clean up any errors that are lying around. */ tsk_error_reset(); /* Zero out buffer before reading */ memset(xtaf_buffer, 0, sizeof(xtaf_buffer)); sector_size = img_info->sector_size; if (0 == sector_size) { tsk_fprintf(stderr, "tsk_vs_xtaf_open: img_info has the sector size of this image as 0 bytes. Guessing 512 instead, but this should be fixed.\n"); sector_size = 512; } vs = (TSK_VS_INFO *) tsk_malloc(sizeof(*vs)); if (vs == NULL) return NULL; vs->vstype = TSK_VS_TYPE_XTAF; vs->tag = TSK_VS_INFO_TAG; vs->img_info = img_info; vs->offset = offset; /* inititialize settings */ vs->part_list = NULL; vs->endian = 0x02; /*AJN TODO Setting this to TSK_BIG_ENDIAN, which is the same value, causes XTAF recognition to immediately fail...why?*/ vs->block_size = 512; /* Assign functions */ vs->close = xtaf_close; vs->part_count = 0; /* Inspect beginning of image for XTAF superblock. If one is present there, assume we're looking at a partition image, and quit early. */ rc_verifysb = tsk_vs_xtaf_verifysb(img_info, 0, sector_size); if (rc_verifysb == 0) { if (tsk_verbose) tsk_fprintf(stderr, "tsk_vs_xtaf_open: Encountered XTAF superblock at beginning of image. Assuming this is a partition image, not a disk image.\n"); xtaf_close(vs); return NULL; } /* check to see if image is a single partition, in which case XTAF would start at the beginning */ memset(xtaf_buffer, 0, sizeof(xtaf_buffer)); cnt = tsk_img_read(img_info, 0x0, (char *) xtaf_buffer, 4); if(strncmp(xtaf_buffer, "XTAF", 4) == 0){ partition_offset = 0; partition_length = img_info->size; rc_verifysb = tsk_vs_xtaf_verifysb(img_info, partition_offset, sector_size); /* Check for XTAF superblock. */ if (rc_verifysb != 0) { if (tsk_verbose) tsk_fprintf(stderr, "Superblock incorrect\n"); xtaf_close(vs); return NULL; } /* Allocate partition label. */ part_label = (char *) tsk_malloc(XTAF_PART_LABEL_MAX_LENGTH * sizeof(char)); for (itor = 0; itor < 6; itor++){ if( (img_info->size/img_info->sector_size) == known_xtaf_lengths[itor]){ /* Allocate partition label. */ part_label = (char *) tsk_malloc(XTAF_PART_LABEL_MAX_LENGTH * sizeof(char)); snprintf(part_label, XTAF_PART_LABEL_MAX_LENGTH, known_xtaf_labels[itor]); break; } } vs->part_count = 1; /* Populate partition struct and append to partition list. */ part = tsk_vs_part_add(vs, partition_offset, partition_length, TSK_VS_PART_FLAG_ALLOC, part_label, 0, 0); if (NULL == part) { tsk_fprintf(stderr, "tsk_vs_xtaf_open: Failed to add partition %d to partition list.\n", itor); xtaf_close(vs); return NULL; } partition_tally = 1; }else{ vs->part_count = 6; /* Loop through the known partition offsets, looking for XTAF file systems only by a sane XTAF superblock being present. */ for (itor = 0; itor < 6; itor++) { /* Reset. */ part = NULL; part_label = NULL; partition_offset = known_xtaf_offsets[itor]*512; /* Check to see if XTAF is at the location it should be */ memset(xtaf_buffer, 0, sizeof(xtaf_buffer)); cnt = tsk_img_read(img_info, partition_offset, (char *) xtaf_buffer, 4); if(strncmp(xtaf_buffer, "XTAF", 4) != 0){ continue; } partition_length = known_xtaf_lengths[itor]; /* Last partition will have variable size depending on the size of drive, this partition will run to the end of the drive */ if( partition_offset == 0x130eb0000){ partition_length = img_info->size - 0x130eb0000; } if (0 == partition_length) { if (tsk_verbose) { tsk_fprintf(stderr, "tsk_vs_xtaf_open: Computing partition length.\n"); tsk_fprintf(stderr, "tsk_vs_xtaf_open: Image size: %" PRIuOFF " bytes.\n", img_info->size); tsk_fprintf(stderr, "tsk_vs_xtaf_open: Sector size: %u bytes.\n", img_info->sector_size); tsk_fprintf(stderr, "tsk_vs_xtaf_open: Partition offset: %" PRIuDADDR " bytes.\n", partition_offset * img_info->sector_size); } /* Compute partition length of the user data partition differently - based on input image's length. */ if ((img_info->size / sector_size) < partition_offset) { if (tsk_verbose) tsk_fprintf(stderr, "tsk_vs_xtaf_open: This image is smaller than the offset of the target partition. Aborting.\n"); xtaf_close(vs); return NULL; } partition_length = (img_info->size / sector_size) - partition_offset; } if (tsk_verbose) { tsk_fprintf(stderr, "tsk_vs_xtaf_open: Testing for partition.\n"); tsk_fprintf(stderr, "tsk_vs_xtaf_open: itor: %d.\n", itor); tsk_fprintf(stderr, "tsk_vs_xtaf_open: offset: %" PRIuDADDR " sectors.\n", partition_offset); tsk_fprintf(stderr, "tsk_vs_xtaf_open: length: %" PRIuDADDR " sectors.\n", partition_length); } /* Check for XTAF superblock. */ rc_verifysb = tsk_vs_xtaf_verifysb(img_info, partition_offset, sector_size); if (rc_verifysb != 0) { continue; } /* Allocate partition label. */ part_label = (char *) tsk_malloc(XTAF_PART_LABEL_MAX_LENGTH * sizeof(char)); snprintf(part_label, XTAF_PART_LABEL_MAX_LENGTH, known_xtaf_labels[itor]); /* Populate partition struct and append to partition list. */ part = tsk_vs_part_add(vs, (partition_offset/(512)), partition_length, TSK_VS_PART_FLAG_ALLOC, part_label, 0, 0); // part->start = (TSK_DADDR_T) partition_offset; if (NULL == part) { tsk_fprintf(stderr, "tsk_vs_xtaf_open: Failed to add partition %d to partition list.\n", itor); break; } partition_tally++; } } /* Don't call this an XTAF volume system if none of the hard-coded partitions were found. */ if (partition_tally == 0) { xtaf_close(vs); return NULL; } /* Denote unallocated space as "Unused" disk area. */ if (tsk_vs_part_unused(vs)) { xtaf_close(vs); return NULL; } return vs; }
/* * 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; }
/* * 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; }