OSDN Git Service

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