/* * Protective (legacy) MBR. * * This MBR contains standard DOS partition table with a single partition, type * of 0xEE. The partition usually encompassing the entire GPT drive - or 2TiB * for large disks. * * Note that Apple uses GPT/MBR hybrid disks, where the DOS partition table is * synchronized with GPT. This synchronization has many restriction of course * (due DOS PT limitations). * * Note that the PMBR detection is optional (enabled by default) and could be * disabled by BLKID_PARTS_FOPCE_GPT flag (see also blkid_paertitions_set_flags()). */ static int is_pmbr_valid(blkid_probe pr) { int flags = blkid_partitions_get_flags(pr); unsigned char *data; struct dos_partition *p; int i; if (flags & BLKID_PARTS_FORCE_GPT) goto ok; /* skip PMBR check */ data = blkid_probe_get_sector(pr, 0); if (!data) goto failed; if (!is_valid_mbr_signature(data)) goto failed; p = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); for (i = 0; i < 4; i++, p++) { if (p->sys_type == BLKID_GPT_PARTITION) goto ok; } failed: return 0; ok: 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; }