OSDN Git Service

mac: avoid NULL-deref-on-OOM and an error-path leak
[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         return !memcmp (part_table->boot_code + 4, "IPL1", 4);
144 }
145
146 static int
147 check_partition_consistency (const PedDevice* dev,
148                              const PC98RawPartition* raw_part)
149 {
150         if (raw_part->ipl_sect >= dev->hw_geom.sectors
151            || raw_part->sector >= dev->hw_geom.sectors
152            || raw_part->end_sector >= dev->hw_geom.sectors
153            || raw_part->ipl_head >= dev->hw_geom.heads
154            || raw_part->head >= dev->hw_geom.heads
155            || raw_part->end_head >= dev->hw_geom.heads
156            || PED_LE16_TO_CPU(raw_part->ipl_cyl) >= dev->hw_geom.cylinders
157            || PED_LE16_TO_CPU(raw_part->cyl) >= dev->hw_geom.cylinders
158            || PED_LE16_TO_CPU(raw_part->end_cyl) >= dev->hw_geom.cylinders
159            || PED_LE16_TO_CPU(raw_part->cyl)
160                 > PED_LE16_TO_CPU(raw_part->end_cyl)
161 #if 0
162            || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->ipl_cyl),
163                              raw_part->ipl_head, raw_part->ipl_sect)
164            || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->cyl),
165                              raw_part->head, raw_part->sector)
166            || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->end_cyl),
167                              raw_part->end_head, raw_part->end_sector)
168 #endif
169            || PED_LE16_TO_CPU(raw_part->end_cyl)
170                         < PED_LE16_TO_CPU(raw_part->cyl))
171                 return 0;
172
173         return 1;
174 }
175
176 static int
177 pc98_probe (const PedDevice *dev)
178 {
179         PC98RawTable            part_table;
180         int                     empty;
181         const PC98RawPartition* p;
182
183         PED_ASSERT (dev != NULL);
184
185         if (dev->sector_size != 512)
186                 return 0;
187
188         if (!ped_device_read (dev, &part_table, 0, 2))
189                 return 0;
190
191         /* check magic */
192         if (!pc98_check_magic (&part_table))
193                 return 0;
194
195         /* check consistency */
196         empty = 1;
197         for (p = part_table.partitions;
198              p < part_table.partitions + MAX_PART_COUNT;
199              p++)
200         {
201                 if (p->mid == 0 && p->sid == 0)
202                         continue;
203                 empty = 0;
204                 if (!check_partition_consistency (dev, p))
205                         return 0;
206         }
207
208         /* check boot loader */
209         if (pc98_check_ipl_signature (&part_table))
210                 return 1;
211         else if (part_table.boot_code[0])       /* invalid boot loader */
212                 return 0;
213
214         /* Not to mistake msdos disk map for PC-9800's empty disk map  */
215         if (empty)
216                 return 0;
217
218         return 1;
219 }
220
221 static PedDisk*
222 pc98_alloc (const PedDevice* dev)
223 {
224         PED_ASSERT (dev != NULL);
225
226         return _ped_disk_alloc (dev, &pc98_disk_type);
227 }
228
229 static PedDisk*
230 pc98_duplicate (const PedDisk* disk)
231 {
232         return ped_disk_new_fresh (disk->dev, &pc98_disk_type);
233 }
234
235 static void
236 pc98_free (PedDisk* disk)
237 {
238         PED_ASSERT (disk != NULL);
239
240         _ped_disk_free (disk);
241 }
242
243 static PedSector
244 chs_to_sector (const PedDevice* dev, int c, int h, int s)
245 {
246         PED_ASSERT (dev != NULL);
247         return (c * dev->hw_geom.heads + h) * dev->hw_geom.sectors + s;
248 }
249
250 static void
251 sector_to_chs (const PedDevice* dev, PedSector sector, int* c, int* h, int* s)
252 {
253         PedSector cyl_size;
254
255         PED_ASSERT (dev != NULL);
256         PED_ASSERT (c != NULL);
257         PED_ASSERT (h != NULL);
258         PED_ASSERT (s != NULL);
259
260         cyl_size = dev->hw_geom.heads * dev->hw_geom.sectors;
261
262         *c = sector / cyl_size;
263         *h = (sector) % cyl_size / dev->hw_geom.sectors;
264         *s = (sector) % cyl_size % dev->hw_geom.sectors;
265 }
266
267 static PedSector
268 legacy_start (const PedDisk* disk, const PC98RawPartition* raw_part)
269 {
270         PED_ASSERT (disk != NULL);
271         PED_ASSERT (raw_part != NULL);
272
273         return chs_to_sector (disk->dev, PED_LE16_TO_CPU(raw_part->cyl),
274                               raw_part->head, raw_part->sector);
275 }
276
277 static PedSector
278 legacy_end (const PedDisk* disk, const PC98RawPartition* raw_part)
279 {
280         PED_ASSERT (disk != NULL);
281         PED_ASSERT (raw_part != NULL);
282
283         if (raw_part->end_head == 0 && raw_part->end_sector == 0) {
284                 return chs_to_sector (disk->dev,
285                                       PED_LE16_TO_CPU(raw_part->end_cyl),
286                                       disk->dev->hw_geom.heads - 1,
287                                       disk->dev->hw_geom.sectors - 1);
288         } else {
289                 return chs_to_sector (disk->dev,
290                                       PED_LE16_TO_CPU(raw_part->end_cyl),
291                                       raw_part->end_head,
292                                       raw_part->end_sector);
293         }
294 }
295
296 static int
297 is_unused_partition(const PC98RawPartition* raw_part)
298 {
299         if (raw_part->mid || raw_part->sid
300             || raw_part->ipl_sect
301             || raw_part->ipl_head
302             || PED_LE16_TO_CPU(raw_part->ipl_cyl)
303             || raw_part->sector
304             || raw_part->head
305             || PED_LE16_TO_CPU(raw_part->cyl)
306             || raw_part->end_sector
307             || raw_part->end_head
308             || PED_LE16_TO_CPU(raw_part->end_cyl))
309                 return 0;
310         return 1;
311 }
312
313 static int
314 read_table (PedDisk* disk)
315 {
316         int                     i;
317         PC98RawTable            table;
318         PedConstraint*          constraint_any;
319
320         PED_ASSERT (disk != NULL);
321         PED_ASSERT (disk->dev != NULL);
322
323         constraint_any = ped_constraint_any (disk->dev);
324
325         if (!ped_device_read (disk->dev, (void*) &table, 0, 2))
326                 goto error;
327
328         if (!pc98_check_magic(&table)) {
329                 if (ped_exception_throw (
330                         PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL,
331                         _("Invalid partition table on %s."),
332                         disk->dev->path))
333                         goto error;
334         }
335
336         for (i = 0; i < MAX_PART_COUNT; i++) {
337                 PC98RawPartition*       raw_part;
338                 PedPartition*           part;
339                 PC98PartitionData*      pc98_data;
340                 PedSector               part_start;
341                 PedSector               part_end;
342
343                 raw_part = &table.partitions [i];
344
345                 if (is_unused_partition(raw_part))
346                         continue;
347
348                 part_start = legacy_start (disk, raw_part);
349                 part_end   = legacy_end (disk, raw_part);
350
351                 part = ped_partition_new (disk, PED_PARTITION_NORMAL,
352                                           NULL, part_start, part_end);
353                 if (!part)
354                         goto error;
355                 pc98_data = part->disk_specific;
356                 PED_ASSERT (pc98_data != NULL);
357
358                 pc98_data->system = (raw_part->mid << 8) | raw_part->sid;
359                 pc98_data->boot = GET_BIT(raw_part->mid, 7);
360                 pc98_data->hidden = !GET_BIT(raw_part->sid, 7);
361
362                 ped_partition_set_name (part, raw_part->name);
363
364                 pc98_data->ipl_sector = chs_to_sector (
365                         disk->dev,
366                         PED_LE16_TO_CPU(raw_part->ipl_cyl),
367                         raw_part->ipl_head,
368                         raw_part->ipl_sect);
369
370                 /* hack */
371                 if (pc98_data->ipl_sector == part->geom.start)
372                         pc98_data->ipl_sector = 0;
373
374                 part->num = i + 1;
375
376                 if (!ped_disk_add_partition (disk, part, constraint_any))
377                         goto error;
378
379                 if (part->geom.start != part_start
380                     || part->geom.end != part_end) {
381                         ped_exception_throw (
382                                 PED_EXCEPTION_NO_FEATURE,
383                                 PED_EXCEPTION_CANCEL,
384                                 _("Partition %d isn't aligned to cylinder "
385                                   "boundaries.  This is still unsupported."),
386                                 part->num);
387                         goto error;
388                 }
389
390                 part->fs_type = ped_file_system_probe (&part->geom);
391         }
392
393         ped_constraint_destroy (constraint_any);
394         return 1;
395
396 error:
397         ped_disk_delete_all (disk);
398         ped_constraint_destroy (constraint_any);
399         return 0;
400 }
401
402 static int
403 pc98_read (PedDisk* disk)
404 {
405         PED_ASSERT (disk != NULL);
406         PED_ASSERT (disk->dev != NULL);
407
408         ped_disk_delete_all (disk);
409         return read_table (disk);
410 }
411
412 #ifndef DISCOVER_ONLY
413 static int
414 fill_raw_part (PC98RawPartition* raw_part, const PedPartition* part)
415 {
416         PC98PartitionData*      pc98_data;
417         int                     c, h, s;
418         const char*             name;
419
420         PED_ASSERT (raw_part != NULL);
421         PED_ASSERT (part != NULL);
422         PED_ASSERT (part->disk_specific != NULL);
423
424         pc98_data = part->disk_specific;
425         raw_part->mid = (pc98_data->system >> 8) & 0xFF;
426         raw_part->sid = pc98_data->system & 0xFF;
427
428         SET_BIT(raw_part->mid, 7, pc98_data->boot);
429         SET_BIT(raw_part->sid, 7, !pc98_data->hidden);
430
431         memset (raw_part->name, ' ', sizeof(raw_part->name));
432         name = ped_partition_get_name (part);
433         PED_ASSERT (name != NULL);
434         PED_ASSERT (strlen (name) <= 16);
435         if (!strlen (name) && part->fs_type)
436                 name = part->fs_type->name;
437         memcpy (raw_part->name, name, strlen (name));
438
439         sector_to_chs (part->disk->dev, part->geom.start, &c, &h, &s);
440         raw_part->cyl    = PED_CPU_TO_LE16(c);
441         raw_part->head   = h;
442         raw_part->sector = s;
443
444         if (pc98_data->ipl_sector) {
445                 sector_to_chs (part->disk->dev, pc98_data->ipl_sector,
446                                &c, &h, &s);
447                 raw_part->ipl_cyl  = PED_CPU_TO_LE16(c);
448                 raw_part->ipl_head = h;
449                 raw_part->ipl_sect = s;
450         } else {
451                 raw_part->ipl_cyl  = raw_part->cyl;
452                 raw_part->ipl_head = raw_part->head;
453                 raw_part->ipl_sect = raw_part->sector;
454         }
455
456         sector_to_chs (part->disk->dev, part->geom.end, &c, &h, &s);
457         if (h != part->disk->dev->hw_geom.heads - 1
458             || s != part->disk->dev->hw_geom.sectors - 1) {
459                 ped_exception_throw (
460                     PED_EXCEPTION_NO_FEATURE,
461                     PED_EXCEPTION_CANCEL,
462                     _("Partition %d isn't aligned to cylinder "
463                       "boundaries.  This is still unsupported."),
464                     part->num);
465                 return 0;
466         }
467         raw_part->end_cyl    = PED_CPU_TO_LE16(c);
468 #if 0
469         raw_part->end_head   = h;
470         raw_part->end_sector = s;
471 #else
472         raw_part->end_head   = 0;
473         raw_part->end_sector = 0;
474 #endif
475
476         return 1;
477 }
478
479 static int
480 pc98_write (const PedDisk* disk)
481 {
482         PedPartition*           part;
483         int                     i;
484
485         PED_ASSERT (disk != NULL);
486         PED_ASSERT (disk->dev != NULL);
487
488         void *s0;
489         if (!ptt_read_sectors (disk->dev, 0, 2, &s0))
490                 return 0;
491         PC98RawTable *table = s0;
492
493         if (!pc98_check_ipl_signature (table)) {
494                 memset (table->boot_code, 0, sizeof(table->boot_code));
495                 memcpy (table->boot_code, MBR_BOOT_CODE, sizeof(MBR_BOOT_CODE));
496         }
497
498         memset (table->partitions, 0, sizeof (table->partitions));
499         table->magic = PED_CPU_TO_LE16(PC9800_EXTFMT_MAGIC);
500
501         for (i = 1; i <= MAX_PART_COUNT; i++) {
502                 part = ped_disk_get_partition (disk, i);
503                 if (!part)
504                         continue;
505
506                 if (!fill_raw_part (&table->partitions [i - 1], part))
507                         return 0;
508         }
509
510         int write_ok = ped_device_write (disk->dev, table, 0, 2);
511         free (s0);
512         if (!write_ok)
513                 return 0;
514         return ped_device_sync (disk->dev);
515 }
516 #endif /* !DISCOVER_ONLY */
517
518 static PedPartition*
519 pc98_partition_new (
520         const PedDisk* disk, PedPartitionType part_type,
521         const PedFileSystemType* fs_type, PedSector start, PedSector end)
522 {
523         PedPartition*           part;
524         PC98PartitionData*      pc98_data;
525
526         part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
527         if (!part)
528                 goto error;
529
530         if (ped_partition_is_active (part)) {
531                 part->disk_specific
532                         = pc98_data = ped_malloc (sizeof (PC98PartitionData));
533                 if (!pc98_data)
534                         goto error_free_part;
535                 pc98_data->ipl_sector = 0;
536                 pc98_data->hidden = 0;
537                 pc98_data->boot = 0;
538                 strcpy (pc98_data->name, "");
539         } else {
540                 part->disk_specific = NULL;
541         }
542         return part;
543
544 error_free_part:
545         free (part);
546 error:
547         return 0;
548 }
549
550 static PedPartition*
551 pc98_partition_duplicate (const PedPartition* part)
552 {
553         PedPartition*           new_part;
554         PC98PartitionData*      new_pc98_data;
555         PC98PartitionData*      old_pc98_data;
556
557         new_part = ped_partition_new (part->disk, part->type,
558                                       part->fs_type, part->geom.start,
559                                       part->geom.end);
560         if (!new_part)
561                 return NULL;
562         new_part->num = part->num;
563
564         old_pc98_data = (PC98PartitionData*) part->disk_specific;
565         new_pc98_data = (PC98PartitionData*) new_part->disk_specific;
566
567         /* ugly, but C is ugly :p */
568         memcpy (new_pc98_data, old_pc98_data, sizeof (PC98PartitionData));
569         return new_part;
570 }
571
572 static void
573 pc98_partition_destroy (PedPartition* part)
574 {
575         PED_ASSERT (part != NULL);
576
577         if (ped_partition_is_active (part))
578                 free (part->disk_specific);
579         free (part);
580 }
581
582 static int
583 pc98_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
584 {
585         PC98PartitionData* pc98_data = part->disk_specific;
586
587         part->fs_type = fs_type;
588
589         pc98_data->system = 0x2062;
590         if (fs_type) {
591                 if (!strcmp (fs_type->name, "fat16")) {
592                         if (part->geom.length * 512 >= 32 * 1024 * 1024)
593                                 pc98_data->system = 0x2021;
594                         else
595                                 pc98_data->system = 0x2011;
596                 } else if (!strcmp (fs_type->name, "fat32")) {
597                         pc98_data->system = 0x2061;
598                 } else if (!strcmp (fs_type->name, "ntfs")) {
599                         pc98_data->system = 0x2031;
600                 } else if (!strncmp (fs_type->name, "ufs", 3)) {
601                         pc98_data->system = 0x2044;
602                 } else { /* ext2, reiser, xfs, etc. */
603                         /* ext2 partitions must be marked boot */
604                         pc98_data->boot = 1;
605                         pc98_data->system = 0xa062;
606                 }
607         }
608
609         if (pc98_data->boot)
610                 pc98_data->system |= 0x8000;
611         if (!pc98_data->hidden)
612                 pc98_data->system |= 0x0080;
613         return 1;
614 }
615
616 static int
617 pc98_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
618 {
619         PC98PartitionData*              pc98_data;
620
621         PED_ASSERT (part != NULL);
622         PED_ASSERT (part->disk_specific != NULL);
623
624         pc98_data = part->disk_specific;
625
626         switch (flag) {
627         case PED_PARTITION_HIDDEN:
628                 pc98_data->hidden = state;
629                 return ped_partition_set_system (part, part->fs_type);
630
631         case PED_PARTITION_BOOT:
632                 pc98_data->boot = state;
633                 return ped_partition_set_system (part, part->fs_type);
634
635         default:
636                 return 0;
637         }
638 }
639
640 static int
641 pc98_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
642 {
643         PC98PartitionData*      pc98_data;
644
645         PED_ASSERT (part != NULL);
646         PED_ASSERT (part->disk_specific != NULL);
647
648         pc98_data = part->disk_specific;
649         switch (flag) {
650         case PED_PARTITION_HIDDEN:
651                 return pc98_data->hidden;
652
653         case PED_PARTITION_BOOT:
654                 return pc98_data->boot;
655
656         default:
657                 return 0;
658         }
659 }
660
661 static int
662 pc98_partition_is_flag_available (
663         const PedPartition* part, PedPartitionFlag flag)
664 {
665         switch (flag) {
666         case PED_PARTITION_HIDDEN:
667         case PED_PARTITION_BOOT:
668                 return 1;
669
670         default:
671                 return 0;
672         }
673 }
674
675 static void
676 pc98_partition_set_name (PedPartition* part, const char* name)
677 {
678         PC98PartitionData*      pc98_data;
679         int                     i;
680
681         PED_ASSERT (part != NULL);
682         PED_ASSERT (part->disk_specific != NULL);
683         pc98_data = part->disk_specific;
684
685         strncpy (pc98_data->name, name, 16);
686         pc98_data->name [16] = 0;
687         for (i = strlen (pc98_data->name) - 1; pc98_data->name[i] == ' '; i--)
688                 pc98_data->name [i] = 0;
689 }
690
691 static const char*
692 pc98_partition_get_name (const PedPartition* part)
693 {
694         PC98PartitionData*      pc98_data;
695
696         PED_ASSERT (part != NULL);
697         PED_ASSERT (part->disk_specific != NULL);
698         pc98_data = part->disk_specific;
699
700         return pc98_data->name;
701 }
702
703 static PedAlignment*
704 pc98_get_partition_alignment(const PedDisk *disk)
705 {
706         PedSector cylinder_size =
707                 disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
708
709         return ped_alignment_new(0, cylinder_size);
710 }
711
712 static PedConstraint*
713 _primary_constraint (PedDisk* disk)
714 {
715         PedDevice*      dev = disk->dev;
716         PedAlignment    start_align;
717         PedAlignment    end_align;
718         PedGeometry     max_geom;
719         PedSector       cylinder_size;
720
721         cylinder_size = dev->hw_geom.sectors * dev->hw_geom.heads;
722
723         if (!ped_alignment_init (&start_align, 0, cylinder_size))
724                 return NULL;
725         if (!ped_alignment_init (&end_align, -1, cylinder_size))
726                 return NULL;
727         if (!ped_geometry_init (&max_geom, dev, cylinder_size,
728                                 dev->length - cylinder_size))
729                 return NULL;
730
731         return ped_constraint_new (&start_align, &end_align, &max_geom,
732                                    &max_geom, 1, dev->length);
733 }
734
735 static int
736 pc98_partition_align (PedPartition* part, const PedConstraint* constraint)
737 {
738         PED_ASSERT (part != NULL);
739
740         if (_ped_partition_attempt_align (part, constraint,
741                                           _primary_constraint (part->disk)))
742                 return 1;
743
744 #ifndef DISCOVER_ONLY
745         ped_exception_throw (
746                 PED_EXCEPTION_ERROR,
747                 PED_EXCEPTION_CANCEL,
748                 _("Unable to satisfy all constraints on the partition."));
749 #endif
750         return 0;
751 }
752
753 static int
754 next_primary (PedDisk* disk)
755 {
756         int     i;
757         for (i=1; i<=MAX_PART_COUNT; i++) {
758                 if (!ped_disk_get_partition (disk, i))
759                         return i;
760         }
761         return 0;
762 }
763
764 static int
765 pc98_partition_enumerate (PedPartition* part)
766 {
767         PED_ASSERT (part != NULL);
768         PED_ASSERT (part->disk != NULL);
769
770         /* don't re-number a partition */
771         if (part->num != -1)
772                 return 1;
773
774         PED_ASSERT (ped_partition_is_active (part));
775
776         part->num = next_primary (part->disk);
777         if (!part->num) {
778                 ped_exception_throw (PED_EXCEPTION_ERROR,
779                         PED_EXCEPTION_CANCEL,
780                         _("Can't add another partition."));
781                 return 0;
782         }
783
784         return 1;
785 }
786
787 static int
788 pc98_alloc_metadata (PedDisk* disk)
789 {
790         PedPartition*           new_part;
791         PedConstraint*          constraint_any = NULL;
792         PedSector               cyl_size;
793
794         PED_ASSERT (disk != NULL);
795         PED_ASSERT (disk->dev != NULL);
796
797         constraint_any = ped_constraint_any (disk->dev);
798
799         cyl_size = disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
800         new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
801                                       0, cyl_size - 1);
802         if (!new_part)
803                 goto error;
804
805         if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
806                 ped_partition_destroy (new_part);
807                 goto error;
808         }
809
810         ped_constraint_destroy (constraint_any);
811         return 1;
812
813 error:
814         ped_constraint_destroy (constraint_any);
815         return 0;
816 }
817
818 static int
819 pc98_get_max_primary_partition_count (const PedDisk* disk)
820 {
821         return MAX_PART_COUNT;
822 }
823
824 static bool
825 pc98_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
826 {
827         *max_n = MAX_PART_COUNT;
828         return true;
829 }
830
831 #include "pt-common.h"
832 PT_define_limit_functions (pc98)
833
834 static PedDiskOps pc98_disk_ops = {
835         clobber:                NULL,
836         write:                  NULL_IF_DISCOVER_ONLY (pc98_write),
837
838         partition_set_name:     pc98_partition_set_name,
839         partition_get_name:     pc98_partition_get_name,
840
841         get_partition_alignment: pc98_get_partition_alignment,
842
843         PT_op_function_initializers (pc98)
844 };
845
846 static PedDiskType pc98_disk_type = {
847         next:           NULL,
848         name:           "pc98",
849         ops:            &pc98_disk_ops,
850         features:       PED_DISK_TYPE_PARTITION_NAME
851 };
852
853 void
854 ped_disk_pc98_init ()
855 {
856         PED_ASSERT (sizeof (PC98RawTable) == 512 * 2);
857         ped_disk_type_register (&pc98_disk_type);
858 }
859
860 void
861 ped_disk_pc98_done ()
862 {
863         ped_disk_type_unregister (&pc98_disk_type);
864 }