/* Scans The partitions */ int scan_partitions(struct disk_info *dsk) { static unsigned char sector[SECTOR_SIZE]; struct MBRpartition *part; struct partition_info *current = NULL; int sector_size; int ret, i; ret = read_disk(dsk->fd, sector, 0, 1, dsk->sector_size); if(ret < 0) return ret; if(ret < sector_size) { LOG_INFO("Error Reading the MBR on %s \n", path); return -1; } if(!valid_part_table_flag(sector)) { LOG_INFO("Partition Table Error on %s\n", dsk->device_file); LOG_INFO("Invalid End of sector marker"); return -INVALID_TABLE; } /* First Scan primary Partitions */ for(i = 0; i < 4; i++) { part = pt_offset(sector, i); if((part->sys_ind != 0x00) || (get_nr_sects(part) != 0x00)) { LOG_INFO("index %d ID %X size %Ld \n", i, part->sys_ind, get_nr_sects(part)); if(!dsk->partition) { current = malloc(sizeof(struct partition_info)); memset(current, 0, sizeof(struct partition_info)); dsk->partition = current; } else { current->next = malloc(sizeof(struct partition_info)); memset(current->next, 0, sizeof(struct partition_info)); current = current->next; } current->fstype = part->sys_ind; current->base = get_start_sect(part); current->size = get_nr_sects(part) * dsk->sector_size; if(is_extended(part->sys_ind)) { current->flag = PARTITION_TYPE_EXTENDED; scan_ebr(dsk, current); } else { current->flag = PARTITION_TYPE_PRIMARY; } } } return 0; }
static void print_one_part(dos_partition_t *p, int ext_part_sector, int part_num, unsigned int disksig) { int lba_start = ext_part_sector + le32_to_int (p->start4); int lba_size = le32_to_int (p->size4); printf("%3d\t%-10d\t%-10d\t%08x-%02x\t%02x%s%s\n", part_num, lba_start, lba_size, disksig, part_num, p->sys_ind, (is_extended(p->sys_ind) ? " Extd" : ""), (is_bootable(p) ? " Boot" : "")); }
/* Reads The Extended Partitions */ int scan_ebr(struct disk_info *dsk, struct partition_info *ext) { static unsigned char sector[SECTOR_SIZE]; struct MBRpartition *part, *part1; struct partition_info *current = NULL, *pt; int logical = 4, ret; lloff_t ebrBase, nextPart, ebr2=0; ebrBase = ext->base; nextPart = ext->base; while (1) { ret = read_disk(dsk->fd, sector, nextPart, 1, dsk->sector_size); if (ret < 0) return ret; if (ret < dsk->sector_size) { LOG_INFO("Error Reading the EBR \n"); return -1; } part = pt_offset(sector, 0); LOG_INFO("index %d ID %X size %Ld \n", logical, part->sys_ind, get_nr_sects(part)); if (is_extended(part->sys_ind)) { // special case. ebr has extended partition with offset to another ebr. ebr2 += get_start_sect(part); nextPart = (ebr2 + ebrBase); continue; } part1 = pt_offset(sector, 1); ebr2 = get_start_sect(part1); nextPart = (ebr2 + ebrBase); pt = malloc(sizeof(struct partition_info)); if (!pt) { LOG_INFO("Allocation Error\n"); } memset(pt, 0, sizeof(struct partition_info)); if (!current) { current = pt; ext->ext = pt; } else { current->next = pt; current = current->next; } pt->fstype = part->sys_ind; pt->base = get_start_sect(part); pt->size = get_nr_sects(part) * dsk->sector_size; logical++; if (part1->sys_ind == 0) break; } return logical; }
static int read_extended_partition(int fd, struct partition *ep, int en, struct slice *sp, int ns) { struct partition p; unsigned long start, here, next; unsigned char *bp; int loopct = 0; int moretodo = 1; int i, n=0; int sector_size_mul = get_sector_size(fd)/512; next = start = sector_size_mul * le32_to_cpu(ep->start_sect); while (moretodo) { here = next; moretodo = 0; if (++loopct > 100) return n; bp = (unsigned char *)getblock(fd, here); if (bp == NULL) return n; if (bp[510] != 0x55 || bp[511] != 0xaa) return n; for (i=0; i<2; i++) { memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p)); if (is_extended(p.sys_type)) { if (p.start_sect && p.nr_sects && !moretodo) { next = start + sector_size_mul * le32_to_cpu(p.start_sect); moretodo = 1; } continue; } if (n < ns) { sp[n].start = here + sector_size_mul * le32_to_cpu(p.start_sect); sp[n].size = sector_size_mul * le32_to_cpu(p.nr_sects); sp[n].container = en + 1; n++; } else { fprintf(stderr, "dos_extd_partition: too many slices\n"); return n; } loopct = 0; } } return n; }
/****************************************************************************** Examine the disk partition table and return a list of chunks A chunk is a block of sectors that is either (1) a partition (2) a partition boot track (3) the block of sectors between two partitions or (4) the block of sectors after the last partition upto the end of the disk ******************************************************************************/ int layout_disk (pte_ptr pt, /* the partition table */ layout_ptr lp, /* the disk layout to return */ disk_control_ptr d)/* the disk containing the partition table */ { int n = 0; int more = 1; pte_ptr min_entry; off_t min = 0, alloc = 0, at; do { min_entry = find_min (pt, min, &at); if (min_entry) { if (alloc < at) { lp[n].pt = NULL; lp[n].lba_start = alloc; lp[n].n_sectors = at /*min_entry -> lba_start*/ - alloc; if (n) lp[n].chunk_class = CHUNK_UNALLOCATED; else lp[n].chunk_class = CHUNK_BOOT; n++; if(n >= MAX_PARTITIONS) { printf("Error: maximum number of partitions (%d) exceeded.\n", MAX_PARTITIONS); exit(1); } } lp[n].pt = min_entry; lp[n].lba_start = at; /*min_entry -> lba_start*/ if (is_extended(min_entry->type)) { lp[n].n_sectors = DISK_MAX_SECTORS; lp[n].chunk_class = CHUNK_BOOT_EXT; } else { lp[n].chunk_class = CHUNK_PARTITION; lp[n].n_sectors = min_entry -> lba_length; } min = lp[n].lba_start + lp[n].n_sectors; alloc = min; n++; } else more = 0; } while (more); if (alloc < n_sectors(d)) { lp[n].pt = NULL; lp[n].chunk_class = CHUNK_UNALLOCATED; lp[n].lba_start = alloc; lp[n].n_sectors = n_sectors(d) - alloc; n++; } return n; }
/* * data_to_part_desc -- * parses raw partition table sector data * to partition description structure * * PARAMETERS: * data - raw partition table sector data * new_part_desc - pointer to returned partition description structure * * RETURNS: * RTEMS_SUCCESSFUL, if success; * RTEMS_NO_MEMOTY, if cannot allocate memory for part_desc_t strucure; * RTEMS_INTERNAL_ERROR, if other error occurs. */ static rtems_status_code data_to_part_desc(uint8_t *data, rtems_part_desc_t **new_part_desc) { rtems_part_desc_t *part_desc; uint32_t temp; if (new_part_desc == NULL) { return RTEMS_INTERNAL_ERROR; } *new_part_desc = NULL; if ((part_desc = calloc(1, sizeof(rtems_part_desc_t))) == NULL) { return RTEMS_NO_MEMORY; } part_desc->bootable = *(data + RTEMS_IDE_PARTITION_BOOTABLE_OFFSET); part_desc->sys_type = *(data + RTEMS_IDE_PARTITION_SYS_TYPE_OFFSET); /* read the offset start position and partition size in sectors */ /* due to incorrect data alignment one have to align data first */ memcpy(&temp, data + RTEMS_IDE_PARTITION_START_OFFSET, sizeof(uint32_t)); part_desc->start = LE_TO_CPU_U32(temp); memcpy(&temp, data + RTEMS_IDE_PARTITION_SIZE_OFFSET, sizeof(uint32_t)); part_desc->size = LE_TO_CPU_U32(temp); /* * use partitions that are * - extended * or * - FAT type and non-zero */ if (is_extended(part_desc->sys_type) || ((is_fat_partition(part_desc->sys_type)) && (part_desc->size != 0))) { *new_part_desc = part_desc; } else { /* empty partition */ free(part_desc); } return RTEMS_SUCCESSFUL; }
/* * partition free -- * frees partition description structure * * PARAMETERS: * part_desc - returned disc description structure * * RETURNS: * N/A */ static void partition_free(rtems_part_desc_t *part_desc) { int part_num; if (part_desc == NULL) return; if (is_extended(part_desc->sys_type)) { for (part_num = 0; part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; part_num++) { partition_free(part_desc->sub_part[part_num]); } } free(part_desc); }
int read_dos_pt(int fd, struct slice all, struct slice *sp, int ns) { struct partition p; unsigned long offset = all.start; int i, n=4; unsigned char *bp; uint64_t sector_size_mul = get_sector_size(fd)/512; bp = (unsigned char *)getblock(fd, offset); if (bp == NULL) return -1; if (bp[510] != 0x55 || bp[511] != 0xaa) return -1; for (i=0; i<4; i++) { memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p)); if (is_gpt(p.sys_type)) return 0; if (i < ns) { sp[i].start = sector_size_mul * le32_to_cpu(p.start_sect); sp[i].size = sector_size_mul * le32_to_cpu(p.nr_sects); } else { fprintf(stderr, "dos_partition: too many slices\n"); break; } if (is_extended(p.sys_type)) { /* extended partitions only get one or two sectors mapped for LILO to install, whichever is needed to have 1kb of space */ if (sector_size_mul == 1) sp[i].size = 2; else sp[i].size = sector_size_mul; n += read_extended_partition(fd, &p, i, sp+n, ns-n); } } return n; }
/** Iterate over an extended partition. * @param disk Disk that the partition is on. * @param lba LBA of the extended partition. * @param cb Callback function. */ static void handle_extended(disk_device_t *disk, uint32_t lba, partition_iterate_cb_t cb) { mbr_t *ebr __cleanup_free; size_t i = 4; ebr = malloc(sizeof(*ebr)); for (uint32_t curr_ebr = lba, next_ebr = 0; curr_ebr; curr_ebr = next_ebr) { mbr_partition_t *partition, *next; if (!read_mbr(disk, ebr, curr_ebr)) { dprintf("mbr: failed to read EBR at %" PRIu32 "\n", curr_ebr); break; } else if (ebr->signature != MBR_SIGNATURE) { dprintf("mbr: warning: invalid EBR, corrupt partition table\n"); break; } /* First entry contains the logical partition, second entry refers to * the next EBR, forming a linked list of EBRs. */ partition = &ebr->partitions[0]; next = &ebr->partitions[1]; /* Calculate the location of the next EBR. The start sector is relative * to the start of the extended partition. Set to 0 if the second * partition doesn't refer to another EBR entry, causes the loop to end. */ next->start_lba += lba; next_ebr = (is_valid(disk, next) && is_extended(next) && next->start_lba > curr_ebr) ? next->start_lba : 0; /* Get the partition. Here the start sector is relative to the current * EBR's location. */ partition->start_lba += curr_ebr; if (!is_valid(disk, partition)) continue; cb(disk, i++, partition->start_lba, partition->num_sectors); } }
/** Iterate over the partitions on a device. * @param disk Disk to iterate over. * @param cb Callback function. * @return Whether the device contained an MBR partition table. */ static bool mbr_partition_iterate(disk_device_t *disk, partition_iterate_cb_t cb) { mbr_t *mbr __cleanup_free; bool seen_extended; /* Read in the MBR, which is in the first block on the device. */ mbr = malloc(sizeof(*mbr)); if (!read_mbr(disk, mbr, 0) || mbr->signature != MBR_SIGNATURE) return false; /* Check if this is a GPT partition table (technically we should not get * here if this is a GPT disk as the GPT code should be reached first). This * is just a safeguard. */ if (mbr->partitions[0].type == MBR_PARTITION_TYPE_GPT) return false; /* Loop through all partitions in the table. */ seen_extended = false; for (size_t i = 0; i < array_size(mbr->partitions); i++) { mbr_partition_t *partition = &mbr->partitions[i]; if (!is_valid(disk, partition)) continue; if (is_extended(partition)) { if (seen_extended) { dprintf("mbr: warning: ignoring multiple extended partitions\n"); continue; } handle_extended(disk, partition->start_lba, cb); seen_extended = true; } else { cb(disk, i, partition->start_lba, partition->num_sectors); } } return true; }
int read_dos_pt(int fd, struct slice all, struct slice *sp, int ns) { struct partition *p; unsigned long offset = all.start; int i, n=0; unsigned char *bp; bp = getblock(fd, offset); if (bp == NULL) return -1; if (bp[510] != 0x55 || bp[511] != 0xaa) return -1; p = (struct partition *) (bp + 0x1be); for (i=0; i<4; i++) { /* always add, even if zero length */ if (n < ns) { sp[n].start = p->start_sect; sp[n].size = p->nr_sects; n++; } else { fprintf(stderr, "dos_partition: too many slices\n"); break; } p++; } p = (struct partition *) (bp + 0x1be); for (i=0; i<4; i++) { if (is_extended(p->sys_type)) n += read_extended_partition(fd, p, sp+n, ns-n); p++; } return n; }
/* Print a partition that is relative to its Extended partition table */ static int get_partition_info_extended (block_dev_desc_t *dev_desc, lbaint_t ext_part_sector, lbaint_t relative, int part_num, int which_part, disk_partition_t *info, unsigned int disksig) { unsigned char buffer[DOS_PART_DEFAULT_SECTOR]; dos_partition_t *pt; int i; int dos_type; if (dev_desc->block_read(dev_desc, ext_part_sector, 1, buffer) != 1) { printf("** Can't read partition table on %d:" LBAFU " **\n", dev_desc->dev, ext_part_sector); return -1; } if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 || buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) { printf ("bad MBR sector signature 0x%02x%02x\n", buffer[DOS_PART_MAGIC_OFFSET], buffer[DOS_PART_MAGIC_OFFSET + 1]); return -1; } // disksig is "Disk identifier" shown in "sudo fdisk -l" if (!ext_part_sector) disksig = le32_to_uint32(&buffer[DOS_PART_DISKSIG_OFFSET]); /* Print all primary/logical partitions */ pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET); for (i = 0; i < 4; i++, pt++) { /* * fdisk does not show the extended partitions that are not in the MBR */ if (((pt->boot_ind & ~0x80) == 0) && (pt->sys_ind != 0) && (part_num == which_part) && (is_extended(pt->sys_ind) == 0)) { info->blksz = DOS_PART_DEFAULT_SECTOR; info->start = (lbaint_t)(ext_part_sector + le32_to_uint32(pt->start4)); info->size = (lbaint_t)le32_to_uint32(pt->size4); switch(dev_desc->if_type) { case IF_TYPE_IDE: case IF_TYPE_SATA: case IF_TYPE_ATAPI: sprintf ((char *)info->name, "hd%c%d", 'a' + dev_desc->dev, part_num); break; case IF_TYPE_SCSI: sprintf ((char *)info->name, "sd%c%d", 'a' + dev_desc->dev, part_num); break; case IF_TYPE_USB: sprintf ((char *)info->name, "usbd%c%d", 'a' + dev_desc->dev, part_num); break; case IF_TYPE_DOC: sprintf ((char *)info->name, "docd%c%d", 'a' + dev_desc->dev, part_num); break; default: sprintf ((char *)info->name, "xx%c%d", 'a' + dev_desc->dev, part_num); break; } /* sprintf(info->type, "%d, pt->sys_ind); */ strcpy((char *)info->type, "U-Boot"); info->bootable = is_bootable(pt); sprintf(info->uuid, "%08x-%02x", disksig, part_num); return 0; } /* Reverse engr the fdisk part# assignment rule! */ if ((ext_part_sector == 0) || (pt->sys_ind != 0 && !is_extended (pt->sys_ind)) ) { part_num++; } } /* Follows the extended partitions */ pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET); for (i = 0; i < 4; i++, pt++) { if (is_extended (pt->sys_ind)) { lbaint_t lba_start = le32_to_uint32(pt->start4) + relative; return get_partition_info_extended (dev_desc, lba_start, ext_part_sector == 0 ? lba_start : relative, part_num, which_part, info, disksig); } } /* Check for DOS PBR if no partition is found */ dos_type = test_block_type(buffer); if (dos_type == DOS_PBR) { info->start = 0; info->size = dev_desc->lba; info->blksz = DOS_PART_DEFAULT_SECTOR; info->bootable = 0; strcpy((char *)info->type, "U-Boot"); info->uuid[0] = 0; return 0; } return -1; }
static int parse_dos_extended(blkid_probe pr, blkid_parttable tab, uint32_t ex_start, uint32_t ex_size, int ssf) { blkid_partlist ls = blkid_probe_get_partlist(pr); uint32_t cur_start = ex_start, cur_size = ex_size; unsigned char *data; int ct_nodata = 0; /* count ext.partitions without data partitions */ int i; while (1) { struct dos_partition *p, *p0; uint32_t start, size; if (++ct_nodata > 100) return 0; data = blkid_probe_get_sector(pr, cur_start); if (!data) goto leave; /* malformed partition? */ if (!is_valid_mbr_signature(data)) goto leave; p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); /* Usually, the first entry is the real data partition, * the 2nd entry is the next extended partition, or empty, * and the 3rd and 4th entries are unused. * However, DRDOS sometimes has the extended partition as * the first entry (when the data partition is empty), * and OS/2 seems to use all four entries. * -- Linux kernel fs/partitions/dos.c * * See also http://en.wikipedia.org/wiki/Extended_boot_record */ /* Parse data partition */ for (p = p0, i = 0; i < 4; i++, p++) { uint32_t abs_start; blkid_partition par; /* the start is relative to the parental ext.partition */ start = dos_partition_start(p) * ssf; size = dos_partition_size(p) * ssf; abs_start = cur_start + start; /* absolute start */ if (!size || is_extended(p)) continue; if (i >= 2) { /* extra checks to detect real data on * 3rd and 4th entries */ if (start + size > cur_size) continue; if (abs_start < ex_start) continue; if (abs_start + size > ex_start + ex_size) continue; } par = blkid_partlist_add_partition(ls, tab, abs_start, size); if (!par) goto err; blkid_partition_set_type(par, p->sys_type); blkid_partition_set_flags(par, p->boot_ind); ct_nodata = 0; } /* The first nested ext.partition should be a link to the next * logical partition. Everything other (recursive ext.partitions) * is junk. */ for (p = p0, i = 0; i < 4; i++, p++) { start = dos_partition_start(p) * ssf; size = dos_partition_size(p) * ssf; if (size && is_extended(p)) break; } if (i == 4) goto leave; cur_start = ex_start + start; cur_size = size; } leave: return 0; err: return -1; }
/* Print a partition that is relative to its Extended partition table */ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part_sector, int relative, int part_num, int which_part, disk_partition_t *info) { unsigned char buffer[DEFAULT_SECTOR_SIZE]; dos_partition_t *pt; int i; if (dev_desc->block_read (dev_desc->dev, ext_part_sector, 1, (ulong *) buffer) != 1) { printf ("** Can't read partition table on %d:%d **\n", dev_desc->dev, ext_part_sector); return -1; } if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 || buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) { printf ("bad MBR sector signature 0x%02x%02x\n", buffer[DOS_PART_MAGIC_OFFSET], buffer[DOS_PART_MAGIC_OFFSET + 1]); return -1; } /* Print all primary/logical partitions */ pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET); for (i = 0; i < 4; i++, pt++) { /* * fdisk does not show the extended partitions that * are not in the MBR */ if (((pt->boot_ind & ~0x80) == 0) && (pt->sys_ind != 0) && (part_num == which_part) && (is_extended(pt->sys_ind) == 0)) { info->blksz = 512; info->start = ext_part_sector + le32_to_int (pt->start4); info->size = le32_to_int (pt->size4); switch(dev_desc->if_type) { case IF_TYPE_IDE: case IF_TYPE_SATA: case IF_TYPE_ATAPI: sprintf ((char *)info->name, "hd%c%d", 'a' + dev_desc->dev, part_num); break; case IF_TYPE_SCSI: sprintf ((char *)info->name, "sd%c%d", 'a' + dev_desc->dev, part_num); break; case IF_TYPE_USB: sprintf ((char *)info->name, "usbd%c%d", 'a' + dev_desc->dev, part_num); break; case IF_TYPE_DOC: sprintf ((char *)info->name, "docd%c%d", 'a' + dev_desc->dev, part_num); break; default: sprintf ((char *)info->name, "xx%c%d", 'a' + dev_desc->dev, part_num); break; } /* sprintf(info->type, "%d, pt->sys_ind); */ sprintf ((char *)info->type, "U-Boot"); return 0; } /* Reverse engr the fdisk part# assignment rule! */ if ((ext_part_sector == 0) || (pt->sys_ind != 0 && !is_extended (pt->sys_ind)) ) { part_num++; } } /* Follows the extended partitions */ pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET); for (i = 0; i < 4; i++, pt++) { if (is_extended (pt->sys_ind)) { int lba_start = le32_to_int (pt->start4) + relative; return get_partition_info_extended (dev_desc, lba_start, ext_part_sector == 0 ? lba_start : relative, part_num, which_part, info); } } return -1; }
int FAST_FUNC volume_id_probe_msdos_part_table(struct volume_id *id, uint64_t off) { const uint8_t *buf; int i; uint64_t poff; uint64_t plen; uint64_t extended = 0; uint64_t current; uint64_t next; int limit; int empty = 1; struct msdos_partition_entry *part; struct volume_id_partition *p; dbg("probing at offset 0x%llx", (unsigned long long) off); buf = volume_id_get_buffer(id, off, 0x200); if (buf == NULL) return -1; if (buf[MSDOS_SIG_OFF] != 0x55 || buf[MSDOS_SIG_OFF + 1] != 0xaa) return -1; /* check flags on all entries for a valid partition table */ part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET]; for (i = 0; i < 4; i++) { if (part[i].boot_ind != 0 && part[i].boot_ind != 0x80 ) { return -1; } if (part[i].nr_sects != 0) empty = 0; } if (empty == 1) return -1; if (id->partitions != NULL) free(id->partitions); id->partitions = xzalloc(VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition)); for (i = 0; i < 4; i++) { poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE; plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE; if (plen == 0) continue; p = &id->partitions[i]; // p->pt_type_raw = part[i].sys_ind; if (is_extended(part[i].sys_ind)) { dbg("found extended partition at 0x%llx", (unsigned long long) poff); // volume_id_set_usage_part(p, VOLUME_ID_PARTITIONTABLE); // p->type = "msdos_extended_partition"; if (extended == 0) extended = off + poff; } else { dbg("found 0x%x data partition at 0x%llx, len 0x%llx", part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen); // if (is_raid(part[i].sys_ind)) // volume_id_set_usage_part(p, VOLUME_ID_RAID); // else // volume_id_set_usage_part(p, VOLUME_ID_UNPROBED); } // p->pt_off = off + poff; // p->pt_len = plen; id->partition_count = i+1; } next = extended; current = extended; limit = 50; /* follow extended partition chain and add data partitions */ while (next != 0) { if (limit-- == 0) { dbg("extended chain limit reached"); break; } buf = volume_id_get_buffer(id, current, 0x200); if (buf == NULL) break; part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET]; if (buf[MSDOS_SIG_OFF] != 0x55 || buf[MSDOS_SIG_OFF + 1] != 0xaa) break; next = 0; for (i = 0; i < 4; i++) { poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE; plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE; if (plen == 0) continue; if (is_extended(part[i].sys_ind)) { dbg("found extended partition at 0x%llx", (unsigned long long) poff); if (next == 0) next = extended + poff; } else { dbg("found 0x%x data partition at 0x%llx, len 0x%llx", part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen); /* we always start at the 5th entry */ // while (id->partition_count < 4) // volume_id_set_usage_part(&id->partitions[id->partition_count++], VOLUME_ID_UNUSED); if (id->partition_count < 4) id->partition_count = 4; // p = &id->partitions[id->partition_count]; // if (is_raid(part[i].sys_ind)) // volume_id_set_usage_part(p, VOLUME_ID_RAID); // else // volume_id_set_usage_part(p, VOLUME_ID_UNPROBED); // p->pt_off = current + poff; // p->pt_len = plen; id->partition_count++; // p->pt_type_raw = part[i].sys_ind; if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) { dbg("too many partitions"); next = 0; } } } current = next; } // volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE); // id->type = "msdos_partition_table"; return 0; }
static int parse_dos_extended(blkid_probe pr, blkid_parttable tab, uint32_t ex_start, uint32_t ex_size, int ssf) { blkid_partlist ls = blkid_probe_get_partlist(pr); uint32_t cur_start = ex_start, cur_size = ex_size; unsigned char *data; int ct_nodata = 0; /* count ext.partitions without data partitions */ int i; DBG(LOWPROBE, ul_debug("parse EBR [start=%d, size=%d]", ex_start/ssf, ex_size/ssf)); if (ex_start == 0) { DBG(LOWPROBE, ul_debug("Bad offset in primary extended partition -- ignore")); return 0; } while (1) { struct dos_partition *p, *p0; uint32_t start, size; if (++ct_nodata > 100) return BLKID_PROBE_OK; data = blkid_probe_get_sector(pr, cur_start); if (!data) { if (errno) return -errno; goto leave; /* malformed partition? */ } if (!mbr_is_valid_magic(data)) goto leave; p0 = mbr_get_partition(data, 0); /* Usually, the first entry is the real data partition, * the 2nd entry is the next extended partition, or empty, * and the 3rd and 4th entries are unused. * However, DRDOS sometimes has the extended partition as * the first entry (when the data partition is empty), * and OS/2 seems to use all four entries. * -- Linux kernel fs/partitions/dos.c * * See also http://en.wikipedia.org/wiki/Extended_boot_record */ /* Parse data partition */ for (p = p0, i = 0; i < 4; i++, p++) { uint32_t abs_start; blkid_partition par; /* the start is relative to the parental ext.partition */ start = dos_partition_get_start(p) * ssf; size = dos_partition_get_size(p) * ssf; abs_start = cur_start + start; /* absolute start */ if (!size || is_extended(p)) continue; if (i >= 2) { /* extra checks to detect real data on * 3rd and 4th entries */ if (start + size > cur_size) continue; if (abs_start < ex_start) continue; if (abs_start + size > ex_start + ex_size) continue; } /* Avoid recursive non-empty links, see ct_nodata counter */ if (blkid_partlist_get_partition_by_start(ls, abs_start)) { DBG(LOWPROBE, ul_debug("#%d: EBR duplicate data partition [abs start=%u] -- ignore", i + 1, abs_start)); continue; } par = blkid_partlist_add_partition(ls, tab, abs_start, size); if (!par) return -ENOMEM; blkid_partition_set_type(par, p->sys_ind); blkid_partition_set_flags(par, p->boot_ind); blkid_partition_gen_uuid(par); ct_nodata = 0; } /* The first nested ext.partition should be a link to the next * logical partition. Everything other (recursive ext.partitions) * is junk. */ for (p = p0, i = 0; i < 4; i++, p++) { start = dos_partition_get_start(p) * ssf; size = dos_partition_get_size(p) * ssf; if (size && is_extended(p)) { if (start == 0) DBG(LOWPROBE, ul_debug("#%d: EBR link offset is zero -- ignore", i + 1)); else break; } } if (i == 4) goto leave; cur_start = ex_start + start; cur_size = size; } leave: return BLKID_PROBE_OK; }
int create_extended_partition(int fd, int secno, int size) { int sec = secno; int cursec = secno; int pno = partno; /* number of extd partition */ int ei = eptsct-1; unsigned char type = 0x5; int lastseen = secno; int ok = 0; if (epts[ei].secno != secno) { fprintf(stderr, "%s: program bug\n", progname); exit(1); } outmsg("candidate ext pt", secno, secno+1, type); addpart(secno, 1, type); /* size to be filled in later */ while(1) { char buf[512]; struct partition *p1, *p2, *pr, *pe; p1 = (struct partition *)(& epts[ei].pt4[0]); p2 = (struct partition *)(& epts[ei].pt4[16]); /* for the time being we just ignore the rest */ if (is_extended(p1->sys_type)) { pr = p2; pe = p1; } else if (is_extended(p2->sys_type)) { pr = p1; pe = p2; } else if (p1->sys_type == 0) { pr = p2; pe = 0; } else if (p2->sys_type == 0) { pr = p1; pe = 0; } else break; /* first handle the real partition, if any */ if (pr->sys_type != 0) { int ss = cursec + pr->start_sect; int es = ss + pr->nr_sects; outmsg("found in ept", ss, es, pr->sys_type); addpart(ss, pr->nr_sects, pr->sys_type); if (lastseen < es - 1) lastseen = es - 1; if (lastseen >= size) break; } /* then the extended link */ if (!pe) { ok = 1; break; } type = pe->sys_type; cursec = sec + pe->start_sect; if (cursec >= size) break; read_sectors(fd, buf, cursec, 1); addepts(cursec, buf); ei = eptsct-1; } if (!ok || lastseen == secno) { printf("# retracted\n"); partno = pno; return 0; } pts[pno].type = type; pts[pno].size = lastseen+1-secno; outmsg("extended part ok", secno, lastseen+1, type); return lastseen; }
/* Print a partition that is relative to its Extended partition table */ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part_sector, int relative, int part_num, int which_part, disk_partition_t *info) { unsigned char tmp_buf[DEFAULT_SECTOR_SIZE]; unsigned char *buffer = KSEG1ADDR(&tmp_buf[0]); dos_partition_t *pt; int i; if (dev_desc->block_read (dev_desc->dev, ext_part_sector, 1, (ulong *) buffer) != 1) { printf ("** Can't read partition table on %d:%d **\n", dev_desc->dev, ext_part_sector); return -1; } if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 || buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) { printf ("bad MBR sector signature 0x%02x%02x\n", buffer[DOS_PART_MAGIC_OFFSET], buffer[DOS_PART_MAGIC_OFFSET + 1]); return -1; } /* Print all primary/logical partitions */ pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET); /* MTK/Ralink 2012/06/28 -- if no partition table in USB storage first sector */ if(pt->boot_ind != 0x80 && pt->boot_ind != 0x0){ boot_sector *bs; printf ("It seems no partition tables existed.\n"); bs = (boot_sector *) (buffer); if(ext_part_sector == 0 && bs->reserved && bs->fats){ info->blksz = 512; info->start = ext_part_sector + 0; //FIXME: how to determine info->size? from FAT struct? //info->size = FAT2CPU32(bs->total_sect); return 0; }else return -1; } for (i = 0; i < 4; i++, pt++) { /* * fdisk does not show the extended partitions that * are not in the MBR */ if ((pt->sys_ind != 0) && (part_num == which_part) && (is_extended(pt->sys_ind) == 0)) { info->blksz = 512; info->start = ext_part_sector + le32_to_int (pt->start4); info->size = le32_to_int (pt->size4); switch(dev_desc->if_type) { case IF_TYPE_IDE: case IF_TYPE_ATAPI: sprintf (info->name, "hd%c%d\n", 'a' + dev_desc->dev, part_num); break; case IF_TYPE_SCSI: sprintf (info->name, "sd%c%d\n", 'a' + dev_desc->dev, part_num); break; case IF_TYPE_USB: sprintf (info->name, "usbd%c%d\n", 'a' + dev_desc->dev, part_num); break; case IF_TYPE_DOC: sprintf (info->name, "docd%c%d\n", 'a' + dev_desc->dev, part_num); break; default: sprintf (info->name, "xx%c%d\n", 'a' + dev_desc->dev, part_num); break; } /* sprintf(info->type, "%d, pt->sys_ind); */ sprintf (info->type, "U-Boot"); return 0; } /* Reverse engr the fdisk part# assignment rule! */ if ((ext_part_sector == 0) || (pt->sys_ind != 0 && !is_extended (pt->sys_ind)) ) { part_num++; } } /* Follows the extended partitions */ pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET); for (i = 0; i < 4; i++, pt++) { if (is_extended (pt->sys_ind)) { int lba_start = le32_to_int (pt->start4) + relative; return get_partition_info_extended (dev_desc, lba_start, ext_part_sector == 0 ? lba_start : relative, part_num, which_part, info); } } return -1; }
/* * read_mbr -- * reads Master Boot Record (sector 0) of physical device and * constructs disk description structure * * PARAMETERS: * disk_desc - returned disc description structure * * RETURNS: * RTEMS_SUCCESSFUL if success, * RTEMS_INTERNAL_ERROR otherwise */ static rtems_status_code read_mbr(int fd, rtems_disk_desc_t *disk_desc) { int part_num; rtems_sector_data_t *sector = NULL; rtems_part_desc_t *part_desc; uint8_t *data; rtems_status_code rc; /* get MBR sector */ rc = get_sector(fd, 0, §or); if (rc != RTEMS_SUCCESSFUL) { if (sector) free(sector); return rc; } /* check if the partition table structure is MS-DOS style */ if (!msdos_signature_check(sector)) { free(sector); return RTEMS_INTERNAL_ERROR; } /* read and process 4 primary partition descriptors */ data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET; for (part_num = 0; part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; part_num++) { rc = data_to_part_desc(data, &part_desc); if (rc != RTEMS_SUCCESSFUL) { free(sector); return rc; } if (part_desc != NULL) { part_desc->log_id = part_num + 1; part_desc->disk_desc = disk_desc; part_desc->end = part_desc->start + part_desc->size - 1; disk_desc->partitions[part_num] = part_desc; } else { disk_desc->partitions[part_num] = NULL; } data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE; } free(sector); disk_desc->last_log_id = RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; /* There cannot be more than one extended partition, but we are to process each primary partition */ for (part_num = 0; part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; part_num++) { part_desc = disk_desc->partitions[part_num]; if (part_desc != NULL && is_extended(part_desc->sys_type)) { read_extended_partition(fd, part_desc->start, part_desc); free(part_desc); disk_desc->partitions[part_num] = NULL; } } return RTEMS_SUCCESSFUL; }
/* * read_extended_partition -- * recursively reads extended partition sector from the device * and constructs the partition table tree * * PARAMETERS: * fd - file descriptor * start - start sector of primary extended partition, used for * calculation of absolute partition sector address * ext_part - description of extended partition to process * * RETURNS: * RTEMS_SUCCESSFUL if success, * RTEMS_NO_MEMOTY if cannot allocate memory for part_desc_t strucure, * RTEMS_INTERNAL_ERROR if other error occurs. */ static rtems_status_code read_extended_partition(int fd, uint32_t start, rtems_part_desc_t *ext_part) { int i; rtems_sector_data_t *sector = NULL; uint32_t here; uint8_t *data; rtems_part_desc_t *new_part_desc; rtems_status_code rc; if ((ext_part == NULL) || (ext_part->disk_desc == NULL)) { return RTEMS_INTERNAL_ERROR; } /* get start sector of current extended partition */ here = ext_part->start; /* get first extended partition sector */ rc = get_sector(fd, here, §or); if (rc != RTEMS_SUCCESSFUL) { if (sector) free(sector); return rc; } if (!msdos_signature_check(sector)) { free(sector); return RTEMS_INTERNAL_ERROR; } /* read and process up to 4 logical partition descriptors */ data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET; for (i = 0; i < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; i++) { /* if data_to_part_desc fails skip this partition * and parse the next one */ rc = data_to_part_desc(data, &new_part_desc); if (rc != RTEMS_SUCCESSFUL) { free(sector); return rc; } if (new_part_desc == NULL) { data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE; continue; } ext_part->sub_part[i] = new_part_desc; new_part_desc->ext_part = ext_part; new_part_desc->disk_desc = ext_part->disk_desc; if (is_extended(new_part_desc->sys_type)) { new_part_desc->log_id = EMPTY_PARTITION; new_part_desc->start += start; read_extended_partition(fd, start, new_part_desc); } else { rtems_disk_desc_t *disk_desc = new_part_desc->disk_desc; disk_desc->partitions[disk_desc->last_log_id] = new_part_desc; new_part_desc->log_id = ++disk_desc->last_log_id; new_part_desc->start += here; new_part_desc->end = new_part_desc->start + new_part_desc->size - 1; } data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE; } free(sector); return RTEMS_SUCCESSFUL; }