Strengthen the check for a PMBR:

o PMBR partitions count to the number of partitions on the disk, which
  means that if a PMBR entry is invalid we will not treat the MBR as a
  PMBR by virtue of it not describing any partitions.
  Previously the checks were inconsistent in that an invalid PMBR entry
  would be harmless when no other partitions exist (we would treat the
  MBR as a PMBR by virtue of it being empty), but it would be fatal when
  there is at least one other partition.
o The partition size of a PMBR partition is one less than the media size
  because the GPT starts at the second sector (LBA 1) and extends to
  the end of the media. For backward bug-compatibility we accept a size
  that's exactly the media size (FreeBSD bug).
  Also, when the partition size can not be represented in a 32-bit
  integral, the partition size in the MBR is to be set to 0xFFFFFFFF.
  Accept this as a valid size, even if the size can be represented.
This commit is contained in:
Marcel Moolenaar 2006-08-09 20:53:01 +00:00
parent 97a337185f
commit f56b5a43dc

View File

@ -360,16 +360,17 @@ g_gpt_has_pmbr(struct g_consumer *cp, int *error)
{
char *buf;
uint8_t *typ;
int i, pmbr, vmbr;
uint16_t magic;
uint64_t mediasize;
int i, pmbr, parts;
uint32_t dp_start, dp_size;
uint16_t magic;
buf = g_read_data(cp, 0L, cp->provider->sectorsize, error);
if (buf == NULL)
return (0);
pmbr = 0;
vmbr = 0;
*error = 0;
magic = le16toh(*(uint16_t *)(uintptr_t)(buf + DOSMAGICOFFSET));
if (magic != DOSMAGIC)
@ -379,31 +380,45 @@ g_gpt_has_pmbr(struct g_consumer *cp, int *error)
* Check that there are at least one partition of type
* DOSPTYP_PMBR that covers the whole unit.
*/
parts = 0;
mediasize = cp->provider->mediasize / cp->provider->sectorsize;
for (i = 0; i < 4; i++) {
typ = buf + DOSPARTOFF + i * sizeof(struct dos_partition) +
offsetof(struct dos_partition, dp_typ);
if (*typ != 0)
parts++;
if (*typ != DOSPTYP_PMBR)
continue;
bcopy(buf + DOSPARTOFF + i * sizeof(struct dos_partition) +
offsetof(struct dos_partition, dp_start), &dp_start, sizeof(dp_start));
bcopy(buf + DOSPARTOFF + i * sizeof(struct dos_partition) +
offsetof(struct dos_partition, dp_size), &dp_size, sizeof(dp_size));
if ((*typ == DOSPTYP_PMBR) &&
(le32toh(dp_start) == 1) &&
(cp->provider->mediasize ==
(le32toh(dp_size) * 512ULL))) {
pmbr = 1;
offsetof(struct dos_partition, dp_start), &dp_start,
sizeof(dp_start));
if (le32toh(dp_start) != 1)
break;
}
if (*typ != 0 && *typ != DOSPTYP_PMBR)
vmbr = 1;
bcopy(buf + DOSPARTOFF + i * sizeof(struct dos_partition) +
offsetof(struct dos_partition, dp_size), &dp_size,
sizeof(dp_size));
if (le32toh(dp_size) != ~0U &&
le32toh(dp_size) != mediasize - 1 &&
/* Catch old FreeBSD bug for backward compatibility. */
le32toh(dp_size) != mediasize)
break;
pmbr = 1;
}
/*
* Treat empty MBRs as PMBRs for increased flexibility. Note that an
* invalid entry of type DOSPTYP_PMBR counts towards the number of
* partitions and will prevent the MBR from being treated as a PMBR.
*/
if (!pmbr && parts == 0)
pmbr = 1;
out:
g_free(buf);
/*
* Return true if protective MBR is detected or if MBR has
* no valid entries at all.
*/
return (pmbr || !vmbr);
return (pmbr);
}
static void
@ -1013,6 +1028,8 @@ g_gpt_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
* is none and fail.
*/
if (!g_gpt_has_pmbr(cp, &error)) {
if (error != 0)
goto fail;
printf("GEOM: %s: GPT detected, but no protective MBR.\n",
pp->name);
error = ENXIO;