2
libparted - a library for manipulating disk partitions
3
Copyright (C) 2000-2001, 2007-2012 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
if (memcmp (part_table->boot_code + 4, "IPL1", 4) == 0)
145
else if (memcmp (part_table->boot_code + 4, "Linux 98", 8) == 0)
147
else if (memcmp (part_table->boot_code + 4, "GRUB/98 ", 8) == 0)
154
pc98_probe (const PedDevice *dev)
156
PC98RawTable part_table;
158
PED_ASSERT (dev != NULL);
160
if (dev->sector_size != 512)
163
if (!ped_device_read (dev, &part_table, 0, 2))
167
if (!pc98_check_magic (&part_table))
170
/* check for boot loader signatures */
171
return pc98_check_ipl_signature (&part_table);
175
pc98_alloc (const PedDevice* dev)
177
PED_ASSERT (dev != NULL);
179
return _ped_disk_alloc (dev, &pc98_disk_type);
183
pc98_duplicate (const PedDisk* disk)
185
return ped_disk_new_fresh (disk->dev, &pc98_disk_type);
189
pc98_free (PedDisk* disk)
191
PED_ASSERT (disk != NULL);
193
_ped_disk_free (disk);
196
static PedSector _GL_ATTRIBUTE_PURE
197
chs_to_sector (const PedDevice* dev, int c, int h, int s)
199
PED_ASSERT (dev != NULL);
200
return (c * dev->hw_geom.heads + h) * dev->hw_geom.sectors + s;
204
sector_to_chs (const PedDevice* dev, PedSector sector, int* c, int* h, int* s)
208
PED_ASSERT (dev != NULL);
209
PED_ASSERT (c != NULL);
210
PED_ASSERT (h != NULL);
211
PED_ASSERT (s != NULL);
213
cyl_size = dev->hw_geom.heads * dev->hw_geom.sectors;
215
*c = sector / cyl_size;
216
*h = (sector) % cyl_size / dev->hw_geom.sectors;
217
*s = (sector) % cyl_size % dev->hw_geom.sectors;
220
static PedSector _GL_ATTRIBUTE_PURE
221
legacy_start (const PedDisk* disk, const PC98RawPartition* raw_part)
223
PED_ASSERT (disk != NULL);
224
PED_ASSERT (raw_part != NULL);
226
return chs_to_sector (disk->dev, PED_LE16_TO_CPU(raw_part->cyl),
227
raw_part->head, raw_part->sector);
230
static PedSector _GL_ATTRIBUTE_PURE
231
legacy_end (const PedDisk* disk, const PC98RawPartition* raw_part)
233
PED_ASSERT (disk != NULL);
234
PED_ASSERT (raw_part != NULL);
236
if (raw_part->end_head == 0 && raw_part->end_sector == 0) {
237
return chs_to_sector (disk->dev,
238
PED_LE16_TO_CPU(raw_part->end_cyl),
239
disk->dev->hw_geom.heads - 1,
240
disk->dev->hw_geom.sectors - 1);
242
return chs_to_sector (disk->dev,
243
PED_LE16_TO_CPU(raw_part->end_cyl),
245
raw_part->end_sector);
250
is_unused_partition(const PC98RawPartition* raw_part)
252
if (raw_part->mid || raw_part->sid
253
|| raw_part->ipl_sect
254
|| raw_part->ipl_head
255
|| PED_LE16_TO_CPU(raw_part->ipl_cyl)
258
|| PED_LE16_TO_CPU(raw_part->cyl)
259
|| raw_part->end_sector
260
|| raw_part->end_head
261
|| PED_LE16_TO_CPU(raw_part->end_cyl))
267
read_table (PedDisk* disk)
271
PedConstraint* constraint_any;
273
PED_ASSERT (disk != NULL);
274
PED_ASSERT (disk->dev != NULL);
276
constraint_any = ped_constraint_any (disk->dev);
278
if (!ped_device_read (disk->dev, (void*) &table, 0, 2))
281
if (!pc98_check_magic(&table)) {
282
if (ped_exception_throw (
283
PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL,
284
_("Invalid partition table on %s."),
289
for (i = 0; i < MAX_PART_COUNT; i++) {
290
PC98RawPartition* raw_part;
292
PC98PartitionData* pc98_data;
293
PedSector part_start;
296
raw_part = &table.partitions [i];
298
if (is_unused_partition(raw_part))
301
part_start = legacy_start (disk, raw_part);
302
part_end = legacy_end (disk, raw_part);
304
part = ped_partition_new (disk, PED_PARTITION_NORMAL,
305
NULL, part_start, part_end);
308
pc98_data = part->disk_specific;
309
PED_ASSERT (pc98_data != NULL);
311
pc98_data->system = (raw_part->mid << 8) | raw_part->sid;
312
pc98_data->boot = GET_BIT(raw_part->mid, 7);
313
pc98_data->hidden = !GET_BIT(raw_part->sid, 7);
315
ped_partition_set_name (part, raw_part->name);
317
pc98_data->ipl_sector = chs_to_sector (
319
PED_LE16_TO_CPU(raw_part->ipl_cyl),
324
if (pc98_data->ipl_sector == part->geom.start)
325
pc98_data->ipl_sector = 0;
329
if (!ped_disk_add_partition (disk, part, constraint_any))
332
if (part->geom.start != part_start
333
|| part->geom.end != part_end) {
334
ped_exception_throw (
335
PED_EXCEPTION_NO_FEATURE,
336
PED_EXCEPTION_CANCEL,
337
_("Partition %d isn't aligned to cylinder "
338
"boundaries. This is still unsupported."),
343
part->fs_type = ped_file_system_probe (&part->geom);
346
ped_constraint_destroy (constraint_any);
350
ped_disk_delete_all (disk);
351
ped_constraint_destroy (constraint_any);
356
pc98_read (PedDisk* disk)
358
PED_ASSERT (disk != NULL);
359
PED_ASSERT (disk->dev != NULL);
361
ped_disk_delete_all (disk);
362
return read_table (disk);
365
#ifndef DISCOVER_ONLY
367
fill_raw_part (PC98RawPartition* raw_part, const PedPartition* part)
369
PC98PartitionData* pc98_data;
373
PED_ASSERT (raw_part != NULL);
374
PED_ASSERT (part != NULL);
375
PED_ASSERT (part->disk_specific != NULL);
377
pc98_data = part->disk_specific;
378
raw_part->mid = (pc98_data->system >> 8) & 0xFF;
379
raw_part->sid = pc98_data->system & 0xFF;
381
SET_BIT(raw_part->mid, 7, pc98_data->boot);
382
SET_BIT(raw_part->sid, 7, !pc98_data->hidden);
384
memset (raw_part->name, ' ', sizeof(raw_part->name));
385
name = ped_partition_get_name (part);
386
PED_ASSERT (name != NULL);
387
PED_ASSERT (strlen (name) <= 16);
388
if (!strlen (name) && part->fs_type)
389
name = part->fs_type->name;
390
memcpy (raw_part->name, name, strlen (name));
392
sector_to_chs (part->disk->dev, part->geom.start, &c, &h, &s);
393
raw_part->cyl = PED_CPU_TO_LE16(c);
395
raw_part->sector = s;
397
if (pc98_data->ipl_sector) {
398
sector_to_chs (part->disk->dev, pc98_data->ipl_sector,
400
raw_part->ipl_cyl = PED_CPU_TO_LE16(c);
401
raw_part->ipl_head = h;
402
raw_part->ipl_sect = s;
404
raw_part->ipl_cyl = raw_part->cyl;
405
raw_part->ipl_head = raw_part->head;
406
raw_part->ipl_sect = raw_part->sector;
409
sector_to_chs (part->disk->dev, part->geom.end, &c, &h, &s);
410
if (h != part->disk->dev->hw_geom.heads - 1
411
|| s != part->disk->dev->hw_geom.sectors - 1) {
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."),
420
raw_part->end_cyl = PED_CPU_TO_LE16(c);
422
raw_part->end_head = h;
423
raw_part->end_sector = s;
425
raw_part->end_head = 0;
426
raw_part->end_sector = 0;
433
pc98_write (const PedDisk* disk)
438
PED_ASSERT (disk != NULL);
439
PED_ASSERT (disk->dev != NULL);
442
if (!ptt_read_sectors (disk->dev, 0, 2, &s0))
444
PC98RawTable *table = s0;
446
if (!pc98_check_ipl_signature (table)) {
447
memset (table->boot_code, 0, sizeof(table->boot_code));
448
memcpy (table->boot_code, MBR_BOOT_CODE, sizeof(MBR_BOOT_CODE));
451
memset (table->partitions, 0, sizeof (table->partitions));
452
table->magic = PED_CPU_TO_LE16(PC9800_EXTFMT_MAGIC);
454
for (i = 1; i <= MAX_PART_COUNT; i++) {
455
part = ped_disk_get_partition (disk, i);
459
if (!fill_raw_part (&table->partitions [i - 1], part))
463
int write_ok = ped_device_write (disk->dev, table, 0, 2);
467
return ped_device_sync (disk->dev);
469
#endif /* !DISCOVER_ONLY */
473
const PedDisk* disk, PedPartitionType part_type,
474
const PedFileSystemType* fs_type, PedSector start, PedSector end)
477
PC98PartitionData* pc98_data;
479
part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
483
if (ped_partition_is_active (part)) {
485
= pc98_data = ped_malloc (sizeof (PC98PartitionData));
487
goto error_free_part;
488
pc98_data->ipl_sector = 0;
489
pc98_data->hidden = 0;
491
strcpy (pc98_data->name, "");
493
part->disk_specific = NULL;
504
pc98_partition_duplicate (const PedPartition* part)
506
PedPartition* new_part;
507
PC98PartitionData* new_pc98_data;
508
PC98PartitionData* old_pc98_data;
510
new_part = ped_partition_new (part->disk, part->type,
511
part->fs_type, part->geom.start,
515
new_part->num = part->num;
517
old_pc98_data = (PC98PartitionData*) part->disk_specific;
518
new_pc98_data = (PC98PartitionData*) new_part->disk_specific;
520
/* ugly, but C is ugly :p */
521
memcpy (new_pc98_data, old_pc98_data, sizeof (PC98PartitionData));
526
pc98_partition_destroy (PedPartition* part)
528
PED_ASSERT (part != NULL);
530
if (ped_partition_is_active (part))
531
free (part->disk_specific);
536
pc98_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
538
PC98PartitionData* pc98_data = part->disk_specific;
540
part->fs_type = fs_type;
542
pc98_data->system = 0x2062;
544
if (!strcmp (fs_type->name, "fat16")) {
545
if (part->geom.length * 512 >= 32 * 1024 * 1024)
546
pc98_data->system = 0x2021;
548
pc98_data->system = 0x2011;
549
} else if (!strcmp (fs_type->name, "fat32")) {
550
pc98_data->system = 0x2061;
551
} else if (!strcmp (fs_type->name, "ntfs")) {
552
pc98_data->system = 0x2031;
553
} else if (!strncmp (fs_type->name, "ufs", 3)) {
554
pc98_data->system = 0x2044;
555
} else { /* ext2, reiser, xfs, etc. */
556
/* ext2 partitions must be marked boot */
558
pc98_data->system = 0xa062;
563
pc98_data->system |= 0x8000;
564
if (!pc98_data->hidden)
565
pc98_data->system |= 0x0080;
570
pc98_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
572
PC98PartitionData* pc98_data;
574
PED_ASSERT (part != NULL);
575
PED_ASSERT (part->disk_specific != NULL);
577
pc98_data = part->disk_specific;
580
case PED_PARTITION_HIDDEN:
581
pc98_data->hidden = state;
582
return ped_partition_set_system (part, part->fs_type);
584
case PED_PARTITION_BOOT:
585
pc98_data->boot = state;
586
return ped_partition_set_system (part, part->fs_type);
593
static int _GL_ATTRIBUTE_PURE
594
pc98_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
596
PC98PartitionData* pc98_data;
598
PED_ASSERT (part != NULL);
599
PED_ASSERT (part->disk_specific != NULL);
601
pc98_data = part->disk_specific;
603
case PED_PARTITION_HIDDEN:
604
return pc98_data->hidden;
606
case PED_PARTITION_BOOT:
607
return pc98_data->boot;
615
pc98_partition_is_flag_available (
616
const PedPartition* part, PedPartitionFlag flag)
619
case PED_PARTITION_HIDDEN:
620
case PED_PARTITION_BOOT:
629
pc98_partition_set_name (PedPartition* part, const char* name)
631
PC98PartitionData* pc98_data;
634
PED_ASSERT (part != NULL);
635
PED_ASSERT (part->disk_specific != NULL);
636
pc98_data = part->disk_specific;
638
strncpy (pc98_data->name, name, 16);
639
pc98_data->name [16] = 0;
640
for (i = strlen (pc98_data->name) - 1; pc98_data->name[i] == ' '; i--)
641
pc98_data->name [i] = 0;
644
static const char* _GL_ATTRIBUTE_PURE
645
pc98_partition_get_name (const PedPartition* part)
647
PC98PartitionData* pc98_data;
649
PED_ASSERT (part != NULL);
650
PED_ASSERT (part->disk_specific != NULL);
651
pc98_data = part->disk_specific;
653
return pc98_data->name;
657
pc98_get_partition_alignment(const PedDisk *disk)
659
PedSector cylinder_size =
660
disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
662
return ped_alignment_new(0, cylinder_size);
665
static PedConstraint*
666
_primary_constraint (PedDisk* disk)
668
PedDevice* dev = disk->dev;
669
PedAlignment start_align;
670
PedAlignment end_align;
671
PedGeometry max_geom;
672
PedSector cylinder_size;
674
cylinder_size = dev->hw_geom.sectors * dev->hw_geom.heads;
676
if (!ped_alignment_init (&start_align, 0, cylinder_size))
678
if (!ped_alignment_init (&end_align, -1, cylinder_size))
680
if (!ped_geometry_init (&max_geom, dev, cylinder_size,
681
dev->length - cylinder_size))
684
return ped_constraint_new (&start_align, &end_align, &max_geom,
685
&max_geom, 1, dev->length);
689
pc98_partition_align (PedPartition* part, const PedConstraint* constraint)
691
PED_ASSERT (part != NULL);
693
if (_ped_partition_attempt_align (part, constraint,
694
_primary_constraint (part->disk)))
697
#ifndef DISCOVER_ONLY
698
ped_exception_throw (
700
PED_EXCEPTION_CANCEL,
701
_("Unable to satisfy all constraints on the partition."));
707
next_primary (PedDisk* disk)
710
for (i=1; i<=MAX_PART_COUNT; i++) {
711
if (!ped_disk_get_partition (disk, i))
718
pc98_partition_enumerate (PedPartition* part)
720
PED_ASSERT (part != NULL);
721
PED_ASSERT (part->disk != NULL);
723
/* don't re-number a partition */
727
PED_ASSERT (ped_partition_is_active (part));
729
part->num = next_primary (part->disk);
731
ped_exception_throw (PED_EXCEPTION_ERROR,
732
PED_EXCEPTION_CANCEL,
733
_("Can't add another partition."));
741
pc98_alloc_metadata (PedDisk* disk)
743
PedPartition* new_part;
744
PedConstraint* constraint_any = NULL;
747
PED_ASSERT (disk != NULL);
748
PED_ASSERT (disk->dev != NULL);
750
constraint_any = ped_constraint_any (disk->dev);
752
cyl_size = disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
753
new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
758
if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
759
ped_partition_destroy (new_part);
763
ped_constraint_destroy (constraint_any);
767
ped_constraint_destroy (constraint_any);
772
pc98_get_max_primary_partition_count (const PedDisk* disk)
774
return MAX_PART_COUNT;
778
pc98_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
780
*max_n = MAX_PART_COUNT;
784
#include "pt-common.h"
785
PT_define_limit_functions (pc98)
787
static PedDiskOps pc98_disk_ops = {
789
write: NULL_IF_DISCOVER_ONLY (pc98_write),
791
partition_set_name: pc98_partition_set_name,
792
partition_get_name: pc98_partition_get_name,
794
get_partition_alignment: pc98_get_partition_alignment,
796
PT_op_function_initializers (pc98)
799
static PedDiskType pc98_disk_type = {
803
features: PED_DISK_TYPE_PARTITION_NAME
807
ped_disk_pc98_init ()
809
PED_ASSERT (sizeof (PC98RawTable) == 512 * 2);
810
ped_disk_type_register (&pc98_disk_type);
814
ped_disk_pc98_done ()
816
ped_disk_type_unregister (&pc98_disk_type);