OSDN Git Service

rename all "support" parameters; avoid new compiler warnings
[android-x86/external-parted.git] / libparted / labels / pc98.c
1 /*
2     libparted - a library for manipulating disk partitions
3     Copyright (C) 2000, 2001, 2007-2009 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, PED_PARTITION_NORMAL,
374                                           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 (const 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         free (pc98_data);
564 error_free_part:
565         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                 free (part->disk_specific);
599         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 bool
836 pc98_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
837 {
838         *max_n = MAX_PART_COUNT;
839         return true;
840 }
841
842 static PedDiskOps pc98_disk_ops = {
843         probe:                  pc98_probe,
844 #ifndef DISCOVER_ONLY
845         clobber:                pc98_clobber,
846 #else
847         clobber:                NULL,
848 #endif
849         alloc:                  pc98_alloc,
850         duplicate:              pc98_duplicate,
851         free:                   pc98_free,
852         read:                   pc98_read,
853 #ifndef DISCOVER_ONLY
854         write:                  pc98_write,
855 #else
856         write:                  NULL,
857 #endif
858         
859         partition_new:          pc98_partition_new,
860         partition_duplicate:    pc98_partition_duplicate,
861         partition_destroy:      pc98_partition_destroy,
862         partition_set_system:   pc98_partition_set_system,
863         partition_set_flag:     pc98_partition_set_flag,
864         partition_get_flag:     pc98_partition_get_flag,
865         partition_is_flag_available:    pc98_partition_is_flag_available,
866         partition_set_name:     pc98_partition_set_name,
867         partition_get_name:     pc98_partition_get_name,
868         partition_align:        pc98_partition_align,
869         partition_enumerate:    pc98_partition_enumerate,
870
871         alloc_metadata:         pc98_alloc_metadata,
872         get_max_primary_partition_count:
873                                 pc98_get_max_primary_partition_count,
874         get_max_supported_partition_count:
875                                 pc98_get_max_supported_partition_count
876 };
877
878 static PedDiskType pc98_disk_type = {
879         next:           NULL,
880         name:           "pc98",
881         ops:            &pc98_disk_ops,
882         features:       PED_DISK_TYPE_PARTITION_NAME
883 };
884
885 void
886 ped_disk_pc98_init ()
887 {
888         PED_ASSERT (sizeof (PC98RawTable) == 512 * 2, return);
889         ped_disk_type_register (&pc98_disk_type);
890 }
891
892 void
893 ped_disk_pc98_done ()
894 {
895         ped_disk_type_unregister (&pc98_disk_type);
896 }