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