OSDN Git Service

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