/* * 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_partitions_set_flags()). */ static int is_pmbr_valid(blkid_probe pr, int *has) { int flags = blkid_partitions_get_flags(pr); unsigned char *data; struct dos_partition *p; int i; if (has) *has = 0; if (flags & BLKID_PARTS_FORCE_GPT) goto ok; /* skip PMBR check */ data = blkid_probe_get_sector(pr, 0); if (!data) { if (errno) return -errno; goto failed; } if (!mbr_is_valid_magic(data)) goto failed; for (i = 0, p = mbr_get_partition(data, 0); i < 4; i++, p++) { if (p->sys_ind == MBR_GPT_PARTITION) goto ok; } failed: return 0; ok: if (has) *has = 1; return 1; }
static inline int is_empty_mbr(unsigned char *mbr) { struct dos_partition *p = mbr_get_partition(mbr, 0); int i, nparts = 0; for (i = 0; i < 4; i++) { if (dos_partition_get_size(p) > 0) nparts++; p++; } return nparts == 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; }
static int fat_valid_superblock(blkid_probe pr, const struct blkid_idmag *mag, struct msdos_super_block *ms, struct vfat_super_block *vs, uint32_t *cluster_count, uint32_t *fat_size) { uint16_t sector_size, dir_entries, reserved; uint32_t sect_count, __fat_size, dir_size, __cluster_count, fat_length; uint32_t max_count; /* extra check for FATs without magic strings */ if (mag->len <= 2) { /* Old floppies have a valid MBR signature */ if (ms->ms_pmagic[0] != 0x55 || ms->ms_pmagic[1] != 0xAA) return 0; /* * OS/2 and apparently DFSee will place a FAT12/16-like * pseudo-superblock in the first 512 bytes of non-FAT * filesystems --- at least JFS and HPFS, and possibly others. * So we explicitly check for those filesystems at the * FAT12/16 filesystem magic field identifier, and if they are * present, we rule this out as a FAT filesystem, despite the * FAT-like pseudo-header. */ if ((memcmp(ms->ms_magic, "JFS ", 8) == 0) || (memcmp(ms->ms_magic, "HPFS ", 8) == 0)) return 0; } /* fat counts(Linux kernel expects at least 1 FAT table) */ if (!ms->ms_fats) return 0; if (!ms->ms_reserved) return 0; if (!(0xf8 <= ms->ms_media || ms->ms_media == 0xf0)) return 0; if (!is_power_of_2(ms->ms_cluster_size)) return 0; sector_size = unaligned_le16(&ms->ms_sector_size); if (!is_power_of_2(sector_size) || sector_size < 512 || sector_size > 4096) return 0; dir_entries = unaligned_le16(&ms->ms_dir_entries); reserved = le16_to_cpu(ms->ms_reserved); sect_count = unaligned_le16(&ms->ms_sectors); if (sect_count == 0) sect_count = le32_to_cpu(ms->ms_total_sect); fat_length = le16_to_cpu(ms->ms_fat_length); if (fat_length == 0) fat_length = le32_to_cpu(vs->vs_fat32_length); __fat_size = fat_length * ms->ms_fats; dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + (sector_size-1)) / sector_size; __cluster_count = (sect_count - (reserved + __fat_size + dir_size)) / ms->ms_cluster_size; if (!ms->ms_fat_length && vs->vs_fat32_length) max_count = FAT32_MAX; else max_count = __cluster_count > FAT12_MAX ? FAT16_MAX : FAT12_MAX; if (__cluster_count > max_count) return 0; if (fat_size) *fat_size = __fat_size; if (cluster_count) *cluster_count = __cluster_count; #if 0 if (blkid_probe_is_wholedisk(pr)) { /* OK, seems like FAT, but it's possible that we found boot * sector with crazy FAT-like stuff (magic strings, media, * etc..) before MBR. Let's make sure that there is no MBR with * usable partition. */ unsigned char *buf = (unsigned char *) ms; if (mbr_is_valid_magic(buf)) { struct dos_partition *p0 = mbr_get_partition(buf, 0); if (dos_partition_get_size(p0) != 0 && (p0->boot_ind == 0 || p0->boot_ind == 0x80)) return 0; } } #endif return 1; /* valid */ }