1 /* 2 libparted - a library for manipulating disk partitions 3 Copyright (C) 2000, 2001, 2007 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <config.h> 20 21 #include <parted/parted.h> 22 #include <parted/debug.h> 23 #include <parted/endian.h> 24 25 #if ENABLE_NLS 26 # include <libintl.h> 27 # define _(String) dgettext (PACKAGE, String) 28 #else 29 # define _(String) (String) 30 #endif /* ENABLE_NLS */ 31 32 /* hacked from Linux/98 source: fs/partitions/nec98.h 33 * 34 * See also: 35 * http://people.FreeBSD.org/~kato/pc98.html 36 * http://www.kmc.kyoto-u.ac.jp/proj/linux98/index-english.html 37 * 38 * Partition types: 39 * 40 * id0(mid): 41 * bit 7: 1=bootable, 0=not bootable 42 * # Linux uses this flag to make a distinction between ext2 and swap. 43 * bit 6--0: 44 * 00H : N88-BASIC(data)?, PC-UX(data)? 45 * 04H : PC-UX(data) 46 * 06H : N88-BASIC 47 * 10H : N88-BASIC 48 * 14H : *BSD, PC-UX 49 * 20H : DOS(data), Windows95/98/NT, Linux 50 * 21H..2FH : DOS(system#1 .. system#15) 51 * 40H : Minix 52 * 53 * id1(sid): 54 * bit 7: 1=active, 0=sleep(hidden) 55 * # PC-UX uses this flag to make a distinction between its file system 56 * # and its swap. 57 * bit 6--0: 58 * 01H: FAT12 59 * 11H: FAT16, <32MB [accessible to DOS 3.3] 60 * 21H: FAT16, >=32MB [Large Partition] 61 * 31H: NTFS 62 * 28H: Windows NT (Volume/Stripe Set?) 63 * 41H: Windows NT (Volume/Stripe Set?) 64 * 48H: Windows NT (Volume/Stripe Set?) 65 * 61H: FAT32 66 * 04H: PC-UX 67 * 06H: N88-BASIC 68 * 44H: *BSD 69 * 62H: ext2, linux-swap 70 */ 71 72 #define MAX_PART_COUNT 16 73 #define PC9800_EXTFMT_MAGIC 0xAA55 74 75 #define BIT(x) (1 << (x)) 76 #define GET_BIT(n,bit) (((n) & BIT(bit)) != 0) 77 #define SET_BIT(n,bit,val) n = (val)? (n | BIT(bit)) : (n & ~BIT(bit)) 78 79 typedef struct _PC98RawPartition PC98RawPartition; 80 typedef struct _PC98RawTable PC98RawTable; 81 82 #ifdef __sun 83 #define __attribute__(X) /*nothing*/ 84 #endif /* __sun */ 85 86 /* ripped from Linux/98 source */ 87 #ifdef __sun 88 #pragma pack(1) 89 #endif 90 struct _PC98RawPartition { 91 uint8_t mid; /* 0x80 - boot */ 92 uint8_t sid; /* 0x80 - active */ 93 uint8_t dum1; /* dummy for padding */ 94 uint8_t dum2; /* dummy for padding */ 95 uint8_t ipl_sect; /* IPL sector */ 96 uint8_t ipl_head; /* IPL head */ 97 uint16_t ipl_cyl; /* IPL cylinder */ 98 uint8_t sector; /* starting sector */ 99 uint8_t head; /* starting head */ 100 uint16_t cyl; /* starting cylinder */ 101 uint8_t end_sector; /* end sector */ 102 uint8_t end_head; /* end head */ 103 uint16_t end_cyl; /* end cylinder */ 104 char name[16]; 105 } __attribute__((packed)); 106 107 struct _PC98RawTable { 108 uint8_t boot_code [510]; 109 uint16_t magic; 110 PC98RawPartition partitions [MAX_PART_COUNT]; 111 } __attribute__((packed)); 112 #ifdef __sun 113 #pragma pack() 114 #endif 115 116 typedef struct { 117 PedSector ipl_sector; 118 int system; 119 int boot; 120 int hidden; 121 char name [17]; 122 } PC98PartitionData; 123 124 /* this MBR boot code is dummy */ 125 static const unsigned char MBR_BOOT_CODE[] = { 126 0xcb, /* retf */ 127 0x00, 0x00, 0x00, /* */ 128 0x49, 0x50, 0x4c, 0x31 /* "IPL1" */ 129 }; 130 131 static PedDiskType pc98_disk_type; 132 133 static PedSector chs_to_sector (const PedDevice* dev, int c, int h, int s); 134 static void sector_to_chs (const PedDevice* dev, PedSector sector, 135 int* c, int* h, int* s); 136 137 /* magic(?) check */ 138 static int 139 pc98_check_magic (const PC98RawTable *part_table) 140 { 141 /* check "extended-format" (have partition table?) */ 142 if (PED_LE16_TO_CPU(part_table->magic) != PC9800_EXTFMT_MAGIC) 143 return 0; 144 145 return 1; 146 } 147 148 static int 149 pc98_check_ipl_signature (const PC98RawTable *part_table) 150 { 151 return !memcmp (part_table->boot_code + 4, "IPL1", 4); 152 } 153 154 static int 155 check_partition_consistency (const PedDevice* dev, 156 const PC98RawPartition* raw_part) 157 { 158 if (raw_part->ipl_sect >= dev->hw_geom.sectors 159 || raw_part->sector >= dev->hw_geom.sectors 160 || raw_part->end_sector >= dev->hw_geom.sectors 161 || raw_part->ipl_head >= dev->hw_geom.heads 162 || raw_part->head >= dev->hw_geom.heads 163 || raw_part->end_head >= dev->hw_geom.heads 164 || PED_LE16_TO_CPU(raw_part->ipl_cyl) >= dev->hw_geom.cylinders 165 || PED_LE16_TO_CPU(raw_part->cyl) >= dev->hw_geom.cylinders 166 || PED_LE16_TO_CPU(raw_part->end_cyl) >= dev->hw_geom.cylinders 167 || PED_LE16_TO_CPU(raw_part->cyl) 168 > PED_LE16_TO_CPU(raw_part->end_cyl) 169 #if 0 170 || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->ipl_cyl), 171 raw_part->ipl_head, raw_part->ipl_sect) 172 || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->cyl), 173 raw_part->head, raw_part->sector) 174 || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->end_cyl), 175 raw_part->end_head, raw_part->end_sector) 176 #endif 177 || PED_LE16_TO_CPU(raw_part->end_cyl) 178 < PED_LE16_TO_CPU(raw_part->cyl)) 179 return 0; 180 181 return 1; 182 } 183 184 static int 185 pc98_probe (const PedDevice *dev) 186 { 187 PC98RawTable part_table; 188 int empty; 189 const PC98RawPartition* p; 190 191 PED_ASSERT (dev != NULL, return 0); 192 193 if (dev->sector_size != 512) 194 return 0; 195 196 if (!ped_device_read (dev, &part_table, 0, 2)) 197 return 0; 198 199 /* check magic */ 200 if (!pc98_check_magic (&part_table)) 201 return 0; 202 203 /* check consistency */ 204 empty = 1; 205 for (p = part_table.partitions; 206 p < part_table.partitions + MAX_PART_COUNT; 207 p++) 208 { 209 if (p->mid == 0 && p->sid == 0) 210 continue; 211 empty = 0; 212 if (!check_partition_consistency (dev, p)) 213 return 0; 214 } 215 216 /* check boot loader */ 217 if (pc98_check_ipl_signature (&part_table)) 218 return 1; 219 else if (part_table.boot_code[0]) /* invalid boot loader */ 220 return 0; 221 222 /* Not to mistake msdos disk map for PC-9800's empty disk map */ 223 if (empty) 224 return 0; 225 226 return 1; 227 } 228 229 #ifndef DISCOVER_ONLY 230 static int 231 pc98_clobber (PedDevice* dev) 232 { 233 PC98RawTable table; 234 235 PED_ASSERT (dev != NULL, return 0); 236 PED_ASSERT (pc98_probe (dev), return 0); 237 238 if (!ped_device_read (dev, &table, 0, 1)) 239 return 0; 240 241 memset (table.partitions, 0, sizeof (table.partitions)); 242 table.magic = PED_CPU_TO_LE16(0); 243 244 if (pc98_check_ipl_signature (&table)) 245 memset (table.boot_code, 0, sizeof (table.boot_code)); 246 247 if (!ped_device_write (dev, (void*) &table, 0, 1)) 248 return 0; 249 return ped_device_sync (dev); 250 } 251 #endif /* !DISCOVER_ONLY */ 252 253 static PedDisk* 254 pc98_alloc (const PedDevice* dev) 255 { 256 PED_ASSERT (dev != NULL, return 0); 257 258 return _ped_disk_alloc (dev, &pc98_disk_type); 259 } 260 261 static PedDisk* 262 pc98_duplicate (const PedDisk* disk) 263 { 264 return ped_disk_new_fresh (disk->dev, &pc98_disk_type); 265 } 266 267 static void 268 pc98_free (PedDisk* disk) 269 { 270 PED_ASSERT (disk != NULL, return); 271 272 _ped_disk_free (disk); 273 } 274 275 static PedSector 276 chs_to_sector (const PedDevice* dev, int c, int h, int s) 277 { 278 PED_ASSERT (dev != NULL, return 0); 279 return (c * dev->hw_geom.heads + h) * dev->hw_geom.sectors + s; 280 } 281 282 static void 283 sector_to_chs (const PedDevice* dev, PedSector sector, int* c, int* h, int* s) 284 { 285 PedSector cyl_size; 286 287 PED_ASSERT (dev != NULL, return); 288 PED_ASSERT (c != NULL, return); 289 PED_ASSERT (h != NULL, return); 290 PED_ASSERT (s != NULL, return); 291 292 cyl_size = dev->hw_geom.heads * dev->hw_geom.sectors; 293 294 *c = sector / cyl_size; 295 *h = (sector) % cyl_size / dev->hw_geom.sectors; 296 *s = (sector) % cyl_size % dev->hw_geom.sectors; 297 } 298 299 static PedSector 300 legacy_start (const PedDisk* disk, const PC98RawPartition* raw_part) 301 { 302 PED_ASSERT (disk != NULL, return 0); 303 PED_ASSERT (raw_part != NULL, return 0); 304 305 return chs_to_sector (disk->dev, PED_LE16_TO_CPU(raw_part->cyl), 306 raw_part->head, raw_part->sector); 307 } 308 309 static PedSector 310 legacy_end (const PedDisk* disk, const PC98RawPartition* raw_part) 311 { 312 PED_ASSERT (disk != NULL, return 0); 313 PED_ASSERT (raw_part != NULL, return 0); 314 315 if (raw_part->end_head == 0 && raw_part->end_sector == 0) { 316 return chs_to_sector (disk->dev, 317 PED_LE16_TO_CPU(raw_part->end_cyl), 318 disk->dev->hw_geom.heads - 1, 319 disk->dev->hw_geom.sectors - 1); 320 } else { 321 return chs_to_sector (disk->dev, 322 PED_LE16_TO_CPU(raw_part->end_cyl), 323 raw_part->end_head, 324 raw_part->end_sector); 325 } 326 } 327 328 static int 329 is_unused_partition(const PC98RawPartition* raw_part) 330 { 331 if (raw_part->mid || raw_part->sid 332 || raw_part->ipl_sect 333 || raw_part->ipl_head 334 || PED_LE16_TO_CPU(raw_part->ipl_cyl) 335 || raw_part->sector 336 || raw_part->head 337 || PED_LE16_TO_CPU(raw_part->cyl) 338 || raw_part->end_sector 339 || raw_part->end_head 340 || PED_LE16_TO_CPU(raw_part->end_cyl)) 341 return 0; 342 return 1; 343 } 344 345 static int 346 read_table (PedDisk* disk) 347 { 348 int i; 349 PC98RawTable table; 350 PedConstraint* constraint_any; 351 352 PED_ASSERT (disk != NULL, return 0); 353 PED_ASSERT (disk->dev != NULL, return 0); 354 355 constraint_any = ped_constraint_any (disk->dev); 356 357 if (!ped_device_read (disk->dev, (void*) &table, 0, 2)) 358 goto error; 359 360 if (!pc98_check_magic(&table)) { 361 if (ped_exception_throw ( 362 PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL, 363 _("Invalid partition table on %s."), 364 disk->dev->path)) 365 goto error; 366 } 367 368 for (i = 0; i < MAX_PART_COUNT; i++) { 369 PC98RawPartition* raw_part; 370 PedPartition* part; 371 PC98PartitionData* pc98_data; 372 PedSector part_start; 373 PedSector part_end; 374 375 raw_part = &table.partitions [i]; 376 377 if (is_unused_partition(raw_part)) 378 continue; 379 380 part_start = legacy_start (disk, raw_part); 381 part_end = legacy_end (disk, raw_part); 382 383 part = ped_partition_new (disk, 0, NULL, part_start, part_end); 384 if (!part) 385 goto error; 386 pc98_data = part->disk_specific; 387 PED_ASSERT (pc98_data != NULL, goto error); 388 389 pc98_data->system = (raw_part->mid << 8) | raw_part->sid; 390 pc98_data->boot = GET_BIT(raw_part->mid, 7); 391 pc98_data->hidden = !GET_BIT(raw_part->sid, 7); 392 393 ped_partition_set_name (part, raw_part->name); 394 395 pc98_data->ipl_sector = chs_to_sector ( 396 disk->dev, 397 PED_LE16_TO_CPU(raw_part->ipl_cyl), 398 raw_part->ipl_head, 399 raw_part->ipl_sect); 400 401 /* hack */ 402 if (pc98_data->ipl_sector == part->geom.start) 403 pc98_data->ipl_sector = 0; 404 405 part->num = i + 1; 406 407 if (!ped_disk_add_partition (disk, part, constraint_any)) 408 goto error; 409 410 if (part->geom.start != part_start 411 || part->geom.end != part_end) { 412 ped_exception_throw ( 413 PED_EXCEPTION_NO_FEATURE, 414 PED_EXCEPTION_CANCEL, 415 _("Partition %d isn't aligned to cylinder " 416 "boundaries. This is still unsupported."), 417 part->num); 418 goto error; 419 } 420 421 part->fs_type = ped_file_system_probe (&part->geom); 422 } 423 424 ped_constraint_destroy (constraint_any); 425 return 1; 426 427 error: 428 ped_disk_delete_all (disk); 429 ped_constraint_destroy (constraint_any); 430 return 0; 431 } 432 433 static int 434 pc98_read (PedDisk* disk) 435 { 436 PED_ASSERT (disk != NULL, return 0); 437 PED_ASSERT (disk->dev != NULL, return 0); 438 439 ped_disk_delete_all (disk); 440 return read_table (disk); 441 } 442 443 #ifndef DISCOVER_ONLY 444 static int 445 fill_raw_part (PC98RawPartition* raw_part, const PedPartition* part) 446 { 447 PC98PartitionData* pc98_data; 448 int c, h, s; 449 const char* name; 450 451 PED_ASSERT (raw_part != NULL, return 0); 452 PED_ASSERT (part != NULL, return 0); 453 PED_ASSERT (part->disk_specific != NULL, return 0); 454 455 pc98_data = part->disk_specific; 456 raw_part->mid = (pc98_data->system >> 8) & 0xFF; 457 raw_part->sid = pc98_data->system & 0xFF; 458 459 SET_BIT(raw_part->mid, 7, pc98_data->boot); 460 SET_BIT(raw_part->sid, 7, !pc98_data->hidden); 461 462 memset (raw_part->name, ' ', sizeof(raw_part->name)); 463 name = ped_partition_get_name (part); 464 PED_ASSERT (name != NULL, return 0); 465 PED_ASSERT (strlen (name) <= 16, return 0); 466 if (!strlen (name) && part->fs_type) 467 name = part->fs_type->name; 468 memcpy (raw_part->name, name, strlen (name)); 469 470 sector_to_chs (part->disk->dev, part->geom.start, &c, &h, &s); 471 raw_part->cyl = PED_CPU_TO_LE16(c); 472 raw_part->head = h; 473 raw_part->sector = s; 474 475 if (pc98_data->ipl_sector) { 476 sector_to_chs (part->disk->dev, pc98_data->ipl_sector, 477 &c, &h, &s); 478 raw_part->ipl_cyl = PED_CPU_TO_LE16(c); 479 raw_part->ipl_head = h; 480 raw_part->ipl_sect = s; 481 } else { 482 raw_part->ipl_cyl = raw_part->cyl; 483 raw_part->ipl_head = raw_part->head; 484 raw_part->ipl_sect = raw_part->sector; 485 } 486 487 sector_to_chs (part->disk->dev, part->geom.end, &c, &h, &s); 488 if (h != part->disk->dev->hw_geom.heads - 1 489 || s != part->disk->dev->hw_geom.sectors - 1) { 490 ped_exception_throw ( 491 PED_EXCEPTION_NO_FEATURE, 492 PED_EXCEPTION_CANCEL, 493 _("Partition %d isn't aligned to cylinder " 494 "boundaries. This is still unsupported."), 495 part->num); 496 return 0; 497 } 498 raw_part->end_cyl = PED_CPU_TO_LE16(c); 499 #if 0 500 raw_part->end_head = h; 501 raw_part->end_sector = s; 502 #else 503 raw_part->end_head = 0; 504 raw_part->end_sector = 0; 505 #endif 506 507 return 1; 508 } 509 510 static int 511 pc98_write (const PedDisk* disk) 512 { 513 PC98RawTable table; 514 PedPartition* part; 515 int i; 516 517 PED_ASSERT (disk != NULL, return 0); 518 PED_ASSERT (disk->dev != NULL, return 0); 519 520 if (!ped_device_read (disk->dev, &table, 0, 2)) 521 return 0; 522 523 if (!pc98_check_ipl_signature (&table)) { 524 memset (table.boot_code, 0, sizeof(table.boot_code)); 525 memcpy (table.boot_code, MBR_BOOT_CODE, sizeof(MBR_BOOT_CODE)); 526 } 527 528 memset (table.partitions, 0, sizeof (table.partitions)); 529 table.magic = PED_CPU_TO_LE16(PC9800_EXTFMT_MAGIC); 530 531 for (i = 1; i <= MAX_PART_COUNT; i++) { 532 part = ped_disk_get_partition (disk, i); 533 if (!part) 534 continue; 535 536 if (!fill_raw_part (&table.partitions [i - 1], part)) 537 return 0; 538 } 539 540 if (!ped_device_write (disk->dev, (void*) &table, 0, 2)) 541 return 0; 542 return ped_device_sync (disk->dev); 543 } 544 #endif /* !DISCOVER_ONLY */ 545 546 static PedPartition* 547 pc98_partition_new ( 548 const PedDisk* disk, PedPartitionType part_type, 549 const PedFileSystemType* fs_type, PedSector start, PedSector end) 550 { 551 PedPartition* part; 552 PC98PartitionData* pc98_data; 553 554 part = _ped_partition_alloc (disk, part_type, fs_type, start, end); 555 if (!part) 556 goto error; 557 558 if (ped_partition_is_active (part)) { 559 part->disk_specific 560 = pc98_data = ped_malloc (sizeof (PC98PartitionData)); 561 if (!pc98_data) 562 goto error_free_part; 563 pc98_data->ipl_sector = 0; 564 pc98_data->hidden = 0; 565 pc98_data->boot = 0; 566 strcpy (pc98_data->name, ""); 567 } else { 568 part->disk_specific = NULL; 569 } 570 return part; 571 572 ped_free (pc98_data); 573 error_free_part: 574 ped_free (part); 575 error: 576 return 0; 577 } 578 579 static PedPartition* 580 pc98_partition_duplicate (const PedPartition* part) 581 { 582 PedPartition* new_part; 583 PC98PartitionData* new_pc98_data; 584 PC98PartitionData* old_pc98_data; 585 586 new_part = ped_partition_new (part->disk, part->type, 587 part->fs_type, part->geom.start, 588 part->geom.end); 589 if (!new_part) 590 return NULL; 591 new_part->num = part->num; 592 593 old_pc98_data = (PC98PartitionData*) part->disk_specific; 594 new_pc98_data = (PC98PartitionData*) new_part->disk_specific; 595 596 /* ugly, but C is ugly :p */ 597 memcpy (new_pc98_data, old_pc98_data, sizeof (PC98PartitionData)); 598 return new_part; 599 } 600 601 static void 602 pc98_partition_destroy (PedPartition* part) 603 { 604 PED_ASSERT (part != NULL, return); 605 606 if (ped_partition_is_active (part)) 607 ped_free (part->disk_specific); 608 ped_free (part); 609 } 610 611 static int 612 pc98_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type) 613 { 614 PC98PartitionData* pc98_data = part->disk_specific; 615 616 part->fs_type = fs_type; 617 618 pc98_data->system = 0x2062; 619 if (fs_type) { 620 if (!strcmp (fs_type->name, "fat16")) { 621 if (part->geom.length * 512 >= 32 * 1024 * 1024) 622 pc98_data->system = 0x2021; 623 else 624 pc98_data->system = 0x2011; 625 } else if (!strcmp (fs_type->name, "fat32")) { 626 pc98_data->system = 0x2061; 627 } else if (!strcmp (fs_type->name, "ntfs")) { 628 pc98_data->system = 0x2031; 629 } else if (!strncmp (fs_type->name, "ufs", 3)) { 630 pc98_data->system = 0x2044; 631 } else { /* ext2, reiser, xfs, etc. */ 632 /* ext2 partitions must be marked boot */ 633 pc98_data->boot = 1; 634 pc98_data->system = 0xa062; 635 } 636 } 637 638 if (pc98_data->boot) 639 pc98_data->system |= 0x8000; 640 if (!pc98_data->hidden) 641 pc98_data->system |= 0x0080; 642 return 1; 643 } 644 645 static int 646 pc98_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state) 647 { 648 PC98PartitionData* pc98_data; 649 650 PED_ASSERT (part != NULL, return 0); 651 PED_ASSERT (part->disk_specific != NULL, return 0); 652 653 pc98_data = part->disk_specific; 654 655 switch (flag) { 656 case PED_PARTITION_HIDDEN: 657 pc98_data->hidden = state; 658 return ped_partition_set_system (part, part->fs_type); 659 660 case PED_PARTITION_BOOT: 661 pc98_data->boot = state; 662 return ped_partition_set_system (part, part->fs_type); 663 664 default: 665 return 0; 666 } 667 } 668 669 static int 670 pc98_partition_get_flag (const PedPartition* part, PedPartitionFlag flag) 671 { 672 PC98PartitionData* pc98_data; 673 674 PED_ASSERT (part != NULL, return 0); 675 PED_ASSERT (part->disk_specific != NULL, return 0); 676 677 pc98_data = part->disk_specific; 678 switch (flag) { 679 case PED_PARTITION_HIDDEN: 680 return pc98_data->hidden; 681 682 case PED_PARTITION_BOOT: 683 return pc98_data->boot; 684 685 default: 686 return 0; 687 } 688 } 689 690 static int 691 pc98_partition_is_flag_available ( 692 const PedPartition* part, PedPartitionFlag flag) 693 { 694 switch (flag) { 695 case PED_PARTITION_HIDDEN: 696 case PED_PARTITION_BOOT: 697 return 1; 698 699 default: 700 return 0; 701 } 702 } 703 704 static void 705 pc98_partition_set_name (PedPartition* part, const char* name) 706 { 707 PC98PartitionData* pc98_data; 708 int i; 709 710 PED_ASSERT (part != NULL, return); 711 PED_ASSERT (part->disk_specific != NULL, return); 712 pc98_data = part->disk_specific; 713 714 strncpy (pc98_data->name, name, 16); 715 pc98_data->name [16] = 0; 716 for (i = strlen (pc98_data->name) - 1; pc98_data->name[i] == ' '; i--) 717 pc98_data->name [i] = 0; 718 } 719 720 static const char* 721 pc98_partition_get_name (const PedPartition* part) 722 { 723 PC98PartitionData* pc98_data; 724 725 PED_ASSERT (part != NULL, return NULL); 726 PED_ASSERT (part->disk_specific != NULL, return NULL); 727 pc98_data = part->disk_specific; 728 729 return pc98_data->name; 730 } 731 732 static PedConstraint* 733 _primary_constraint (PedDisk* disk) 734 { 735 PedDevice* dev = disk->dev; 736 PedAlignment start_align; 737 PedAlignment end_align; 738 PedGeometry max_geom; 739 PedSector cylinder_size; 740 741 cylinder_size = dev->hw_geom.sectors * dev->hw_geom.heads; 742 743 if (!ped_alignment_init (&start_align, 0, cylinder_size)) 744 return NULL; 745 if (!ped_alignment_init (&end_align, -1, cylinder_size)) 746 return NULL; 747 if (!ped_geometry_init (&max_geom, dev, cylinder_size, 748 dev->length - cylinder_size)) 749 return NULL; 750 751 return ped_constraint_new (&start_align, &end_align, &max_geom, 752 &max_geom, 1, dev->length); 753 } 754 755 static int 756 pc98_partition_align (PedPartition* part, const PedConstraint* constraint) 757 { 758 PED_ASSERT (part != NULL, return 0); 759 760 if (_ped_partition_attempt_align (part, constraint, 761 _primary_constraint (part->disk))) 762 return 1; 763 764 #ifndef DISCOVER_ONLY 765 ped_exception_throw ( 766 PED_EXCEPTION_ERROR, 767 PED_EXCEPTION_CANCEL, 768 _("Unable to satisfy all constraints on the partition.")); 769 #endif 770 return 0; 771 } 772 773 static int 774 next_primary (PedDisk* disk) 775 { 776 int i; 777 for (i=1; i<=MAX_PART_COUNT; i++) { 778 if (!ped_disk_get_partition (disk, i)) 779 return i; 780 } 781 return 0; 782 } 783 784 static int 785 pc98_partition_enumerate (PedPartition* part) 786 { 787 PED_ASSERT (part != NULL, return 0); 788 PED_ASSERT (part->disk != NULL, return 0); 789 790 /* don't re-number a partition */ 791 if (part->num != -1) 792 return 1; 793 794 PED_ASSERT (ped_partition_is_active (part), return 0); 795 796 part->num = next_primary (part->disk); 797 if (!part->num) { 798 ped_exception_throw (PED_EXCEPTION_ERROR, 799 PED_EXCEPTION_CANCEL, 800 _("Can't add another partition.")); 801 return 0; 802 } 803 804 return 1; 805 } 806 807 static int 808 pc98_alloc_metadata (PedDisk* disk) 809 { 810 PedPartition* new_part; 811 PedConstraint* constraint_any = NULL; 812 PedSector cyl_size; 813 814 PED_ASSERT (disk != NULL, goto error); 815 PED_ASSERT (disk->dev != NULL, goto error); 816 817 constraint_any = ped_constraint_any (disk->dev); 818 819 cyl_size = disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads; 820 new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, 821 0, cyl_size - 1); 822 if (!new_part) 823 goto error; 824 825 if (!ped_disk_add_partition (disk, new_part, constraint_any)) { 826 ped_partition_destroy (new_part); 827 goto error; 828 } 829 830 ped_constraint_destroy (constraint_any); 831 return 1; 832 833 error: 834 ped_constraint_destroy (constraint_any); 835 return 0; 836 } 837 838 static int 839 pc98_get_max_primary_partition_count (const PedDisk* disk) 840 { 841 return MAX_PART_COUNT; 842 } 843 844 static PedDiskOps pc98_disk_ops = { 845 .probe = pc98_probe, 846 #ifndef DISCOVER_ONLY 847 .clobber = pc98_clobber, 848 #else 849 .clobber = NULL, 850 #endif 851 .alloc = pc98_alloc, 852 .duplicate = pc98_duplicate, 853 .free = pc98_free, 854 .read = pc98_read, 855 #ifndef DISCOVER_ONLY 856 .write = pc98_write, 857 #else 858 .write = NULL, 859 #endif 860 861 .partition_new = pc98_partition_new, 862 .partition_duplicate = pc98_partition_duplicate, 863 .partition_destroy = pc98_partition_destroy, 864 .partition_set_system = pc98_partition_set_system, 865 .partition_set_flag = pc98_partition_set_flag, 866 .partition_get_flag = pc98_partition_get_flag, 867 .partition_is_flag_available = pc98_partition_is_flag_available, 868 .partition_set_name = pc98_partition_set_name, 869 .partition_get_name = pc98_partition_get_name, 870 .partition_align = pc98_partition_align, 871 .partition_enumerate = pc98_partition_enumerate, 872 873 .alloc_metadata = pc98_alloc_metadata, 874 .get_max_primary_partition_count = 875 pc98_get_max_primary_partition_count 876 }; 877 878 static PedDiskType pc98_disk_type = { 879 .next = NULL, 880 .name = "pc98", 881 .ops = &pc98_disk_ops, 882 .features = PED_DISK_TYPE_PARTITION_NAME 883 }; 884 885 void 886 ped_disk_pc98_init () 887 { 888 PED_ASSERT (sizeof (PC98RawTable) == 512 * 2, return); 889 ped_disk_type_register (&pc98_disk_type); 890 } 891 892 void 893 ped_disk_pc98_done () 894 { 895 ped_disk_type_unregister (&pc98_disk_type); 896 }