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 }