2 libparted - a library for manipulating disk partitions
3 Copyright (C) 1999-2001, 2004-2005, 2007-2011 Free Software Foundation,
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include <parted/parted.h>
25 #include <parted/debug.h>
26 #include <parted/endian.h>
30 # define _(String) dgettext (PACKAGE, String)
32 # define _(String) (String)
33 #endif /* ENABLE_NLS */
38 /* this MBR boot code is loaded into 0000:7c00 by the BIOS. See mbr.s for
39 * the source, and how to build it
42 static const char MBR_BOOT_CODE[] = {
43 0xfa, 0xb8, 0x00, 0x10, 0x8e, 0xd0, 0xbc, 0x00,
44 0xb0, 0xb8, 0x00, 0x00, 0x8e, 0xd8, 0x8e, 0xc0,
45 0xfb, 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x06, 0xb9,
46 0x00, 0x02, 0xf3, 0xa4, 0xea, 0x21, 0x06, 0x00,
47 0x00, 0xbe, 0xbe, 0x07, 0x38, 0x04, 0x75, 0x0b,
48 0x83, 0xc6, 0x10, 0x81, 0xfe, 0xfe, 0x07, 0x75,
49 0xf3, 0xeb, 0x16, 0xb4, 0x02, 0xb0, 0x01, 0xbb,
50 0x00, 0x7c, 0xb2, 0x80, 0x8a, 0x74, 0x01, 0x8b,
51 0x4c, 0x02, 0xcd, 0x13, 0xea, 0x00, 0x7c, 0x00,
55 #define MSDOS_MAGIC 0xAA55
56 #define PARTITION_MAGIC_MAGIC 0xf6f6
58 /* The maximum number of DOS primary partitions. */
59 #define DOS_N_PRI_PARTITIONS 4
61 #define PARTITION_EMPTY 0x00
62 #define PARTITION_FAT12 0x01
63 #define PARTITION_FAT16_SM 0x04
64 #define PARTITION_DOS_EXT 0x05
65 #define PARTITION_FAT16 0x06
66 #define PARTITION_NTFS 0x07
67 #define PARTITION_HPFS 0x07
68 #define PARTITION_FAT32 0x0b
69 #define PARTITION_FAT32_LBA 0x0c
70 #define PARTITION_FAT16_LBA 0x0e
71 #define PARTITION_EXT_LBA 0x0f
73 #define PART_FLAG_HIDDEN 0x10 /* Valid for FAT/NTFS only */
74 #define PARTITION_FAT12_H (PARTITION_FAT12 | PART_FLAG_HIDDEN)
75 #define PARTITION_FAT16_SM_H (PARTITION_FAT16_SM | PART_FLAG_HIDDEN)
76 #define PARTITION_DOS_EXT_H (PARTITION_DOS_EXT | PART_FLAG_HIDDEN)
77 #define PARTITION_FAT16_H (PARTITION_FAT16 | PART_FLAG_HIDDEN)
78 #define PARTITION_NTFS_H (PARTITION_NTFS | PART_FLAG_HIDDEN)
79 #define PARTITION_FAT32_H (PARTITION_FAT32 | PART_FLAG_HIDDEN)
80 #define PARTITION_FAT32_LBA_H (PARTITION_FAT32_LBA | PART_FLAG_HIDDEN)
81 #define PARTITION_FAT16_LBA_H (PARTITION_FAT16_LBA | PART_FLAG_HIDDEN)
83 #define PARTITION_COMPAQ_DIAG 0x12
84 #define PARTITION_MSFT_RECOVERY 0x27
85 #define PARTITION_LDM 0x42
86 #define PARTITION_LINUX_SWAP 0x82
87 #define PARTITION_LINUX 0x83
88 #define PARTITION_LINUX_EXT 0x85
89 #define PARTITION_LINUX_LVM 0x8e
90 #define PARTITION_HFS 0xaf
91 #define PARTITION_SUN_UFS 0xbf
92 #define PARTITION_DELL_DIAG 0xde
93 #define PARTITION_GPT 0xee
94 #define PARTITION_PALO 0xf0
95 #define PARTITION_PREP 0x41
96 #define PARTITION_LINUX_RAID 0xfd
97 #define PARTITION_LINUX_LVM_OLD 0xfe
99 /* This constant contains the maximum cylinder number that can be represented
100 * in (C,H,S) notation. Higher cylinder numbers are reserved for
101 * "too big" indicators (in which case only LBA addressing can be used).
102 * Some partition tables in the wild indicate this number is 1021.
103 * (i.e. 1022 is sometimes used to indicate "use LBA").
105 #define MAX_CHS_CYLINDER 1021
106 #define MAX_TOTAL_PART 16
108 typedef struct _DosRawPartition DosRawPartition;
109 typedef struct _DosRawTable DosRawTable;
111 /* note: lots of bit-bashing here, thus, you shouldn't look inside it.
112 * Use chs_to_sector() and sector_to_chs() instead.
118 } __attribute__((packed)) RawCHS;
120 /* ripped from Linux source */
121 struct _DosRawPartition {
122 uint8_t boot_ind; /* 00: 0x80 - active */
123 RawCHS chs_start; /* 01: */
124 uint8_t type; /* 04: partition type */
125 RawCHS chs_end; /* 05: */
126 uint32_t start; /* 08: starting sector counting from 0 */
127 uint32_t length; /* 0c: nr of sectors in partition */
128 } __attribute__((packed));
130 struct _DosRawTable {
131 char boot_code [440];
132 uint32_t mbr_signature; /* really a unique ID */
134 DosRawPartition partitions [DOS_N_PRI_PARTITIONS];
136 } __attribute__((packed));
138 /* OrigState is information we want to preserve about the partition for
139 * dealing with CHS issues
143 DosRawPartition raw_part;
144 PedSector lba_offset; /* needed for computing start/end for
145 * logical partitions */
149 int cylinder_alignment;
153 unsigned char system;
162 OrigState* orig; /* used for CHS stuff */
165 static PedDiskType msdos_disk_type;
168 From http://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html
170 The 2-byte numbers are stored little endian (low order byte first).
172 Here the FAT12 version, that is also the common part of the FAT12, FAT16 and FAT32 boot sectors. See further below.
175 0-2 Jump to bootstrap (E.g. eb 3c 90; on i86: JMP 003E NOP.
176 One finds either eb xx 90, or e9 xx xx.
177 The position of the bootstrap varies.)
178 3-10 OEM name/version (E.g. "IBM 3.3", "IBM 20.0", "MSDOS5.0", "MSWIN4.0".
179 Various format utilities leave their own name, like "CH-FOR18".
180 Sometimes just garbage. Microsoft recommends "MSWIN4.1".)
181 /* BIOS Parameter Block starts here */
182 11-12 Number of bytes per sector (512)
183 Must be one of 512, 1024, 2048, 4096.
184 13 Number of sectors per cluster (1)
185 Must be one of 1, 2, 4, 8, 16, 32, 64, 128.
186 A cluster should have at most 32768 bytes. In rare cases 65536 is OK.
187 14-15 Number of reserved sectors (1)
188 FAT12 and FAT16 use 1. FAT32 uses 32.
189 16 Number of FAT copies (2)
190 17-18 Number of root directory entries (224)
191 0 for FAT32. 512 is recommended for FAT16.
192 19-20 Total number of sectors in the filesystem (2880)
193 (in case the partition is not FAT32 and smaller than 32 MB)
194 21 Media descriptor type (f0: 1.4 MB floppy, f8: hard disk; see below)
195 22-23 Number of sectors per FAT (9)
197 24-25 Number of sectors per track (12)
198 26-27 Number of heads (2, for a double-sided diskette)
199 28-29 Number of hidden sectors (0)
200 Hidden sectors are sectors preceding the partition.
201 /* BIOS Parameter Block ends here */
203 510-511 Signature 55 aa
206 /* There is a significant risk of misclassifying (as msdos)
207 a disk that is composed solely of a single FAT partition.
208 Return false if sector S could not be a valid FAT boot sector.
209 Otherwise, return true. */
211 maybe_FAT (unsigned char const *s)
213 if (! (s[0] == 0xeb || s[0] == 0xe9))
216 unsigned int sector_size = PED_LE16_TO_CPU (*(uint16_t *) (s + 11));
228 if (! (s[21] == 0xf0 || s[21] == 0xf8))
235 msdos_probe (const PedDevice *dev)
237 PedDiskType* disk_type;
238 DosRawTable* part_table;
241 PED_ASSERT (dev != NULL, return 0);
243 if (dev->sector_size < sizeof *part_table)
247 if (!ptt_read_sector (dev, 0, &label))
250 part_table = (DosRawTable *) label;
253 if (PED_LE16_TO_CPU (part_table->magic) != MSDOS_MAGIC)
256 /* If this is a FAT fs, fail here. Checking for the FAT signature
257 * has some false positives; instead, do what the Linux kernel does
258 * and ensure that each partition has a boot indicator that is
261 unsigned int n_active = 0;
262 for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
263 if (part_table->partitions[i].boot_ind == 0x80)
265 if (part_table->partitions[i].boot_ind != 0
266 && part_table->partitions[i].boot_ind != 0x80)
270 /* If there are no active partitions and this is probably
271 a FAT file system, do not classify it as msdos. */
272 if (n_active == 0 && maybe_FAT (label))
275 /* If this is a GPT disk, fail here */
276 for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
277 if (part_table->partitions[i].type == PARTITION_GPT)
281 /* If this is an AIX Physical Volume, fail here. IBMA in EBCDIC */
282 if (part_table->boot_code[0] == (char) 0xc9 &&
283 part_table->boot_code[1] == (char) 0xc2 &&
284 part_table->boot_code[2] == (char) 0xd4 &&
285 part_table->boot_code[3] == (char) 0xc1)
289 /* HACK: it's impossible to tell PC98 and msdos disk labels apart.
290 * Someone made the signatures the same (very clever). Since
291 * PC98 has some idiosyncracies with it's boot-loader, it's detection
292 * is more reliable */
293 disk_type = ped_disk_type_get ("pc98");
294 if (disk_type && disk_type->ops->probe (dev))
296 #endif /* ENABLE_PC98 */
307 msdos_alloc (const PedDevice* dev)
310 PED_ASSERT (dev != NULL, return NULL);
312 disk = _ped_disk_alloc ((PedDevice*)dev, &msdos_disk_type);
314 DosDiskData *disk_specific = ped_malloc(sizeof *disk_specific);
315 if (!disk_specific) {
319 disk_specific->cylinder_alignment = 1;
320 disk->disk_specific = disk_specific;
327 msdos_duplicate (const PedDisk* disk)
331 new_disk = ped_disk_new_fresh (disk->dev, &msdos_disk_type);
335 memcpy(new_disk->disk_specific, disk->disk_specific,
336 sizeof(DosDiskData));
342 msdos_free (PedDisk* disk)
344 PED_ASSERT (disk != NULL, return);
346 DosDiskData *disk_specific = disk->disk_specific;
347 _ped_disk_free (disk);
352 msdos_disk_set_flag (PedDisk *disk, PedDiskFlag flag, int state)
354 DosDiskData *disk_specific = disk->disk_specific;
356 case PED_DISK_CYLINDER_ALIGNMENT:
357 disk_specific->cylinder_alignment = !!state;
365 msdos_disk_get_flag (const PedDisk *disk, PedDiskFlag flag)
367 DosDiskData *disk_specific = disk->disk_specific;
369 case PED_DISK_CYLINDER_ALIGNMENT:
370 return disk_specific->cylinder_alignment;
377 msdos_disk_is_flag_available (const PedDisk *disk, PedDiskFlag flag)
380 case PED_DISK_CYLINDER_ALIGNMENT:
388 chs_get_cylinder (const RawCHS* chs)
390 return chs->cylinder + ((chs->sector >> 6) << 8);
394 chs_get_head (const RawCHS* chs)
401 chs_get_sector (const RawCHS* chs)
403 return (chs->sector & 0x3f) - 1;
407 chs_to_sector (const PedDevice* dev, const PedCHSGeometry *bios_geom,
410 PedSector c; /* not measured in sectors, but need */
411 PedSector h; /* lots of bits */
414 PED_ASSERT (bios_geom != NULL, return 0);
415 PED_ASSERT (chs != NULL, return 0);
417 c = chs_get_cylinder (chs);
418 h = chs_get_head (chs);
419 s = chs_get_sector (chs);
421 if (c > MAX_CHS_CYLINDER) /* MAGIC: C/H/S is irrelevant */
425 return (c * bios_geom->heads + h) * bios_geom->sectors + s;
429 sector_to_chs (const PedDevice* dev, const PedCHSGeometry* bios_geom,
430 PedSector sector, RawCHS* chs)
432 PedSector real_c, real_h, real_s;
434 PED_ASSERT (dev != NULL, return);
435 PED_ASSERT (chs != NULL, return);
438 bios_geom = &dev->bios_geom;
440 real_c = sector / (bios_geom->heads * bios_geom->sectors);
441 real_h = (sector / bios_geom->sectors) % bios_geom->heads;
442 real_s = sector % bios_geom->sectors;
444 if (real_c > MAX_CHS_CYLINDER) {
446 real_h = bios_geom->heads - 1;
447 real_s = bios_geom->sectors - 1;
450 chs->cylinder = real_c % 0x100;
452 chs->sector = real_s + 1 + (real_c >> 8 << 6);
456 legacy_start (const PedDisk* disk, const PedCHSGeometry* bios_geom,
457 const DosRawPartition* raw_part)
459 PED_ASSERT (disk != NULL, return 0);
460 PED_ASSERT (raw_part != NULL, return 0);
462 return chs_to_sector (disk->dev, bios_geom, &raw_part->chs_start);
466 legacy_end (const PedDisk* disk, const PedCHSGeometry* bios_geom,
467 const DosRawPartition* raw_part)
469 PED_ASSERT (disk != NULL, return 0);
470 PED_ASSERT (raw_part != NULL, return 0);
472 return chs_to_sector (disk->dev, bios_geom, &raw_part->chs_end);
476 linear_start (const PedDisk* disk, const DosRawPartition* raw_part,
479 PED_ASSERT (disk != NULL, return 0);
480 PED_ASSERT (raw_part != NULL, return 0);
482 return offset + PED_LE32_TO_CPU (raw_part->start);
486 linear_end (const PedDisk* disk, const DosRawPartition* raw_part,
489 PED_ASSERT (disk != NULL, return 0);
490 PED_ASSERT (raw_part != NULL, return 0);
492 return (linear_start (disk, raw_part, offset)
493 + (PED_LE32_TO_CPU (raw_part->length) - 1));
496 #ifndef DISCOVER_ONLY
498 partition_check_bios_geometry (PedPartition* part, PedCHSGeometry* bios_geom)
500 PedSector leg_start, leg_end;
501 DosPartitionData* dos_data;
504 PED_ASSERT (part != NULL, return 0);
505 PED_ASSERT (part->disk != NULL, return 0);
506 PED_ASSERT (part->disk_specific != NULL, return 0);
507 dos_data = part->disk_specific;
513 leg_start = legacy_start (disk, bios_geom, &dos_data->orig->raw_part);
514 leg_end = legacy_end (disk, bios_geom, &dos_data->orig->raw_part);
516 if (leg_start && leg_start != dos_data->orig->geom.start)
518 if (leg_end && leg_end != dos_data->orig->geom.end)
524 disk_check_bios_geometry (const PedDisk* disk, PedCHSGeometry* bios_geom)
526 PedPartition* part = NULL;
528 PED_ASSERT (disk != NULL, return 0);
530 while ((part = ped_disk_next_partition (disk, part))) {
531 if (ped_partition_is_active (part)) {
532 if (!partition_check_bios_geometry (part, bios_geom))
541 probe_filesystem_for_geom (const PedPartition* part, PedCHSGeometry* bios_geom)
543 const char* ms_types[] = {"ntfs", "fat16", "fat32", NULL};
551 PED_ASSERT (bios_geom != NULL, return 0);
552 PED_ASSERT (part != NULL, return 0);
553 PED_ASSERT (part->disk != NULL, return 0);
554 PED_ASSERT (part->disk->dev != NULL, return 0);
555 PED_ASSERT (part->disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0,
558 buf = ped_malloc (part->disk->dev->sector_size);
567 for (i = 0; ms_types[i]; i++) {
568 if (!strcmp(ms_types[i], part->fs_type->name))
574 if (!ped_geometry_read(&part->geom, buf, 0, 1))
577 /* shared by the start of all Microsoft file systems */
578 sectors = buf[0x18] + (buf[0x19] << 8);
579 heads = buf[0x1a] + (buf[0x1b] << 8);
581 if (sectors < 1 || sectors > 63)
583 if (heads > 255 || heads < 1)
586 bios_geom->sectors = sectors;
587 bios_geom->heads = heads;
588 bios_geom->cylinders = part->disk->dev->length / (sectors * heads);
595 /* This function attempts to infer the BIOS CHS geometry of the hard disk
596 * from the CHS + LBA information contained in the partition table from
597 * a single partition's entry.
599 * This involves some maths. Let (c,h,s,a) be the starting cylinder,
600 * starting head, starting sector and LBA start address of the partition.
601 * Likewise, (C,H,S,A) the end addresses. Using both of these pieces
602 * of information, we want to deduce cyl_sectors and head_sectors which
603 * are the sizes of a single cylinder and a single head, respectively.
605 * The relationships are:
606 * c*cyl_sectors + h * head_sectors + s = a
607 * C*cyl_sectors + H * head_sectors + S = A
609 * We can rewrite this in matrix form:
611 * [ c h ] [ cyl_sectors ] = [ s - a ] = [ a_ ]
612 * [ C H ] [ head_sectors ] [ S - A ] [ A_ ].
614 * (s - a is abbreviated to a_to simplify the notation.)
616 * This can be abbreviated into augmented matrix form:
621 * Solving these equations requires following the row reduction algorithm. We
622 * need to be careful about a few things though:
623 * - the equations might be linearly dependent, in which case there
624 * are many solutions.
625 * - the equations might be inconsistent, in which case there
626 * are no solutions. (Inconsistent partition table entry!)
627 * - there might be zeros, so we need to be careful about applying
628 * the algorithm. We know, however, that C > 0.
631 probe_partition_for_geom (const PedPartition* part, PedCHSGeometry* bios_geom)
633 DosPartitionData* dos_data;
636 PedSector c, h, s, a, a_; /* start */
637 PedSector C, H, S, A, A_; /* end */
638 PedSector dont_overflow, denum;
639 PedSector cyl_size, head_size;
640 PedSector cylinders, heads, sectors;
642 PED_ASSERT (part != NULL, return 0);
643 PED_ASSERT (part->disk_specific != NULL, return 0);
644 PED_ASSERT (bios_geom != NULL, return 0);
646 dos_data = part->disk_specific;
651 start_chs = &dos_data->orig->raw_part.chs_start;
652 c = chs_get_cylinder (start_chs);
653 h = chs_get_head (start_chs);
654 s = chs_get_sector (start_chs);
655 a = dos_data->orig->geom.start;
658 end_chs = &dos_data->orig->raw_part.chs_end;
659 C = chs_get_cylinder (end_chs);
660 H = chs_get_head (end_chs);
661 S = chs_get_sector (end_chs);
662 A = dos_data->orig->geom.end;
665 if (h < 0 || H < 0 || h > 254 || H > 254)
670 /* If no geometry is feasible, then don't even bother.
671 * Useful for eliminating assertions for broken partition
672 * tables generated by Norton Ghost et al.
674 if (A > (C+1) * 255 * 63)
677 /* Not enough information. In theory, we can do better. Should we? */
678 if (C > MAX_CHS_CYLINDER)
683 /* Calculate the maximum number that can be multiplied by
684 * any head count without overflowing a PedSector
685 * 2^8 = 256, 8 bits + 1(sign bit) = 9
688 dont_overflow <<= (8*sizeof(dont_overflow)) - 9;
691 if (a_ > dont_overflow || A_ > dont_overflow)
694 /* The matrix is solved by :
699 * (cH - Ch) cyl_size = a_H - A_h H R1 - h R2
700 * => (if cH - Ch != 0) cyl_size = (a_H - A_h) / (cH - Ch)
702 * (Hc - hC) head_size = A_c - a_C c R2 - C R1
703 * => (if cH - Ch != 0) head_size = (A_c - a_C) / (cH - Ch)
705 * But this calculation of head_size would need
706 * not overflowing A_c or a_C
707 * So substitution is use instead, to minimize dimension
708 * of temporary results :
710 * If h != 0 : head_size = ( a_ - c cyl_size ) / h
711 * If H != 0 : head_size = ( A_ - C cyl_size ) / H
714 denum = c * H - C * h;
718 cyl_size = (a_*H - A_*h) / denum;
719 /* Check for non integer result */
720 if (cyl_size * denum != a_*H - A_*h)
723 PED_ASSERT (cyl_size > 0, return 0);
724 PED_ASSERT (cyl_size <= 255 * 63, return 0);
727 head_size = ( a_ - c * cyl_size ) / h;
729 head_size = ( A_ - C * cyl_size ) / H;
731 /* should not happen because denum != 0 */
732 PED_ASSERT (0, return 0);
735 PED_ASSERT (head_size > 0, return 0);
736 PED_ASSERT (head_size <= 63, return 0);
738 cylinders = part->disk->dev->length / cyl_size;
739 heads = cyl_size / head_size;
742 PED_ASSERT (heads > 0, return 0);
743 PED_ASSERT (heads < 256, return 0);
745 PED_ASSERT (sectors > 0, return 0);
746 PED_ASSERT (sectors <= 63, return 0);
748 /* Some broken OEM partitioning program(s) seem to have an out-by-one
749 * error on the end of partitions. We should offer to fix the
752 if (((C + 1) * heads + H) * sectors + S == A)
755 PED_ASSERT ((c * heads + h) * sectors + s == a, return 0);
756 PED_ASSERT ((C * heads + H) * sectors + S == A, return 0);
758 bios_geom->cylinders = cylinders;
759 bios_geom->heads = heads;
760 bios_geom->sectors = sectors;
766 partition_probe_bios_geometry (const PedPartition* part,
767 PedCHSGeometry* bios_geom)
769 PED_ASSERT (part != NULL, return);
770 PED_ASSERT (part->disk != NULL, return);
771 PED_ASSERT (bios_geom != NULL, return);
773 if (ped_partition_is_active (part)) {
774 if (probe_partition_for_geom (part, bios_geom))
776 if (part->type & PED_PARTITION_EXTENDED) {
777 if (probe_filesystem_for_geom (part, bios_geom))
781 if (part->type & PED_PARTITION_LOGICAL) {
782 PedPartition* ext_part;
783 ext_part = ped_disk_extended_partition (part->disk);
784 PED_ASSERT (ext_part != NULL, return);
785 partition_probe_bios_geometry (ext_part, bios_geom);
787 *bios_geom = part->disk->dev->bios_geom;
792 disk_probe_bios_geometry (const PedDisk* disk, PedCHSGeometry* bios_geom)
796 /* first look at the boot partition */
798 while ((part = ped_disk_next_partition (disk, part))) {
799 if (!ped_partition_is_active (part))
801 if (ped_partition_get_flag (part, PED_PARTITION_BOOT)) {
802 if (probe_filesystem_for_geom (part, bios_geom))
804 if (probe_partition_for_geom (part, bios_geom))
809 /* that didn't work... try all partition table entries */
811 while ((part = ped_disk_next_partition (disk, part))) {
812 if (ped_partition_is_active (part)) {
813 if (probe_partition_for_geom (part, bios_geom))
818 /* that didn't work... look at all file systems */
820 while ((part = ped_disk_next_partition (disk, part))) {
821 if (ped_partition_is_active (part)) {
822 if (probe_filesystem_for_geom (part, bios_geom))
827 #endif /* !DISCOVER_ONLY */
830 raw_part_is_extended (const DosRawPartition* raw_part)
832 PED_ASSERT (raw_part != NULL, return 0);
834 switch (raw_part->type) {
835 case PARTITION_DOS_EXT:
836 case PARTITION_EXT_LBA:
837 case PARTITION_LINUX_EXT:
848 raw_part_is_hidden (const DosRawPartition* raw_part)
850 PED_ASSERT (raw_part != NULL, return 0);
852 switch (raw_part->type) {
853 case PARTITION_FAT12_H:
854 case PARTITION_FAT16_SM_H:
855 case PARTITION_FAT16_H:
856 case PARTITION_FAT32_H:
857 case PARTITION_NTFS_H:
858 case PARTITION_FAT32_LBA_H:
859 case PARTITION_FAT16_LBA_H:
870 raw_part_is_lba (const DosRawPartition* raw_part)
872 PED_ASSERT (raw_part != NULL, return 0);
874 switch (raw_part->type) {
875 case PARTITION_FAT32_LBA:
876 case PARTITION_FAT16_LBA:
877 case PARTITION_EXT_LBA:
878 case PARTITION_FAT32_LBA_H:
879 case PARTITION_FAT16_LBA_H:
890 raw_part_parse (const PedDisk* disk, const DosRawPartition* raw_part,
891 PedSector lba_offset, PedPartitionType type)
894 DosPartitionData* dos_data;
896 PED_ASSERT (disk != NULL, return NULL);
897 PED_ASSERT (raw_part != NULL, return NULL);
899 part = ped_partition_new (
901 linear_start (disk, raw_part, lba_offset),
902 linear_end (disk, raw_part, lba_offset));
905 dos_data = part->disk_specific;
906 dos_data->system = raw_part->type;
907 dos_data->boot = raw_part->boot_ind != 0;
908 dos_data->diag = raw_part->type == PARTITION_COMPAQ_DIAG ||
909 raw_part->type == PARTITION_MSFT_RECOVERY ||
910 raw_part->type == PARTITION_DELL_DIAG;
911 dos_data->hidden = raw_part_is_hidden (raw_part);
912 dos_data->raid = raw_part->type == PARTITION_LINUX_RAID;
913 dos_data->lvm = raw_part->type == PARTITION_LINUX_LVM_OLD
914 || raw_part->type == PARTITION_LINUX_LVM;
915 dos_data->lba = raw_part_is_lba (raw_part);
916 dos_data->palo = raw_part->type == PARTITION_PALO;
917 dos_data->prep = raw_part->type == PARTITION_PREP;
918 dos_data->orig = ped_malloc (sizeof (OrigState));
919 if (!dos_data->orig) {
920 ped_partition_destroy (part);
923 dos_data->orig->geom = part->geom;
924 dos_data->orig->raw_part = *raw_part;
925 dos_data->orig->lba_offset = lba_offset;
930 read_table (PedDisk* disk, PedSector sector, int is_extended_table)
934 DosRawPartition* raw_part;
936 PedPartitionType type;
937 PedSector lba_offset;
939 PED_ASSERT (disk != NULL, return 0);
940 PED_ASSERT (disk->dev != NULL, return 0);
943 if (!ptt_read_sector (disk->dev, sector, &label))
946 table = (DosRawTable *) label;
948 /* weird: empty extended partitions are filled with 0xf6 by PM */
949 if (is_extended_table
950 && PED_LE16_TO_CPU (table->magic) == PARTITION_MAGIC_MAGIC)
953 #ifndef DISCOVER_ONLY
954 if (PED_LE16_TO_CPU (table->magic) != MSDOS_MAGIC) {
955 if (ped_exception_throw (
956 PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL,
957 _("Invalid partition table on %s "
958 "-- wrong signature %x."),
960 PED_LE16_TO_CPU (table->magic))
961 != PED_EXCEPTION_IGNORE)
967 /* parse the partitions from this table */
968 for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
969 raw_part = &table->partitions [i];
970 if (raw_part->type == PARTITION_EMPTY || !raw_part->length)
973 /* process nested extended partitions after normal logical
974 * partitions, to make sure we get the order right.
976 if (is_extended_table && raw_part_is_extended (raw_part))
979 lba_offset = is_extended_table ? sector : 0;
981 if (linear_start (disk, raw_part, lba_offset) == sector) {
982 if (ped_exception_throw (
984 PED_EXCEPTION_IGNORE_CANCEL,
985 _("Invalid partition table - recursive "
988 != PED_EXCEPTION_IGNORE)
990 continue; /* avoid infinite recursion */
993 if (is_extended_table)
994 type = PED_PARTITION_LOGICAL;
995 else if (raw_part_is_extended (raw_part))
996 type = PED_PARTITION_EXTENDED;
998 type = PED_PARTITION_NORMAL;
1000 part = raw_part_parse (disk, raw_part, lba_offset, type);
1003 if (!is_extended_table)
1005 if (type != PED_PARTITION_EXTENDED)
1006 part->fs_type = ped_file_system_probe (&part->geom);
1008 PedConstraint *constraint_exact
1009 = ped_constraint_exact (&part->geom);
1010 bool ok = ped_disk_add_partition (disk, part, constraint_exact);
1011 ped_constraint_destroy (constraint_exact);
1015 /* non-nested extended partition */
1016 if (part->type == PED_PARTITION_EXTENDED) {
1017 if (!read_table (disk, part->geom.start, 1))
1022 if (is_extended_table) {
1023 /* process the nested extended partitions */
1024 for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
1025 PedSector part_start;
1027 raw_part = &table->partitions [i];
1028 if (!raw_part_is_extended (raw_part))
1031 lba_offset = ped_disk_extended_partition
1033 part_start = linear_start (disk, raw_part, lba_offset);
1034 if (part_start == sector) {
1035 /* recursive table - already threw an
1040 if (!read_table (disk, part_start, 1))
1051 ped_disk_delete_all (disk);
1056 msdos_read (PedDisk* disk)
1058 PED_ASSERT (disk != NULL, return 0);
1059 PED_ASSERT (disk->dev != NULL, return 0);
1061 ped_disk_delete_all (disk);
1062 if (!read_table (disk, 0, 0))
1065 #ifndef DISCOVER_ONLY
1066 /* try to figure out the correct BIOS CHS values */
1067 if (!disk_check_bios_geometry (disk, &disk->dev->bios_geom)) {
1068 PedCHSGeometry bios_geom = disk->dev->bios_geom;
1069 disk_probe_bios_geometry (disk, &bios_geom);
1071 /* if the geometry was wrong, then we should reread, to
1072 * make sure the metadata is allocated in the right places.
1074 if (disk->dev->bios_geom.cylinders != bios_geom.cylinders
1075 || disk->dev->bios_geom.heads != bios_geom.heads
1076 || disk->dev->bios_geom.sectors != bios_geom.sectors) {
1077 disk->dev->bios_geom = bios_geom;
1078 return msdos_read (disk);
1086 #ifndef DISCOVER_ONLY
1088 fill_raw_part (DosRawPartition* raw_part,
1089 const PedPartition* part, PedSector offset)
1091 DosPartitionData* dos_data;
1092 PedCHSGeometry bios_geom;
1094 PED_ASSERT (raw_part != NULL, return 0);
1095 PED_ASSERT (part != NULL, return 0);
1097 partition_probe_bios_geometry (part, &bios_geom);
1099 dos_data = part->disk_specific;
1101 raw_part->boot_ind = 0x80 * dos_data->boot;
1102 raw_part->type = dos_data->system;
1103 raw_part->start = PED_CPU_TO_LE32 (part->geom.start - offset);
1104 raw_part->length = PED_CPU_TO_LE32 (part->geom.length);
1106 sector_to_chs (part->disk->dev, &bios_geom, part->geom.start,
1107 &raw_part->chs_start);
1108 sector_to_chs (part->disk->dev, &bios_geom, part->geom.end,
1109 &raw_part->chs_end);
1111 if (dos_data->orig) {
1112 DosRawPartition* orig_raw_part = &dos_data->orig->raw_part;
1113 if (dos_data->orig->geom.start == part->geom.start)
1114 raw_part->chs_start = orig_raw_part->chs_start;
1115 if (dos_data->orig->geom.end == part->geom.end)
1116 raw_part->chs_end = orig_raw_part->chs_end;
1123 fill_ext_raw_part_geom (DosRawPartition* raw_part,
1124 const PedCHSGeometry* bios_geom,
1125 const PedGeometry* geom, PedSector offset)
1127 PED_ASSERT (raw_part != NULL, return 0);
1128 PED_ASSERT (geom != NULL, return 0);
1129 PED_ASSERT (geom->dev != NULL, return 0);
1131 raw_part->boot_ind = 0;
1132 raw_part->type = PARTITION_DOS_EXT;
1133 raw_part->start = PED_CPU_TO_LE32 (geom->start - offset);
1134 raw_part->length = PED_CPU_TO_LE32 (geom->length);
1136 sector_to_chs (geom->dev, bios_geom, geom->start, &raw_part->chs_start);
1137 sector_to_chs (geom->dev, bios_geom, geom->start + geom->length - 1,
1138 &raw_part->chs_end);
1144 write_ext_table (const PedDisk* disk,
1145 PedSector sector, const PedPartition* logical)
1148 PedSector lba_offset;
1150 PED_ASSERT (disk != NULL, return 0);
1151 PED_ASSERT (ped_disk_extended_partition (disk) != NULL, return 0);
1152 PED_ASSERT (logical != NULL, return 0);
1154 lba_offset = ped_disk_extended_partition (disk)->geom.start;
1157 if (!ptt_read_sector (disk->dev, sector, &s))
1160 DosRawTable *table = s;
1161 memset(&(table->partitions), 0, sizeof (table->partitions));
1162 table->magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
1165 if (!fill_raw_part (&table->partitions[0], logical, sector))
1168 part = ped_disk_get_partition (disk, logical->num + 1);
1171 PedCHSGeometry bios_geom;
1173 geom = ped_geometry_new (disk->dev, part->prev->geom.start,
1174 part->geom.end - part->prev->geom.start + 1);
1177 partition_probe_bios_geometry (part, &bios_geom);
1178 fill_ext_raw_part_geom (&table->partitions[1], &bios_geom,
1180 ped_geometry_destroy (geom);
1182 if (!write_ext_table (disk, part->prev->geom.start, part))
1186 ok = ped_device_write (disk->dev, table, sector, 1);
1193 write_empty_table (const PedDisk* disk, PedSector sector)
1198 PED_ASSERT (disk != NULL, return 0);
1200 if (ptt_read_sector (disk->dev, sector, &table_sector)) {
1201 memcpy (&table, table_sector, sizeof (table));
1204 memset (&(table.partitions), 0, sizeof (table.partitions));
1205 table.magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
1207 return ped_device_write (disk->dev, (void*) &table, sector, 1);
1210 /* Find the first logical partition, and write the partition table for it.
1213 write_extended_partitions (const PedDisk* disk)
1215 PedPartition* ext_part;
1217 PedCHSGeometry bios_geom;
1219 PED_ASSERT (disk != NULL, return 0);
1221 ext_part = ped_disk_extended_partition (disk);
1222 partition_probe_bios_geometry (ext_part, &bios_geom);
1223 part = ped_disk_get_partition (disk, 5);
1225 return write_ext_table (disk, ext_part->geom.start, part);
1227 return write_empty_table (disk, ext_part->geom.start);
1230 static inline uint32_t generate_random_id (void)
1234 rc = gettimeofday(&tv, NULL);
1237 return (uint32_t)(tv.tv_usec & 0xFFFFFFFFUL);
1241 msdos_write (const PedDisk* disk)
1246 PED_ASSERT (disk != NULL, return 0);
1247 PED_ASSERT (disk->dev != NULL, return 0);
1250 if (!ptt_read_sector (disk->dev, 0, &s0))
1252 DosRawTable *table = (DosRawTable *) s0;
1254 if (!table->boot_code[0]) {
1255 memset (table->boot_code, 0, 512);
1256 memcpy (table->boot_code, MBR_BOOT_CODE, sizeof (MBR_BOOT_CODE));
1259 /* If there is no unique identifier, generate a random one */
1260 if (!table->mbr_signature)
1261 table->mbr_signature = generate_random_id();
1263 memset (table->partitions, 0, sizeof (table->partitions));
1264 table->magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
1266 for (i=1; i<=DOS_N_PRI_PARTITIONS; i++) {
1267 part = ped_disk_get_partition (disk, i);
1271 if (!fill_raw_part (&table->partitions [i - 1], part, 0))
1274 if (part->type == PED_PARTITION_EXTENDED) {
1275 if (!write_extended_partitions (disk))
1280 int write_ok = ped_device_write (disk->dev, (void*) table, 0, 1);
1284 return ped_device_sync (disk->dev);
1291 #endif /* !DISCOVER_ONLY */
1293 static PedPartition*
1294 msdos_partition_new (const PedDisk* disk, PedPartitionType part_type,
1295 const PedFileSystemType* fs_type,
1296 PedSector start, PedSector end)
1299 DosPartitionData* dos_data;
1301 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1305 if (ped_partition_is_active (part)) {
1307 = dos_data = ped_malloc (sizeof (DosPartitionData));
1309 goto error_free_part;
1310 dos_data->orig = NULL;
1311 dos_data->system = PARTITION_LINUX;
1312 dos_data->hidden = 0;
1321 part->disk_specific = NULL;
1331 static PedPartition*
1332 msdos_partition_duplicate (const PedPartition* part)
1334 PedPartition* new_part;
1335 DosPartitionData* new_dos_data;
1336 DosPartitionData* old_dos_data;
1338 new_part = ped_partition_new (part->disk, part->type, part->fs_type,
1339 part->geom.start, part->geom.end);
1342 new_part->num = part->num;
1344 old_dos_data = (DosPartitionData*) part->disk_specific;
1345 new_dos_data = (DosPartitionData*) new_part->disk_specific;
1346 new_dos_data->system = old_dos_data->system;
1347 new_dos_data->boot = old_dos_data->boot;
1348 new_dos_data->diag = old_dos_data->diag;
1349 new_dos_data->hidden = old_dos_data->hidden;
1350 new_dos_data->raid = old_dos_data->raid;
1351 new_dos_data->lvm = old_dos_data->lvm;
1352 new_dos_data->lba = old_dos_data->lba;
1353 new_dos_data->palo = old_dos_data->palo;
1354 new_dos_data->prep = old_dos_data->prep;
1356 if (old_dos_data->orig) {
1357 new_dos_data->orig = ped_malloc (sizeof (OrigState));
1358 if (!new_dos_data->orig) {
1359 ped_partition_destroy (new_part);
1362 new_dos_data->orig->geom = old_dos_data->orig->geom;
1363 new_dos_data->orig->raw_part = old_dos_data->orig->raw_part;
1364 new_dos_data->orig->lba_offset = old_dos_data->orig->lba_offset;
1370 msdos_partition_destroy (PedPartition* part)
1372 PED_ASSERT (part != NULL, return);
1374 if (ped_partition_is_active (part)) {
1375 DosPartitionData* dos_data;
1376 dos_data = (DosPartitionData*) part->disk_specific;
1377 free (dos_data->orig);
1378 free (part->disk_specific);
1384 msdos_partition_set_system (PedPartition* part,
1385 const PedFileSystemType* fs_type)
1387 DosPartitionData* dos_data = part->disk_specific;
1389 part->fs_type = fs_type;
1391 if (dos_data->hidden
1393 && strncmp (fs_type->name, "fat", 3) != 0
1394 && strcmp (fs_type->name, "ntfs") != 0)
1395 dos_data->hidden = 0;
1397 if (part->type & PED_PARTITION_EXTENDED) {
1404 dos_data->system = PARTITION_EXT_LBA;
1406 dos_data->system = PARTITION_DOS_EXT;
1410 if (dos_data->diag) {
1411 /* Don't change the system if it already is a diag type,
1412 otherwise use Compaq as almost all vendors use that. */
1413 if (dos_data->system != PARTITION_COMPAQ_DIAG &&
1414 dos_data->system != PARTITION_MSFT_RECOVERY &&
1415 dos_data->system != PARTITION_DELL_DIAG)
1416 dos_data->system = PARTITION_COMPAQ_DIAG;
1419 if (dos_data->lvm) {
1420 dos_data->system = PARTITION_LINUX_LVM;
1423 if (dos_data->raid) {
1424 dos_data->system = PARTITION_LINUX_RAID;
1427 if (dos_data->palo) {
1428 dos_data->system = PARTITION_PALO;
1431 if (dos_data->prep) {
1432 dos_data->system = PARTITION_PREP;
1437 dos_data->system = PARTITION_LINUX;
1438 else if (!strcmp (fs_type->name, "fat16")) {
1439 dos_data->system = dos_data->lba
1440 ? PARTITION_FAT16_LBA : PARTITION_FAT16;
1441 dos_data->system |= dos_data->hidden ? PART_FLAG_HIDDEN : 0;
1442 } else if (!strcmp (fs_type->name, "fat32")) {
1443 dos_data->system = dos_data->lba
1444 ? PARTITION_FAT32_LBA : PARTITION_FAT32;
1445 dos_data->system |= dos_data->hidden ? PART_FLAG_HIDDEN : 0;
1446 } else if (!strcmp (fs_type->name, "ntfs")
1447 || !strcmp (fs_type->name, "hpfs")) {
1448 dos_data->system = PARTITION_NTFS;
1449 dos_data->system |= dos_data->hidden ? PART_FLAG_HIDDEN : 0;
1450 } else if (!strcmp (fs_type->name, "hfs")
1451 || !strcmp (fs_type->name, "hfs+"))
1452 dos_data->system = PARTITION_HFS;
1453 else if (!strcmp (fs_type->name, "sun-ufs"))
1454 dos_data->system = PARTITION_SUN_UFS;
1455 else if (is_linux_swap (fs_type->name))
1456 dos_data->system = PARTITION_LINUX_SWAP;
1458 dos_data->system = PARTITION_LINUX;
1464 clear_flags (DosPartitionData *dos_data)
1467 dos_data->hidden = 0;
1475 msdos_partition_set_flag (PedPartition* part,
1476 PedPartitionFlag flag, int state)
1480 DosPartitionData* dos_data;
1482 PED_ASSERT (part != NULL, return 0);
1483 PED_ASSERT (part->disk_specific != NULL, return 0);
1484 PED_ASSERT (part->disk != NULL, return 0);
1486 dos_data = part->disk_specific;
1490 case PED_PARTITION_HIDDEN:
1491 if (part->type == PED_PARTITION_EXTENDED) {
1492 ped_exception_throw (
1493 PED_EXCEPTION_ERROR,
1494 PED_EXCEPTION_CANCEL,
1495 _("Extended partitions cannot be hidden on "
1496 "msdos disk labels."));
1499 dos_data->hidden = state;
1500 return ped_partition_set_system (part, part->fs_type);
1502 case PED_PARTITION_BOOT:
1503 dos_data->boot = state;
1507 walk = ped_disk_next_partition (disk, NULL);
1508 for (; walk; walk = ped_disk_next_partition (disk, walk)) {
1509 if (walk == part || !ped_partition_is_active (walk))
1511 msdos_partition_set_flag (walk, PED_PARTITION_BOOT, 0);
1515 case PED_PARTITION_DIAG:
1517 clear_flags (dos_data);
1518 dos_data->diag = state;
1519 return ped_partition_set_system (part, part->fs_type);
1521 case PED_PARTITION_RAID:
1523 clear_flags (dos_data);
1524 dos_data->raid = state;
1525 return ped_partition_set_system (part, part->fs_type);
1527 case PED_PARTITION_LVM:
1529 clear_flags (dos_data);
1530 dos_data->lvm = state;
1531 return ped_partition_set_system (part, part->fs_type);
1533 case PED_PARTITION_LBA:
1534 dos_data->lba = state;
1535 return ped_partition_set_system (part, part->fs_type);
1537 case PED_PARTITION_PALO:
1539 clear_flags (dos_data);
1540 dos_data->palo = state;
1541 return ped_partition_set_system (part, part->fs_type);
1543 case PED_PARTITION_PREP:
1545 clear_flags (dos_data);
1546 dos_data->prep = state;
1547 return ped_partition_set_system (part, part->fs_type);
1555 msdos_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
1557 DosPartitionData* dos_data;
1559 PED_ASSERT (part != NULL, return 0);
1560 PED_ASSERT (part->disk_specific != NULL, return 0);
1562 dos_data = part->disk_specific;
1564 case PED_PARTITION_HIDDEN:
1565 if (part->type == PED_PARTITION_EXTENDED)
1568 return dos_data->hidden;
1570 case PED_PARTITION_BOOT:
1571 return dos_data->boot;
1573 case PED_PARTITION_DIAG:
1574 return dos_data->diag;
1576 case PED_PARTITION_RAID:
1577 return dos_data->raid;
1579 case PED_PARTITION_LVM:
1580 return dos_data->lvm;
1582 case PED_PARTITION_LBA:
1583 return dos_data->lba;
1585 case PED_PARTITION_PALO:
1586 return dos_data->palo;
1588 case PED_PARTITION_PREP:
1589 return dos_data->prep;
1597 msdos_partition_is_flag_available (const PedPartition* part,
1598 PedPartitionFlag flag)
1601 case PED_PARTITION_HIDDEN:
1602 if (part->type == PED_PARTITION_EXTENDED)
1607 case PED_PARTITION_BOOT:
1608 case PED_PARTITION_RAID:
1609 case PED_PARTITION_LVM:
1610 case PED_PARTITION_LBA:
1611 case PED_PARTITION_PALO:
1612 case PED_PARTITION_PREP:
1613 case PED_PARTITION_DIAG:
1622 _try_constraint (const PedPartition* part, const PedConstraint* external,
1623 PedConstraint* internal)
1625 PedConstraint* intersection;
1626 PedGeometry* solution;
1628 intersection = ped_constraint_intersect (external, internal);
1629 ped_constraint_destroy (internal);
1633 solution = ped_constraint_solve_nearest (intersection, &part->geom);
1634 ped_constraint_destroy (intersection);
1639 _best_solution (const PedPartition* part, const PedCHSGeometry* bios_geom,
1640 PedGeometry* a, PedGeometry* b)
1642 PedSector cyl_size = bios_geom->heads * bios_geom->sectors;
1651 a_cylinder = a->start / cyl_size;
1652 b_cylinder = b->start / cyl_size;
1654 if (a_cylinder == b_cylinder) {
1655 if ( (a->start / bios_geom->sectors) % bios_geom->heads
1656 < (b->start / bios_geom->sectors) % bios_geom->heads)
1664 a_delta = abs (part->geom.start - a->start);
1665 b_delta = abs (part->geom.start - b->start);
1667 if (a_delta < b_delta)
1673 return NULL; /* never get here! */
1676 ped_geometry_destroy (b);
1680 ped_geometry_destroy (a);
1684 /* This constraint is for "normal" primary partitions, that start at the
1685 * beginning of a cylinder, and end at the end of a cylinder.
1686 * Note: you can't start a partition at the beginning of the 1st
1687 * cylinder, because that's where the partition table is! There are different
1688 * rules for that - see the _primary_start_constraint.
1690 static PedConstraint*
1691 _primary_constraint (const PedDisk* disk, const PedCHSGeometry* bios_geom,
1692 PedGeometry* min_geom)
1694 PedDevice* dev = disk->dev;
1695 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
1696 PedAlignment start_align;
1697 PedAlignment end_align;
1698 PedGeometry start_geom;
1699 PedGeometry end_geom;
1701 if (!ped_alignment_init (&start_align, 0, cylinder_size))
1703 if (!ped_alignment_init (&end_align, -1, cylinder_size))
1707 if (min_geom->start < cylinder_size)
1709 if (!ped_geometry_init (&start_geom, dev, cylinder_size,
1710 min_geom->start + 1 - cylinder_size))
1712 if (!ped_geometry_init (&end_geom, dev, min_geom->end,
1713 dev->length - min_geom->end))
1716 /* Use cylinder_size as the starting sector number
1717 when the device is large enough to accommodate that.
1718 Otherwise, use sector 1. */
1719 PedSector start = (cylinder_size < dev->length
1720 ? cylinder_size : 1);
1721 if (!ped_geometry_init (&start_geom, dev, start,
1722 dev->length - start))
1724 if (!ped_geometry_init (&end_geom, dev, 0, dev->length))
1728 return ped_constraint_new (&start_align, &end_align, &start_geom,
1729 &end_geom, 1, dev->length);
1732 /* This constraint is for partitions starting on the first cylinder. They
1733 * must start on the 2nd head of the 1st cylinder.
1735 * NOTE: We don't always start on the 2nd head of the 1st cylinder. Windows
1736 * Vista aligns starting partitions at sector 2048 (0x800) by default. See:
1737 * http://support.microsoft.com/kb/923332
1739 static PedConstraint*
1740 _primary_start_constraint (const PedDisk* disk,
1741 const PedPartition *part,
1742 const PedCHSGeometry* bios_geom,
1743 const PedGeometry* min_geom)
1745 PedDevice* dev = disk->dev;
1746 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
1747 PedAlignment start_align;
1748 PedAlignment end_align;
1749 PedGeometry start_geom;
1750 PedGeometry end_geom;
1751 PedSector start_pos;
1753 if (part->geom.start == 2048)
1754 /* check for known Windows Vista (NTFS >= 3.1) alignments */
1755 /* sector 0x800 == 2048 */
1758 /* all other primary partitions on a DOS label align to */
1759 /* the 2nd head of the first cylinder (0x3F == 63) */
1760 start_pos = bios_geom->sectors;
1762 if (!ped_alignment_init (&start_align, start_pos, 0))
1764 if (!ped_alignment_init (&end_align, -1, cylinder_size))
1767 if (!ped_geometry_init (&start_geom, dev, start_pos, 1))
1769 if (!ped_geometry_init (&end_geom, dev, min_geom->end,
1770 dev->length - min_geom->end))
1773 if (!ped_geometry_init (&start_geom, dev, start_pos,
1774 dev->length - start_pos))
1776 if (!ped_geometry_init (&end_geom, dev, 0, dev->length))
1780 return ped_constraint_new (&start_align, &end_align, &start_geom,
1781 &end_geom, 1, dev->length);
1784 /* constraints for logical partitions:
1785 * - start_offset is the offset in the start alignment. "normally",
1786 * this is bios_geom->sectors. exceptions: MINOR > 5 at the beginning of the
1787 * extended partition, or MINOR == 5 in the middle of the extended partition
1788 * - is_start_part == 1 if the constraint is for the first cylinder of
1789 * the extended partition, or == 0 if the constraint is for the second cylinder
1790 * onwards of the extended partition.
1792 static PedConstraint*
1793 _logical_constraint (const PedDisk* disk, const PedCHSGeometry* bios_geom,
1794 PedSector start_offset, int is_start_part)
1796 PedPartition* ext_part = ped_disk_extended_partition (disk);
1797 PedDevice* dev = disk->dev;
1798 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
1799 PedAlignment start_align;
1800 PedAlignment end_align;
1801 PedGeometry max_geom;
1803 PED_ASSERT (ext_part != NULL, return NULL);
1805 if (!ped_alignment_init (&start_align, start_offset, cylinder_size))
1807 if (!ped_alignment_init (&end_align, -1, cylinder_size))
1809 if (is_start_part) {
1810 if (!ped_geometry_init (&max_geom, dev,
1811 ext_part->geom.start,
1812 ext_part->geom.length))
1815 PedSector min_start;
1816 PedSector max_length;
1818 min_start = ped_round_up_to (ext_part->geom.start + 1,
1820 max_length = ext_part->geom.end - min_start + 1;
1821 if (min_start >= ext_part->geom.end)
1824 if (!ped_geometry_init (&max_geom, dev, min_start, max_length))
1828 return ped_constraint_new (&start_align, &end_align, &max_geom,
1829 &max_geom, 1, dev->length);
1832 /* returns the minimum geometry for the extended partition, given that the
1833 * extended partition must contain:
1834 * * all logical partitions
1835 * * all partition tables for all logical partitions (except the first)
1836 * * the extended partition table
1839 _get_min_extended_part_geom (const PedPartition* ext_part,
1840 const PedCHSGeometry* bios_geom)
1842 PedDisk* disk = ext_part->disk;
1843 PedSector head_size = bios_geom ? bios_geom->sectors : 1;
1845 PedGeometry* min_geom;
1847 walk = ped_disk_get_partition (disk, 5);
1851 min_geom = ped_geometry_duplicate (&walk->geom);
1854 /* We must always allow at least two sectors at the start, to leave
1855 * room for LILO. See linux/fs/partitions/msdos.c.
1857 ped_geometry_set_start (min_geom,
1858 walk->geom.start - PED_MAX (1 * head_size, 2));
1860 for (walk = ext_part->part_list; walk; walk = walk->next) {
1861 if (!ped_partition_is_active (walk) || walk->num == 5)
1863 if (walk->geom.start < min_geom->start)
1864 ped_geometry_set_start (min_geom,
1865 walk->geom.start - 2 * head_size);
1866 if (walk->geom.end > min_geom->end)
1867 ped_geometry_set_end (min_geom, walk->geom.end);
1874 _align_primary (PedPartition* part, const PedCHSGeometry* bios_geom,
1875 const PedConstraint* constraint)
1877 PedDisk* disk = part->disk;
1878 PedGeometry* min_geom = NULL;
1879 PedGeometry* solution = NULL;
1881 if (part->type == PED_PARTITION_EXTENDED)
1882 min_geom = _get_min_extended_part_geom (part, bios_geom);
1884 solution = _best_solution (part, bios_geom, solution,
1885 _try_constraint (part, constraint,
1886 _primary_start_constraint (disk, part,
1887 bios_geom, min_geom)));
1889 solution = _best_solution (part, bios_geom, solution,
1890 _try_constraint (part, constraint,
1891 _primary_constraint (disk, bios_geom,
1895 ped_geometry_destroy (min_geom);
1898 ped_geometry_set (&part->geom, solution->start,
1900 ped_geometry_destroy (solution);
1908 _logical_min_start_head (const PedPartition* part,
1909 const PedCHSGeometry* bios_geom,
1910 const PedPartition* ext_part,
1911 int is_start_ext_part)
1913 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
1914 PedSector base_head;
1916 if (is_start_ext_part)
1917 base_head = 1 + (ext_part->geom.start % cylinder_size)
1918 / bios_geom->sectors;
1923 return base_head + 0;
1925 return base_head + 1;
1928 /* Shamelessly copied and adapted from _partition_get_overlap_constraint
1930 * This should get rid of the infamous Assertion (metadata_length > 0) failed
1931 * bug for extended msdos disklabels generated by Parted.
1932 * 1) There always is a partition table at the start of ext_part, so we leave
1933 * a one sector gap there.
1934 * 2)*The partition table of part5 is always at the beginning of the ext_part
1935 * so there is no need to leave a one sector gap before part5.
1936 * *There always is a partition table at the beginning of each partition != 5.
1937 * We don't need to worry to much about consistency with
1938 * _partition_get_overlap_constraint because missing it means we are in edge
1939 * cases anyway, and we don't lose anything by just refusing to do the job in
1942 static PedConstraint*
1943 _log_meta_overlap_constraint (PedPartition* part, const PedGeometry* geom)
1945 PedGeometry safe_space;
1946 PedSector min_start;
1948 PedPartition* ext_part = ped_disk_extended_partition (part->disk);
1950 int not_5 = (part->num != 5);
1952 PED_ASSERT (ext_part != NULL, return NULL);
1954 walk = ext_part->part_list;
1957 min_start = ext_part->geom.start + 1 + not_5;
1958 max_end = ext_part->geom.end;
1960 while (walk != NULL /* 2) 2) */
1961 && ( walk->geom.start - (walk->num != 5) < geom->start - not_5
1962 || walk->geom.start - (walk->num != 5) <= min_start )) {
1963 if (walk != part && ped_partition_is_active (walk))
1964 min_start = walk->geom.end + 1 + not_5; /* 2) */
1968 while (walk && (walk == part || !ped_partition_is_active (walk)))
1972 max_end = walk->geom.start - 1 - (walk->num != 5); /* 2) */
1974 if (min_start >= max_end)
1977 ped_geometry_init (&safe_space, part->disk->dev,
1978 min_start, max_end - min_start + 1);
1979 return ped_constraint_new_from_max (&safe_space);
1983 _align_logical (PedPartition* part, const PedCHSGeometry* bios_geom,
1984 const PedConstraint* constraint)
1986 PedDisk* disk = part->disk;
1987 PedPartition* ext_part = ped_disk_extended_partition (disk);
1988 PedSector cyl_size = bios_geom->sectors * bios_geom->heads;
1989 PedSector start_base;
1991 PedGeometry* solution = NULL;
1992 PedConstraint *intersect, *log_meta_overlap;
1994 PED_ASSERT (ext_part != NULL, return 0);
1996 log_meta_overlap = _log_meta_overlap_constraint(part, &part->geom);
1997 intersect = ped_constraint_intersect (constraint, log_meta_overlap);
1998 ped_constraint_destroy (log_meta_overlap);
2002 start_base = ped_round_down_to (part->geom.start, cyl_size);
2004 for (head = _logical_min_start_head (part, bios_geom, ext_part, 0);
2005 head < PED_MIN (5, bios_geom->heads); head++) {
2006 PedConstraint* disk_constraint;
2007 PedSector start = start_base + head * bios_geom->sectors;
2009 if (head >= _logical_min_start_head (part, bios_geom,
2012 _logical_constraint (disk, bios_geom, start, 1);
2015 _logical_constraint (disk, bios_geom, start, 0);
2017 solution = _best_solution (part, bios_geom, solution,
2018 _try_constraint (part, intersect,
2022 ped_constraint_destroy (intersect);
2025 ped_geometry_set (&part->geom, solution->start,
2027 ped_geometry_destroy (solution);
2035 _align (PedPartition* part, const PedCHSGeometry* bios_geom,
2036 const PedConstraint* constraint)
2038 if (part->type == PED_PARTITION_LOGICAL)
2039 return _align_logical (part, bios_geom, constraint);
2041 return _align_primary (part, bios_geom, constraint);
2044 static PedConstraint*
2045 _no_geom_constraint (const PedDisk* disk, PedSector start, PedSector end)
2049 ped_geometry_init (&max, disk->dev, start, end - start + 1);
2050 return ped_constraint_new_from_max (&max);
2053 static PedConstraint*
2054 _no_geom_extended_constraint (const PedPartition* part)
2056 PedDevice* dev = part->disk->dev;
2057 PedGeometry* min = _get_min_extended_part_geom (part, NULL);
2058 PedGeometry start_range;
2059 PedGeometry end_range;
2060 PedConstraint* constraint;
2063 ped_geometry_init (&start_range, dev, 1, min->start);
2064 ped_geometry_init (&end_range, dev, min->end,
2065 dev->length - min->end);
2066 ped_geometry_destroy (min);
2068 ped_geometry_init (&start_range, dev, 1, dev->length - 1);
2069 ped_geometry_init (&end_range, dev, 1, dev->length - 1);
2071 constraint = ped_constraint_new (ped_alignment_any, ped_alignment_any,
2072 &start_range, &end_range, 1, dev->length);
2077 _align_primary_no_geom (PedPartition* part, const PedConstraint* constraint)
2079 PedDisk* disk = part->disk;
2080 PedGeometry* solution;
2082 if (part->type == PED_PARTITION_EXTENDED) {
2083 solution = _try_constraint (part, constraint,
2084 _no_geom_extended_constraint (part));
2086 solution = _try_constraint (part, constraint,
2087 _no_geom_constraint (disk, 1,
2088 disk->dev->length - 1));
2092 ped_geometry_set (&part->geom, solution->start,
2094 ped_geometry_destroy (solution);
2101 _align_logical_no_geom (PedPartition* part, const PedConstraint* constraint)
2103 PedGeometry* solution;
2105 solution = _try_constraint (part, constraint,
2106 _log_meta_overlap_constraint (part, &part->geom));
2109 ped_geometry_set (&part->geom, solution->start,
2111 ped_geometry_destroy (solution);
2118 _align_no_geom (PedPartition* part, const PedConstraint* constraint)
2120 if (part->type == PED_PARTITION_LOGICAL)
2121 return _align_logical_no_geom (part, constraint);
2123 return _align_primary_no_geom (part, constraint);
2127 msdos_partition_align (PedPartition* part, const PedConstraint* constraint)
2129 PedCHSGeometry bios_geom;
2130 DosPartitionData* dos_data;
2132 PED_ASSERT (part != NULL, return 0);
2133 PED_ASSERT (part->disk_specific != NULL, return 0);
2135 dos_data = part->disk_specific;
2137 if (dos_data->system == PARTITION_LDM && dos_data->orig) {
2138 PedGeometry *orig_geom = &dos_data->orig->geom;
2140 if (ped_geometry_test_equal (&part->geom, orig_geom)
2141 && ped_constraint_is_solution (constraint, &part->geom))
2144 ped_geometry_set (&part->geom, orig_geom->start,
2146 ped_exception_throw (
2147 PED_EXCEPTION_ERROR,
2148 PED_EXCEPTION_CANCEL,
2149 _("Parted can't resize partitions managed by "
2150 "Windows Dynamic Disk."));
2154 partition_probe_bios_geometry (part, &bios_geom);
2156 DosDiskData *disk_specific = part->disk->disk_specific;
2157 if (disk_specific->cylinder_alignment
2158 && _align(part, &bios_geom, constraint))
2160 if (_align_no_geom (part, constraint))
2163 #ifndef DISCOVER_ONLY
2164 ped_exception_throw (
2165 PED_EXCEPTION_ERROR,
2166 PED_EXCEPTION_CANCEL,
2167 _("Unable to satisfy all constraints on the partition."));
2173 add_metadata_part (PedDisk* disk, PedPartitionType type, PedSector start,
2176 PedPartition* new_part;
2178 PED_ASSERT (disk != NULL, return 0);
2180 new_part = ped_partition_new (disk, type | PED_PARTITION_METADATA, NULL,
2184 if (!ped_disk_add_partition (disk, new_part, NULL))
2185 goto error_destroy_new_part;
2189 error_destroy_new_part:
2190 ped_partition_destroy (new_part);
2195 /* There are a few objectives here:
2196 * - avoid having lots of "free space" partitions lying around, to confuse
2198 * - ensure that there's enough room to put in the extended partition
2202 add_logical_part_metadata (PedDisk* disk, const PedPartition* log_part)
2204 PedPartition* ext_part = ped_disk_extended_partition (disk);
2205 PedPartition* prev = log_part->prev;
2206 PedCHSGeometry bios_geom;
2208 PedSector metadata_start;
2209 PedSector metadata_end;
2210 PedSector metadata_length;
2212 partition_probe_bios_geometry (ext_part, &bios_geom);
2213 cyl_size = bios_geom.sectors * bios_geom.heads;
2215 /* if there's metadata shortly before the partition (on the same
2216 * cylinder), then make this new metadata partition touch the end of
2217 * the other. No point having 63 bytes (or whatever) of free space
2218 * partition - just confuses front-ends, etc.
2219 * Otherwise, start the metadata at the start of the cylinder
2222 metadata_end = log_part->geom.start - 1;
2223 metadata_start = ped_round_down_to (metadata_end, cyl_size);
2225 metadata_start = PED_MAX (metadata_start, prev->geom.end + 1);
2227 metadata_start = PED_MAX (metadata_start,
2228 ext_part->geom.start + 1);
2229 metadata_length = metadata_end - metadata_start + 1;
2231 /* partition 5 doesn't need to have any metadata */
2232 if (log_part->num == 5 && metadata_length < bios_geom.sectors)
2235 PED_ASSERT (metadata_length > 0, return 0);
2237 return add_metadata_part (disk, PED_PARTITION_LOGICAL,
2238 metadata_start, metadata_end);
2242 * Find the starting sector number of the first non-free partition,
2243 * set *SECTOR to that value, and return 1.
2244 * If there is no non-free partition, don't modify *SECTOR and return 0.
2247 get_start_first_nonfree_part (const PedDisk* disk, PedSector *sector)
2251 // disk->part_list is the first partition on the disk.
2252 if (!disk->part_list)
2255 for (walk = disk->part_list; walk; walk = walk->next) {
2256 if (walk->type == PED_PARTITION_NORMAL ||
2257 walk->type == PED_PARTITION_EXTENDED) {
2258 *sector = walk->geom.start;
2266 * Find the ending sector number of the last non-free partition,
2267 * set *SECTOR to that value, and return 1.
2268 * If there is no non-free partition, don't modify *SECTOR and return 0.
2271 get_end_last_nonfree_part (const PedDisk* disk, PedSector *sector)
2273 PedPartition* last_part = NULL;
2276 // disk->part_list is the first partition on the disk.
2277 if (!disk->part_list)
2280 for (walk = disk->part_list; walk; walk = walk->next) {
2281 if (walk->type == PED_PARTITION_NORMAL ||
2282 walk->type == PED_PARTITION_EXTENDED) {
2290 *sector = last_part->geom.end;
2295 /* Adds metadata placeholder partitions to cover the partition table (and
2296 * "free" space after it that often has bootloader stuff), and the last
2297 * incomplete cylinder at the end of the disk.
2298 * Parted has to be mindful of the uncertainty of dev->bios_geom.
2299 * It therefore makes sure this metadata doesn't overlap with partitions.
2302 add_startend_metadata (PedDisk* disk)
2304 PedDevice* dev = disk->dev;
2305 PedSector cyl_size = dev->bios_geom.sectors * dev->bios_geom.heads;
2306 PedSector init_start, init_end, final_start, final_end;
2308 // Ranges for the initial and final metadata partition.
2310 if (!get_start_first_nonfree_part(disk, &init_end))
2311 init_end = dev->bios_geom.sectors - 1;
2313 init_end = PED_MIN (dev->bios_geom.sectors - 1, init_end - 1);
2315 DosDiskData *disk_specific = disk->disk_specific;
2316 if (!disk_specific->cylinder_alignment)
2317 final_start = dev->length - 1;
2318 else if (!get_end_last_nonfree_part(disk, &final_start))
2319 final_start = ped_round_down_to (dev->length, cyl_size);
2321 final_start = PED_MAX (final_start + 1,
2322 ped_round_down_to (dev->length, cyl_size));
2323 final_end = dev->length - 1;
2325 // Create the metadata partitions.
2326 // init_end <= dev->length for devices that are _real_ small.
2327 if (init_start < init_end &&
2328 init_end <= dev->length &&
2329 !add_metadata_part (disk, PED_PARTITION_NORMAL,
2330 init_start, init_end))
2333 // init_end < final_start so they dont overlap. For very small devs.
2334 if (final_start < final_end &&
2335 init_end < final_start &&
2336 final_end <= dev->length &&
2337 !add_metadata_part (disk, PED_PARTITION_NORMAL,
2338 final_start, final_end))
2345 msdos_alloc_metadata (PedDisk* disk)
2347 PedPartition* ext_part;
2349 PED_ASSERT (disk != NULL, return 0);
2350 PED_ASSERT (disk->dev != NULL, return 0);
2352 if (!add_startend_metadata (disk))
2355 ext_part = ped_disk_extended_partition (disk);
2358 PedSector start, end;
2359 PedCHSGeometry bios_geom;
2362 PedPartition* log_part;
2363 log_part = ped_disk_get_partition (disk, i);
2366 if (!add_logical_part_metadata (disk, log_part))
2370 partition_probe_bios_geometry (ext_part, &bios_geom);
2371 start = ext_part->geom.start;
2372 end = start + bios_geom.sectors - 1;
2373 if (ext_part->part_list)
2375 ext_part->part_list->geom.start - 1);
2376 if (!add_metadata_part (disk, PED_PARTITION_LOGICAL,
2385 next_primary (const PedDisk* disk)
2388 for (i=1; i<=DOS_N_PRI_PARTITIONS; i++) {
2389 if (!ped_disk_get_partition (disk, i))
2396 next_logical (const PedDisk* disk)
2400 if (!ped_disk_get_partition (disk, i))
2406 msdos_partition_enumerate (PedPartition* part)
2408 PED_ASSERT (part != NULL, return 0);
2409 PED_ASSERT (part->disk != NULL, return 0);
2411 /* don't re-number a primary partition */
2412 if (part->num != -1 && part->num <= DOS_N_PRI_PARTITIONS)
2417 if (part->type & PED_PARTITION_LOGICAL)
2418 part->num = next_logical (part->disk);
2420 part->num = next_primary (part->disk);
2426 msdos_get_max_primary_partition_count (const PedDisk* disk)
2428 return DOS_N_PRI_PARTITIONS;
2432 msdos_get_max_supported_partition_count(const PedDisk* disk, int *max_n)
2434 *max_n = MAX_TOTAL_PART;
2438 #include "pt-common.h"
2439 PT_define_limit_functions (msdos)
2441 static PedDiskOps msdos_disk_ops = {
2443 write: NULL_IF_DISCOVER_ONLY (msdos_write),
2445 disk_set_flag: msdos_disk_set_flag,
2446 disk_get_flag: msdos_disk_get_flag,
2447 disk_is_flag_available: msdos_disk_is_flag_available,
2449 partition_set_name: NULL,
2450 partition_get_name: NULL,
2452 PT_op_function_initializers (msdos)
2455 static PedDiskType msdos_disk_type = {
2458 ops: &msdos_disk_ops,
2459 features: PED_DISK_TYPE_EXTENDED
2463 ped_disk_msdos_init ()
2465 PED_ASSERT (sizeof (DosRawPartition) == 16, return);
2466 PED_ASSERT (sizeof (DosRawTable) == 512, return);
2468 ped_disk_type_register (&msdos_disk_type);
2472 ped_disk_msdos_done ()
2474 ped_disk_type_unregister (&msdos_disk_type);