OSDN Git Service

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