#define PARTITION_FAT16_LBA_H (PARTITION_FAT16_LBA | PART_FLAG_HIDDEN)
#define PARTITION_COMPAQ_DIAG 0x12
+#define PARTITION_MSFT_RECOVERY 0x27
#define PARTITION_LDM 0x42
#define PARTITION_LINUX_SWAP 0x82
#define PARTITION_LINUX 0x83
int lba;
int palo;
int prep;
+ int diag;
OrigState* orig; /* used for CHS stuff */
} DosPartitionData;
static PedDiskType msdos_disk_type;
+#if 0
+From http://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html
+
+The 2-byte numbers are stored little endian (low order byte first).
+
+Here the FAT12 version, that is also the common part of the FAT12, FAT16 and FAT32 boot sectors. See further below.
+
+Bytes Content
+0-2 Jump to bootstrap (E.g. eb 3c 90; on i86: JMP 003E NOP.
+ One finds either eb xx 90, or e9 xx xx.
+ The position of the bootstrap varies.)
+3-10 OEM name/version (E.g. "IBM 3.3", "IBM 20.0", "MSDOS5.0", "MSWIN4.0".
+ Various format utilities leave their own name, like "CH-FOR18".
+ Sometimes just garbage. Microsoft recommends "MSWIN4.1".)
+ /* BIOS Parameter Block starts here */
+11-12 Number of bytes per sector (512)
+ Must be one of 512, 1024, 2048, 4096.
+13 Number of sectors per cluster (1)
+ Must be one of 1, 2, 4, 8, 16, 32, 64, 128.
+ A cluster should have at most 32768 bytes. In rare cases 65536 is OK.
+14-15 Number of reserved sectors (1)
+ FAT12 and FAT16 use 1. FAT32 uses 32.
+16 Number of FAT copies (2)
+17-18 Number of root directory entries (224)
+ 0 for FAT32. 512 is recommended for FAT16.
+19-20 Total number of sectors in the filesystem (2880)
+ (in case the partition is not FAT32 and smaller than 32 MB)
+21 Media descriptor type (f0: 1.4 MB floppy, f8: hard disk; see below)
+22-23 Number of sectors per FAT (9)
+ 0 for FAT32.
+24-25 Number of sectors per track (12)
+26-27 Number of heads (2, for a double-sided diskette)
+28-29 Number of hidden sectors (0)
+ Hidden sectors are sectors preceding the partition.
+ /* BIOS Parameter Block ends here */
+30-509 Bootstrap
+510-511 Signature 55 aa
+#endif
+
+/* There is a significant risk of misclassifying (as msdos)
+ a disk that is composed solely of a single FAT partition.
+ Return false if sector S could not be a valid FAT boot sector.
+ Otherwise, return true. */
+static bool
+maybe_FAT (unsigned char const *s)
+{
+ if (! (s[0] == 0xeb || s[0] == 0xe9))
+ return false;
+
+ unsigned int sector_size = PED_LE16_TO_CPU (*(uint16_t *) (s + 11));
+ switch (sector_size)
+ {
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ break;
+ default:
+ return false;
+ }
+
+ if (! (s[21] == 0xf0 || s[21] == 0xf8))
+ return false;
+
+ return true;
+}
+
static int
msdos_probe (const PedDevice *dev)
{
* and ensure that each partition has a boot indicator that is
* either 0 or 0x80.
*/
+ unsigned int n_active = 0;
for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
+ if (part_table->partitions[i].boot_ind == 0x80)
+ ++n_active;
if (part_table->partitions[i].boot_ind != 0
&& part_table->partitions[i].boot_ind != 0x80)
goto probe_fail;
}
+ /* If there are no active partitions and this is probably
+ a FAT file system, do not classify it as msdos. */
+ if (n_active == 0 && maybe_FAT (label))
+ goto probe_fail;
+
/* If this is a GPT disk, fail here */
for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
if (part_table->partitions[i].type == PARTITION_GPT)
dos_data = part->disk_specific;
dos_data->system = raw_part->type;
dos_data->boot = raw_part->boot_ind != 0;
+ dos_data->diag = raw_part->type == PARTITION_COMPAQ_DIAG ||
+ raw_part->type == PARTITION_MSFT_RECOVERY ||
+ raw_part->type == PARTITION_DELL_DIAG;
dos_data->hidden = raw_part_is_hidden (raw_part);
dos_data->raid = raw_part->type == PARTITION_LINUX_RAID;
dos_data->lvm = raw_part->type == PARTITION_LINUX_LVM_OLD
dos_data->system = PARTITION_LINUX;
dos_data->hidden = 0;
dos_data->boot = 0;
+ dos_data->diag = 0;
dos_data->raid = 0;
dos_data->lvm = 0;
dos_data->lba = 0;
new_dos_data = (DosPartitionData*) new_part->disk_specific;
new_dos_data->system = old_dos_data->system;
new_dos_data->boot = old_dos_data->boot;
+ new_dos_data->diag = old_dos_data->diag;
new_dos_data->hidden = old_dos_data->hidden;
new_dos_data->raid = old_dos_data->raid;
new_dos_data->lvm = old_dos_data->lvm;
dos_data->hidden = 0;
if (part->type & PED_PARTITION_EXTENDED) {
+ dos_data->diag = 0;
dos_data->raid = 0;
dos_data->lvm = 0;
dos_data->palo = 0;
return 1;
}
+ if (dos_data->diag) {
+ /* Don't change the system if it already is a diag type,
+ otherwise use Compaq as almost all vendors use that. */
+ if (dos_data->system != PARTITION_COMPAQ_DIAG &&
+ dos_data->system != PARTITION_MSFT_RECOVERY &&
+ dos_data->system != PARTITION_DELL_DIAG)
+ dos_data->system = PARTITION_COMPAQ_DIAG;
+ return 1;
+ }
if (dos_data->lvm) {
dos_data->system = PARTITION_LINUX_LVM;
return 1;
return 1;
}
+static void
+clear_flags (DosPartitionData *dos_data)
+{
+ dos_data->diag = 0;
+ dos_data->hidden = 0;
+ dos_data->lvm = 0;
+ dos_data->palo = 0;
+ dos_data->prep = 0;
+ dos_data->raid = 0;
+}
+
static int
msdos_partition_set_flag (PedPartition* part,
PedPartitionFlag flag, int state)
}
return 1;
+ case PED_PARTITION_DIAG:
+ if (state)
+ clear_flags (dos_data);
+ dos_data->diag = state;
+ return ped_partition_set_system (part, part->fs_type);
+
case PED_PARTITION_RAID:
- if (state) {
- dos_data->hidden = 0;
- dos_data->lvm = 0;
- dos_data->palo = 0;
- dos_data->prep = 0;
- }
+ if (state)
+ clear_flags (dos_data);
dos_data->raid = state;
return ped_partition_set_system (part, part->fs_type);
case PED_PARTITION_LVM:
- if (state) {
- dos_data->hidden = 0;
- dos_data->raid = 0;
- dos_data->palo = 0;
- dos_data->prep = 0;
- }
+ if (state)
+ clear_flags (dos_data);
dos_data->lvm = state;
return ped_partition_set_system (part, part->fs_type);
return ped_partition_set_system (part, part->fs_type);
case PED_PARTITION_PALO:
- if (state) {
- dos_data->hidden = 0;
- dos_data->raid = 0;
- dos_data->lvm = 0;
- }
+ if (state)
+ clear_flags (dos_data);
dos_data->palo = state;
return ped_partition_set_system (part, part->fs_type);
case PED_PARTITION_PREP:
- if (state) {
- dos_data->hidden = 0;
- dos_data->raid = 0;
- dos_data->lvm = 0;
- }
+ if (state)
+ clear_flags (dos_data);
dos_data->prep = state;
return ped_partition_set_system (part, part->fs_type);
dos_data = part->disk_specific;
switch (flag) {
case PED_PARTITION_HIDDEN:
- return dos_data->hidden;
+ if (part->type == PED_PARTITION_EXTENDED)
+ return 0;
+ else
+ return dos_data->hidden;
case PED_PARTITION_BOOT:
return dos_data->boot;
+ case PED_PARTITION_DIAG:
+ return dos_data->diag;
+
case PED_PARTITION_RAID:
return dos_data->raid;
{
switch (flag) {
case PED_PARTITION_HIDDEN:
+ if (part->type == PED_PARTITION_EXTENDED)
+ return 0;
+ else
+ return 1;
+
case PED_PARTITION_BOOT:
case PED_PARTITION_RAID:
case PED_PARTITION_LVM:
case PED_PARTITION_LBA:
case PED_PARTITION_PALO:
case PED_PARTITION_PREP:
+ case PED_PARTITION_DIAG:
return 1;
default:
dev->length - min_geom->end))
return NULL;
} else {
- if (!ped_geometry_init (&start_geom, dev, cylinder_size,
- dev->length - cylinder_size))
+ /* Use cylinder_size as the starting sector number
+ when the device is large enough to accommodate that.
+ Otherwise, use sector 1. */
+ PedSector start = (cylinder_size < dev->length
+ ? cylinder_size : 1);
+ if (!ped_geometry_init (&start_geom, dev, start,
+ dev->length - start))
return NULL;
if (!ped_geometry_init (&end_geom, dev, 0, dev->length))
return NULL;
min_geom = ped_geometry_duplicate (&walk->geom);
if (!min_geom)
return NULL;
- ped_geometry_set_start (min_geom, walk->geom.start - 1 * head_size);
+ /* We must always allow at least two sectors at the start, to leave
+ * room for LILO. See linux/fs/partitions/msdos.c.
+ */
+ ped_geometry_set_start (min_geom,
+ walk->geom.start - PED_MAX (1 * head_size, 2));
for (walk = ext_part->part_list; walk; walk = walk->next) {
if (!ped_partition_is_active (walk) || walk->num == 5)
/* Shamelessly copied and adapted from _partition_get_overlap_constraint
* (in disk.c)
- * This should get ride of the infamous Assertion (metadata_length > 0) failed
+ * This should get rid of the infamous Assertion (metadata_length > 0) failed
* bug for extended msdos disklabels generated by Parted.
* 1) There always is a partition table at the start of ext_part, so we leave
* a one sector gap there.