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);
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);
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);
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;
406 static PedSector _GL_ATTRIBUTE_PURE
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);
415 PED_ASSERT (chs != NULL);
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);
435 PED_ASSERT (chs != NULL);
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);
455 static PedSector _GL_ATTRIBUTE_PURE
456 legacy_start (const PedDisk* disk, const PedCHSGeometry* bios_geom,
457 const DosRawPartition* raw_part)
459 PED_ASSERT (disk != NULL);
460 PED_ASSERT (raw_part != NULL);
462 return chs_to_sector (disk->dev, bios_geom, &raw_part->chs_start);
465 static PedSector _GL_ATTRIBUTE_PURE
466 legacy_end (const PedDisk* disk, const PedCHSGeometry* bios_geom,
467 const DosRawPartition* raw_part)
469 PED_ASSERT (disk != NULL);
470 PED_ASSERT (raw_part != NULL);
472 return chs_to_sector (disk->dev, bios_geom, &raw_part->chs_end);
475 static PedSector _GL_ATTRIBUTE_PURE
476 linear_start (const PedDisk* disk, const DosRawPartition* raw_part,
479 PED_ASSERT (disk != NULL);
480 PED_ASSERT (raw_part != NULL);
482 return offset + PED_LE32_TO_CPU (raw_part->start);
485 static PedSector _GL_ATTRIBUTE_PURE
486 linear_end (const PedDisk* disk, const DosRawPartition* raw_part,
489 PED_ASSERT (disk != NULL);
490 PED_ASSERT (raw_part != NULL);
492 return (linear_start (disk, raw_part, offset)
493 + (PED_LE32_TO_CPU (raw_part->length) - 1));
496 #ifndef DISCOVER_ONLY
497 static int _GL_ATTRIBUTE_PURE
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);
505 PED_ASSERT (part->disk != NULL);
506 PED_ASSERT (part->disk_specific != NULL);
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)
523 static int _GL_ATTRIBUTE_PURE
524 disk_check_bios_geometry (const PedDisk* disk, PedCHSGeometry* bios_geom)
526 PedPartition* part = NULL;
528 PED_ASSERT (disk != NULL);
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);
552 PED_ASSERT (part != NULL);
553 PED_ASSERT (part->disk != NULL);
554 PED_ASSERT (part->disk->dev != NULL);
555 PED_ASSERT (part->disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
557 buf = ped_malloc (part->disk->dev->sector_size);
566 for (i = 0; ms_types[i]; i++) {
567 if (!strcmp(ms_types[i], part->fs_type->name))
573 if (!ped_geometry_read(&part->geom, buf, 0, 1))
576 /* shared by the start of all Microsoft file systems */
577 sectors = buf[0x18] + (buf[0x19] << 8);
578 heads = buf[0x1a] + (buf[0x1b] << 8);
580 if (sectors < 1 || sectors > 63)
582 if (heads > 255 || heads < 1)
585 bios_geom->sectors = sectors;
586 bios_geom->heads = heads;
587 bios_geom->cylinders = part->disk->dev->length / (sectors * heads);
594 /* This function attempts to infer the BIOS CHS geometry of the hard disk
595 * from the CHS + LBA information contained in the partition table from
596 * a single partition's entry.
598 * This involves some maths. Let (c,h,s,a) be the starting cylinder,
599 * starting head, starting sector and LBA start address of the partition.
600 * Likewise, (C,H,S,A) the end addresses. Using both of these pieces
601 * of information, we want to deduce cyl_sectors and head_sectors which
602 * are the sizes of a single cylinder and a single head, respectively.
604 * The relationships are:
605 * c*cyl_sectors + h * head_sectors + s = a
606 * C*cyl_sectors + H * head_sectors + S = A
608 * We can rewrite this in matrix form:
610 * [ c h ] [ cyl_sectors ] = [ s - a ] = [ a_ ]
611 * [ C H ] [ head_sectors ] [ S - A ] [ A_ ].
613 * (s - a is abbreviated to a_to simplify the notation.)
615 * This can be abbreviated into augmented matrix form:
620 * Solving these equations requires following the row reduction algorithm. We
621 * need to be careful about a few things though:
622 * - the equations might be linearly dependent, in which case there
623 * are many solutions.
624 * - the equations might be inconsistent, in which case there
625 * are no solutions. (Inconsistent partition table entry!)
626 * - there might be zeros, so we need to be careful about applying
627 * the algorithm. We know, however, that C > 0.
630 probe_partition_for_geom (const PedPartition* part, PedCHSGeometry* bios_geom)
632 DosPartitionData* dos_data;
635 PedSector c, h, s, a, a_; /* start */
636 PedSector C, H, S, A, A_; /* end */
637 PedSector dont_overflow, denum;
638 PedSector cyl_size, head_size;
639 PedSector cylinders, heads, sectors;
641 PED_ASSERT (part != NULL);
642 PED_ASSERT (part->disk_specific != NULL);
643 PED_ASSERT (bios_geom != NULL);
645 dos_data = part->disk_specific;
650 start_chs = &dos_data->orig->raw_part.chs_start;
651 c = chs_get_cylinder (start_chs);
652 h = chs_get_head (start_chs);
653 s = chs_get_sector (start_chs);
654 a = dos_data->orig->geom.start;
657 end_chs = &dos_data->orig->raw_part.chs_end;
658 C = chs_get_cylinder (end_chs);
659 H = chs_get_head (end_chs);
660 S = chs_get_sector (end_chs);
661 A = dos_data->orig->geom.end;
664 if (h < 0 || H < 0 || h > 254 || H > 254)
669 /* If no geometry is feasible, then don't even bother.
670 * Useful for eliminating assertions for broken partition
671 * tables generated by Norton Ghost et al.
673 if (A > (C+1) * 255 * 63)
676 /* Not enough information. In theory, we can do better. Should we? */
677 if (C > MAX_CHS_CYLINDER)
682 /* Calculate the maximum number that can be multiplied by
683 * any head count without overflowing a PedSector
684 * 2^8 = 256, 8 bits + 1(sign bit) = 9
687 dont_overflow <<= (8*sizeof(dont_overflow)) - 9;
690 if (a_ > dont_overflow || A_ > dont_overflow)
693 /* The matrix is solved by :
698 * (cH - Ch) cyl_size = a_H - A_h H R1 - h R2
699 * => (if cH - Ch != 0) cyl_size = (a_H - A_h) / (cH - Ch)
701 * (Hc - hC) head_size = A_c - a_C c R2 - C R1
702 * => (if cH - Ch != 0) head_size = (A_c - a_C) / (cH - Ch)
704 * But this calculation of head_size would need
705 * not overflowing A_c or a_C
706 * So substitution is use instead, to minimize dimension
707 * of temporary results :
709 * If h != 0 : head_size = ( a_ - c cyl_size ) / h
710 * If H != 0 : head_size = ( A_ - C cyl_size ) / H
713 denum = c * H - C * h;
717 cyl_size = (a_*H - A_*h) / denum;
718 /* Check for non integer result */
719 if (cyl_size * denum != a_*H - A_*h)
724 if (!(cyl_size <= 255 * 63))
728 head_size = ( a_ - c * cyl_size ) / h;
730 head_size = ( A_ - C * cyl_size ) / H;
732 /* should not happen because denum != 0 */
736 if (!(head_size > 0))
738 if (!(head_size <= 63))
741 cylinders = part->disk->dev->length / cyl_size;
742 heads = cyl_size / head_size;
752 if (!(sectors <= 63))
755 /* Some broken OEM partitioning program(s) seem to have an out-by-one
756 * error on the end of partitions. We should offer to fix the
759 if (((C + 1) * heads + H) * sectors + S == A)
762 if (!((c * heads + h) * sectors + s == a))
764 if (!((C * heads + H) * sectors + S == A))
767 bios_geom->cylinders = cylinders;
768 bios_geom->heads = heads;
769 bios_geom->sectors = sectors;
775 partition_probe_bios_geometry (const PedPartition* part,
776 PedCHSGeometry* bios_geom)
778 PED_ASSERT (part != NULL);
779 PED_ASSERT (part->disk != NULL);
780 PED_ASSERT (bios_geom != NULL);
782 if (ped_partition_is_active (part)) {
783 if (probe_partition_for_geom (part, bios_geom))
785 if (part->type & PED_PARTITION_EXTENDED) {
786 if (probe_filesystem_for_geom (part, bios_geom))
790 if (part->type & PED_PARTITION_LOGICAL) {
791 PedPartition* ext_part;
792 ext_part = ped_disk_extended_partition (part->disk);
793 PED_ASSERT (ext_part != NULL);
794 partition_probe_bios_geometry (ext_part, bios_geom);
796 *bios_geom = part->disk->dev->bios_geom;
801 disk_probe_bios_geometry (const PedDisk* disk, PedCHSGeometry* bios_geom)
805 /* first look at the boot partition */
807 while ((part = ped_disk_next_partition (disk, part))) {
808 if (!ped_partition_is_active (part))
810 if (ped_partition_get_flag (part, PED_PARTITION_BOOT)) {
811 if (probe_filesystem_for_geom (part, bios_geom))
813 if (probe_partition_for_geom (part, bios_geom))
818 /* that didn't work... try all partition table entries */
820 while ((part = ped_disk_next_partition (disk, part))) {
821 if (ped_partition_is_active (part)) {
822 if (probe_partition_for_geom (part, bios_geom))
827 /* that didn't work... look at all file systems */
829 while ((part = ped_disk_next_partition (disk, part))) {
830 if (ped_partition_is_active (part)) {
831 if (probe_filesystem_for_geom (part, bios_geom))
836 #endif /* !DISCOVER_ONLY */
838 static int _GL_ATTRIBUTE_PURE
839 raw_part_is_extended (const DosRawPartition* raw_part)
841 PED_ASSERT (raw_part != NULL);
843 switch (raw_part->type) {
844 case PARTITION_DOS_EXT:
845 case PARTITION_EXT_LBA:
846 case PARTITION_LINUX_EXT:
856 static int _GL_ATTRIBUTE_PURE
857 raw_part_is_hidden (const DosRawPartition* raw_part)
859 PED_ASSERT (raw_part != NULL);
861 switch (raw_part->type) {
862 case PARTITION_FAT12_H:
863 case PARTITION_FAT16_SM_H:
864 case PARTITION_FAT16_H:
865 case PARTITION_FAT32_H:
866 case PARTITION_NTFS_H:
867 case PARTITION_FAT32_LBA_H:
868 case PARTITION_FAT16_LBA_H:
878 static int _GL_ATTRIBUTE_PURE
879 raw_part_is_lba (const DosRawPartition* raw_part)
881 PED_ASSERT (raw_part != NULL);
883 switch (raw_part->type) {
884 case PARTITION_FAT32_LBA:
885 case PARTITION_FAT16_LBA:
886 case PARTITION_EXT_LBA:
887 case PARTITION_FAT32_LBA_H:
888 case PARTITION_FAT16_LBA_H:
899 raw_part_parse (const PedDisk* disk, const DosRawPartition* raw_part,
900 PedSector lba_offset, PedPartitionType type)
903 DosPartitionData* dos_data;
905 PED_ASSERT (disk != NULL);
906 PED_ASSERT (raw_part != NULL);
908 part = ped_partition_new (
910 linear_start (disk, raw_part, lba_offset),
911 linear_end (disk, raw_part, lba_offset));
914 dos_data = part->disk_specific;
915 dos_data->system = raw_part->type;
916 dos_data->boot = raw_part->boot_ind != 0;
917 dos_data->diag = raw_part->type == PARTITION_COMPAQ_DIAG ||
918 raw_part->type == PARTITION_MSFT_RECOVERY ||
919 raw_part->type == PARTITION_DELL_DIAG;
920 dos_data->hidden = raw_part_is_hidden (raw_part);
921 dos_data->raid = raw_part->type == PARTITION_LINUX_RAID;
922 dos_data->lvm = raw_part->type == PARTITION_LINUX_LVM_OLD
923 || raw_part->type == PARTITION_LINUX_LVM;
924 dos_data->lba = raw_part_is_lba (raw_part);
925 dos_data->palo = raw_part->type == PARTITION_PALO;
926 dos_data->prep = raw_part->type == PARTITION_PREP;
927 dos_data->orig = ped_malloc (sizeof (OrigState));
928 if (!dos_data->orig) {
929 ped_partition_destroy (part);
932 dos_data->orig->geom = part->geom;
933 dos_data->orig->raw_part = *raw_part;
934 dos_data->orig->lba_offset = lba_offset;
939 read_table (PedDisk* disk, PedSector sector, int is_extended_table)
943 DosRawPartition* raw_part;
945 PedPartitionType type;
946 PedSector lba_offset;
948 PED_ASSERT (disk != NULL);
949 PED_ASSERT (disk->dev != NULL);
952 if (!ptt_read_sector (disk->dev, sector, &label))
955 table = (DosRawTable *) label;
957 /* weird: empty extended partitions are filled with 0xf6 by PM */
958 if (is_extended_table
959 && PED_LE16_TO_CPU (table->magic) == PARTITION_MAGIC_MAGIC)
962 #ifndef DISCOVER_ONLY
963 if (PED_LE16_TO_CPU (table->magic) != MSDOS_MAGIC) {
964 if (ped_exception_throw (
965 PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL,
966 _("Invalid partition table on %s "
967 "-- wrong signature %x."),
969 PED_LE16_TO_CPU (table->magic))
970 != PED_EXCEPTION_IGNORE)
976 /* parse the partitions from this table */
977 for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
978 raw_part = &table->partitions [i];
979 if (raw_part->type == PARTITION_EMPTY || !raw_part->length)
982 /* process nested extended partitions after normal logical
983 * partitions, to make sure we get the order right.
985 if (is_extended_table && raw_part_is_extended (raw_part))
988 lba_offset = is_extended_table ? sector : 0;
990 if (linear_start (disk, raw_part, lba_offset) == sector) {
991 if (ped_exception_throw (
993 PED_EXCEPTION_IGNORE_CANCEL,
994 _("Invalid partition table - recursive "
997 != PED_EXCEPTION_IGNORE)
999 continue; /* avoid infinite recursion */
1002 if (is_extended_table)
1003 type = PED_PARTITION_LOGICAL;
1004 else if (raw_part_is_extended (raw_part))
1005 type = PED_PARTITION_EXTENDED;
1007 type = PED_PARTITION_NORMAL;
1009 part = raw_part_parse (disk, raw_part, lba_offset, type);
1012 if (!is_extended_table)
1014 if (type != PED_PARTITION_EXTENDED)
1015 part->fs_type = ped_file_system_probe (&part->geom);
1017 PedConstraint *constraint_exact
1018 = ped_constraint_exact (&part->geom);
1019 bool ok = ped_disk_add_partition (disk, part, constraint_exact);
1020 ped_constraint_destroy (constraint_exact);
1024 /* non-nested extended partition */
1025 if (part->type == PED_PARTITION_EXTENDED) {
1026 if (!read_table (disk, part->geom.start, 1))
1031 if (is_extended_table) {
1032 /* process the nested extended partitions */
1033 for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
1034 PedSector part_start;
1036 raw_part = &table->partitions [i];
1037 if (!raw_part_is_extended (raw_part))
1040 lba_offset = ped_disk_extended_partition
1042 part_start = linear_start (disk, raw_part, lba_offset);
1043 if (part_start == sector) {
1044 /* recursive table - already threw an
1049 if (!read_table (disk, part_start, 1))
1060 ped_disk_delete_all (disk);
1065 msdos_read (PedDisk* disk)
1067 PED_ASSERT (disk != NULL);
1068 PED_ASSERT (disk->dev != NULL);
1070 ped_disk_delete_all (disk);
1071 if (!read_table (disk, 0, 0))
1074 #ifndef DISCOVER_ONLY
1075 /* try to figure out the correct BIOS CHS values */
1076 if (!disk_check_bios_geometry (disk, &disk->dev->bios_geom)) {
1077 PedCHSGeometry bios_geom = disk->dev->bios_geom;
1078 disk_probe_bios_geometry (disk, &bios_geom);
1080 /* if the geometry was wrong, then we should reread, to
1081 * make sure the metadata is allocated in the right places.
1083 if (disk->dev->bios_geom.cylinders != bios_geom.cylinders
1084 || disk->dev->bios_geom.heads != bios_geom.heads
1085 || disk->dev->bios_geom.sectors != bios_geom.sectors) {
1086 disk->dev->bios_geom = bios_geom;
1087 return msdos_read (disk);
1095 #ifndef DISCOVER_ONLY
1097 fill_raw_part (DosRawPartition* raw_part,
1098 const PedPartition* part, PedSector offset)
1100 DosPartitionData* dos_data;
1101 PedCHSGeometry bios_geom;
1103 PED_ASSERT (raw_part != NULL);
1104 PED_ASSERT (part != NULL);
1106 partition_probe_bios_geometry (part, &bios_geom);
1108 dos_data = part->disk_specific;
1110 raw_part->boot_ind = 0x80 * dos_data->boot;
1111 raw_part->type = dos_data->system;
1112 raw_part->start = PED_CPU_TO_LE32 (part->geom.start - offset);
1113 raw_part->length = PED_CPU_TO_LE32 (part->geom.length);
1115 sector_to_chs (part->disk->dev, &bios_geom, part->geom.start,
1116 &raw_part->chs_start);
1117 sector_to_chs (part->disk->dev, &bios_geom, part->geom.end,
1118 &raw_part->chs_end);
1120 if (dos_data->orig) {
1121 DosRawPartition* orig_raw_part = &dos_data->orig->raw_part;
1122 if (dos_data->orig->geom.start == part->geom.start)
1123 raw_part->chs_start = orig_raw_part->chs_start;
1124 if (dos_data->orig->geom.end == part->geom.end)
1125 raw_part->chs_end = orig_raw_part->chs_end;
1132 fill_ext_raw_part_geom (DosRawPartition* raw_part,
1133 const PedCHSGeometry* bios_geom,
1134 const PedGeometry* geom, PedSector offset)
1136 PED_ASSERT (raw_part != NULL);
1137 PED_ASSERT (geom != NULL);
1138 PED_ASSERT (geom->dev != NULL);
1140 raw_part->boot_ind = 0;
1141 raw_part->type = PARTITION_DOS_EXT;
1142 raw_part->start = PED_CPU_TO_LE32 (geom->start - offset);
1143 raw_part->length = PED_CPU_TO_LE32 (geom->length);
1145 sector_to_chs (geom->dev, bios_geom, geom->start, &raw_part->chs_start);
1146 sector_to_chs (geom->dev, bios_geom, geom->start + geom->length - 1,
1147 &raw_part->chs_end);
1153 write_ext_table (const PedDisk* disk,
1154 PedSector sector, const PedPartition* logical)
1157 PedSector lba_offset;
1159 PED_ASSERT (disk != NULL);
1160 PED_ASSERT (ped_disk_extended_partition (disk) != NULL);
1161 PED_ASSERT (logical != NULL);
1163 lba_offset = ped_disk_extended_partition (disk)->geom.start;
1166 if (!ptt_read_sector (disk->dev, sector, &s))
1169 DosRawTable *table = s;
1170 memset(&(table->partitions), 0, sizeof (table->partitions));
1171 table->magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
1174 if (!fill_raw_part (&table->partitions[0], logical, sector))
1177 part = ped_disk_get_partition (disk, logical->num + 1);
1180 PedCHSGeometry bios_geom;
1182 geom = ped_geometry_new (disk->dev, part->prev->geom.start,
1183 part->geom.end - part->prev->geom.start + 1);
1186 partition_probe_bios_geometry (part, &bios_geom);
1187 fill_ext_raw_part_geom (&table->partitions[1], &bios_geom,
1189 ped_geometry_destroy (geom);
1191 if (!write_ext_table (disk, part->prev->geom.start, part))
1195 ok = ped_device_write (disk->dev, table, sector, 1);
1202 write_empty_table (const PedDisk* disk, PedSector sector)
1207 PED_ASSERT (disk != NULL);
1209 if (ptt_read_sector (disk->dev, sector, &table_sector)) {
1210 memcpy (&table, table_sector, sizeof (table));
1213 memset (&(table.partitions), 0, sizeof (table.partitions));
1214 table.magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
1216 return ped_device_write (disk->dev, (void*) &table, sector, 1);
1219 /* Find the first logical partition, and write the partition table for it.
1222 write_extended_partitions (const PedDisk* disk)
1224 PedPartition* ext_part;
1226 PedCHSGeometry bios_geom;
1228 PED_ASSERT (disk != NULL);
1230 ext_part = ped_disk_extended_partition (disk);
1231 partition_probe_bios_geometry (ext_part, &bios_geom);
1232 part = ped_disk_get_partition (disk, 5);
1234 return write_ext_table (disk, ext_part->geom.start, part);
1236 return write_empty_table (disk, ext_part->geom.start);
1239 static inline uint32_t generate_random_id (void)
1243 rc = gettimeofday(&tv, NULL);
1246 return (uint32_t)(tv.tv_usec & 0xFFFFFFFFUL);
1250 msdos_write (const PedDisk* disk)
1255 PED_ASSERT (disk != NULL);
1256 PED_ASSERT (disk->dev != NULL);
1259 if (!ptt_read_sector (disk->dev, 0, &s0))
1261 DosRawTable *table = (DosRawTable *) s0;
1263 if (!table->boot_code[0]) {
1264 memset (table->boot_code, 0, 512);
1265 memcpy (table->boot_code, MBR_BOOT_CODE, sizeof (MBR_BOOT_CODE));
1268 /* If there is no unique identifier, generate a random one */
1269 if (!table->mbr_signature)
1270 table->mbr_signature = generate_random_id();
1272 memset (table->partitions, 0, sizeof (table->partitions));
1273 table->magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
1275 for (i=1; i<=DOS_N_PRI_PARTITIONS; i++) {
1276 part = ped_disk_get_partition (disk, i);
1280 if (!fill_raw_part (&table->partitions [i - 1], part, 0))
1283 if (part->type == PED_PARTITION_EXTENDED) {
1284 if (!write_extended_partitions (disk))
1289 int write_ok = ped_device_write (disk->dev, (void*) table, 0, 1);
1293 return ped_device_sync (disk->dev);
1300 #endif /* !DISCOVER_ONLY */
1302 static PedPartition*
1303 msdos_partition_new (const PedDisk* disk, PedPartitionType part_type,
1304 const PedFileSystemType* fs_type,
1305 PedSector start, PedSector end)
1308 DosPartitionData* dos_data;
1310 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1314 if (ped_partition_is_active (part)) {
1316 = dos_data = ped_malloc (sizeof (DosPartitionData));
1318 goto error_free_part;
1319 dos_data->orig = NULL;
1320 dos_data->system = PARTITION_LINUX;
1321 dos_data->hidden = 0;
1330 part->disk_specific = NULL;
1340 static PedPartition*
1341 msdos_partition_duplicate (const PedPartition* part)
1343 PedPartition* new_part;
1344 DosPartitionData* new_dos_data;
1345 DosPartitionData* old_dos_data;
1347 new_part = ped_partition_new (part->disk, part->type, part->fs_type,
1348 part->geom.start, part->geom.end);
1351 new_part->num = part->num;
1353 old_dos_data = (DosPartitionData*) part->disk_specific;
1354 new_dos_data = (DosPartitionData*) new_part->disk_specific;
1355 new_dos_data->system = old_dos_data->system;
1356 new_dos_data->boot = old_dos_data->boot;
1357 new_dos_data->diag = old_dos_data->diag;
1358 new_dos_data->hidden = old_dos_data->hidden;
1359 new_dos_data->raid = old_dos_data->raid;
1360 new_dos_data->lvm = old_dos_data->lvm;
1361 new_dos_data->lba = old_dos_data->lba;
1362 new_dos_data->palo = old_dos_data->palo;
1363 new_dos_data->prep = old_dos_data->prep;
1365 if (old_dos_data->orig) {
1366 new_dos_data->orig = ped_malloc (sizeof (OrigState));
1367 if (!new_dos_data->orig) {
1368 ped_partition_destroy (new_part);
1371 new_dos_data->orig->geom = old_dos_data->orig->geom;
1372 new_dos_data->orig->raw_part = old_dos_data->orig->raw_part;
1373 new_dos_data->orig->lba_offset = old_dos_data->orig->lba_offset;
1379 msdos_partition_destroy (PedPartition* part)
1381 PED_ASSERT (part != NULL);
1383 if (ped_partition_is_active (part)) {
1384 DosPartitionData* dos_data;
1385 dos_data = (DosPartitionData*) part->disk_specific;
1386 free (dos_data->orig);
1387 free (part->disk_specific);
1393 msdos_partition_set_system (PedPartition* part,
1394 const PedFileSystemType* fs_type)
1396 DosPartitionData* dos_data = part->disk_specific;
1398 part->fs_type = fs_type;
1400 if (dos_data->hidden
1402 && strncmp (fs_type->name, "fat", 3) != 0
1403 && strcmp (fs_type->name, "ntfs") != 0)
1404 dos_data->hidden = 0;
1406 if (part->type & PED_PARTITION_EXTENDED) {
1413 dos_data->system = PARTITION_EXT_LBA;
1415 dos_data->system = PARTITION_DOS_EXT;
1419 if (dos_data->diag) {
1420 /* Don't change the system if it already is a diag type,
1421 otherwise use Compaq as almost all vendors use that. */
1422 if (dos_data->system != PARTITION_COMPAQ_DIAG &&
1423 dos_data->system != PARTITION_MSFT_RECOVERY &&
1424 dos_data->system != PARTITION_DELL_DIAG)
1425 dos_data->system = PARTITION_COMPAQ_DIAG;
1428 if (dos_data->lvm) {
1429 dos_data->system = PARTITION_LINUX_LVM;
1432 if (dos_data->raid) {
1433 dos_data->system = PARTITION_LINUX_RAID;
1436 if (dos_data->palo) {
1437 dos_data->system = PARTITION_PALO;
1440 if (dos_data->prep) {
1441 dos_data->system = PARTITION_PREP;
1446 dos_data->system = PARTITION_LINUX;
1447 else if (!strcmp (fs_type->name, "fat16")) {
1448 dos_data->system = dos_data->lba
1449 ? PARTITION_FAT16_LBA : PARTITION_FAT16;
1450 dos_data->system |= dos_data->hidden ? PART_FLAG_HIDDEN : 0;
1451 } else if (!strcmp (fs_type->name, "fat32")) {
1452 dos_data->system = dos_data->lba
1453 ? PARTITION_FAT32_LBA : PARTITION_FAT32;
1454 dos_data->system |= dos_data->hidden ? PART_FLAG_HIDDEN : 0;
1455 } else if (!strcmp (fs_type->name, "ntfs")
1456 || !strcmp (fs_type->name, "hpfs")) {
1457 dos_data->system = PARTITION_NTFS;
1458 dos_data->system |= dos_data->hidden ? PART_FLAG_HIDDEN : 0;
1459 } else if (!strcmp (fs_type->name, "hfs")
1460 || !strcmp (fs_type->name, "hfs+"))
1461 dos_data->system = PARTITION_HFS;
1462 else if (!strcmp (fs_type->name, "sun-ufs"))
1463 dos_data->system = PARTITION_SUN_UFS;
1464 else if (is_linux_swap (fs_type->name))
1465 dos_data->system = PARTITION_LINUX_SWAP;
1467 dos_data->system = PARTITION_LINUX;
1473 clear_flags (DosPartitionData *dos_data)
1476 dos_data->hidden = 0;
1484 msdos_partition_set_flag (PedPartition* part,
1485 PedPartitionFlag flag, int state)
1489 DosPartitionData* dos_data;
1491 PED_ASSERT (part != NULL);
1492 PED_ASSERT (part->disk_specific != NULL);
1493 PED_ASSERT (part->disk != NULL);
1495 dos_data = part->disk_specific;
1499 case PED_PARTITION_HIDDEN:
1500 if (part->type == PED_PARTITION_EXTENDED) {
1501 ped_exception_throw (
1502 PED_EXCEPTION_ERROR,
1503 PED_EXCEPTION_CANCEL,
1504 _("Extended partitions cannot be hidden on "
1505 "msdos disk labels."));
1508 dos_data->hidden = state;
1509 return ped_partition_set_system (part, part->fs_type);
1511 case PED_PARTITION_BOOT:
1512 dos_data->boot = state;
1516 walk = ped_disk_next_partition (disk, NULL);
1517 for (; walk; walk = ped_disk_next_partition (disk, walk)) {
1518 if (walk == part || !ped_partition_is_active (walk))
1520 msdos_partition_set_flag (walk, PED_PARTITION_BOOT, 0);
1524 case PED_PARTITION_DIAG:
1526 clear_flags (dos_data);
1527 dos_data->diag = state;
1528 return ped_partition_set_system (part, part->fs_type);
1530 case PED_PARTITION_RAID:
1532 clear_flags (dos_data);
1533 dos_data->raid = state;
1534 return ped_partition_set_system (part, part->fs_type);
1536 case PED_PARTITION_LVM:
1538 clear_flags (dos_data);
1539 dos_data->lvm = state;
1540 return ped_partition_set_system (part, part->fs_type);
1542 case PED_PARTITION_LBA:
1543 dos_data->lba = state;
1544 return ped_partition_set_system (part, part->fs_type);
1546 case PED_PARTITION_PALO:
1548 clear_flags (dos_data);
1549 dos_data->palo = state;
1550 return ped_partition_set_system (part, part->fs_type);
1552 case PED_PARTITION_PREP:
1554 clear_flags (dos_data);
1555 dos_data->prep = state;
1556 return ped_partition_set_system (part, part->fs_type);
1563 static int _GL_ATTRIBUTE_PURE
1564 msdos_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
1566 DosPartitionData* dos_data;
1568 PED_ASSERT (part != NULL);
1569 PED_ASSERT (part->disk_specific != NULL);
1571 dos_data = part->disk_specific;
1573 case PED_PARTITION_HIDDEN:
1574 if (part->type == PED_PARTITION_EXTENDED)
1577 return dos_data->hidden;
1579 case PED_PARTITION_BOOT:
1580 return dos_data->boot;
1582 case PED_PARTITION_DIAG:
1583 return dos_data->diag;
1585 case PED_PARTITION_RAID:
1586 return dos_data->raid;
1588 case PED_PARTITION_LVM:
1589 return dos_data->lvm;
1591 case PED_PARTITION_LBA:
1592 return dos_data->lba;
1594 case PED_PARTITION_PALO:
1595 return dos_data->palo;
1597 case PED_PARTITION_PREP:
1598 return dos_data->prep;
1606 msdos_partition_is_flag_available (const PedPartition* part,
1607 PedPartitionFlag flag)
1610 case PED_PARTITION_HIDDEN:
1611 if (part->type == PED_PARTITION_EXTENDED)
1616 case PED_PARTITION_BOOT:
1617 case PED_PARTITION_RAID:
1618 case PED_PARTITION_LVM:
1619 case PED_PARTITION_LBA:
1620 case PED_PARTITION_PALO:
1621 case PED_PARTITION_PREP:
1622 case PED_PARTITION_DIAG:
1631 _try_constraint (const PedPartition* part, const PedConstraint* external,
1632 PedConstraint* internal)
1634 PedConstraint* intersection;
1635 PedGeometry* solution;
1637 intersection = ped_constraint_intersect (external, internal);
1638 ped_constraint_destroy (internal);
1642 solution = ped_constraint_solve_nearest (intersection, &part->geom);
1643 ped_constraint_destroy (intersection);
1648 _best_solution (const PedPartition* part, const PedCHSGeometry* bios_geom,
1649 PedGeometry* a, PedGeometry* b)
1651 PedSector cyl_size = bios_geom->heads * bios_geom->sectors;
1660 a_cylinder = a->start / cyl_size;
1661 b_cylinder = b->start / cyl_size;
1663 if (a_cylinder == b_cylinder) {
1664 if ( (a->start / bios_geom->sectors) % bios_geom->heads
1665 < (b->start / bios_geom->sectors) % bios_geom->heads)
1673 a_delta = abs (part->geom.start - a->start);
1674 b_delta = abs (part->geom.start - b->start);
1676 if (a_delta < b_delta)
1682 return NULL; /* never get here! */
1685 ped_geometry_destroy (b);
1689 ped_geometry_destroy (a);
1693 /* This constraint is for "normal" primary partitions, that start at the
1694 * beginning of a cylinder, and end at the end of a cylinder.
1695 * Note: you can't start a partition at the beginning of the 1st
1696 * cylinder, because that's where the partition table is! There are different
1697 * rules for that - see the _primary_start_constraint.
1699 static PedConstraint*
1700 _primary_constraint (const PedDisk* disk, const PedCHSGeometry* bios_geom,
1701 PedGeometry* min_geom)
1703 PedDevice* dev = disk->dev;
1704 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
1705 PedAlignment start_align;
1706 PedAlignment end_align;
1707 PedGeometry start_geom;
1708 PedGeometry end_geom;
1710 if (!ped_alignment_init (&start_align, 0, cylinder_size))
1712 if (!ped_alignment_init (&end_align, -1, cylinder_size))
1716 if (min_geom->start < cylinder_size)
1718 if (!ped_geometry_init (&start_geom, dev, cylinder_size,
1719 min_geom->start + 1 - cylinder_size))
1721 if (!ped_geometry_init (&end_geom, dev, min_geom->end,
1722 dev->length - min_geom->end))
1725 /* Use cylinder_size as the starting sector number
1726 when the device is large enough to accommodate that.
1727 Otherwise, use sector 1. */
1728 PedSector start = (cylinder_size < dev->length
1729 ? cylinder_size : 1);
1730 if (!ped_geometry_init (&start_geom, dev, start,
1731 dev->length - start))
1733 if (!ped_geometry_init (&end_geom, dev, 0, dev->length))
1737 return ped_constraint_new (&start_align, &end_align, &start_geom,
1738 &end_geom, 1, dev->length);
1741 /* This constraint is for partitions starting on the first cylinder. They
1742 * must start on the 2nd head of the 1st cylinder.
1744 * NOTE: We don't always start on the 2nd head of the 1st cylinder. Windows
1745 * Vista aligns starting partitions at sector 2048 (0x800) by default. See:
1746 * http://support.microsoft.com/kb/923332
1748 static PedConstraint*
1749 _primary_start_constraint (const PedDisk* disk,
1750 const PedPartition *part,
1751 const PedCHSGeometry* bios_geom,
1752 const PedGeometry* min_geom)
1754 PedDevice* dev = disk->dev;
1755 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
1756 PedAlignment start_align;
1757 PedAlignment end_align;
1758 PedGeometry start_geom;
1759 PedGeometry end_geom;
1760 PedSector start_pos;
1762 if (part->geom.start == 2048)
1763 /* check for known Windows Vista (NTFS >= 3.1) alignments */
1764 /* sector 0x800 == 2048 */
1767 /* all other primary partitions on a DOS label align to */
1768 /* the 2nd head of the first cylinder (0x3F == 63) */
1769 start_pos = bios_geom->sectors;
1771 if (!ped_alignment_init (&start_align, start_pos, 0))
1773 if (!ped_alignment_init (&end_align, -1, cylinder_size))
1776 if (!ped_geometry_init (&start_geom, dev, start_pos, 1))
1778 if (!ped_geometry_init (&end_geom, dev, min_geom->end,
1779 dev->length - min_geom->end))
1782 if (!ped_geometry_init (&start_geom, dev, start_pos,
1783 dev->length - start_pos))
1785 if (!ped_geometry_init (&end_geom, dev, 0, dev->length))
1789 return ped_constraint_new (&start_align, &end_align, &start_geom,
1790 &end_geom, 1, dev->length);
1793 /* constraints for logical partitions:
1794 * - start_offset is the offset in the start alignment. "normally",
1795 * this is bios_geom->sectors. exceptions: MINOR > 5 at the beginning of the
1796 * extended partition, or MINOR == 5 in the middle of the extended partition
1797 * - is_start_part == 1 if the constraint is for the first cylinder of
1798 * the extended partition, or == 0 if the constraint is for the second cylinder
1799 * onwards of the extended partition.
1801 static PedConstraint*
1802 _logical_constraint (const PedDisk* disk, const PedCHSGeometry* bios_geom,
1803 PedSector start_offset, int is_start_part)
1805 PedPartition* ext_part = ped_disk_extended_partition (disk);
1806 PedDevice* dev = disk->dev;
1807 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
1808 PedAlignment start_align;
1809 PedAlignment end_align;
1810 PedGeometry max_geom;
1812 PED_ASSERT (ext_part != NULL);
1814 if (!ped_alignment_init (&start_align, start_offset, cylinder_size))
1816 if (!ped_alignment_init (&end_align, -1, cylinder_size))
1818 if (is_start_part) {
1819 if (!ped_geometry_init (&max_geom, dev,
1820 ext_part->geom.start,
1821 ext_part->geom.length))
1824 PedSector min_start;
1825 PedSector max_length;
1827 min_start = ped_round_up_to (ext_part->geom.start + 1,
1829 max_length = ext_part->geom.end - min_start + 1;
1830 if (min_start >= ext_part->geom.end)
1833 if (!ped_geometry_init (&max_geom, dev, min_start, max_length))
1837 return ped_constraint_new (&start_align, &end_align, &max_geom,
1838 &max_geom, 1, dev->length);
1841 /* returns the minimum geometry for the extended partition, given that the
1842 * extended partition must contain:
1843 * * all logical partitions
1844 * * all partition tables for all logical partitions (except the first)
1845 * * the extended partition table
1848 _get_min_extended_part_geom (const PedPartition* ext_part,
1849 const PedCHSGeometry* bios_geom)
1851 PedDisk* disk = ext_part->disk;
1852 PedSector head_size = bios_geom ? bios_geom->sectors : 1;
1854 PedGeometry* min_geom;
1856 walk = ped_disk_get_partition (disk, 5);
1860 min_geom = ped_geometry_duplicate (&walk->geom);
1863 /* We must always allow at least two sectors at the start, to leave
1864 * room for LILO. See linux/fs/partitions/msdos.c.
1866 ped_geometry_set_start (min_geom,
1867 walk->geom.start - PED_MAX (1 * head_size, 2));
1869 for (walk = ext_part->part_list; walk; walk = walk->next) {
1870 if (!ped_partition_is_active (walk) || walk->num == 5)
1872 if (walk->geom.start < min_geom->start)
1873 ped_geometry_set_start (min_geom,
1874 walk->geom.start - 2 * head_size);
1875 if (walk->geom.end > min_geom->end)
1876 ped_geometry_set_end (min_geom, walk->geom.end);
1883 _align_primary (PedPartition* part, const PedCHSGeometry* bios_geom,
1884 const PedConstraint* constraint)
1886 PedDisk* disk = part->disk;
1887 PedGeometry* min_geom = NULL;
1888 PedGeometry* solution = NULL;
1890 if (part->type == PED_PARTITION_EXTENDED)
1891 min_geom = _get_min_extended_part_geom (part, bios_geom);
1893 solution = _best_solution (part, bios_geom, solution,
1894 _try_constraint (part, constraint,
1895 _primary_start_constraint (disk, part,
1896 bios_geom, min_geom)));
1898 solution = _best_solution (part, bios_geom, solution,
1899 _try_constraint (part, constraint,
1900 _primary_constraint (disk, bios_geom,
1904 ped_geometry_destroy (min_geom);
1907 ped_geometry_set (&part->geom, solution->start,
1909 ped_geometry_destroy (solution);
1917 _logical_min_start_head (const PedPartition* part,
1918 const PedCHSGeometry* bios_geom,
1919 const PedPartition* ext_part,
1920 int is_start_ext_part)
1922 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
1923 PedSector base_head;
1925 if (is_start_ext_part)
1926 base_head = 1 + (ext_part->geom.start % cylinder_size)
1927 / bios_geom->sectors;
1932 return base_head + 0;
1934 return base_head + 1;
1937 /* Shamelessly copied and adapted from _partition_get_overlap_constraint
1939 * This should get rid of the infamous Assertion (metadata_length > 0) failed
1940 * bug for extended msdos disklabels generated by Parted.
1941 * 1) There always is a partition table at the start of ext_part, so we leave
1942 * a one sector gap there.
1943 * 2)*The partition table of part5 is always at the beginning of the ext_part
1944 * so there is no need to leave a one sector gap before part5.
1945 * *There always is a partition table at the beginning of each partition != 5.
1946 * We don't need to worry to much about consistency with
1947 * _partition_get_overlap_constraint because missing it means we are in edge
1948 * cases anyway, and we don't lose anything by just refusing to do the job in
1951 static PedConstraint*
1952 _log_meta_overlap_constraint (PedPartition* part, const PedGeometry* geom)
1954 PedGeometry safe_space;
1955 PedSector min_start;
1957 PedPartition* ext_part = ped_disk_extended_partition (part->disk);
1959 int not_5 = (part->num != 5);
1961 PED_ASSERT (ext_part != NULL);
1963 walk = ext_part->part_list;
1966 min_start = ext_part->geom.start + 1 + not_5;
1967 max_end = ext_part->geom.end;
1969 while (walk != NULL /* 2) 2) */
1970 && ( walk->geom.start - (walk->num != 5) < geom->start - not_5
1971 || walk->geom.start - (walk->num != 5) <= min_start )) {
1972 if (walk != part && ped_partition_is_active (walk))
1973 min_start = walk->geom.end + 1 + not_5; /* 2) */
1977 while (walk && (walk == part || !ped_partition_is_active (walk)))
1981 max_end = walk->geom.start - 1 - (walk->num != 5); /* 2) */
1983 if (min_start >= max_end)
1986 ped_geometry_init (&safe_space, part->disk->dev,
1987 min_start, max_end - min_start + 1);
1988 return ped_constraint_new_from_max (&safe_space);
1992 _align_logical (PedPartition* part, const PedCHSGeometry* bios_geom,
1993 const PedConstraint* constraint)
1995 PedDisk* disk = part->disk;
1996 PedPartition* ext_part = ped_disk_extended_partition (disk);
1997 PedSector cyl_size = bios_geom->sectors * bios_geom->heads;
1998 PedSector start_base;
2000 PedGeometry* solution = NULL;
2001 PedConstraint *intersect, *log_meta_overlap;
2003 PED_ASSERT (ext_part != NULL);
2005 log_meta_overlap = _log_meta_overlap_constraint(part, &part->geom);
2006 intersect = ped_constraint_intersect (constraint, log_meta_overlap);
2007 ped_constraint_destroy (log_meta_overlap);
2011 start_base = ped_round_down_to (part->geom.start, cyl_size);
2013 for (head = _logical_min_start_head (part, bios_geom, ext_part, 0);
2014 head < PED_MIN (5, bios_geom->heads); head++) {
2015 PedConstraint* disk_constraint;
2016 PedSector start = start_base + head * bios_geom->sectors;
2018 if (head >= _logical_min_start_head (part, bios_geom,
2021 _logical_constraint (disk, bios_geom, start, 1);
2024 _logical_constraint (disk, bios_geom, start, 0);
2026 solution = _best_solution (part, bios_geom, solution,
2027 _try_constraint (part, intersect,
2031 ped_constraint_destroy (intersect);
2034 ped_geometry_set (&part->geom, solution->start,
2036 ped_geometry_destroy (solution);
2044 _align (PedPartition* part, const PedCHSGeometry* bios_geom,
2045 const PedConstraint* constraint)
2047 if (part->type == PED_PARTITION_LOGICAL)
2048 return _align_logical (part, bios_geom, constraint);
2050 return _align_primary (part, bios_geom, constraint);
2053 static PedConstraint*
2054 _no_geom_constraint (const PedDisk* disk, PedSector start, PedSector end)
2058 ped_geometry_init (&max, disk->dev, start, end - start + 1);
2059 return ped_constraint_new_from_max (&max);
2062 static PedConstraint*
2063 _no_geom_extended_constraint (const PedPartition* part)
2065 PedDevice* dev = part->disk->dev;
2066 PedGeometry* min = _get_min_extended_part_geom (part, NULL);
2067 PedGeometry start_range;
2068 PedGeometry end_range;
2069 PedConstraint* constraint;
2072 ped_geometry_init (&start_range, dev, 1, min->start);
2073 ped_geometry_init (&end_range, dev, min->end,
2074 dev->length - min->end);
2075 ped_geometry_destroy (min);
2077 ped_geometry_init (&start_range, dev, 1, dev->length - 1);
2078 ped_geometry_init (&end_range, dev, 1, dev->length - 1);
2080 constraint = ped_constraint_new (ped_alignment_any, ped_alignment_any,
2081 &start_range, &end_range, 1, dev->length);
2086 _align_primary_no_geom (PedPartition* part, const PedConstraint* constraint)
2088 PedDisk* disk = part->disk;
2089 PedGeometry* solution;
2091 if (part->type == PED_PARTITION_EXTENDED) {
2092 solution = _try_constraint (part, constraint,
2093 _no_geom_extended_constraint (part));
2095 solution = _try_constraint (part, constraint,
2096 _no_geom_constraint (disk, 1,
2097 disk->dev->length - 1));
2101 ped_geometry_set (&part->geom, solution->start,
2103 ped_geometry_destroy (solution);
2110 _align_logical_no_geom (PedPartition* part, const PedConstraint* constraint)
2112 PedGeometry* solution;
2114 solution = _try_constraint (part, constraint,
2115 _log_meta_overlap_constraint (part, &part->geom));
2118 ped_geometry_set (&part->geom, solution->start,
2120 ped_geometry_destroy (solution);
2127 _align_no_geom (PedPartition* part, const PedConstraint* constraint)
2129 if (part->type == PED_PARTITION_LOGICAL)
2130 return _align_logical_no_geom (part, constraint);
2132 return _align_primary_no_geom (part, constraint);
2136 msdos_partition_align (PedPartition* part, const PedConstraint* constraint)
2138 PedCHSGeometry bios_geom;
2139 DosPartitionData* dos_data;
2141 PED_ASSERT (part != NULL);
2142 PED_ASSERT (part->disk_specific != NULL);
2144 dos_data = part->disk_specific;
2146 if (dos_data->system == PARTITION_LDM && dos_data->orig) {
2147 PedGeometry *orig_geom = &dos_data->orig->geom;
2149 if (ped_geometry_test_equal (&part->geom, orig_geom)
2150 && ped_constraint_is_solution (constraint, &part->geom))
2153 ped_geometry_set (&part->geom, orig_geom->start,
2155 ped_exception_throw (
2156 PED_EXCEPTION_ERROR,
2157 PED_EXCEPTION_CANCEL,
2158 _("Parted can't resize partitions managed by "
2159 "Windows Dynamic Disk."));
2163 partition_probe_bios_geometry (part, &bios_geom);
2165 DosDiskData *disk_specific = part->disk->disk_specific;
2166 if (disk_specific->cylinder_alignment
2167 && _align(part, &bios_geom, constraint))
2169 if (_align_no_geom (part, constraint))
2172 #ifndef DISCOVER_ONLY
2173 ped_exception_throw (
2174 PED_EXCEPTION_ERROR,
2175 PED_EXCEPTION_CANCEL,
2176 _("Unable to satisfy all constraints on the partition."));
2182 add_metadata_part (PedDisk* disk, PedPartitionType type, PedSector start,
2185 PedPartition* new_part;
2187 PED_ASSERT (disk != NULL);
2189 new_part = ped_partition_new (disk, type | PED_PARTITION_METADATA, NULL,
2193 if (!ped_disk_add_partition (disk, new_part, NULL))
2194 goto error_destroy_new_part;
2198 error_destroy_new_part:
2199 ped_partition_destroy (new_part);
2204 /* There are a few objectives here:
2205 * - avoid having lots of "free space" partitions lying around, to confuse
2207 * - ensure that there's enough room to put in the extended partition
2211 add_logical_part_metadata (PedDisk* disk, const PedPartition* log_part)
2213 PedPartition* ext_part = ped_disk_extended_partition (disk);
2214 PedPartition* prev = log_part->prev;
2215 PedCHSGeometry bios_geom;
2217 PedSector metadata_start;
2218 PedSector metadata_end;
2219 PedSector metadata_length;
2221 partition_probe_bios_geometry (ext_part, &bios_geom);
2222 cyl_size = bios_geom.sectors * bios_geom.heads;
2224 /* if there's metadata shortly before the partition (on the same
2225 * cylinder), then make this new metadata partition touch the end of
2226 * the other. No point having 63 bytes (or whatever) of free space
2227 * partition - just confuses front-ends, etc.
2228 * Otherwise, start the metadata at the start of the cylinder
2231 metadata_end = log_part->geom.start - 1;
2232 metadata_start = ped_round_down_to (metadata_end, cyl_size);
2234 metadata_start = PED_MAX (metadata_start, prev->geom.end + 1);
2236 metadata_start = PED_MAX (metadata_start,
2237 ext_part->geom.start + 1);
2238 metadata_length = metadata_end - metadata_start + 1;
2240 /* partition 5 doesn't need to have any metadata */
2241 if (log_part->num == 5 && metadata_length < bios_geom.sectors)
2244 PED_ASSERT (metadata_length > 0);
2246 return add_metadata_part (disk, PED_PARTITION_LOGICAL,
2247 metadata_start, metadata_end);
2251 * Find the starting sector number of the first non-free partition,
2252 * set *SECTOR to that value, and return 1.
2253 * If there is no non-free partition, don't modify *SECTOR and return 0.
2256 get_start_first_nonfree_part (const PedDisk* disk, PedSector *sector)
2260 // disk->part_list is the first partition on the disk.
2261 if (!disk->part_list)
2264 for (walk = disk->part_list; walk; walk = walk->next) {
2265 if (walk->type == PED_PARTITION_NORMAL ||
2266 walk->type == PED_PARTITION_EXTENDED) {
2267 *sector = walk->geom.start;
2275 * Find the ending sector number of the last non-free partition,
2276 * set *SECTOR to that value, and return 1.
2277 * If there is no non-free partition, don't modify *SECTOR and return 0.
2280 get_end_last_nonfree_part (const PedDisk* disk, PedSector *sector)
2282 PedPartition* last_part = NULL;
2285 // disk->part_list is the first partition on the disk.
2286 if (!disk->part_list)
2289 for (walk = disk->part_list; walk; walk = walk->next) {
2290 if (walk->type == PED_PARTITION_NORMAL ||
2291 walk->type == PED_PARTITION_EXTENDED) {
2299 *sector = last_part->geom.end;
2304 /* Adds metadata placeholder partitions to cover the partition table (and
2305 * "free" space after it that often has bootloader stuff), and the last
2306 * incomplete cylinder at the end of the disk.
2307 * Parted has to be mindful of the uncertainty of dev->bios_geom.
2308 * It therefore makes sure this metadata doesn't overlap with partitions.
2311 add_startend_metadata (PedDisk* disk)
2313 PedDevice* dev = disk->dev;
2314 PedSector cyl_size = dev->bios_geom.sectors * dev->bios_geom.heads;
2315 PedSector init_start, init_end, final_start, final_end;
2317 // Ranges for the initial and final metadata partition.
2319 if (!get_start_first_nonfree_part(disk, &init_end))
2320 init_end = dev->bios_geom.sectors - 1;
2322 init_end = PED_MIN (dev->bios_geom.sectors - 1, init_end - 1);
2324 DosDiskData *disk_specific = disk->disk_specific;
2325 if (!disk_specific->cylinder_alignment)
2326 final_start = dev->length - 1;
2327 else if (!get_end_last_nonfree_part(disk, &final_start))
2328 final_start = ped_round_down_to (dev->length, cyl_size);
2330 final_start = PED_MAX (final_start + 1,
2331 ped_round_down_to (dev->length, cyl_size));
2332 final_end = dev->length - 1;
2334 // Create the metadata partitions.
2335 // init_end <= dev->length for devices that are _real_ small.
2336 if (init_start < init_end &&
2337 init_end <= dev->length &&
2338 !add_metadata_part (disk, PED_PARTITION_NORMAL,
2339 init_start, init_end))
2342 // init_end < final_start so they dont overlap. For very small devs.
2343 if (final_start < final_end &&
2344 init_end < final_start &&
2345 final_end <= dev->length &&
2346 !add_metadata_part (disk, PED_PARTITION_NORMAL,
2347 final_start, final_end))
2354 msdos_alloc_metadata (PedDisk* disk)
2356 PedPartition* ext_part;
2358 PED_ASSERT (disk != NULL);
2359 PED_ASSERT (disk->dev != NULL);
2361 if (!add_startend_metadata (disk))
2364 ext_part = ped_disk_extended_partition (disk);
2367 PedSector start, end;
2368 PedCHSGeometry bios_geom;
2371 PedPartition* log_part;
2372 log_part = ped_disk_get_partition (disk, i);
2375 if (!add_logical_part_metadata (disk, log_part))
2379 partition_probe_bios_geometry (ext_part, &bios_geom);
2380 start = ext_part->geom.start;
2381 end = start + bios_geom.sectors - 1;
2382 if (ext_part->part_list)
2384 ext_part->part_list->geom.start - 1);
2385 if (!add_metadata_part (disk, PED_PARTITION_LOGICAL,
2394 next_primary (const PedDisk* disk)
2397 for (i=1; i<=DOS_N_PRI_PARTITIONS; i++) {
2398 if (!ped_disk_get_partition (disk, i))
2404 static int _GL_ATTRIBUTE_PURE
2405 next_logical (const PedDisk* disk)
2409 if (!ped_disk_get_partition (disk, i))
2415 msdos_partition_enumerate (PedPartition* part)
2417 PED_ASSERT (part != NULL);
2418 PED_ASSERT (part->disk != NULL);
2420 /* don't re-number a primary partition */
2421 if (part->num != -1 && part->num <= DOS_N_PRI_PARTITIONS)
2426 if (part->type & PED_PARTITION_LOGICAL)
2427 part->num = next_logical (part->disk);
2429 part->num = next_primary (part->disk);
2435 msdos_get_max_primary_partition_count (const PedDisk* disk)
2437 return DOS_N_PRI_PARTITIONS;
2441 msdos_get_max_supported_partition_count(const PedDisk* disk, int *max_n)
2443 *max_n = MAX_TOTAL_PART;
2447 #include "pt-common.h"
2448 PT_define_limit_functions (msdos)
2450 static PedDiskOps msdos_disk_ops = {
2452 write: NULL_IF_DISCOVER_ONLY (msdos_write),
2454 disk_set_flag: msdos_disk_set_flag,
2455 disk_get_flag: msdos_disk_get_flag,
2456 disk_is_flag_available: msdos_disk_is_flag_available,
2458 partition_set_name: NULL,
2459 partition_get_name: NULL,
2461 PT_op_function_initializers (msdos)
2464 static PedDiskType msdos_disk_type = {
2467 ops: &msdos_disk_ops,
2468 features: PED_DISK_TYPE_EXTENDED
2472 ped_disk_msdos_init ()
2474 PED_ASSERT (sizeof (DosRawPartition) == 16);
2475 PED_ASSERT (sizeof (DosRawTable) == 512);
2477 ped_disk_type_register (&msdos_disk_type);
2481 ped_disk_msdos_done ()
2483 ped_disk_type_unregister (&msdos_disk_type);