2 libparted - a library for manipulating disk partitions
3 Copyright (C) 2000-2001, 2007-2011 Free Software Foundation, Inc.
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.
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.
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/>.
21 #include <parted/parted.h>
22 #include <parted/debug.h>
23 #include <parted/endian.h>
29 # define _(String) dgettext (PACKAGE, String)
31 # define _(String) (String)
32 #endif /* ENABLE_NLS */
34 /* hacked from Linux/98 source: fs/partitions/nec98.h
37 * http://people.FreeBSD.org/~kato/pc98.html
38 * http://www.kmc.kyoto-u.ac.jp/proj/linux98/index-english.html
43 * bit 7: 1=bootable, 0=not bootable
44 * # Linux uses this flag to make a distinction between ext2 and swap.
46 * 00H : N88-BASIC(data)?, PC-UX(data)?
51 * 20H : DOS(data), Windows95/98/NT, Linux
52 * 21H..2FH : DOS(system#1 .. system#15)
56 * bit 7: 1=active, 0=sleep(hidden)
57 * # PC-UX uses this flag to make a distinction between its file system
61 * 11H: FAT16, <32MB [accessible to DOS 3.3]
62 * 21H: FAT16, >=32MB [Large Partition]
64 * 28H: Windows NT (Volume/Stripe Set?)
65 * 41H: Windows NT (Volume/Stripe Set?)
66 * 48H: Windows NT (Volume/Stripe Set?)
71 * 62H: ext2, linux-swap
74 #define MAX_PART_COUNT 16
75 #define PC9800_EXTFMT_MAGIC 0xAA55
77 #define BIT(x) (1 << (x))
78 #define GET_BIT(n,bit) (((n) & BIT(bit)) != 0)
79 #define SET_BIT(n,bit,val) n = (val)? (n | BIT(bit)) : (n & ~BIT(bit))
81 typedef struct _PC98RawPartition PC98RawPartition;
82 typedef struct _PC98RawTable PC98RawTable;
84 /* ripped from Linux/98 source */
85 struct _PC98RawPartition {
86 uint8_t mid; /* 0x80 - boot */
87 uint8_t sid; /* 0x80 - active */
88 uint8_t dum1; /* dummy for padding */
89 uint8_t dum2; /* dummy for padding */
90 uint8_t ipl_sect; /* IPL sector */
91 uint8_t ipl_head; /* IPL head */
92 uint16_t ipl_cyl; /* IPL cylinder */
93 uint8_t sector; /* starting sector */
94 uint8_t head; /* starting head */
95 uint16_t cyl; /* starting cylinder */
96 uint8_t end_sector; /* end sector */
97 uint8_t end_head; /* end head */
98 uint16_t end_cyl; /* end cylinder */
100 } __attribute__((packed));
102 struct _PC98RawTable {
103 uint8_t boot_code [510];
105 PC98RawPartition partitions [MAX_PART_COUNT];
106 } __attribute__((packed));
109 PedSector ipl_sector;
116 /* this MBR boot code is dummy */
117 static const char MBR_BOOT_CODE[] = {
119 0x00, 0x00, 0x00, /* */
120 0x49, 0x50, 0x4c, 0x31 /* "IPL1" */
123 static PedDiskType pc98_disk_type;
125 static PedSector chs_to_sector (const PedDevice* dev, int c, int h, int s);
126 static void sector_to_chs (const PedDevice* dev, PedSector sector,
127 int* c, int* h, int* s);
131 pc98_check_magic (const PC98RawTable *part_table)
133 /* check "extended-format" (have partition table?) */
134 if (PED_LE16_TO_CPU(part_table->magic) != PC9800_EXTFMT_MAGIC)
141 pc98_check_ipl_signature (const PC98RawTable *part_table)
143 return !memcmp (part_table->boot_code + 4, "IPL1", 4);
147 check_partition_consistency (const PedDevice* dev,
148 const PC98RawPartition* raw_part)
150 if (raw_part->ipl_sect >= dev->hw_geom.sectors
151 || raw_part->sector >= dev->hw_geom.sectors
152 || raw_part->end_sector >= dev->hw_geom.sectors
153 || raw_part->ipl_head >= dev->hw_geom.heads
154 || raw_part->head >= dev->hw_geom.heads
155 || raw_part->end_head >= dev->hw_geom.heads
156 || PED_LE16_TO_CPU(raw_part->ipl_cyl) >= dev->hw_geom.cylinders
157 || PED_LE16_TO_CPU(raw_part->cyl) >= dev->hw_geom.cylinders
158 || PED_LE16_TO_CPU(raw_part->end_cyl) >= dev->hw_geom.cylinders
159 || PED_LE16_TO_CPU(raw_part->cyl)
160 > PED_LE16_TO_CPU(raw_part->end_cyl)
162 || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->ipl_cyl),
163 raw_part->ipl_head, raw_part->ipl_sect)
164 || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->cyl),
165 raw_part->head, raw_part->sector)
166 || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->end_cyl),
167 raw_part->end_head, raw_part->end_sector)
169 || PED_LE16_TO_CPU(raw_part->end_cyl)
170 < PED_LE16_TO_CPU(raw_part->cyl))
177 pc98_probe (const PedDevice *dev)
179 PC98RawTable part_table;
181 const PC98RawPartition* p;
183 PED_ASSERT (dev != NULL);
185 if (dev->sector_size != 512)
188 if (!ped_device_read (dev, &part_table, 0, 2))
192 if (!pc98_check_magic (&part_table))
195 /* check consistency */
197 for (p = part_table.partitions;
198 p < part_table.partitions + MAX_PART_COUNT;
201 if (p->mid == 0 && p->sid == 0)
204 if (!check_partition_consistency (dev, p))
208 /* check boot loader */
209 if (pc98_check_ipl_signature (&part_table))
211 else if (part_table.boot_code[0]) /* invalid boot loader */
214 /* Not to mistake msdos disk map for PC-9800's empty disk map */
222 pc98_alloc (const PedDevice* dev)
224 PED_ASSERT (dev != NULL);
226 return _ped_disk_alloc (dev, &pc98_disk_type);
230 pc98_duplicate (const PedDisk* disk)
232 return ped_disk_new_fresh (disk->dev, &pc98_disk_type);
236 pc98_free (PedDisk* disk)
238 PED_ASSERT (disk != NULL);
240 _ped_disk_free (disk);
244 chs_to_sector (const PedDevice* dev, int c, int h, int s)
246 PED_ASSERT (dev != NULL);
247 return (c * dev->hw_geom.heads + h) * dev->hw_geom.sectors + s;
251 sector_to_chs (const PedDevice* dev, PedSector sector, int* c, int* h, int* s)
255 PED_ASSERT (dev != NULL);
256 PED_ASSERT (c != NULL);
257 PED_ASSERT (h != NULL);
258 PED_ASSERT (s != NULL);
260 cyl_size = dev->hw_geom.heads * dev->hw_geom.sectors;
262 *c = sector / cyl_size;
263 *h = (sector) % cyl_size / dev->hw_geom.sectors;
264 *s = (sector) % cyl_size % dev->hw_geom.sectors;
268 legacy_start (const PedDisk* disk, const PC98RawPartition* raw_part)
270 PED_ASSERT (disk != NULL);
271 PED_ASSERT (raw_part != NULL);
273 return chs_to_sector (disk->dev, PED_LE16_TO_CPU(raw_part->cyl),
274 raw_part->head, raw_part->sector);
278 legacy_end (const PedDisk* disk, const PC98RawPartition* raw_part)
280 PED_ASSERT (disk != NULL);
281 PED_ASSERT (raw_part != NULL);
283 if (raw_part->end_head == 0 && raw_part->end_sector == 0) {
284 return chs_to_sector (disk->dev,
285 PED_LE16_TO_CPU(raw_part->end_cyl),
286 disk->dev->hw_geom.heads - 1,
287 disk->dev->hw_geom.sectors - 1);
289 return chs_to_sector (disk->dev,
290 PED_LE16_TO_CPU(raw_part->end_cyl),
292 raw_part->end_sector);
297 is_unused_partition(const PC98RawPartition* raw_part)
299 if (raw_part->mid || raw_part->sid
300 || raw_part->ipl_sect
301 || raw_part->ipl_head
302 || PED_LE16_TO_CPU(raw_part->ipl_cyl)
305 || PED_LE16_TO_CPU(raw_part->cyl)
306 || raw_part->end_sector
307 || raw_part->end_head
308 || PED_LE16_TO_CPU(raw_part->end_cyl))
314 read_table (PedDisk* disk)
318 PedConstraint* constraint_any;
320 PED_ASSERT (disk != NULL);
321 PED_ASSERT (disk->dev != NULL);
323 constraint_any = ped_constraint_any (disk->dev);
325 if (!ped_device_read (disk->dev, (void*) &table, 0, 2))
328 if (!pc98_check_magic(&table)) {
329 if (ped_exception_throw (
330 PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL,
331 _("Invalid partition table on %s."),
336 for (i = 0; i < MAX_PART_COUNT; i++) {
337 PC98RawPartition* raw_part;
339 PC98PartitionData* pc98_data;
340 PedSector part_start;
343 raw_part = &table.partitions [i];
345 if (is_unused_partition(raw_part))
348 part_start = legacy_start (disk, raw_part);
349 part_end = legacy_end (disk, raw_part);
351 part = ped_partition_new (disk, PED_PARTITION_NORMAL,
352 NULL, part_start, part_end);
355 pc98_data = part->disk_specific;
356 PED_ASSERT (pc98_data != NULL);
358 pc98_data->system = (raw_part->mid << 8) | raw_part->sid;
359 pc98_data->boot = GET_BIT(raw_part->mid, 7);
360 pc98_data->hidden = !GET_BIT(raw_part->sid, 7);
362 ped_partition_set_name (part, raw_part->name);
364 pc98_data->ipl_sector = chs_to_sector (
366 PED_LE16_TO_CPU(raw_part->ipl_cyl),
371 if (pc98_data->ipl_sector == part->geom.start)
372 pc98_data->ipl_sector = 0;
376 if (!ped_disk_add_partition (disk, part, constraint_any))
379 if (part->geom.start != part_start
380 || part->geom.end != part_end) {
381 ped_exception_throw (
382 PED_EXCEPTION_NO_FEATURE,
383 PED_EXCEPTION_CANCEL,
384 _("Partition %d isn't aligned to cylinder "
385 "boundaries. This is still unsupported."),
390 part->fs_type = ped_file_system_probe (&part->geom);
393 ped_constraint_destroy (constraint_any);
397 ped_disk_delete_all (disk);
398 ped_constraint_destroy (constraint_any);
403 pc98_read (PedDisk* disk)
405 PED_ASSERT (disk != NULL);
406 PED_ASSERT (disk->dev != NULL);
408 ped_disk_delete_all (disk);
409 return read_table (disk);
412 #ifndef DISCOVER_ONLY
414 fill_raw_part (PC98RawPartition* raw_part, const PedPartition* part)
416 PC98PartitionData* pc98_data;
420 PED_ASSERT (raw_part != NULL);
421 PED_ASSERT (part != NULL);
422 PED_ASSERT (part->disk_specific != NULL);
424 pc98_data = part->disk_specific;
425 raw_part->mid = (pc98_data->system >> 8) & 0xFF;
426 raw_part->sid = pc98_data->system & 0xFF;
428 SET_BIT(raw_part->mid, 7, pc98_data->boot);
429 SET_BIT(raw_part->sid, 7, !pc98_data->hidden);
431 memset (raw_part->name, ' ', sizeof(raw_part->name));
432 name = ped_partition_get_name (part);
433 PED_ASSERT (name != NULL);
434 PED_ASSERT (strlen (name) <= 16);
435 if (!strlen (name) && part->fs_type)
436 name = part->fs_type->name;
437 memcpy (raw_part->name, name, strlen (name));
439 sector_to_chs (part->disk->dev, part->geom.start, &c, &h, &s);
440 raw_part->cyl = PED_CPU_TO_LE16(c);
442 raw_part->sector = s;
444 if (pc98_data->ipl_sector) {
445 sector_to_chs (part->disk->dev, pc98_data->ipl_sector,
447 raw_part->ipl_cyl = PED_CPU_TO_LE16(c);
448 raw_part->ipl_head = h;
449 raw_part->ipl_sect = s;
451 raw_part->ipl_cyl = raw_part->cyl;
452 raw_part->ipl_head = raw_part->head;
453 raw_part->ipl_sect = raw_part->sector;
456 sector_to_chs (part->disk->dev, part->geom.end, &c, &h, &s);
457 if (h != part->disk->dev->hw_geom.heads - 1
458 || s != part->disk->dev->hw_geom.sectors - 1) {
459 ped_exception_throw (
460 PED_EXCEPTION_NO_FEATURE,
461 PED_EXCEPTION_CANCEL,
462 _("Partition %d isn't aligned to cylinder "
463 "boundaries. This is still unsupported."),
467 raw_part->end_cyl = PED_CPU_TO_LE16(c);
469 raw_part->end_head = h;
470 raw_part->end_sector = s;
472 raw_part->end_head = 0;
473 raw_part->end_sector = 0;
480 pc98_write (const PedDisk* disk)
485 PED_ASSERT (disk != NULL);
486 PED_ASSERT (disk->dev != NULL);
489 if (!ptt_read_sectors (disk->dev, 0, 2, &s0))
491 PC98RawTable *table = s0;
493 if (!pc98_check_ipl_signature (table)) {
494 memset (table->boot_code, 0, sizeof(table->boot_code));
495 memcpy (table->boot_code, MBR_BOOT_CODE, sizeof(MBR_BOOT_CODE));
498 memset (table->partitions, 0, sizeof (table->partitions));
499 table->magic = PED_CPU_TO_LE16(PC9800_EXTFMT_MAGIC);
501 for (i = 1; i <= MAX_PART_COUNT; i++) {
502 part = ped_disk_get_partition (disk, i);
506 if (!fill_raw_part (&table->partitions [i - 1], part))
510 int write_ok = ped_device_write (disk->dev, table, 0, 2);
514 return ped_device_sync (disk->dev);
516 #endif /* !DISCOVER_ONLY */
520 const PedDisk* disk, PedPartitionType part_type,
521 const PedFileSystemType* fs_type, PedSector start, PedSector end)
524 PC98PartitionData* pc98_data;
526 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
530 if (ped_partition_is_active (part)) {
532 = pc98_data = ped_malloc (sizeof (PC98PartitionData));
534 goto error_free_part;
535 pc98_data->ipl_sector = 0;
536 pc98_data->hidden = 0;
538 strcpy (pc98_data->name, "");
540 part->disk_specific = NULL;
552 pc98_partition_duplicate (const PedPartition* part)
554 PedPartition* new_part;
555 PC98PartitionData* new_pc98_data;
556 PC98PartitionData* old_pc98_data;
558 new_part = ped_partition_new (part->disk, part->type,
559 part->fs_type, part->geom.start,
563 new_part->num = part->num;
565 old_pc98_data = (PC98PartitionData*) part->disk_specific;
566 new_pc98_data = (PC98PartitionData*) new_part->disk_specific;
568 /* ugly, but C is ugly :p */
569 memcpy (new_pc98_data, old_pc98_data, sizeof (PC98PartitionData));
574 pc98_partition_destroy (PedPartition* part)
576 PED_ASSERT (part != NULL);
578 if (ped_partition_is_active (part))
579 free (part->disk_specific);
584 pc98_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
586 PC98PartitionData* pc98_data = part->disk_specific;
588 part->fs_type = fs_type;
590 pc98_data->system = 0x2062;
592 if (!strcmp (fs_type->name, "fat16")) {
593 if (part->geom.length * 512 >= 32 * 1024 * 1024)
594 pc98_data->system = 0x2021;
596 pc98_data->system = 0x2011;
597 } else if (!strcmp (fs_type->name, "fat32")) {
598 pc98_data->system = 0x2061;
599 } else if (!strcmp (fs_type->name, "ntfs")) {
600 pc98_data->system = 0x2031;
601 } else if (!strncmp (fs_type->name, "ufs", 3)) {
602 pc98_data->system = 0x2044;
603 } else { /* ext2, reiser, xfs, etc. */
604 /* ext2 partitions must be marked boot */
606 pc98_data->system = 0xa062;
611 pc98_data->system |= 0x8000;
612 if (!pc98_data->hidden)
613 pc98_data->system |= 0x0080;
618 pc98_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
620 PC98PartitionData* pc98_data;
622 PED_ASSERT (part != NULL);
623 PED_ASSERT (part->disk_specific != NULL);
625 pc98_data = part->disk_specific;
628 case PED_PARTITION_HIDDEN:
629 pc98_data->hidden = state;
630 return ped_partition_set_system (part, part->fs_type);
632 case PED_PARTITION_BOOT:
633 pc98_data->boot = state;
634 return ped_partition_set_system (part, part->fs_type);
642 pc98_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
644 PC98PartitionData* pc98_data;
646 PED_ASSERT (part != NULL);
647 PED_ASSERT (part->disk_specific != NULL);
649 pc98_data = part->disk_specific;
651 case PED_PARTITION_HIDDEN:
652 return pc98_data->hidden;
654 case PED_PARTITION_BOOT:
655 return pc98_data->boot;
663 pc98_partition_is_flag_available (
664 const PedPartition* part, PedPartitionFlag flag)
667 case PED_PARTITION_HIDDEN:
668 case PED_PARTITION_BOOT:
677 pc98_partition_set_name (PedPartition* part, const char* name)
679 PC98PartitionData* pc98_data;
682 PED_ASSERT (part != NULL);
683 PED_ASSERT (part->disk_specific != NULL);
684 pc98_data = part->disk_specific;
686 strncpy (pc98_data->name, name, 16);
687 pc98_data->name [16] = 0;
688 for (i = strlen (pc98_data->name) - 1; pc98_data->name[i] == ' '; i--)
689 pc98_data->name [i] = 0;
693 pc98_partition_get_name (const PedPartition* part)
695 PC98PartitionData* pc98_data;
697 PED_ASSERT (part != NULL);
698 PED_ASSERT (part->disk_specific != NULL);
699 pc98_data = part->disk_specific;
701 return pc98_data->name;
705 pc98_get_partition_alignment(const PedDisk *disk)
707 PedSector cylinder_size =
708 disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
710 return ped_alignment_new(0, cylinder_size);
713 static PedConstraint*
714 _primary_constraint (PedDisk* disk)
716 PedDevice* dev = disk->dev;
717 PedAlignment start_align;
718 PedAlignment end_align;
719 PedGeometry max_geom;
720 PedSector cylinder_size;
722 cylinder_size = dev->hw_geom.sectors * dev->hw_geom.heads;
724 if (!ped_alignment_init (&start_align, 0, cylinder_size))
726 if (!ped_alignment_init (&end_align, -1, cylinder_size))
728 if (!ped_geometry_init (&max_geom, dev, cylinder_size,
729 dev->length - cylinder_size))
732 return ped_constraint_new (&start_align, &end_align, &max_geom,
733 &max_geom, 1, dev->length);
737 pc98_partition_align (PedPartition* part, const PedConstraint* constraint)
739 PED_ASSERT (part != NULL);
741 if (_ped_partition_attempt_align (part, constraint,
742 _primary_constraint (part->disk)))
745 #ifndef DISCOVER_ONLY
746 ped_exception_throw (
748 PED_EXCEPTION_CANCEL,
749 _("Unable to satisfy all constraints on the partition."));
755 next_primary (PedDisk* disk)
758 for (i=1; i<=MAX_PART_COUNT; i++) {
759 if (!ped_disk_get_partition (disk, i))
766 pc98_partition_enumerate (PedPartition* part)
768 PED_ASSERT (part != NULL);
769 PED_ASSERT (part->disk != NULL);
771 /* don't re-number a partition */
775 PED_ASSERT (ped_partition_is_active (part));
777 part->num = next_primary (part->disk);
779 ped_exception_throw (PED_EXCEPTION_ERROR,
780 PED_EXCEPTION_CANCEL,
781 _("Can't add another partition."));
789 pc98_alloc_metadata (PedDisk* disk)
791 PedPartition* new_part;
792 PedConstraint* constraint_any = NULL;
795 PED_ASSERT (disk != NULL);
796 PED_ASSERT (disk->dev != NULL);
798 constraint_any = ped_constraint_any (disk->dev);
800 cyl_size = disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
801 new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
806 if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
807 ped_partition_destroy (new_part);
811 ped_constraint_destroy (constraint_any);
815 ped_constraint_destroy (constraint_any);
820 pc98_get_max_primary_partition_count (const PedDisk* disk)
822 return MAX_PART_COUNT;
826 pc98_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
828 *max_n = MAX_PART_COUNT;
832 #include "pt-common.h"
833 PT_define_limit_functions (pc98)
835 static PedDiskOps pc98_disk_ops = {
837 write: NULL_IF_DISCOVER_ONLY (pc98_write),
839 partition_set_name: pc98_partition_set_name,
840 partition_get_name: pc98_partition_get_name,
842 get_partition_alignment: pc98_get_partition_alignment,
844 PT_op_function_initializers (pc98)
847 static PedDiskType pc98_disk_type = {
851 features: PED_DISK_TYPE_PARTITION_NAME
855 ped_disk_pc98_init ()
857 PED_ASSERT (sizeof (PC98RawTable) == 512 * 2);
858 ped_disk_type_register (&pc98_disk_type);
862 ped_disk_pc98_done ()
864 ped_disk_type_unregister (&pc98_disk_type);