1 /* 2 libparted - a library for manipulating disk partitions 3 Copyright (C) 1999, 2000, 2001, 2004, 2005, 2007 4 Free Software Foundation, Inc. 5 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. 10 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. 15 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/>. 18 */ 19 20 #include <config.h> 21 22 #include <sys/time.h> 23 #include <stdbool.h> 24 #include <parted/parted.h> 25 #include <parted/debug.h> 26 #include <parted/endian.h> 27 28 #if ENABLE_NLS 29 # include <libintl.h> 30 # define _(String) dgettext (PACKAGE, String) 31 #else 32 # define _(String) (String) 33 #endif /* ENABLE_NLS */ 34 35 /* this MBR boot code is loaded into 0000:7c00 by the BIOS. See mbr.s for 36 * the source, and how to build it 37 */ 38 39 static const unsigned char MBR_BOOT_CODE[] = { 40 0xfa, 0xb8, 0x00, 0x10, 0x8e, 0xd0, 0xbc, 0x00, 41 0xb0, 0xb8, 0x00, 0x00, 0x8e, 0xd8, 0x8e, 0xc0, 42 0xfb, 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x06, 0xb9, 43 0x00, 0x02, 0xf3, 0xa4, 0xea, 0x21, 0x06, 0x00, 44 0x00, 0xbe, 0xbe, 0x07, 0x38, 0x04, 0x75, 0x0b, 45 0x83, 0xc6, 0x10, 0x81, 0xfe, 0xfe, 0x07, 0x75, 46 0xf3, 0xeb, 0x16, 0xb4, 0x02, 0xb0, 0x01, 0xbb, 47 0x00, 0x7c, 0xb2, 0x80, 0x8a, 0x74, 0x01, 0x8b, 48 0x4c, 0x02, 0xcd, 0x13, 0xea, 0x00, 0x7c, 0x00, 49 0x00, 0xeb, 0xfe 50 }; 51 52 #define MSDOS_MAGIC 0xAA55 53 #define PARTITION_MAGIC_MAGIC 0xf6f6 54 55 #define PARTITION_EMPTY 0x00 56 #define PARTITION_FAT12 0x01 57 #define PARTITION_FAT16_SM 0x04 58 #define PARTITION_DOS_EXT 0x05 59 #define PARTITION_FAT16 0x06 60 #define PARTITION_NTFS 0x07 61 #define PARTITION_HPFS 0x07 62 #define PARTITION_FAT32 0x0b 63 #define PARTITION_FAT32_LBA 0x0c 64 #define PARTITION_FAT16_LBA 0x0e 65 #define PARTITION_EXT_LBA 0x0f 66 67 #define PART_FLAG_HIDDEN 0x10 /* Valid for FAT/NTFS only */ 68 #define PARTITION_FAT12_H (PARTITION_FAT12 | PART_FLAG_HIDDEN) 69 #define PARTITION_FAT16_SM_H (PARTITION_FAT16_SM | PART_FLAG_HIDDEN) 70 #define PARTITION_DOS_EXT_H (PARTITION_DOS_EXT | PART_FLAG_HIDDEN) 71 #define PARTITION_FAT16_H (PARTITION_FAT16 | PART_FLAG_HIDDEN) 72 #define PARTITION_NTFS_H (PARTITION_NTFS | PART_FLAG_HIDDEN) 73 #define PARTITION_FAT32_H (PARTITION_FAT32 | PART_FLAG_HIDDEN) 74 #define PARTITION_FAT32_LBA_H (PARTITION_FAT32_LBA | PART_FLAG_HIDDEN) 75 #define PARTITION_FAT16_LBA_H (PARTITION_FAT16_LBA | PART_FLAG_HIDDEN) 76 77 #define PARTITION_COMPAQ_DIAG 0x12 78 #define PARTITION_LDM 0x42 79 #define PARTITION_LINUX_SWAP 0x82 80 #define PARTITION_LINUX 0x83 81 #define PARTITION_LINUX_EXT 0x85 82 #define PARTITION_LINUX_LVM 0x8e 83 #define PARTITION_SUN_UFS 0xbf 84 #define PARTITION_DELL_DIAG 0xde 85 #define PARTITION_GPT 0xee 86 #define PARTITION_PALO 0xf0 87 #define PARTITION_PREP 0x41 88 #define PARTITION_LINUX_RAID 0xfd 89 #define PARTITION_LINUX_LVM_OLD 0xfe 90 91 /* This constant contains the maximum cylinder number that can be represented 92 * in (C,H,S) notation. Higher cylinder numbers are reserved for 93 * "too big" indicators (in which case only LBA addressing can be used). 94 * Some partition tables in the wild indicate this number is 1021. 95 * (i.e. 1022 is sometimes used to indicate "use LBA"). 96 */ 97 #define MAX_CHS_CYLINDER 1021 98 99 typedef struct _DosRawPartition DosRawPartition; 100 typedef struct _DosRawTable DosRawTable; 101 102 #ifdef __sun 103 #define __attribute__(X) /*nothing*/ 104 #endif /* __sun */ 105 106 /* note: lots of bit-bashing here, thus, you shouldn't look inside it. 107 * Use chs_to_sector() and sector_to_chs() instead. 108 */ 109 #ifdef __sun 110 #pragma pack(1) 111 #endif 112 typedef struct { 113 uint8_t head; 114 uint8_t sector; 115 uint8_t cylinder; 116 } __attribute__((packed)) RawCHS; 117 118 /* ripped from Linux source */ 119 struct _DosRawPartition { 120 uint8_t boot_ind; /* 00: 0x80 - active */ 121 RawCHS chs_start; /* 01: */ 122 uint8_t type; /* 04: partition type */ 123 RawCHS chs_end; /* 05: */ 124 uint32_t start; /* 08: starting sector counting from 0 */ 125 uint32_t length; /* 0c: nr of sectors in partition */ 126 } __attribute__((packed)); 127 128 struct _DosRawTable { 129 char boot_code [440]; 130 uint32_t mbr_signature; /* really a unique ID */ 131 uint16_t Unknown; 132 DosRawPartition partitions [4]; 133 uint16_t magic; 134 } __attribute__((packed)); 135 #ifdef __sun 136 #pragma pack() 137 #endif 138 139 140 /* OrigState is information we want to preserve about the partition for 141 * dealing with CHS issues 142 */ 143 typedef struct { 144 PedGeometry geom; 145 DosRawPartition raw_part; 146 PedSector lba_offset; /* needed for computing start/end for 147 * logical partitions */ 148 } OrigState; 149 150 typedef struct { 151 unsigned char system; 152 int boot; 153 int hidden; 154 int raid; 155 int lvm; 156 int lba; 157 int palo; 158 int prep; 159 OrigState* orig; /* used for CHS stuff */ 160 } DosPartitionData; 161 162 static PedDiskType msdos_disk_type; 163 164 /* FIXME: factor out this function: copied from aix.c, with changes to 165 the description, and an added sector number argument. 166 Read sector, SECTOR_NUM (which has length DEV->sector_size) into malloc'd 167 storage. If the read fails, free the memory and return zero without 168 modifying *BUF. Otherwise, set *BUF to the new buffer and return 1. */ 169 static int 170 read_sector (const PedDevice *dev, PedSector sector_num, char **buf) 171 { 172 char *b = ped_malloc (dev->sector_size); 173 PED_ASSERT (b != NULL, return 0); 174 if (!ped_device_read (dev, b, sector_num, 1)) { 175 ped_free (b); 176 return 0; 177 } 178 *buf = b; 179 return 1; 180 } 181 182 static int 183 msdos_probe (const PedDevice *dev) 184 { 185 PedDiskType* disk_type; 186 DosRawTable* part_table; 187 int i; 188 189 PED_ASSERT (dev != NULL, return 0); 190 191 if (dev->sector_size < sizeof *part_table) 192 return 0; 193 194 char *label; 195 if (!read_sector (dev, 0, &label)) 196 return 0; 197 198 part_table = (DosRawTable *) label; 199 200 /* check magic */ 201 if (PED_LE16_TO_CPU (part_table->magic) != MSDOS_MAGIC) 202 goto probe_fail; 203 204 /* if this is a FAT fs, fail here. Note that the Smart Boot Manager 205 * Loader (SBML) signature indicates a partition table, not a file 206 * system. 207 */ 208 if ((!strncmp (part_table->boot_code + 0x36, "FAT", 3) 209 && strncmp (part_table->boot_code + 0x40, "SBML", 4) != 0) 210 || !strncmp (part_table->boot_code + 0x52, "FAT", 3)) 211 goto probe_fail; 212 213 /* If this is a GPT disk, fail here */ 214 for (i = 0; i < 4; i++) { 215 if (part_table->partitions[i].type == PARTITION_GPT) 216 goto probe_fail; 217 } 218 219 /* If this is an AIX Physical Volume, fail here. IBMA in EBCDIC */ 220 if (part_table->boot_code[0] == (char) 0xc9 && 221 part_table->boot_code[1] == (char) 0xc2 && 222 part_table->boot_code[2] == (char) 0xd4 && 223 part_table->boot_code[3] == (char) 0xc1) 224 goto probe_fail; 225 226 #ifdef ENABLE_PC98 227 /* HACK: it's impossible to tell PC98 and msdos disk labels apart. 228 * Someone made the signatures the same (very clever). Since 229 * PC98 has some idiosyncracies with it's boot-loader, it's detection 230 * is more reliable */ 231 disk_type = ped_disk_type_get ("pc98"); 232 if (disk_type && disk_type->ops->probe (dev)) 233 goto probe_fail; 234 #endif /* ENABLE_PC98 */ 235 236 free (label); 237 return 1; 238 239 probe_fail: 240 free (label); 241 return 0; 242 } 243 244 static PedDisk* 245 msdos_alloc (const PedDevice* dev) 246 { 247 PedDisk* disk; 248 PED_ASSERT (dev != NULL, return NULL); 249 250 disk = _ped_disk_alloc ((PedDevice*)dev, &msdos_disk_type); 251 if (disk) 252 disk->disk_specific = NULL; 253 return disk; 254 } 255 256 static PedDisk* 257 msdos_duplicate (const PedDisk* disk) 258 { 259 PedDisk* new_disk; 260 261 new_disk = ped_disk_new_fresh (disk->dev, &msdos_disk_type); 262 if (!new_disk) 263 return NULL; 264 new_disk->disk_specific = NULL; 265 return new_disk; 266 } 267 268 static void 269 msdos_free (PedDisk* disk) 270 { 271 PED_ASSERT (disk != NULL, return); 272 273 _ped_disk_free (disk); 274 } 275 276 #ifndef DISCOVER_ONLY 277 static int 278 msdos_clobber (PedDevice* dev) 279 { 280 DosRawTable table; 281 282 PED_ASSERT (dev != NULL, return 0); 283 PED_ASSERT (msdos_probe (dev), return 0); 284 285 if (!ped_device_read (dev, &table, 0, 1)) 286 return 0; 287 table.magic = 0; 288 return ped_device_write (dev, (void*) &table, 0, 1); 289 } 290 #endif /* !DISCOVER_ONLY */ 291 292 static int 293 chs_get_cylinder (const RawCHS* chs) 294 { 295 return chs->cylinder + ((chs->sector >> 6) << 8); 296 } 297 298 static int 299 chs_get_head (const RawCHS* chs) 300 { 301 return chs->head; 302 } 303 304 /* counts from 0 */ 305 static int 306 chs_get_sector (const RawCHS* chs) 307 { 308 return (chs->sector & 0x3f) - 1; 309 } 310 311 static PedSector 312 chs_to_sector (const PedDevice* dev, const PedCHSGeometry *bios_geom, 313 const RawCHS* chs) 314 { 315 PedSector c; /* not measured in sectors, but need */ 316 PedSector h; /* lots of bits */ 317 PedSector s; 318 319 PED_ASSERT (bios_geom != NULL, return 0); 320 PED_ASSERT (chs != NULL, return 0); 321 322 c = chs_get_cylinder (chs); 323 h = chs_get_head (chs); 324 s = chs_get_sector (chs); 325 326 if (c > MAX_CHS_CYLINDER) /* MAGIC: C/H/S is irrelevant */ 327 return 0; 328 if (s < 0) 329 return 0; 330 return ((c * bios_geom->heads + h) * bios_geom->sectors + s) 331 * (dev->sector_size / 512); 332 } 333 334 static void 335 sector_to_chs (const PedDevice* dev, const PedCHSGeometry* bios_geom, 336 PedSector sector, RawCHS* chs) 337 { 338 PedSector real_c, real_h, real_s; 339 340 PED_ASSERT (dev != NULL, return); 341 PED_ASSERT (chs != NULL, return); 342 343 if (!bios_geom) 344 bios_geom = &dev->bios_geom; 345 346 sector /= (dev->sector_size / 512); 347 348 real_c = sector / (bios_geom->heads * bios_geom->sectors); 349 real_h = (sector / bios_geom->sectors) % bios_geom->heads; 350 real_s = sector % bios_geom->sectors; 351 352 if (real_c > MAX_CHS_CYLINDER) { 353 real_c = 1023; 354 real_h = bios_geom->heads - 1; 355 real_s = bios_geom->sectors - 1; 356 } 357 358 chs->cylinder = real_c % 0x100; 359 chs->head = real_h; 360 chs->sector = real_s + 1 + (real_c >> 8 << 6); 361 } 362 363 static PedSector 364 legacy_start (const PedDisk* disk, const PedCHSGeometry* bios_geom, 365 const DosRawPartition* raw_part) 366 { 367 PED_ASSERT (disk != NULL, return 0); 368 PED_ASSERT (raw_part != NULL, return 0); 369 370 return chs_to_sector (disk->dev, bios_geom, &raw_part->chs_start); 371 } 372 373 static PedSector 374 legacy_end (const PedDisk* disk, const PedCHSGeometry* bios_geom, 375 const DosRawPartition* raw_part) 376 { 377 PED_ASSERT (disk != NULL, return 0); 378 PED_ASSERT (raw_part != NULL, return 0); 379 380 return chs_to_sector (disk->dev, bios_geom, &raw_part->chs_end); 381 } 382 383 static PedSector 384 linear_start (const PedDisk* disk, const DosRawPartition* raw_part, 385 PedSector offset) 386 { 387 PED_ASSERT (disk != NULL, return 0); 388 PED_ASSERT (raw_part != NULL, return 0); 389 390 return offset 391 + PED_LE32_TO_CPU (raw_part->start) 392 * (disk->dev->sector_size / 512); 393 } 394 395 static PedSector 396 linear_end (const PedDisk* disk, const DosRawPartition* raw_part, 397 PedSector offset) 398 { 399 PED_ASSERT (disk != NULL, return 0); 400 PED_ASSERT (raw_part != NULL, return 0); 401 402 return linear_start (disk, raw_part, offset) 403 + (PED_LE32_TO_CPU (raw_part->length) - 1) 404 * (disk->dev->sector_size / 512); 405 } 406 407 #ifndef DISCOVER_ONLY 408 static int 409 partition_check_bios_geometry (PedPartition* part, PedCHSGeometry* bios_geom) 410 { 411 PedSector leg_start, leg_end; 412 DosPartitionData* dos_data; 413 PedDisk* disk; 414 415 PED_ASSERT (part != NULL, return 0); 416 PED_ASSERT (part->disk != NULL, return 0); 417 PED_ASSERT (part->disk_specific != NULL, return 0); 418 dos_data = part->disk_specific; 419 420 if (!dos_data->orig) 421 return 1; 422 423 disk = part->disk; 424 leg_start = legacy_start (disk, bios_geom, &dos_data->orig->raw_part); 425 leg_end = legacy_end (disk, bios_geom, &dos_data->orig->raw_part); 426 427 if (leg_start && leg_start != dos_data->orig->geom.start) 428 return 0; 429 if (leg_end && leg_end != dos_data->orig->geom.end) 430 return 0; 431 return 1; 432 } 433 434 static int 435 disk_check_bios_geometry (const PedDisk* disk, PedCHSGeometry* bios_geom) 436 { 437 PedPartition* part = NULL; 438 439 PED_ASSERT (disk != NULL, return 0); 440 441 while ((part = ped_disk_next_partition (disk, part))) { 442 if (ped_partition_is_active (part)) { 443 if (!partition_check_bios_geometry (part, bios_geom)) 444 return 0; 445 } 446 } 447 448 return 1; 449 } 450 451 static int 452 probe_filesystem_for_geom (const PedPartition* part, PedCHSGeometry* bios_geom) 453 { 454 const char* ms_types[] = {"ntfs", "fat16", "fat32", NULL}; 455 int i; 456 int found; 457 unsigned char* buf; 458 int sectors; 459 int heads; 460 int res = 0; 461 462 PED_ASSERT (bios_geom != NULL, return 0); 463 PED_ASSERT (part != NULL, return 0); 464 PED_ASSERT (part->disk != NULL, return 0); 465 PED_ASSERT (part->disk->dev != NULL, return 0); 466 PED_ASSERT (part->disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, 467 return 0); 468 469 buf = ped_malloc (part->disk->dev->sector_size); 470 471 if (!buf) 472 return 0; 473 474 if (!part->fs_type) 475 goto end; 476 477 found = 0; 478 for (i = 0; ms_types[i]; i++) { 479 if (!strcmp(ms_types[i], part->fs_type->name)) 480 found = 1; 481 } 482 if (!found) 483 goto end; 484 485 if (!ped_geometry_read(&part->geom, buf, 0, 1)) 486 goto end; 487 488 /* shared by the start of all Microsoft file systems */ 489 sectors = buf[0x18] + (buf[0x19] << 8); 490 heads = buf[0x1a] + (buf[0x1b] << 8); 491 492 if (sectors < 1 || sectors > 63) 493 goto end; 494 if (heads > 255 || heads < 1) 495 goto end; 496 497 bios_geom->sectors = sectors; 498 bios_geom->heads = heads; 499 bios_geom->cylinders = part->disk->dev->length / (sectors * heads); 500 res = 1; 501 end: 502 ped_free(buf); 503 return res; 504 } 505 506 /* This function attempts to infer the BIOS CHS geometry of the hard disk 507 * from the CHS + LBA information contained in the partition table from 508 * a single partition's entry. 509 * 510 * This involves some maths. Let (c,h,s,a) be the starting cylinder, 511 * starting head, starting sector and LBA start address of the partition. 512 * Likewise, (C,H,S,A) the end addresses. Using both of these pieces 513 * of information, we want to deduce cyl_sectors and head_sectors which 514 * are the sizes of a single cylinder and a single head, respectively. 515 * 516 * The relationships are: 517 * c*cyl_sectors + h * head_sectors + s = a 518 * C*cyl_sectors + H * head_sectors + S = A 519 * 520 * We can rewrite this in matrix form: 521 * 522 * [ c h ] [ cyl_sectors ] = [ s - a ] = [ a_ ] 523 * [ C H ] [ head_sectors ] [ S - A ] [ A_ ]. 524 * 525 * (s - a is abbreviated to a_to simplify the notation.) 526 * 527 * This can be abbreviated into augmented matrix form: 528 * 529 * [ c h | a_ ] 530 * [ C H | A_ ]. 531 * 532 * Solving these equations requires following the row reduction algorithm. We 533 * need to be careful about a few things though: 534 * - the equations might be linearly dependent, in which case there 535 * are many solutions. 536 * - the equations might be inconsistent, in which case there 537 * are no solutions. (Inconsistent partition table entry!) 538 * - there might be zeros, so we need to be careful about applying 539 * the algorithm. We know, however, that C > 0. 540 */ 541 static int 542 probe_partition_for_geom (const PedPartition* part, PedCHSGeometry* bios_geom) 543 { 544 DosPartitionData* dos_data; 545 RawCHS* start_chs; 546 RawCHS* end_chs; 547 PedSector c, h, s, a, a_; /* start */ 548 PedSector C, H, S, A, A_; /* end */ 549 PedSector dont_overflow, denum; 550 PedSector cyl_size, head_size; 551 PedSector cylinders, heads, sectors; 552 553 PED_ASSERT (part != NULL, return 0); 554 PED_ASSERT (part->disk_specific != NULL, return 0); 555 PED_ASSERT (bios_geom != NULL, return 0); 556 557 dos_data = part->disk_specific; 558 559 if (!dos_data->orig) 560 return 0; 561 562 start_chs = &dos_data->orig->raw_part.chs_start; 563 c = chs_get_cylinder (start_chs); 564 h = chs_get_head (start_chs); 565 s = chs_get_sector (start_chs); 566 a = dos_data->orig->geom.start; 567 a_ = a - s; 568 569 end_chs = &dos_data->orig->raw_part.chs_end; 570 C = chs_get_cylinder (end_chs); 571 H = chs_get_head (end_chs); 572 S = chs_get_sector (end_chs); 573 A = dos_data->orig->geom.end; 574 A_ = A - S; 575 576 if (h < 0 || H < 0 || h > 254 || H > 254) 577 return 0; 578 if (c > C) 579 return 0; 580 581 /* If no geometry is feasible, then don't even bother. 582 * Useful for eliminating assertions for broken partition 583 * tables generated by Norton Ghost et al. 584 */ 585 if (A > (C+1) * 255 * 63) 586 return 0; 587 588 /* Not enough information. In theory, we can do better. Should we? */ 589 if (C > MAX_CHS_CYLINDER) 590 return 0; 591 if (C == 0) 592 return 0; 593 594 /* Calculate the maximum number that can be multiplied by 595 * any head count without overflowing a PedSector 596 * 2^8 = 256, 8 bits + 1(sign bit) = 9 597 */ 598 dont_overflow = 1; 599 dont_overflow <<= (8*sizeof(dont_overflow)) - 9; 600 dont_overflow--; 601 602 if (a_ > dont_overflow || A_ > dont_overflow) 603 return 0; 604 605 /* The matrix is solved by : 606 * 607 * [ c h | a_] R1 608 * [ C H | A_] R2 609 * 610 * (cH - Ch) cyl_size = a_H - A_h H R1 - h R2 611 * => (if cH - Ch != 0) cyl_size = (a_H - A_h) / (cH - Ch) 612 * 613 * (Hc - hC) head_size = A_c - a_C c R2 - C R1 614 * => (if cH - Ch != 0) head_size = (A_c - a_C) / (cH - Ch) 615 * 616 * But this calculation of head_size would need 617 * not overflowing A_c or a_C 618 * So substitution is use instead, to minimize dimension 619 * of temporary results : 620 * 621 * If h != 0 : head_size = ( a_ - c cyl_size ) / h 622 * If H != 0 : head_size = ( A_ - C cyl_size ) / H 623 * 624 */ 625 denum = c * H - C * h; 626 if (denum == 0) 627 return 0; 628 629 cyl_size = (a_*H - A_*h) / denum; 630 /* Check for non integer result */ 631 if (cyl_size * denum != a_*H - A_*h) 632 return 0; 633 634 PED_ASSERT (cyl_size > 0, return 0); 635 PED_ASSERT (cyl_size <= 255 * 63, return 0); 636 637 if (h > 0) 638 head_size = ( a_ - c * cyl_size ) / h; 639 else if (H > 0) 640 head_size = ( A_ - C * cyl_size ) / H; 641 else { 642 /* should not happen because denum != 0 */ 643 head_size = 0; 644 PED_ASSERT (0, return 0); 645 } 646 647 PED_ASSERT (head_size > 0, return 0); 648 PED_ASSERT (head_size <= 63, return 0); 649 650 cylinders = part->disk->dev->length / cyl_size; 651 heads = cyl_size / head_size; 652 sectors = head_size; 653 654 PED_ASSERT (heads > 0, return 0); 655 PED_ASSERT (heads < 256, return 0); 656 657 PED_ASSERT (sectors > 0, return 0); 658 PED_ASSERT (sectors <= 63, return 0); 659 660 /* Some broken OEM partitioning program(s) seem to have an out-by-one 661 * error on the end of partitions. We should offer to fix the 662 * partition table... 663 */ 664 if (((C + 1) * heads + H) * sectors + S == A) 665 C++; 666 667 PED_ASSERT ((c * heads + h) * sectors + s == a, return 0); 668 PED_ASSERT ((C * heads + H) * sectors + S == A, return 0); 669 670 bios_geom->cylinders = cylinders; 671 bios_geom->heads = heads; 672 bios_geom->sectors = sectors; 673 674 return 1; 675 } 676 677 static void 678 partition_probe_bios_geometry (const PedPartition* part, 679 PedCHSGeometry* bios_geom) 680 { 681 PED_ASSERT (part != NULL, return); 682 PED_ASSERT (part->disk != NULL, return); 683 PED_ASSERT (bios_geom != NULL, return); 684 685 if (ped_partition_is_active (part)) { 686 if (probe_partition_for_geom (part, bios_geom)) 687 return; 688 if (part->type & PED_PARTITION_EXTENDED) { 689 if (probe_filesystem_for_geom (part, bios_geom)) 690 return; 691 } 692 } 693 if (part->type & PED_PARTITION_LOGICAL) { 694 PedPartition* ext_part; 695 ext_part = ped_disk_extended_partition (part->disk); 696 PED_ASSERT (ext_part != NULL, return); 697 partition_probe_bios_geometry (ext_part, bios_geom); 698 } else { 699 *bios_geom = part->disk->dev->bios_geom; 700 } 701 } 702 703 static void 704 disk_probe_bios_geometry (const PedDisk* disk, PedCHSGeometry* bios_geom) 705 { 706 PedPartition* part; 707 708 /* first look at the boot partition */ 709 part = NULL; 710 while ((part = ped_disk_next_partition (disk, part))) { 711 if (!ped_partition_is_active (part)) 712 continue; 713 if (ped_partition_get_flag (part, PED_PARTITION_BOOT)) { 714 if (probe_filesystem_for_geom (part, bios_geom)) 715 return; 716 if (probe_partition_for_geom (part, bios_geom)) 717 return; 718 } 719 } 720 721 /* that didn't work... try all partition table entries */ 722 part = NULL; 723 while ((part = ped_disk_next_partition (disk, part))) { 724 if (ped_partition_is_active (part)) { 725 if (probe_partition_for_geom (part, bios_geom)) 726 return; 727 } 728 } 729 730 /* that didn't work... look at all file systems */ 731 part = NULL; 732 while ((part = ped_disk_next_partition (disk, part))) { 733 if (ped_partition_is_active (part)) { 734 if (probe_filesystem_for_geom (part, bios_geom)) 735 return; 736 } 737 } 738 } 739 #endif /* !DISCOVER_ONLY */ 740 741 static int 742 raw_part_is_extended (const DosRawPartition* raw_part) 743 { 744 PED_ASSERT (raw_part != NULL, return 0); 745 746 switch (raw_part->type) { 747 case PARTITION_DOS_EXT: 748 case PARTITION_EXT_LBA: 749 case PARTITION_LINUX_EXT: 750 return 1; 751 752 default: 753 return 0; 754 } 755 756 return 0; 757 } 758 759 static int 760 raw_part_is_hidden (const DosRawPartition* raw_part) 761 { 762 PED_ASSERT (raw_part != NULL, return 0); 763 764 switch (raw_part->type) { 765 case PARTITION_FAT12_H: 766 case PARTITION_FAT16_SM_H: 767 case PARTITION_FAT16_H: 768 case PARTITION_FAT32_H: 769 case PARTITION_NTFS_H: 770 case PARTITION_FAT32_LBA_H: 771 case PARTITION_FAT16_LBA_H: 772 return 1; 773 774 default: 775 return 0; 776 } 777 778 return 0; 779 } 780 781 static int 782 raw_part_is_lba (const DosRawPartition* raw_part) 783 { 784 PED_ASSERT (raw_part != NULL, return 0); 785 786 switch (raw_part->type) { 787 case PARTITION_FAT32_LBA: 788 case PARTITION_FAT16_LBA: 789 case PARTITION_EXT_LBA: 790 case PARTITION_FAT32_LBA_H: 791 case PARTITION_FAT16_LBA_H: 792 return 1; 793 794 default: 795 return 0; 796 } 797 798 return 0; 799 } 800 801 static PedPartition* 802 raw_part_parse (const PedDisk* disk, const DosRawPartition* raw_part, 803 PedSector lba_offset, PedPartitionType type) 804 { 805 PedPartition* part; 806 DosPartitionData* dos_data; 807 808 PED_ASSERT (disk != NULL, return NULL); 809 PED_ASSERT (raw_part != NULL, return NULL); 810 811 part = ped_partition_new ( 812 disk, type, NULL, 813 linear_start (disk, raw_part, lba_offset), 814 linear_end (disk, raw_part, lba_offset)); 815 if (!part) 816 return NULL; 817 dos_data = part->disk_specific; 818 dos_data->system = raw_part->type; 819 dos_data->boot = raw_part->boot_ind != 0; 820 dos_data->hidden = raw_part_is_hidden (raw_part); 821 dos_data->raid = raw_part->type == PARTITION_LINUX_RAID; 822 dos_data->lvm = raw_part->type == PARTITION_LINUX_LVM_OLD 823 || raw_part->type == PARTITION_LINUX_LVM; 824 dos_data->lba = raw_part_is_lba (raw_part); 825 dos_data->palo = raw_part->type == PARTITION_PALO; 826 dos_data->prep = raw_part->type == PARTITION_PREP; 827 dos_data->orig = ped_malloc (sizeof (OrigState)); 828 if (!dos_data->orig) { 829 ped_partition_destroy (part); 830 return NULL; 831 } 832 dos_data->orig->geom = part->geom; 833 dos_data->orig->raw_part = *raw_part; 834 dos_data->orig->lba_offset = lba_offset; 835 return part; 836 } 837 838 static int 839 read_table (PedDisk* disk, PedSector sector, int is_extended_table) 840 { 841 int i; 842 DosRawTable* table; 843 DosRawPartition* raw_part; 844 PedPartition* part; 845 PedPartitionType type; 846 PedSector lba_offset; 847 PedConstraint* constraint_exact; 848 849 PED_ASSERT (disk != NULL, return 0); 850 PED_ASSERT (disk->dev != NULL, return 0); 851 852 char *label = NULL; 853 if (!read_sector (disk->dev, sector, &label)) 854 goto error; 855 856 table = (DosRawTable *) label; 857 858 /* weird: empty extended partitions are filled with 0xf6 by PM */ 859 if (is_extended_table 860 && PED_LE16_TO_CPU (table->magic) == PARTITION_MAGIC_MAGIC) 861 goto read_ok; 862 863 #ifndef DISCOVER_ONLY 864 if (PED_LE16_TO_CPU (table->magic) != MSDOS_MAGIC) { 865 if (ped_exception_throw ( 866 PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL, 867 _("Invalid partition table on %s " 868 "-- wrong signature %x."), 869 disk->dev->path, 870 PED_LE16_TO_CPU (table->magic)) 871 != PED_EXCEPTION_IGNORE) 872 goto error; 873 goto read_ok; 874 } 875 #endif 876 877 /* parse the partitions from this table */ 878 for (i = 0; i < 4; i++) { 879 raw_part = &table->partitions [i]; 880 if (raw_part->type == PARTITION_EMPTY || !raw_part->length) 881 continue; 882 883 /* process nested extended partitions after normal logical 884 * partitions, to make sure we get the order right. 885 */ 886 if (is_extended_table && raw_part_is_extended (raw_part)) 887 continue; 888 889 lba_offset = is_extended_table ? sector : 0; 890 891 if (linear_start (disk, raw_part, lba_offset) == sector) { 892 if (ped_exception_throw ( 893 PED_EXCEPTION_ERROR, 894 PED_EXCEPTION_IGNORE_CANCEL, 895 _("Invalid partition table - recursive " 896 "partition on %s."), 897 disk->dev->path) 898 != PED_EXCEPTION_IGNORE) 899 goto error; 900 continue; /* avoid infinite recursion */ 901 } 902 903 if (is_extended_table) 904 type = PED_PARTITION_LOGICAL; 905 else if (raw_part_is_extended (raw_part)) 906 type = PED_PARTITION_EXTENDED; 907 else 908 type = PED_PARTITION_NORMAL; 909 910 part = raw_part_parse (disk, raw_part, lba_offset, type); 911 if (!part) 912 goto error; 913 if (!is_extended_table) 914 part->num = i + 1; 915 if (type != PED_PARTITION_EXTENDED) 916 part->fs_type = ped_file_system_probe (&part->geom); 917 918 constraint_exact = ped_constraint_exact (&part->geom); 919 if (!ped_disk_add_partition (disk, part, constraint_exact)) 920 goto error; 921 ped_constraint_destroy (constraint_exact); 922 923 /* non-nested extended partition */ 924 if (part->type == PED_PARTITION_EXTENDED) { 925 if (!read_table (disk, part->geom.start, 1)) 926 goto error; 927 } 928 } 929 930 if (is_extended_table) { 931 /* process the nested extended partitions */ 932 for (i = 0; i < 4; i++) { 933 PedSector part_start; 934 935 raw_part = &table->partitions [i]; 936 if (!raw_part_is_extended (raw_part)) 937 continue; 938 939 lba_offset = ped_disk_extended_partition 940 (disk)->geom.start; 941 part_start = linear_start (disk, raw_part, lba_offset); 942 if (part_start == sector) { 943 /* recursive table - already threw an 944 * exception above. 945 */ 946 continue; 947 } 948 if (!read_table (disk, part_start, 1)) 949 goto error; 950 } 951 } 952 953 read_ok: 954 free (label); 955 return 1; 956 957 error: 958 free (label); 959 ped_disk_delete_all (disk); 960 return 0; 961 } 962 963 static int 964 msdos_read (PedDisk* disk) 965 { 966 PED_ASSERT (disk != NULL, return 0); 967 PED_ASSERT (disk->dev != NULL, return 0); 968 969 ped_disk_delete_all (disk); 970 if (!read_table (disk, 0, 0)) 971 return 0; 972 973 #ifndef DISCOVER_ONLY 974 /* try to figure out the correct BIOS CHS values */ 975 if (!disk_check_bios_geometry (disk, &disk->dev->bios_geom)) { 976 PedCHSGeometry bios_geom = disk->dev->bios_geom; 977 disk_probe_bios_geometry (disk, &bios_geom); 978 979 /* if the geometry was wrong, then we should reread, to 980 * make sure the metadata is allocated in the right places. 981 */ 982 if (disk->dev->bios_geom.cylinders != bios_geom.cylinders 983 || disk->dev->bios_geom.heads != bios_geom.heads 984 || disk->dev->bios_geom.sectors != bios_geom.sectors) { 985 disk->dev->bios_geom = bios_geom; 986 return msdos_read (disk); 987 } 988 } 989 #endif 990 991 return 1; 992 } 993 994 #ifndef DISCOVER_ONLY 995 static int 996 fill_raw_part (DosRawPartition* raw_part, 997 const PedPartition* part, PedSector offset) 998 { 999 DosPartitionData* dos_data; 1000 PedCHSGeometry bios_geom; 1001 1002 PED_ASSERT (raw_part != NULL, return 0); 1003 PED_ASSERT (part != NULL, return 0); 1004 1005 partition_probe_bios_geometry (part, &bios_geom); 1006 1007 dos_data = part->disk_specific; 1008 1009 raw_part->boot_ind = 0x80 * dos_data->boot; 1010 raw_part->type = dos_data->system; 1011 raw_part->start = PED_CPU_TO_LE32 ((part->geom.start - offset) 1012 / (part->disk->dev->sector_size / 512)); 1013 raw_part->length = PED_CPU_TO_LE32 (part->geom.length 1014 / (part->disk->dev->sector_size / 512)); 1015 1016 sector_to_chs (part->disk->dev, &bios_geom, part->geom.start, 1017 &raw_part->chs_start); 1018 sector_to_chs (part->disk->dev, &bios_geom, part->geom.end, 1019 &raw_part->chs_end); 1020 1021 if (dos_data->orig) { 1022 DosRawPartition* orig_raw_part = &dos_data->orig->raw_part; 1023 if (dos_data->orig->geom.start == part->geom.start) 1024 raw_part->chs_start = orig_raw_part->chs_start; 1025 if (dos_data->orig->geom.end == part->geom.end) 1026 raw_part->chs_end = orig_raw_part->chs_end; 1027 } 1028 1029 return 1; 1030 } 1031 1032 static int 1033 fill_ext_raw_part_geom (DosRawPartition* raw_part, 1034 const PedCHSGeometry* bios_geom, 1035 const PedGeometry* geom, PedSector offset) 1036 { 1037 PED_ASSERT (raw_part != NULL, return 0); 1038 PED_ASSERT (geom != NULL, return 0); 1039 PED_ASSERT (geom->dev != NULL, return 0); 1040 1041 raw_part->boot_ind = 0; 1042 raw_part->type = PARTITION_DOS_EXT; 1043 raw_part->start = PED_CPU_TO_LE32 ((geom->start - offset) 1044 / (geom->dev->sector_size / 512)); 1045 raw_part->length = PED_CPU_TO_LE32 (geom->length 1046 / (geom->dev->sector_size / 512)); 1047 1048 sector_to_chs (geom->dev, bios_geom, geom->start, &raw_part->chs_start); 1049 sector_to_chs (geom->dev, bios_geom, geom->start + geom->length - 1, 1050 &raw_part->chs_end); 1051 1052 return 1; 1053 } 1054 1055 static int 1056 write_ext_table (const PedDisk* disk, 1057 PedSector sector, const PedPartition* logical) 1058 { 1059 DosRawTable table; 1060 PedPartition* part; 1061 PedSector lba_offset; 1062 1063 PED_ASSERT (disk != NULL, return 0); 1064 PED_ASSERT (ped_disk_extended_partition (disk) != NULL, return 0); 1065 PED_ASSERT (logical != NULL, return 0); 1066 1067 lba_offset = ped_disk_extended_partition (disk)->geom.start; 1068 1069 memset (&table, 0, sizeof (DosRawTable)); 1070 table.magic = PED_CPU_TO_LE16 (MSDOS_MAGIC); 1071 1072 if (!fill_raw_part (&table.partitions[0], logical, sector)) 1073 return 0; 1074 1075 part = ped_disk_get_partition (disk, logical->num + 1); 1076 if (part) { 1077 PedGeometry* geom; 1078 PedCHSGeometry bios_geom; 1079 1080 geom = ped_geometry_new (disk->dev, part->prev->geom.start, 1081 part->geom.end - part->prev->geom.start + 1); 1082 if (!geom) 1083 return 0; 1084 partition_probe_bios_geometry (part, &bios_geom); 1085 fill_ext_raw_part_geom (&table.partitions[1], &bios_geom, 1086 geom, lba_offset); 1087 ped_geometry_destroy (geom); 1088 1089 if (!write_ext_table (disk, part->prev->geom.start, part)) 1090 return 0; 1091 } 1092 1093 return ped_device_write (disk->dev, (void*) &table, sector, 1); 1094 } 1095 1096 static int 1097 write_empty_table (const PedDisk* disk, PedSector sector) 1098 { 1099 DosRawTable table; 1100 1101 PED_ASSERT (disk != NULL, return 0); 1102 1103 memset (&table, 0, sizeof (DosRawTable)); 1104 table.magic = PED_CPU_TO_LE16 (MSDOS_MAGIC); 1105 1106 return ped_device_write (disk->dev, (void*) &table, sector, 1); 1107 } 1108 1109 /* Find the first logical partition, and write the partition table for it. 1110 */ 1111 static int 1112 write_extended_partitions (const PedDisk* disk) 1113 { 1114 PedPartition* ext_part; 1115 PedPartition* part; 1116 PedCHSGeometry bios_geom; 1117 1118 PED_ASSERT (disk != NULL, return 0); 1119 1120 ext_part = ped_disk_extended_partition (disk); 1121 partition_probe_bios_geometry (ext_part, &bios_geom); 1122 part = ped_disk_get_partition (disk, 5); 1123 if (part) 1124 return write_ext_table (disk, ext_part->geom.start, part); 1125 else 1126 return write_empty_table (disk, ext_part->geom.start); 1127 } 1128 1129 static inline uint32_t generate_random_id (void) 1130 { 1131 struct timeval tv; 1132 int rc; 1133 rc = gettimeofday(&tv, NULL); 1134 if (rc == -1) 1135 return 0; 1136 return (uint32_t)(tv.tv_usec & 0xFFFFFFFFUL); 1137 } 1138 1139 static int 1140 msdos_write (const PedDisk* disk) 1141 { 1142 DosRawTable table; 1143 PedPartition* part; 1144 int i; 1145 1146 PED_ASSERT (disk != NULL, return 0); 1147 PED_ASSERT (disk->dev != NULL, return 0); 1148 1149 ped_device_read (disk->dev, &table, 0, 1); 1150 1151 if (!table.boot_code[0]) { 1152 memset (table.boot_code, 0, 512); 1153 memcpy (table.boot_code, MBR_BOOT_CODE, sizeof (MBR_BOOT_CODE)); 1154 } 1155 1156 /* If there is no unique identifier, generate a random one */ 1157 if (!table.mbr_signature) 1158 table.mbr_signature = generate_random_id(); 1159 1160 memset (table.partitions, 0, sizeof (DosRawPartition) * 4); 1161 table.magic = PED_CPU_TO_LE16 (MSDOS_MAGIC); 1162 1163 for (i=1; i<=4; i++) { 1164 part = ped_disk_get_partition (disk, i); 1165 if (!part) 1166 continue; 1167 1168 if (!fill_raw_part (&table.partitions [i - 1], part, 0)) 1169 return 0; 1170 1171 if (part->type == PED_PARTITION_EXTENDED) { 1172 if (!write_extended_partitions (disk)) 1173 return 0; 1174 } 1175 } 1176 1177 if (!ped_device_write (disk->dev, (void*) &table, 0, 1)) 1178 return 0; 1179 return ped_device_sync (disk->dev); 1180 } 1181 #endif /* !DISCOVER_ONLY */ 1182 1183 static PedPartition* 1184 msdos_partition_new (const PedDisk* disk, PedPartitionType part_type, 1185 const PedFileSystemType* fs_type, 1186 PedSector start, PedSector end) 1187 { 1188 PedPartition* part; 1189 DosPartitionData* dos_data; 1190 1191 part = _ped_partition_alloc (disk, part_type, fs_type, start, end); 1192 if (!part) 1193 goto error; 1194 1195 if (ped_partition_is_active (part)) { 1196 part->disk_specific 1197 = dos_data = ped_malloc (sizeof (DosPartitionData)); 1198 if (!dos_data) 1199 goto error_free_part; 1200 dos_data->orig = NULL; 1201 dos_data->system = PARTITION_LINUX; 1202 dos_data->hidden = 0; 1203 dos_data->boot = 0; 1204 dos_data->raid = 0; 1205 dos_data->lvm = 0; 1206 dos_data->lba = 0; 1207 dos_data->palo = 0; 1208 dos_data->prep = 0; 1209 } else { 1210 part->disk_specific = NULL; 1211 } 1212 return part; 1213 1214 ped_free (dos_data); 1215 error_free_part: 1216 ped_free (part); 1217 error: 1218 return 0; 1219 } 1220 1221 static PedPartition* 1222 msdos_partition_duplicate (const PedPartition* part) 1223 { 1224 PedPartition* new_part; 1225 DosPartitionData* new_dos_data; 1226 DosPartitionData* old_dos_data; 1227 1228 new_part = ped_partition_new (part->disk, part->type, part->fs_type, 1229 part->geom.start, part->geom.end); 1230 if (!new_part) 1231 return NULL; 1232 new_part->num = part->num; 1233 1234 old_dos_data = (DosPartitionData*) part->disk_specific; 1235 new_dos_data = (DosPartitionData*) new_part->disk_specific; 1236 new_dos_data->system = old_dos_data->system; 1237 new_dos_data->boot = old_dos_data->boot; 1238 new_dos_data->hidden = old_dos_data->hidden; 1239 new_dos_data->raid = old_dos_data->raid; 1240 new_dos_data->lvm = old_dos_data->lvm; 1241 new_dos_data->lba = old_dos_data->lba; 1242 new_dos_data->palo = old_dos_data->palo; 1243 new_dos_data->prep = old_dos_data->prep; 1244 1245 if (old_dos_data->orig) { 1246 new_dos_data->orig = ped_malloc (sizeof (OrigState)); 1247 if (!new_dos_data->orig) { 1248 ped_partition_destroy (new_part); 1249 return NULL; 1250 } 1251 new_dos_data->orig->geom = old_dos_data->orig->geom; 1252 new_dos_data->orig->raw_part = old_dos_data->orig->raw_part; 1253 new_dos_data->orig->lba_offset = old_dos_data->orig->lba_offset; 1254 } 1255 return new_part; 1256 } 1257 1258 static void 1259 msdos_partition_destroy (PedPartition* part) 1260 { 1261 PED_ASSERT (part != NULL, return); 1262 1263 if (ped_partition_is_active (part)) { 1264 DosPartitionData* dos_data; 1265 dos_data = (DosPartitionData*) part->disk_specific; 1266 if (dos_data->orig) 1267 ped_free (dos_data->orig); 1268 ped_free (part->disk_specific); 1269 } 1270 ped_free (part); 1271 } 1272 1273 static int 1274 msdos_partition_set_system (PedPartition* part, 1275 const PedFileSystemType* fs_type) 1276 { 1277 DosPartitionData* dos_data = part->disk_specific; 1278 1279 part->fs_type = fs_type; 1280 1281 if (dos_data->hidden 1282 && fs_type 1283 && strncmp (fs_type->name, "fat", 3) != 0 1284 && strcmp (fs_type->name, "ntfs") != 0) 1285 dos_data->hidden = 0; 1286 1287 if (part->type & PED_PARTITION_EXTENDED) { 1288 dos_data->raid = 0; 1289 dos_data->lvm = 0; 1290 dos_data->palo = 0; 1291 dos_data->prep = 0; 1292 if (dos_data->lba) 1293 dos_data->system = PARTITION_EXT_LBA; 1294 else 1295 dos_data->system = PARTITION_DOS_EXT; 1296 return 1; 1297 } 1298 1299 if (dos_data->lvm) { 1300 dos_data->system = PARTITION_LINUX_LVM; 1301 return 1; 1302 } 1303 if (dos_data->raid) { 1304 dos_data->system = PARTITION_LINUX_RAID; 1305 return 1; 1306 } 1307 if (dos_data->palo) { 1308 dos_data->system = PARTITION_PALO; 1309 return 1; 1310 } 1311 if (dos_data->prep) { 1312 dos_data->system = PARTITION_PREP; 1313 return 1; 1314 } 1315 1316 if (!fs_type) 1317 dos_data->system = PARTITION_LINUX; 1318 else if (!strcmp (fs_type->name, "fat16")) { 1319 dos_data->system = dos_data->lba 1320 ? PARTITION_FAT16_LBA : PARTITION_FAT16; 1321 dos_data->system |= dos_data->hidden ? PART_FLAG_HIDDEN : 0; 1322 } else if (!strcmp (fs_type->name, "fat32")) { 1323 dos_data->system = dos_data->lba 1324 ? PARTITION_FAT32_LBA : PARTITION_FAT32; 1325 dos_data->system |= dos_data->hidden ? PART_FLAG_HIDDEN : 0; 1326 } else if (!strcmp (fs_type->name, "ntfs") 1327 || !strcmp (fs_type->name, "hpfs")) { 1328 dos_data->system = PARTITION_NTFS; 1329 dos_data->system |= dos_data->hidden ? PART_FLAG_HIDDEN : 0; 1330 } else if (!strcmp (fs_type->name, "sun-ufs")) 1331 dos_data->system = PARTITION_SUN_UFS; 1332 else if (!strcmp (fs_type->name, "solaris")) 1333 dos_data->system = PARTITION_SUN_UFS; 1334 else if (!strcmp (fs_type->name, "linux-swap")) 1335 dos_data->system = PARTITION_LINUX_SWAP; 1336 else 1337 dos_data->system = PARTITION_LINUX; 1338 1339 return 1; 1340 } 1341 1342 static int 1343 msdos_partition_set_flag (PedPartition* part, 1344 PedPartitionFlag flag, int state) 1345 { 1346 PedDisk* disk; 1347 PedPartition* walk; 1348 DosPartitionData* dos_data; 1349 1350 PED_ASSERT (part != NULL, return 0); 1351 PED_ASSERT (part->disk_specific != NULL, return 0); 1352 PED_ASSERT (part->disk != NULL, return 0); 1353 1354 dos_data = part->disk_specific; 1355 disk = part->disk; 1356 1357 switch (flag) { 1358 case PED_PARTITION_HIDDEN: 1359 if (part->type == PED_PARTITION_EXTENDED) { 1360 ped_exception_throw ( 1361 PED_EXCEPTION_ERROR, 1362 PED_EXCEPTION_CANCEL, 1363 _("Extended partitions cannot be hidden on " 1364 "msdos disk labels.")); 1365 return 0; 1366 } 1367 dos_data->hidden = state; 1368 return ped_partition_set_system (part, part->fs_type); 1369 1370 case PED_PARTITION_BOOT: 1371 dos_data->boot = state; 1372 if (!state) 1373 return 1; 1374 1375 walk = ped_disk_next_partition (disk, NULL); 1376 for (; walk; walk = ped_disk_next_partition (disk, walk)) { 1377 if (walk == part || !ped_partition_is_active (walk)) 1378 continue; 1379 msdos_partition_set_flag (walk, PED_PARTITION_BOOT, 0); 1380 } 1381 return 1; 1382 1383 case PED_PARTITION_RAID: 1384 if (state) { 1385 dos_data->hidden = 0; 1386 dos_data->lvm = 0; 1387 dos_data->palo = 0; 1388 dos_data->prep = 0; 1389 } 1390 dos_data->raid = state; 1391 return ped_partition_set_system (part, part->fs_type); 1392 1393 case PED_PARTITION_LVM: 1394 if (state) { 1395 dos_data->hidden = 0; 1396 dos_data->raid = 0; 1397 dos_data->palo = 0; 1398 dos_data->prep = 0; 1399 } 1400 dos_data->lvm = state; 1401 return ped_partition_set_system (part, part->fs_type); 1402 1403 case PED_PARTITION_LBA: 1404 dos_data->lba = state; 1405 return ped_partition_set_system (part, part->fs_type); 1406 1407 case PED_PARTITION_PALO: 1408 if (state) { 1409 dos_data->hidden = 0; 1410 dos_data->raid = 0; 1411 dos_data->lvm = 0; 1412 } 1413 dos_data->palo = state; 1414 return ped_partition_set_system (part, part->fs_type); 1415 1416 case PED_PARTITION_PREP: 1417 if (state) { 1418 dos_data->hidden = 0; 1419 dos_data->raid = 0; 1420 dos_data->lvm = 0; 1421 } 1422 dos_data->prep = state; 1423 return ped_partition_set_system (part, part->fs_type); 1424 1425 default: 1426 return 0; 1427 } 1428 } 1429 1430 static int 1431 msdos_partition_get_flag (const PedPartition* part, PedPartitionFlag flag) 1432 { 1433 DosPartitionData* dos_data; 1434 1435 PED_ASSERT (part != NULL, return 0); 1436 PED_ASSERT (part->disk_specific != NULL, return 0); 1437 1438 dos_data = part->disk_specific; 1439 switch (flag) { 1440 case PED_PARTITION_HIDDEN: 1441 return dos_data->hidden; 1442 1443 case PED_PARTITION_BOOT: 1444 return dos_data->boot; 1445 1446 case PED_PARTITION_RAID: 1447 return dos_data->raid; 1448 1449 case PED_PARTITION_LVM: 1450 return dos_data->lvm; 1451 1452 case PED_PARTITION_LBA: 1453 return dos_data->lba; 1454 1455 case PED_PARTITION_PALO: 1456 return dos_data->palo; 1457 1458 case PED_PARTITION_PREP: 1459 return dos_data->prep; 1460 1461 default: 1462 return 0; 1463 } 1464 } 1465 1466 static int 1467 msdos_partition_is_flag_available (const PedPartition* part, 1468 PedPartitionFlag flag) 1469 { 1470 switch (flag) { 1471 case PED_PARTITION_HIDDEN: 1472 case PED_PARTITION_BOOT: 1473 case PED_PARTITION_RAID: 1474 case PED_PARTITION_LVM: 1475 case PED_PARTITION_LBA: 1476 case PED_PARTITION_PALO: 1477 case PED_PARTITION_PREP: 1478 return 1; 1479 1480 default: 1481 return 0; 1482 } 1483 } 1484 1485 static PedGeometry* 1486 _try_constraint (const PedPartition* part, const PedConstraint* external, 1487 PedConstraint* internal) 1488 { 1489 PedConstraint* intersection; 1490 PedGeometry* solution; 1491 1492 intersection = ped_constraint_intersect (external, internal); 1493 ped_constraint_destroy (internal); 1494 if (!intersection) 1495 return NULL; 1496 1497 solution = ped_constraint_solve_nearest (intersection, &part->geom); 1498 ped_constraint_destroy (intersection); 1499 return solution; 1500 } 1501 1502 static PedGeometry* 1503 _best_solution (const PedPartition* part, const PedCHSGeometry* bios_geom, 1504 PedGeometry* a, PedGeometry* b) 1505 { 1506 PedSector cyl_size = bios_geom->heads * bios_geom->sectors; 1507 int a_cylinder; 1508 int b_cylinder; 1509 1510 if (!a) 1511 return b; 1512 if (!b) 1513 return a; 1514 1515 a_cylinder = a->start / cyl_size; 1516 b_cylinder = b->start / cyl_size; 1517 1518 if (a_cylinder == b_cylinder) { 1519 if ( (a->start / bios_geom->sectors) % bios_geom->heads 1520 < (b->start / bios_geom->sectors) % bios_geom->heads) 1521 goto choose_a; 1522 else 1523 goto choose_b; 1524 } else { 1525 PedSector a_delta; 1526 PedSector b_delta; 1527 1528 a_delta = abs (part->geom.start - a->start); 1529 b_delta = abs (part->geom.start - b->start); 1530 1531 if (a_delta < b_delta) 1532 goto choose_a; 1533 else 1534 goto choose_b; 1535 } 1536 1537 return NULL; /* never get here! */ 1538 1539 choose_a: 1540 ped_geometry_destroy (b); 1541 return a; 1542 1543 choose_b: 1544 ped_geometry_destroy (a); 1545 return b; 1546 } 1547 1548 /* This constraint is for "normal" primary partitions, that start at the 1549 * beginning of a cylinder, and end at the end of a cylinder. 1550 * Note: you can't start a partition at the beginning of the 1st 1551 * cylinder, because that's where the partition table is! There are different 1552 * rules for that - see the _primary_start_constraint. 1553 */ 1554 static PedConstraint* 1555 _primary_constraint (const PedDisk* disk, const PedCHSGeometry* bios_geom, 1556 PedGeometry* min_geom) 1557 { 1558 PedDevice* dev = disk->dev; 1559 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads; 1560 PedAlignment start_align; 1561 PedAlignment end_align; 1562 PedGeometry start_geom; 1563 PedGeometry end_geom; 1564 1565 if (!ped_alignment_init (&start_align, 0, cylinder_size)) 1566 return NULL; 1567 if (!ped_alignment_init (&end_align, -1, cylinder_size)) 1568 return NULL; 1569 1570 if (min_geom) { 1571 if (min_geom->start < cylinder_size) 1572 return NULL; 1573 if (!ped_geometry_init (&start_geom, dev, cylinder_size, 1574 min_geom->start + 1 - cylinder_size)) 1575 return NULL; 1576 if (!ped_geometry_init (&end_geom, dev, min_geom->end, 1577 dev->length - min_geom->end)) 1578 return NULL; 1579 } else { 1580 if (!ped_geometry_init (&start_geom, dev, cylinder_size, 1581 dev->length - cylinder_size)) 1582 return NULL; 1583 if (!ped_geometry_init (&end_geom, dev, 0, dev->length)) 1584 return NULL; 1585 } 1586 1587 return ped_constraint_new (&start_align, &end_align, &start_geom, 1588 &end_geom, 1, dev->length); 1589 } 1590 1591 /* This constraint is for partitions starting on the first cylinder. They 1592 * must start on the 2nd head of the 1st cylinder. 1593 * 1594 * NOTE: We don't always start on the 2nd head of the 1st cylinder. Windows 1595 * Vista aligns starting partitions at sector 2048 (0x800) by default. See: 1596 * http://support.microsoft.com/kb/923332 1597 */ 1598 static PedConstraint* 1599 _primary_start_constraint (const PedDisk* disk, 1600 const PedPartition *part, 1601 const PedCHSGeometry* bios_geom, 1602 const PedGeometry* min_geom) 1603 { 1604 PedDevice* dev = disk->dev; 1605 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads; 1606 PedAlignment start_align; 1607 PedAlignment end_align; 1608 PedGeometry start_geom; 1609 PedGeometry end_geom; 1610 PedSector start_pos; 1611 1612 if (part->geom.start == 2048) 1613 /* check for known Windows Vista (NTFS >= 3.1) alignments */ 1614 /* sector 0x800 == 2048 */ 1615 start_pos = 2048; 1616 else 1617 /* all other primary partitions on a DOS label align to */ 1618 /* the 2nd head of the first cylinder (0x3F == 63) */ 1619 start_pos = bios_geom->sectors; 1620 1621 if (!ped_alignment_init (&start_align, start_pos, 0)) 1622 return NULL; 1623 if (!ped_alignment_init (&end_align, -1, cylinder_size)) 1624 return NULL; 1625 if (min_geom) { 1626 if (!ped_geometry_init (&start_geom, dev, start_pos, 1)) 1627 return NULL; 1628 if (!ped_geometry_init (&end_geom, dev, min_geom->end, 1629 dev->length - min_geom->end)) 1630 return NULL; 1631 } else { 1632 if (!ped_geometry_init (&start_geom, dev, start_pos, 1633 dev->length - start_pos)) 1634 return NULL; 1635 if (!ped_geometry_init (&end_geom, dev, 0, dev->length)) 1636 return NULL; 1637 } 1638 1639 return ped_constraint_new (&start_align, &end_align, &start_geom, 1640 &end_geom, 1, dev->length); 1641 } 1642 1643 /* constraints for logical partitions: 1644 * - start_offset is the offset in the start alignment. "normally", 1645 * this is bios_geom->sectors. exceptions: MINOR > 5 at the beginning of the 1646 * extended partition, or MINOR == 5 in the middle of the extended partition 1647 * - is_start_part == 1 if the constraint is for the first cylinder of 1648 * the extended partition, or == 0 if the constraint is for the second cylinder 1649 * onwards of the extended partition. 1650 */ 1651 static PedConstraint* 1652 _logical_constraint (const PedDisk* disk, const PedCHSGeometry* bios_geom, 1653 PedSector start_offset, int is_start_part) 1654 { 1655 PedPartition* ext_part = ped_disk_extended_partition (disk); 1656 PedDevice* dev = disk->dev; 1657 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads; 1658 PedAlignment start_align; 1659 PedAlignment end_align; 1660 PedGeometry max_geom; 1661 1662 PED_ASSERT (ext_part != NULL, return NULL); 1663 1664 if (!ped_alignment_init (&start_align, start_offset, cylinder_size)) 1665 return NULL; 1666 if (!ped_alignment_init (&end_align, -1, cylinder_size)) 1667 return NULL; 1668 if (is_start_part) { 1669 if (!ped_geometry_init (&max_geom, dev, 1670 ext_part->geom.start, 1671 ext_part->geom.length)) 1672 return NULL; 1673 } else { 1674 PedSector min_start; 1675 PedSector max_length; 1676 1677 min_start = ped_round_up_to (ext_part->geom.start + 1, 1678 cylinder_size); 1679 max_length = ext_part->geom.end - min_start + 1; 1680 if (min_start >= ext_part->geom.end) 1681 return NULL; 1682 1683 if (!ped_geometry_init (&max_geom, dev, min_start, max_length)) 1684 return NULL; 1685 } 1686 1687 return ped_constraint_new (&start_align, &end_align, &max_geom, 1688 &max_geom, 1, dev->length); 1689 } 1690 1691 /* returns the minimum geometry for the extended partition, given that the 1692 * extended partition must contain: 1693 * * all logical partitions 1694 * * all partition tables for all logical partitions (except the first) 1695 * * the extended partition table 1696 */ 1697 static PedGeometry* 1698 _get_min_extended_part_geom (const PedPartition* ext_part, 1699 const PedCHSGeometry* bios_geom) 1700 { 1701 PedDisk* disk = ext_part->disk; 1702 PedSector head_size = bios_geom ? bios_geom->sectors : 1; 1703 PedPartition* walk; 1704 PedGeometry* min_geom; 1705 1706 walk = ped_disk_get_partition (disk, 5); 1707 if (!walk) 1708 return NULL; 1709 1710 min_geom = ped_geometry_duplicate (&walk->geom); 1711 if (!min_geom) 1712 return NULL; 1713 ped_geometry_set_start (min_geom, walk->geom.start - 1 * head_size); 1714 1715 for (walk = ext_part->part_list; walk; walk = walk->next) { 1716 if (!ped_partition_is_active (walk) || walk->num == 5) 1717 continue; 1718 if (walk->geom.start < min_geom->start) 1719 ped_geometry_set_start (min_geom, 1720 walk->geom.start - 2 * head_size); 1721 if (walk->geom.end > min_geom->end) 1722 ped_geometry_set_end (min_geom, walk->geom.end); 1723 } 1724 1725 return min_geom; 1726 } 1727 1728 static int 1729 _align_primary (PedPartition* part, const PedCHSGeometry* bios_geom, 1730 const PedConstraint* constraint) 1731 { 1732 PedDisk* disk = part->disk; 1733 PedGeometry* min_geom = NULL; 1734 PedGeometry* solution = NULL; 1735 1736 if (part->type == PED_PARTITION_EXTENDED) 1737 min_geom = _get_min_extended_part_geom (part, bios_geom); 1738 1739 solution = _best_solution (part, bios_geom, solution, 1740 _try_constraint (part, constraint, 1741 _primary_start_constraint (disk, part, 1742 bios_geom, min_geom))); 1743 1744 solution = _best_solution (part, bios_geom, solution, 1745 _try_constraint (part, constraint, 1746 _primary_constraint (disk, bios_geom, 1747 min_geom))); 1748 1749 if (min_geom) 1750 ped_geometry_destroy (min_geom); 1751 1752 if (solution) { 1753 ped_geometry_set (&part->geom, solution->start, 1754 solution->length); 1755 ped_geometry_destroy (solution); 1756 return 1; 1757 } 1758 1759 return 0; 1760 } 1761 1762 static int 1763 _logical_min_start_head (const PedPartition* part, 1764 const PedCHSGeometry* bios_geom, 1765 const PedPartition* ext_part, 1766 int is_start_ext_part) 1767 { 1768 PedSector cylinder_size = bios_geom->sectors * bios_geom->heads; 1769 PedSector base_head; 1770 1771 if (is_start_ext_part) 1772 base_head = 1 + (ext_part->geom.start % cylinder_size) 1773 / bios_geom->sectors; 1774 else 1775 base_head = 0; 1776 1777 if (part->num == 5) 1778 return base_head + 0; 1779 else 1780 return base_head + 1; 1781 } 1782 1783 /* Shamelessly copied and adapted from _partition_get_overlap_constraint 1784 * (in disk.c) 1785 * This should get ride of the infamous Assertion (metadata_length > 0) failed 1786 * bug for extended msdos disklabels generated by Parted. 1787 * 1) There always is a partition table at the start of ext_part, so we leave 1788 * a one sector gap there. 1789 * 2)*The partition table of part5 is always at the beginning of the ext_part 1790 * so there is no need to leave a one sector gap before part5. 1791 * *There always is a partition table at the beginning of each partition != 5. 1792 * We don't need to worry to much about consistency with 1793 * _partition_get_overlap_constraint because missing it means we are in edge 1794 * cases anyway, and we don't lose anything by just refusing to do the job in 1795 * those cases. 1796 */ 1797 static PedConstraint* 1798 _log_meta_overlap_constraint (PedPartition* part, const PedGeometry* geom) 1799 { 1800 PedGeometry safe_space; 1801 PedSector min_start; 1802 PedSector max_end; 1803 PedPartition* ext_part = ped_disk_extended_partition (part->disk); 1804 PedPartition* walk; 1805 int not_5 = (part->num != 5); 1806 1807 PED_ASSERT (ext_part != NULL, return NULL); 1808 1809 walk = ext_part->part_list; 1810 1811 /* 1) 2) */ 1812 min_start = ext_part->geom.start + 1 + not_5; 1813 max_end = ext_part->geom.end; 1814 1815 while (walk != NULL /* 2) 2) */ 1816 && ( walk->geom.start - (walk->num != 5) < geom->start - not_5 1817 || walk->geom.start - (walk->num != 5) <= min_start )) { 1818 if (walk != part && ped_partition_is_active (walk)) 1819 min_start = walk->geom.end + 1 + not_5; /* 2) */ 1820 walk = walk->next; 1821 } 1822 1823 while (walk && (walk == part || !ped_partition_is_active (walk))) 1824 walk = walk->next; 1825 1826 if (walk) 1827 max_end = walk->geom.start - 1 - (walk->num != 5); /* 2) */ 1828 1829 if (min_start >= max_end) 1830 return NULL; 1831 1832 ped_geometry_init (&safe_space, part->disk->dev, 1833 min_start, max_end - min_start + 1); 1834 return ped_constraint_new_from_max (&safe_space); 1835 } 1836 1837 static int 1838 _align_logical (PedPartition* part, const PedCHSGeometry* bios_geom, 1839 const PedConstraint* constraint) 1840 { 1841 PedDisk* disk = part->disk; 1842 PedPartition* ext_part = ped_disk_extended_partition (disk); 1843 PedSector cyl_size = bios_geom->sectors * bios_geom->heads; 1844 PedSector start_base; 1845 int head; 1846 PedGeometry* solution = NULL; 1847 PedConstraint *intersect, *log_meta_overlap; 1848 1849 PED_ASSERT (ext_part != NULL, return 0); 1850 1851 log_meta_overlap = _log_meta_overlap_constraint(part, &part->geom); 1852 intersect = ped_constraint_intersect (constraint, log_meta_overlap); 1853 ped_constraint_destroy (log_meta_overlap); 1854 if (!intersect) 1855 return 0; 1856 1857 start_base = ped_round_down_to (part->geom.start, cyl_size); 1858 1859 for (head = _logical_min_start_head (part, bios_geom, ext_part, 0); 1860 head < PED_MIN (5, bios_geom->heads); head++) { 1861 PedConstraint* disk_constraint; 1862 PedSector start = start_base + head * bios_geom->sectors; 1863 1864 if (head >= _logical_min_start_head (part, bios_geom, 1865 ext_part, 1)) 1866 disk_constraint = 1867 _logical_constraint (disk, bios_geom, start, 1); 1868 else 1869 disk_constraint = 1870 _logical_constraint (disk, bios_geom, start, 0); 1871 1872 solution = _best_solution (part, bios_geom, solution, 1873 _try_constraint (part, intersect, 1874 disk_constraint)); 1875 } 1876 1877 ped_constraint_destroy (intersect); 1878 1879 if (solution) { 1880 ped_geometry_set (&part->geom, solution->start, 1881 solution->length); 1882 ped_geometry_destroy (solution); 1883 return 1; 1884 } 1885 1886 return 0; 1887 } 1888 1889 static int 1890 _align (PedPartition* part, const PedCHSGeometry* bios_geom, 1891 const PedConstraint* constraint) 1892 { 1893 if (part->type == PED_PARTITION_LOGICAL) 1894 return _align_logical (part, bios_geom, constraint); 1895 else 1896 return _align_primary (part, bios_geom, constraint); 1897 } 1898 1899 static PedConstraint* 1900 _no_geom_constraint (const PedDisk* disk, PedSector start, PedSector end) 1901 { 1902 PedGeometry max; 1903 1904 ped_geometry_init (&max, disk->dev, start, end - start + 1); 1905 return ped_constraint_new_from_max (&max); 1906 } 1907 1908 static PedConstraint* 1909 _no_geom_extended_constraint (const PedPartition* part) 1910 { 1911 PedDevice* dev = part->disk->dev; 1912 PedGeometry* min = _get_min_extended_part_geom (part, NULL); 1913 PedGeometry start_range; 1914 PedGeometry end_range; 1915 PedConstraint* constraint; 1916 1917 if (min) { 1918 ped_geometry_init (&start_range, dev, 1, min->start); 1919 ped_geometry_init (&end_range, dev, min->end, 1920 dev->length - min->end); 1921 ped_geometry_destroy (min); 1922 } else { 1923 ped_geometry_init (&start_range, dev, 1, dev->length - 1); 1924 ped_geometry_init (&end_range, dev, 1, dev->length - 1); 1925 } 1926 constraint = ped_constraint_new (ped_alignment_any, ped_alignment_any, 1927 &start_range, &end_range, 1, dev->length); 1928 return constraint; 1929 } 1930 1931 static int 1932 _align_primary_no_geom (PedPartition* part, const PedConstraint* constraint) 1933 { 1934 PedDisk* disk = part->disk; 1935 PedGeometry* solution; 1936 1937 if (part->type == PED_PARTITION_EXTENDED) { 1938 solution = _try_constraint (part, constraint, 1939 _no_geom_extended_constraint (part)); 1940 } else { 1941 solution = _try_constraint (part, constraint, 1942 _no_geom_constraint (disk, 1, 1943 disk->dev->length - 1)); 1944 } 1945 1946 if (solution) { 1947 ped_geometry_set (&part->geom, solution->start, 1948 solution->length); 1949 ped_geometry_destroy (solution); 1950 return 1; 1951 } 1952 return 0; 1953 } 1954 1955 static int 1956 _align_logical_no_geom (PedPartition* part, const PedConstraint* constraint) 1957 { 1958 PedGeometry* solution; 1959 1960 solution = _try_constraint (part, constraint, 1961 _log_meta_overlap_constraint (part, &part->geom)); 1962 1963 if (solution) { 1964 ped_geometry_set (&part->geom, solution->start, 1965 solution->length); 1966 ped_geometry_destroy (solution); 1967 return 1; 1968 } 1969 return 0; 1970 } 1971 1972 static int 1973 _align_no_geom (PedPartition* part, const PedConstraint* constraint) 1974 { 1975 if (part->type == PED_PARTITION_LOGICAL) 1976 return _align_logical_no_geom (part, constraint); 1977 else 1978 return _align_primary_no_geom (part, constraint); 1979 } 1980 1981 static int 1982 msdos_partition_align (PedPartition* part, const PedConstraint* constraint) 1983 { 1984 PedCHSGeometry bios_geom; 1985 DosPartitionData* dos_data; 1986 1987 PED_ASSERT (part != NULL, return 0); 1988 PED_ASSERT (part->disk_specific != NULL, return 0); 1989 1990 dos_data = part->disk_specific; 1991 if (dos_data->system == PARTITION_LDM && dos_data->orig) { 1992 PedGeometry *orig_geom = &dos_data->orig->geom; 1993 1994 if (ped_geometry_test_equal (&part->geom, orig_geom) 1995 && ped_constraint_is_solution (constraint, &part->geom)) 1996 return 1; 1997 1998 ped_geometry_set (&part->geom, orig_geom->start, 1999 orig_geom->length); 2000 ped_exception_throw ( 2001 PED_EXCEPTION_ERROR, 2002 PED_EXCEPTION_CANCEL, 2003 _("Parted can't resize partitions managed by " 2004 "Windows Dynamic Disk.")); 2005 return 0; 2006 } 2007 2008 partition_probe_bios_geometry (part, &bios_geom); 2009 2010 if (_align (part, &bios_geom, constraint)) 2011 return 1; 2012 if (_align_no_geom (part, constraint)) 2013 return 1; 2014 2015 #ifndef DISCOVER_ONLY 2016 ped_exception_throw ( 2017 PED_EXCEPTION_ERROR, 2018 PED_EXCEPTION_CANCEL, 2019 _("Unable to satisfy all constraints on the partition.")); 2020 #endif 2021 return 0; 2022 } 2023 2024 static int 2025 add_metadata_part (PedDisk* disk, PedPartitionType type, PedSector start, 2026 PedSector end) 2027 { 2028 PedPartition* new_part; 2029 2030 PED_ASSERT (disk != NULL, return 0); 2031 2032 new_part = ped_partition_new (disk, type | PED_PARTITION_METADATA, NULL, 2033 start, end); 2034 if (!new_part) 2035 goto error; 2036 if (!ped_disk_add_partition (disk, new_part, NULL)) 2037 goto error_destroy_new_part; 2038 2039 return 1; 2040 2041 error_destroy_new_part: 2042 ped_partition_destroy (new_part); 2043 error: 2044 return 0; 2045 } 2046 2047 /* There are a few objectives here: 2048 * - avoid having lots of "free space" partitions lying around, to confuse 2049 * the front end. 2050 * - ensure that there's enough room to put in the extended partition 2051 * tables, etc. 2052 */ 2053 static int 2054 add_logical_part_metadata (PedDisk* disk, const PedPartition* log_part) 2055 { 2056 PedPartition* ext_part = ped_disk_extended_partition (disk); 2057 PedPartition* prev = log_part->prev; 2058 PedCHSGeometry bios_geom; 2059 PedSector cyl_size; 2060 PedSector metadata_start; 2061 PedSector metadata_end; 2062 PedSector metadata_length; 2063 2064 partition_probe_bios_geometry (ext_part, &bios_geom); 2065 cyl_size = bios_geom.sectors * bios_geom.heads; 2066 2067 /* if there's metadata shortly before the partition (on the same 2068 * cylinder), then make this new metadata partition touch the end of 2069 * the other. No point having 63 bytes (or whatever) of free space 2070 * partition - just confuses front-ends, etc. 2071 * Otherwise, start the metadata at the start of the cylinder 2072 */ 2073 2074 metadata_end = log_part->geom.start - 1; 2075 metadata_start = ped_round_down_to (metadata_end, cyl_size); 2076 if (prev) 2077 metadata_start = PED_MAX (metadata_start, prev->geom.end + 1); 2078 else 2079 metadata_start = PED_MAX (metadata_start, 2080 ext_part->geom.start + 1); 2081 metadata_length = metadata_end - metadata_start + 1; 2082 2083 /* partition 5 doesn't need to have any metadata */ 2084 if (log_part->num == 5 && metadata_length < bios_geom.sectors) 2085 return 1; 2086 2087 PED_ASSERT (metadata_length > 0, return 0); 2088 2089 return add_metadata_part (disk, PED_PARTITION_LOGICAL, 2090 metadata_start, metadata_end); 2091 } 2092 2093 static PedPartition* 2094 get_last_part (const PedDisk* disk) 2095 { 2096 PedPartition* first_part = disk->part_list; 2097 PedPartition* walk; 2098 2099 if (!first_part) 2100 return NULL; 2101 for (walk = first_part; walk->next; walk = walk->next); 2102 return walk; 2103 } 2104 2105 /* Adds metadata placeholder partitions to cover the partition table (and 2106 * "free" space after it that often has bootloader stuff), and the last 2107 * incomplete cylinder at the end of the disk. 2108 * Parted has to be mindful of the uncertainty of dev->bios_geom. 2109 * It therefore makes sure this metadata doesn't overlap with partitions. 2110 */ 2111 static int 2112 add_startend_metadata (PedDisk* disk) 2113 { 2114 PedDevice* dev = disk->dev; 2115 PedSector cyl_size = dev->bios_geom.sectors * dev->bios_geom.heads; 2116 PedPartition* first_part = disk->part_list; 2117 PedPartition* last_part = get_last_part (disk); 2118 PedSector start, end; 2119 2120 if (!first_part) 2121 return 1; 2122 2123 start = 0; 2124 end = PED_MIN (dev->bios_geom.sectors - 1, first_part->geom.start - 1); 2125 if (!add_metadata_part (disk, PED_PARTITION_NORMAL, start, end)) 2126 return 0; 2127 2128 start = PED_MAX (last_part->geom.end + 1, 2129 ped_round_down_to (dev->length, cyl_size)); 2130 end = dev->length - 1; 2131 if (start < end) { 2132 if (!add_metadata_part (disk, PED_PARTITION_NORMAL, start, end)) 2133 return 0; 2134 } 2135 2136 return 1; 2137 } 2138 2139 static int 2140 msdos_alloc_metadata (PedDisk* disk) 2141 { 2142 PedPartition* ext_part; 2143 2144 PED_ASSERT (disk != NULL, return 0); 2145 PED_ASSERT (disk->dev != NULL, return 0); 2146 2147 if (!add_startend_metadata (disk)) 2148 return 0; 2149 2150 ext_part = ped_disk_extended_partition (disk); 2151 if (ext_part) { 2152 int i; 2153 PedSector start, end; 2154 PedCHSGeometry bios_geom; 2155 2156 for (i=5; 1; i++) { 2157 PedPartition* log_part; 2158 log_part = ped_disk_get_partition (disk, i); 2159 if (!log_part) 2160 break; 2161 if (!add_logical_part_metadata (disk, log_part)) 2162 return 0; 2163 } 2164 2165 partition_probe_bios_geometry (ext_part, &bios_geom); 2166 start = ext_part->geom.start; 2167 end = start + bios_geom.sectors - 1; 2168 if (ext_part->part_list) 2169 end = PED_MIN (end, 2170 ext_part->part_list->geom.start - 1); 2171 if (!add_metadata_part (disk, PED_PARTITION_LOGICAL, 2172 start, end)) 2173 return 0; 2174 } 2175 2176 return 1; 2177 } 2178 2179 static int 2180 next_primary (const PedDisk* disk) 2181 { 2182 int i; 2183 for (i=1; i<=4; i++) { 2184 if (!ped_disk_get_partition (disk, i)) 2185 return i; 2186 } 2187 return 0; 2188 } 2189 2190 static int 2191 next_logical (const PedDisk* disk) 2192 { 2193 int i; 2194 for (i=5; 1; i++) { 2195 if (!ped_disk_get_partition (disk, i)) 2196 return i; 2197 } 2198 } 2199 2200 static int 2201 msdos_partition_enumerate (PedPartition* part) 2202 { 2203 PED_ASSERT (part != NULL, return 0); 2204 PED_ASSERT (part->disk != NULL, return 0); 2205 2206 /* don't re-number a primary partition */ 2207 if (part->num != -1 && part->num <= 4) 2208 return 1; 2209 2210 part->num = -1; 2211 2212 if (part->type & PED_PARTITION_LOGICAL) 2213 part->num = next_logical (part->disk); 2214 else 2215 part->num = next_primary (part->disk); 2216 2217 return 1; 2218 } 2219 2220 static int 2221 msdos_get_max_primary_partition_count (const PedDisk* disk) 2222 { 2223 return 4; 2224 } 2225 2226 static PedDiskOps msdos_disk_ops = { 2227 .probe = msdos_probe, 2228 #ifndef DISCOVER_ONLY 2229 .clobber = msdos_clobber, 2230 #else 2231 .clobber = NULL, 2232 #endif 2233 .alloc = msdos_alloc, 2234 .duplicate = msdos_duplicate, 2235 .free = msdos_free, 2236 .read = msdos_read, 2237 #ifndef DISCOVER_ONLY 2238 .write = msdos_write, 2239 #else 2240 .write = NULL, 2241 #endif 2242 2243 .partition_new = msdos_partition_new, 2244 .partition_duplicate = msdos_partition_duplicate, 2245 .partition_destroy = msdos_partition_destroy, 2246 .partition_set_system = msdos_partition_set_system, 2247 .partition_set_flag = msdos_partition_set_flag, 2248 .partition_get_flag = msdos_partition_get_flag, 2249 .partition_is_flag_available = msdos_partition_is_flag_available, 2250 .partition_set_name = NULL, 2251 .partition_get_name = NULL, 2252 .partition_align = msdos_partition_align, 2253 .partition_enumerate = msdos_partition_enumerate, 2254 2255 .alloc_metadata = msdos_alloc_metadata, 2256 .get_max_primary_partition_count = 2257 msdos_get_max_primary_partition_count 2258 }; 2259 2260 static PedDiskType msdos_disk_type = { 2261 .next = NULL, 2262 .name = "msdos", 2263 .ops = &msdos_disk_ops, 2264 .features = PED_DISK_TYPE_EXTENDED 2265 }; 2266 2267 void 2268 ped_disk_msdos_init () 2269 { 2270 PED_ASSERT (sizeof (DosRawPartition) == 16, return); 2271 PED_ASSERT (sizeof (DosRawTable) == 512, return); 2272 2273 ped_disk_type_register (&msdos_disk_type); 2274 } 2275 2276 void 2277 ped_disk_msdos_done () 2278 { 2279 ped_disk_type_unregister (&msdos_disk_type); 2280 }