2 libparted - a library for manipulating disk partitions
3 Copyright (C) 2000-2001, 2007-2009 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>
27 # define _(String) dgettext (PACKAGE, String)
29 # define _(String) (String)
30 #endif /* ENABLE_NLS */
32 /* hacked from Linux/98 source: fs/partitions/nec98.h
35 * http://people.FreeBSD.org/~kato/pc98.html
36 * http://www.kmc.kyoto-u.ac.jp/proj/linux98/index-english.html
41 * bit 7: 1=bootable, 0=not bootable
42 * # Linux uses this flag to make a distinction between ext2 and swap.
44 * 00H : N88-BASIC(data)?, PC-UX(data)?
49 * 20H : DOS(data), Windows95/98/NT, Linux
50 * 21H..2FH : DOS(system#1 .. system#15)
54 * bit 7: 1=active, 0=sleep(hidden)
55 * # PC-UX uses this flag to make a distinction between its file system
59 * 11H: FAT16, <32MB [accessible to DOS 3.3]
60 * 21H: FAT16, >=32MB [Large Partition]
62 * 28H: Windows NT (Volume/Stripe Set?)
63 * 41H: Windows NT (Volume/Stripe Set?)
64 * 48H: Windows NT (Volume/Stripe Set?)
69 * 62H: ext2, linux-swap
72 #define MAX_PART_COUNT 16
73 #define PC9800_EXTFMT_MAGIC 0xAA55
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))
79 typedef struct _PC98RawPartition PC98RawPartition;
80 typedef struct _PC98RawTable PC98RawTable;
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 */
98 } __attribute__((packed));
100 struct _PC98RawTable {
101 uint8_t boot_code [510];
103 PC98RawPartition partitions [MAX_PART_COUNT];
104 } __attribute__((packed));
107 PedSector ipl_sector;
114 /* this MBR boot code is dummy */
115 static const char MBR_BOOT_CODE[] = {
117 0x00, 0x00, 0x00, /* */
118 0x49, 0x50, 0x4c, 0x31 /* "IPL1" */
121 static PedDiskType pc98_disk_type;
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);
129 pc98_check_magic (const PC98RawTable *part_table)
131 /* check "extended-format" (have partition table?) */
132 if (PED_LE16_TO_CPU(part_table->magic) != PC9800_EXTFMT_MAGIC)
139 pc98_check_ipl_signature (const PC98RawTable *part_table)
141 return !memcmp (part_table->boot_code + 4, "IPL1", 4);
145 check_partition_consistency (const PedDevice* dev,
146 const PC98RawPartition* raw_part)
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)
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)
167 || PED_LE16_TO_CPU(raw_part->end_cyl)
168 < PED_LE16_TO_CPU(raw_part->cyl))
175 pc98_probe (const PedDevice *dev)
177 PC98RawTable part_table;
179 const PC98RawPartition* p;
181 PED_ASSERT (dev != NULL, return 0);
183 if (dev->sector_size != 512)
186 if (!ped_device_read (dev, &part_table, 0, 2))
190 if (!pc98_check_magic (&part_table))
193 /* check consistency */
195 for (p = part_table.partitions;
196 p < part_table.partitions + MAX_PART_COUNT;
199 if (p->mid == 0 && p->sid == 0)
202 if (!check_partition_consistency (dev, p))
206 /* check boot loader */
207 if (pc98_check_ipl_signature (&part_table))
209 else if (part_table.boot_code[0]) /* invalid boot loader */
212 /* Not to mistake msdos disk map for PC-9800's empty disk map */
219 #ifndef DISCOVER_ONLY
221 pc98_clobber (PedDevice* dev)
225 PED_ASSERT (dev != NULL, return 0);
226 PED_ASSERT (pc98_probe (dev), return 0);
228 if (!ped_device_read (dev, &table, 0, 1))
231 memset (table.partitions, 0, sizeof (table.partitions));
232 table.magic = PED_CPU_TO_LE16(0);
234 if (pc98_check_ipl_signature (&table))
235 memset (table.boot_code, 0, sizeof (table.boot_code));
237 if (!ped_device_write (dev, (void*) &table, 0, 1))
239 return ped_device_sync (dev);
241 #endif /* !DISCOVER_ONLY */
244 pc98_alloc (const PedDevice* dev)
246 PED_ASSERT (dev != NULL, return 0);
248 return _ped_disk_alloc (dev, &pc98_disk_type);
252 pc98_duplicate (const PedDisk* disk)
254 return ped_disk_new_fresh (disk->dev, &pc98_disk_type);
258 pc98_free (PedDisk* disk)
260 PED_ASSERT (disk != NULL, return);
262 _ped_disk_free (disk);
266 chs_to_sector (const PedDevice* dev, int c, int h, int s)
268 PED_ASSERT (dev != NULL, return 0);
269 return (c * dev->hw_geom.heads + h) * dev->hw_geom.sectors + s;
273 sector_to_chs (const PedDevice* dev, PedSector sector, int* c, int* h, int* s)
277 PED_ASSERT (dev != NULL, return);
278 PED_ASSERT (c != NULL, return);
279 PED_ASSERT (h != NULL, return);
280 PED_ASSERT (s != NULL, return);
282 cyl_size = dev->hw_geom.heads * dev->hw_geom.sectors;
284 *c = sector / cyl_size;
285 *h = (sector) % cyl_size / dev->hw_geom.sectors;
286 *s = (sector) % cyl_size % dev->hw_geom.sectors;
290 legacy_start (const PedDisk* disk, const PC98RawPartition* raw_part)
292 PED_ASSERT (disk != NULL, return 0);
293 PED_ASSERT (raw_part != NULL, return 0);
295 return chs_to_sector (disk->dev, PED_LE16_TO_CPU(raw_part->cyl),
296 raw_part->head, raw_part->sector);
300 legacy_end (const PedDisk* disk, const PC98RawPartition* raw_part)
302 PED_ASSERT (disk != NULL, return 0);
303 PED_ASSERT (raw_part != NULL, return 0);
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);
311 return chs_to_sector (disk->dev,
312 PED_LE16_TO_CPU(raw_part->end_cyl),
314 raw_part->end_sector);
319 is_unused_partition(const PC98RawPartition* raw_part)
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)
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))
336 read_table (PedDisk* disk)
340 PedConstraint* constraint_any;
342 PED_ASSERT (disk != NULL, return 0);
343 PED_ASSERT (disk->dev != NULL, return 0);
345 constraint_any = ped_constraint_any (disk->dev);
347 if (!ped_device_read (disk->dev, (void*) &table, 0, 2))
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."),
358 for (i = 0; i < MAX_PART_COUNT; i++) {
359 PC98RawPartition* raw_part;
361 PC98PartitionData* pc98_data;
362 PedSector part_start;
365 raw_part = &table.partitions [i];
367 if (is_unused_partition(raw_part))
370 part_start = legacy_start (disk, raw_part);
371 part_end = legacy_end (disk, raw_part);
373 part = ped_partition_new (disk, PED_PARTITION_NORMAL,
374 NULL, part_start, part_end);
377 pc98_data = part->disk_specific;
378 PED_ASSERT (pc98_data != NULL, goto error);
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);
384 ped_partition_set_name (part, raw_part->name);
386 pc98_data->ipl_sector = chs_to_sector (
388 PED_LE16_TO_CPU(raw_part->ipl_cyl),
393 if (pc98_data->ipl_sector == part->geom.start)
394 pc98_data->ipl_sector = 0;
398 if (!ped_disk_add_partition (disk, part, constraint_any))
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."),
412 part->fs_type = ped_file_system_probe (&part->geom);
415 ped_constraint_destroy (constraint_any);
419 ped_disk_delete_all (disk);
420 ped_constraint_destroy (constraint_any);
425 pc98_read (PedDisk* disk)
427 PED_ASSERT (disk != NULL, return 0);
428 PED_ASSERT (disk->dev != NULL, return 0);
430 ped_disk_delete_all (disk);
431 return read_table (disk);
434 #ifndef DISCOVER_ONLY
436 fill_raw_part (PC98RawPartition* raw_part, const PedPartition* part)
438 PC98PartitionData* pc98_data;
442 PED_ASSERT (raw_part != NULL, return 0);
443 PED_ASSERT (part != NULL, return 0);
444 PED_ASSERT (part->disk_specific != NULL, return 0);
446 pc98_data = part->disk_specific;
447 raw_part->mid = (pc98_data->system >> 8) & 0xFF;
448 raw_part->sid = pc98_data->system & 0xFF;
450 SET_BIT(raw_part->mid, 7, pc98_data->boot);
451 SET_BIT(raw_part->sid, 7, !pc98_data->hidden);
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));
461 sector_to_chs (part->disk->dev, part->geom.start, &c, &h, &s);
462 raw_part->cyl = PED_CPU_TO_LE16(c);
464 raw_part->sector = s;
466 if (pc98_data->ipl_sector) {
467 sector_to_chs (part->disk->dev, pc98_data->ipl_sector,
469 raw_part->ipl_cyl = PED_CPU_TO_LE16(c);
470 raw_part->ipl_head = h;
471 raw_part->ipl_sect = s;
473 raw_part->ipl_cyl = raw_part->cyl;
474 raw_part->ipl_head = raw_part->head;
475 raw_part->ipl_sect = raw_part->sector;
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."),
489 raw_part->end_cyl = PED_CPU_TO_LE16(c);
491 raw_part->end_head = h;
492 raw_part->end_sector = s;
494 raw_part->end_head = 0;
495 raw_part->end_sector = 0;
502 pc98_write (const PedDisk* disk)
508 PED_ASSERT (disk != NULL, return 0);
509 PED_ASSERT (disk->dev != NULL, return 0);
511 if (!ped_device_read (disk->dev, &table, 0, 2))
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));
519 memset (table.partitions, 0, sizeof (table.partitions));
520 table.magic = PED_CPU_TO_LE16(PC9800_EXTFMT_MAGIC);
522 for (i = 1; i <= MAX_PART_COUNT; i++) {
523 part = ped_disk_get_partition (disk, i);
527 if (!fill_raw_part (&table.partitions [i - 1], part))
531 if (!ped_device_write (disk->dev, (void*) &table, 0, 2))
533 return ped_device_sync (disk->dev);
535 #endif /* !DISCOVER_ONLY */
539 const PedDisk* disk, PedPartitionType part_type,
540 const PedFileSystemType* fs_type, PedSector start, PedSector end)
543 PC98PartitionData* pc98_data;
545 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
549 if (ped_partition_is_active (part)) {
551 = pc98_data = ped_malloc (sizeof (PC98PartitionData));
553 goto error_free_part;
554 pc98_data->ipl_sector = 0;
555 pc98_data->hidden = 0;
557 strcpy (pc98_data->name, "");
559 part->disk_specific = NULL;
571 pc98_partition_duplicate (const PedPartition* part)
573 PedPartition* new_part;
574 PC98PartitionData* new_pc98_data;
575 PC98PartitionData* old_pc98_data;
577 new_part = ped_partition_new (part->disk, part->type,
578 part->fs_type, part->geom.start,
582 new_part->num = part->num;
584 old_pc98_data = (PC98PartitionData*) part->disk_specific;
585 new_pc98_data = (PC98PartitionData*) new_part->disk_specific;
587 /* ugly, but C is ugly :p */
588 memcpy (new_pc98_data, old_pc98_data, sizeof (PC98PartitionData));
593 pc98_partition_destroy (PedPartition* part)
595 PED_ASSERT (part != NULL, return);
597 if (ped_partition_is_active (part))
598 free (part->disk_specific);
603 pc98_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
605 PC98PartitionData* pc98_data = part->disk_specific;
607 part->fs_type = fs_type;
609 pc98_data->system = 0x2062;
611 if (!strcmp (fs_type->name, "fat16")) {
612 if (part->geom.length * 512 >= 32 * 1024 * 1024)
613 pc98_data->system = 0x2021;
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 */
625 pc98_data->system = 0xa062;
630 pc98_data->system |= 0x8000;
631 if (!pc98_data->hidden)
632 pc98_data->system |= 0x0080;
637 pc98_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
639 PC98PartitionData* pc98_data;
641 PED_ASSERT (part != NULL, return 0);
642 PED_ASSERT (part->disk_specific != NULL, return 0);
644 pc98_data = part->disk_specific;
647 case PED_PARTITION_HIDDEN:
648 pc98_data->hidden = state;
649 return ped_partition_set_system (part, part->fs_type);
651 case PED_PARTITION_BOOT:
652 pc98_data->boot = state;
653 return ped_partition_set_system (part, part->fs_type);
661 pc98_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
663 PC98PartitionData* pc98_data;
665 PED_ASSERT (part != NULL, return 0);
666 PED_ASSERT (part->disk_specific != NULL, return 0);
668 pc98_data = part->disk_specific;
670 case PED_PARTITION_HIDDEN:
671 return pc98_data->hidden;
673 case PED_PARTITION_BOOT:
674 return pc98_data->boot;
682 pc98_partition_is_flag_available (
683 const PedPartition* part, PedPartitionFlag flag)
686 case PED_PARTITION_HIDDEN:
687 case PED_PARTITION_BOOT:
696 pc98_partition_set_name (PedPartition* part, const char* name)
698 PC98PartitionData* pc98_data;
701 PED_ASSERT (part != NULL, return);
702 PED_ASSERT (part->disk_specific != NULL, return);
703 pc98_data = part->disk_specific;
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;
712 pc98_partition_get_name (const PedPartition* part)
714 PC98PartitionData* pc98_data;
716 PED_ASSERT (part != NULL, return NULL);
717 PED_ASSERT (part->disk_specific != NULL, return NULL);
718 pc98_data = part->disk_specific;
720 return pc98_data->name;
723 static PedConstraint*
724 _primary_constraint (PedDisk* disk)
726 PedDevice* dev = disk->dev;
727 PedAlignment start_align;
728 PedAlignment end_align;
729 PedGeometry max_geom;
730 PedSector cylinder_size;
732 cylinder_size = dev->hw_geom.sectors * dev->hw_geom.heads;
734 if (!ped_alignment_init (&start_align, 0, cylinder_size))
736 if (!ped_alignment_init (&end_align, -1, cylinder_size))
738 if (!ped_geometry_init (&max_geom, dev, cylinder_size,
739 dev->length - cylinder_size))
742 return ped_constraint_new (&start_align, &end_align, &max_geom,
743 &max_geom, 1, dev->length);
747 pc98_partition_align (PedPartition* part, const PedConstraint* constraint)
749 PED_ASSERT (part != NULL, return 0);
751 if (_ped_partition_attempt_align (part, constraint,
752 _primary_constraint (part->disk)))
755 #ifndef DISCOVER_ONLY
756 ped_exception_throw (
758 PED_EXCEPTION_CANCEL,
759 _("Unable to satisfy all constraints on the partition."));
765 next_primary (PedDisk* disk)
768 for (i=1; i<=MAX_PART_COUNT; i++) {
769 if (!ped_disk_get_partition (disk, i))
776 pc98_partition_enumerate (PedPartition* part)
778 PED_ASSERT (part != NULL, return 0);
779 PED_ASSERT (part->disk != NULL, return 0);
781 /* don't re-number a partition */
785 PED_ASSERT (ped_partition_is_active (part), return 0);
787 part->num = next_primary (part->disk);
789 ped_exception_throw (PED_EXCEPTION_ERROR,
790 PED_EXCEPTION_CANCEL,
791 _("Can't add another partition."));
799 pc98_alloc_metadata (PedDisk* disk)
801 PedPartition* new_part;
802 PedConstraint* constraint_any = NULL;
805 PED_ASSERT (disk != NULL, goto error);
806 PED_ASSERT (disk->dev != NULL, goto error);
808 constraint_any = ped_constraint_any (disk->dev);
810 cyl_size = disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
811 new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
816 if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
817 ped_partition_destroy (new_part);
821 ped_constraint_destroy (constraint_any);
825 ped_constraint_destroy (constraint_any);
830 pc98_get_max_primary_partition_count (const PedDisk* disk)
832 return MAX_PART_COUNT;
836 pc98_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
838 *max_n = MAX_PART_COUNT;
843 pc98_partition_check (const PedPartition* part)
848 static PedDiskOps pc98_disk_ops = {
850 #ifndef DISCOVER_ONLY
851 clobber: pc98_clobber,
856 duplicate: pc98_duplicate,
859 #ifndef DISCOVER_ONLY
865 partition_new: pc98_partition_new,
866 partition_duplicate: pc98_partition_duplicate,
867 partition_destroy: pc98_partition_destroy,
868 partition_set_system: pc98_partition_set_system,
869 partition_set_flag: pc98_partition_set_flag,
870 partition_get_flag: pc98_partition_get_flag,
871 partition_is_flag_available: pc98_partition_is_flag_available,
872 partition_set_name: pc98_partition_set_name,
873 partition_get_name: pc98_partition_get_name,
874 partition_align: pc98_partition_align,
875 partition_enumerate: pc98_partition_enumerate,
876 partition_check: pc98_partition_check,
878 alloc_metadata: pc98_alloc_metadata,
879 get_max_primary_partition_count:
880 pc98_get_max_primary_partition_count,
881 get_max_supported_partition_count:
882 pc98_get_max_supported_partition_count
885 static PedDiskType pc98_disk_type = {
889 features: PED_DISK_TYPE_PARTITION_NAME
893 ped_disk_pc98_init ()
895 PED_ASSERT (sizeof (PC98RawTable) == 512 * 2, return);
896 ped_disk_type_register (&pc98_disk_type);
900 ped_disk_pc98_done ()
902 ped_disk_type_unregister (&pc98_disk_type);