| /* |
| libparted - a library for manipulating disk partitions |
| Copyright (C) 2000, 2001, 2007 Free Software Foundation, Inc. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <config.h> |
| |
| #include <parted/parted.h> |
| #include <parted/debug.h> |
| #include <parted/endian.h> |
| |
| #if ENABLE_NLS |
| # include <libintl.h> |
| # define _(String) dgettext (PACKAGE, String) |
| #else |
| # define _(String) (String) |
| #endif /* ENABLE_NLS */ |
| |
| /* hacked from Linux/98 source: fs/partitions/nec98.h |
| * |
| * See also: |
| * http://people.FreeBSD.org/~kato/pc98.html |
| * http://www.kmc.kyoto-u.ac.jp/proj/linux98/index-english.html |
| * |
| * Partition types: |
| * |
| * id0(mid): |
| * bit 7: 1=bootable, 0=not bootable |
| * # Linux uses this flag to make a distinction between ext2 and swap. |
| * bit 6--0: |
| * 00H : N88-BASIC(data)?, PC-UX(data)? |
| * 04H : PC-UX(data) |
| * 06H : N88-BASIC |
| * 10H : N88-BASIC |
| * 14H : *BSD, PC-UX |
| * 20H : DOS(data), Windows95/98/NT, Linux |
| * 21H..2FH : DOS(system#1 .. system#15) |
| * 40H : Minix |
| * |
| * id1(sid): |
| * bit 7: 1=active, 0=sleep(hidden) |
| * # PC-UX uses this flag to make a distinction between its file system |
| * # and its swap. |
| * bit 6--0: |
| * 01H: FAT12 |
| * 11H: FAT16, <32MB [accessible to DOS 3.3] |
| * 21H: FAT16, >=32MB [Large Partition] |
| * 31H: NTFS |
| * 28H: Windows NT (Volume/Stripe Set?) |
| * 41H: Windows NT (Volume/Stripe Set?) |
| * 48H: Windows NT (Volume/Stripe Set?) |
| * 61H: FAT32 |
| * 04H: PC-UX |
| * 06H: N88-BASIC |
| * 44H: *BSD |
| * 62H: ext2, linux-swap |
| */ |
| |
| #define MAX_PART_COUNT 16 |
| #define PC9800_EXTFMT_MAGIC 0xAA55 |
| |
| #define BIT(x) (1 << (x)) |
| #define GET_BIT(n,bit) (((n) & BIT(bit)) != 0) |
| #define SET_BIT(n,bit,val) n = (val)? (n | BIT(bit)) : (n & ~BIT(bit)) |
| |
| typedef struct _PC98RawPartition PC98RawPartition; |
| typedef struct _PC98RawTable PC98RawTable; |
| |
| /* ripped from Linux/98 source */ |
| struct _PC98RawPartition { |
| uint8_t mid; /* 0x80 - boot */ |
| uint8_t sid; /* 0x80 - active */ |
| uint8_t dum1; /* dummy for padding */ |
| uint8_t dum2; /* dummy for padding */ |
| uint8_t ipl_sect; /* IPL sector */ |
| uint8_t ipl_head; /* IPL head */ |
| uint16_t ipl_cyl; /* IPL cylinder */ |
| uint8_t sector; /* starting sector */ |
| uint8_t head; /* starting head */ |
| uint16_t cyl; /* starting cylinder */ |
| uint8_t end_sector; /* end sector */ |
| uint8_t end_head; /* end head */ |
| uint16_t end_cyl; /* end cylinder */ |
| char name[16]; |
| } __attribute__((packed)); |
| |
| struct _PC98RawTable { |
| uint8_t boot_code [510]; |
| uint16_t magic; |
| PC98RawPartition partitions [MAX_PART_COUNT]; |
| } __attribute__((packed)); |
| |
| typedef struct { |
| PedSector ipl_sector; |
| int system; |
| int boot; |
| int hidden; |
| char name [17]; |
| } PC98PartitionData; |
| |
| /* this MBR boot code is dummy */ |
| static const char MBR_BOOT_CODE[] = { |
| 0xcb, /* retf */ |
| 0x00, 0x00, 0x00, /* */ |
| 0x49, 0x50, 0x4c, 0x31 /* "IPL1" */ |
| }; |
| |
| static PedDiskType pc98_disk_type; |
| |
| static PedSector chs_to_sector (const PedDevice* dev, int c, int h, int s); |
| static void sector_to_chs (const PedDevice* dev, PedSector sector, |
| int* c, int* h, int* s); |
| |
| /* magic(?) check */ |
| static int |
| pc98_check_magic (const PC98RawTable *part_table) |
| { |
| /* check "extended-format" (have partition table?) */ |
| if (PED_LE16_TO_CPU(part_table->magic) != PC9800_EXTFMT_MAGIC) |
| return 0; |
| |
| return 1; |
| } |
| |
| static int |
| pc98_check_ipl_signature (const PC98RawTable *part_table) |
| { |
| return !memcmp (part_table->boot_code + 4, "IPL1", 4); |
| } |
| |
| static int |
| check_partition_consistency (const PedDevice* dev, |
| const PC98RawPartition* raw_part) |
| { |
| if (raw_part->ipl_sect >= dev->hw_geom.sectors |
| || raw_part->sector >= dev->hw_geom.sectors |
| || raw_part->end_sector >= dev->hw_geom.sectors |
| || raw_part->ipl_head >= dev->hw_geom.heads |
| || raw_part->head >= dev->hw_geom.heads |
| || raw_part->end_head >= dev->hw_geom.heads |
| || PED_LE16_TO_CPU(raw_part->ipl_cyl) >= dev->hw_geom.cylinders |
| || PED_LE16_TO_CPU(raw_part->cyl) >= dev->hw_geom.cylinders |
| || PED_LE16_TO_CPU(raw_part->end_cyl) >= dev->hw_geom.cylinders |
| || PED_LE16_TO_CPU(raw_part->cyl) |
| > PED_LE16_TO_CPU(raw_part->end_cyl) |
| #if 0 |
| || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->ipl_cyl), |
| raw_part->ipl_head, raw_part->ipl_sect) |
| || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->cyl), |
| raw_part->head, raw_part->sector) |
| || !chs_to_sector(dev, PED_LE16_TO_CPU(raw_part->end_cyl), |
| raw_part->end_head, raw_part->end_sector) |
| #endif |
| || PED_LE16_TO_CPU(raw_part->end_cyl) |
| < PED_LE16_TO_CPU(raw_part->cyl)) |
| return 0; |
| |
| return 1; |
| } |
| |
| static int |
| pc98_probe (const PedDevice *dev) |
| { |
| PC98RawTable part_table; |
| int empty; |
| const PC98RawPartition* p; |
| |
| PED_ASSERT (dev != NULL, return 0); |
| |
| if (dev->sector_size != 512) |
| return 0; |
| |
| if (!ped_device_read (dev, &part_table, 0, 2)) |
| return 0; |
| |
| /* check magic */ |
| if (!pc98_check_magic (&part_table)) |
| return 0; |
| |
| /* check consistency */ |
| empty = 1; |
| for (p = part_table.partitions; |
| p < part_table.partitions + MAX_PART_COUNT; |
| p++) |
| { |
| if (p->mid == 0 && p->sid == 0) |
| continue; |
| empty = 0; |
| if (!check_partition_consistency (dev, p)) |
| return 0; |
| } |
| |
| /* check boot loader */ |
| if (pc98_check_ipl_signature (&part_table)) |
| return 1; |
| else if (part_table.boot_code[0]) /* invalid boot loader */ |
| return 0; |
| |
| /* Not to mistake msdos disk map for PC-9800's empty disk map */ |
| if (empty) |
| return 0; |
| |
| return 1; |
| } |
| |
| #ifndef DISCOVER_ONLY |
| static int |
| pc98_clobber (PedDevice* dev) |
| { |
| PC98RawTable table; |
| |
| PED_ASSERT (dev != NULL, return 0); |
| PED_ASSERT (pc98_probe (dev), return 0); |
| |
| if (!ped_device_read (dev, &table, 0, 1)) |
| return 0; |
| |
| memset (table.partitions, 0, sizeof (table.partitions)); |
| table.magic = PED_CPU_TO_LE16(0); |
| |
| if (pc98_check_ipl_signature (&table)) |
| memset (table.boot_code, 0, sizeof (table.boot_code)); |
| |
| if (!ped_device_write (dev, (void*) &table, 0, 1)) |
| return 0; |
| return ped_device_sync (dev); |
| } |
| #endif /* !DISCOVER_ONLY */ |
| |
| static PedDisk* |
| pc98_alloc (const PedDevice* dev) |
| { |
| PED_ASSERT (dev != NULL, return 0); |
| |
| return _ped_disk_alloc (dev, &pc98_disk_type); |
| } |
| |
| static PedDisk* |
| pc98_duplicate (const PedDisk* disk) |
| { |
| return ped_disk_new_fresh (disk->dev, &pc98_disk_type); |
| } |
| |
| static void |
| pc98_free (PedDisk* disk) |
| { |
| PED_ASSERT (disk != NULL, return); |
| |
| _ped_disk_free (disk); |
| } |
| |
| static PedSector |
| chs_to_sector (const PedDevice* dev, int c, int h, int s) |
| { |
| PED_ASSERT (dev != NULL, return 0); |
| return (c * dev->hw_geom.heads + h) * dev->hw_geom.sectors + s; |
| } |
| |
| static void |
| sector_to_chs (const PedDevice* dev, PedSector sector, int* c, int* h, int* s) |
| { |
| PedSector cyl_size; |
| |
| PED_ASSERT (dev != NULL, return); |
| PED_ASSERT (c != NULL, return); |
| PED_ASSERT (h != NULL, return); |
| PED_ASSERT (s != NULL, return); |
| |
| cyl_size = dev->hw_geom.heads * dev->hw_geom.sectors; |
| |
| *c = sector / cyl_size; |
| *h = (sector) % cyl_size / dev->hw_geom.sectors; |
| *s = (sector) % cyl_size % dev->hw_geom.sectors; |
| } |
| |
| static PedSector |
| legacy_start (const PedDisk* disk, const PC98RawPartition* raw_part) |
| { |
| PED_ASSERT (disk != NULL, return 0); |
| PED_ASSERT (raw_part != NULL, return 0); |
| |
| return chs_to_sector (disk->dev, PED_LE16_TO_CPU(raw_part->cyl), |
| raw_part->head, raw_part->sector); |
| } |
| |
| static PedSector |
| legacy_end (const PedDisk* disk, const PC98RawPartition* raw_part) |
| { |
| PED_ASSERT (disk != NULL, return 0); |
| PED_ASSERT (raw_part != NULL, return 0); |
| |
| if (raw_part->end_head == 0 && raw_part->end_sector == 0) { |
| return chs_to_sector (disk->dev, |
| PED_LE16_TO_CPU(raw_part->end_cyl), |
| disk->dev->hw_geom.heads - 1, |
| disk->dev->hw_geom.sectors - 1); |
| } else { |
| return chs_to_sector (disk->dev, |
| PED_LE16_TO_CPU(raw_part->end_cyl), |
| raw_part->end_head, |
| raw_part->end_sector); |
| } |
| } |
| |
| static int |
| is_unused_partition(const PC98RawPartition* raw_part) |
| { |
| if (raw_part->mid || raw_part->sid |
| || raw_part->ipl_sect |
| || raw_part->ipl_head |
| || PED_LE16_TO_CPU(raw_part->ipl_cyl) |
| || raw_part->sector |
| || raw_part->head |
| || PED_LE16_TO_CPU(raw_part->cyl) |
| || raw_part->end_sector |
| || raw_part->end_head |
| || PED_LE16_TO_CPU(raw_part->end_cyl)) |
| return 0; |
| return 1; |
| } |
| |
| static int |
| read_table (PedDisk* disk) |
| { |
| int i; |
| PC98RawTable table; |
| PedConstraint* constraint_any; |
| |
| PED_ASSERT (disk != NULL, return 0); |
| PED_ASSERT (disk->dev != NULL, return 0); |
| |
| constraint_any = ped_constraint_any (disk->dev); |
| |
| if (!ped_device_read (disk->dev, (void*) &table, 0, 2)) |
| goto error; |
| |
| if (!pc98_check_magic(&table)) { |
| if (ped_exception_throw ( |
| PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL, |
| _("Invalid partition table on %s."), |
| disk->dev->path)) |
| goto error; |
| } |
| |
| for (i = 0; i < MAX_PART_COUNT; i++) { |
| PC98RawPartition* raw_part; |
| PedPartition* part; |
| PC98PartitionData* pc98_data; |
| PedSector part_start; |
| PedSector part_end; |
| |
| raw_part = &table.partitions [i]; |
| |
| if (is_unused_partition(raw_part)) |
| continue; |
| |
| part_start = legacy_start (disk, raw_part); |
| part_end = legacy_end (disk, raw_part); |
| |
| part = ped_partition_new (disk, 0, NULL, part_start, part_end); |
| if (!part) |
| goto error; |
| pc98_data = part->disk_specific; |
| PED_ASSERT (pc98_data != NULL, goto error); |
| |
| pc98_data->system = (raw_part->mid << 8) | raw_part->sid; |
| pc98_data->boot = GET_BIT(raw_part->mid, 7); |
| pc98_data->hidden = !GET_BIT(raw_part->sid, 7); |
| |
| ped_partition_set_name (part, raw_part->name); |
| |
| pc98_data->ipl_sector = chs_to_sector ( |
| disk->dev, |
| PED_LE16_TO_CPU(raw_part->ipl_cyl), |
| raw_part->ipl_head, |
| raw_part->ipl_sect); |
| |
| /* hack */ |
| if (pc98_data->ipl_sector == part->geom.start) |
| pc98_data->ipl_sector = 0; |
| |
| part->num = i + 1; |
| |
| if (!ped_disk_add_partition (disk, part, constraint_any)) |
| goto error; |
| |
| if (part->geom.start != part_start |
| || part->geom.end != part_end) { |
| ped_exception_throw ( |
| PED_EXCEPTION_NO_FEATURE, |
| PED_EXCEPTION_CANCEL, |
| _("Partition %d isn't aligned to cylinder " |
| "boundaries. This is still unsupported."), |
| part->num); |
| goto error; |
| } |
| |
| part->fs_type = ped_file_system_probe (&part->geom); |
| } |
| |
| ped_constraint_destroy (constraint_any); |
| return 1; |
| |
| error: |
| ped_disk_delete_all (disk); |
| ped_constraint_destroy (constraint_any); |
| return 0; |
| } |
| |
| static int |
| pc98_read (PedDisk* disk) |
| { |
| PED_ASSERT (disk != NULL, return 0); |
| PED_ASSERT (disk->dev != NULL, return 0); |
| |
| ped_disk_delete_all (disk); |
| return read_table (disk); |
| } |
| |
| #ifndef DISCOVER_ONLY |
| static int |
| fill_raw_part (PC98RawPartition* raw_part, const PedPartition* part) |
| { |
| PC98PartitionData* pc98_data; |
| int c, h, s; |
| const char* name; |
| |
| PED_ASSERT (raw_part != NULL, return 0); |
| PED_ASSERT (part != NULL, return 0); |
| PED_ASSERT (part->disk_specific != NULL, return 0); |
| |
| pc98_data = part->disk_specific; |
| raw_part->mid = (pc98_data->system >> 8) & 0xFF; |
| raw_part->sid = pc98_data->system & 0xFF; |
| |
| SET_BIT(raw_part->mid, 7, pc98_data->boot); |
| SET_BIT(raw_part->sid, 7, !pc98_data->hidden); |
| |
| memset (raw_part->name, ' ', sizeof(raw_part->name)); |
| name = ped_partition_get_name (part); |
| PED_ASSERT (name != NULL, return 0); |
| PED_ASSERT (strlen (name) <= 16, return 0); |
| if (!strlen (name) && part->fs_type) |
| name = part->fs_type->name; |
| memcpy (raw_part->name, name, strlen (name)); |
| |
| sector_to_chs (part->disk->dev, part->geom.start, &c, &h, &s); |
| raw_part->cyl = PED_CPU_TO_LE16(c); |
| raw_part->head = h; |
| raw_part->sector = s; |
| |
| if (pc98_data->ipl_sector) { |
| sector_to_chs (part->disk->dev, pc98_data->ipl_sector, |
| &c, &h, &s); |
| raw_part->ipl_cyl = PED_CPU_TO_LE16(c); |
| raw_part->ipl_head = h; |
| raw_part->ipl_sect = s; |
| } else { |
| raw_part->ipl_cyl = raw_part->cyl; |
| raw_part->ipl_head = raw_part->head; |
| raw_part->ipl_sect = raw_part->sector; |
| } |
| |
| sector_to_chs (part->disk->dev, part->geom.end, &c, &h, &s); |
| if (h != part->disk->dev->hw_geom.heads - 1 |
| || s != part->disk->dev->hw_geom.sectors - 1) { |
| ped_exception_throw ( |
| PED_EXCEPTION_NO_FEATURE, |
| PED_EXCEPTION_CANCEL, |
| _("Partition %d isn't aligned to cylinder " |
| "boundaries. This is still unsupported."), |
| part->num); |
| return 0; |
| } |
| raw_part->end_cyl = PED_CPU_TO_LE16(c); |
| #if 0 |
| raw_part->end_head = h; |
| raw_part->end_sector = s; |
| #else |
| raw_part->end_head = 0; |
| raw_part->end_sector = 0; |
| #endif |
| |
| return 1; |
| } |
| |
| static int |
| pc98_write (const PedDisk* disk) |
| { |
| PC98RawTable table; |
| PedPartition* part; |
| int i; |
| |
| PED_ASSERT (disk != NULL, return 0); |
| PED_ASSERT (disk->dev != NULL, return 0); |
| |
| if (!ped_device_read (disk->dev, &table, 0, 2)) |
| return 0; |
| |
| if (!pc98_check_ipl_signature (&table)) { |
| memset (table.boot_code, 0, sizeof(table.boot_code)); |
| memcpy (table.boot_code, MBR_BOOT_CODE, sizeof(MBR_BOOT_CODE)); |
| } |
| |
| memset (table.partitions, 0, sizeof (table.partitions)); |
| table.magic = PED_CPU_TO_LE16(PC9800_EXTFMT_MAGIC); |
| |
| for (i = 1; i <= MAX_PART_COUNT; i++) { |
| part = ped_disk_get_partition (disk, i); |
| if (!part) |
| continue; |
| |
| if (!fill_raw_part (&table.partitions [i - 1], part)) |
| return 0; |
| } |
| |
| if (!ped_device_write (disk->dev, (void*) &table, 0, 2)) |
| return 0; |
| return ped_device_sync (disk->dev); |
| } |
| #endif /* !DISCOVER_ONLY */ |
| |
| static PedPartition* |
| pc98_partition_new ( |
| const PedDisk* disk, PedPartitionType part_type, |
| const PedFileSystemType* fs_type, PedSector start, PedSector end) |
| { |
| PedPartition* part; |
| PC98PartitionData* pc98_data; |
| |
| part = _ped_partition_alloc (disk, part_type, fs_type, start, end); |
| if (!part) |
| goto error; |
| |
| if (ped_partition_is_active (part)) { |
| part->disk_specific |
| = pc98_data = ped_malloc (sizeof (PC98PartitionData)); |
| if (!pc98_data) |
| goto error_free_part; |
| pc98_data->ipl_sector = 0; |
| pc98_data->hidden = 0; |
| pc98_data->boot = 0; |
| strcpy (pc98_data->name, ""); |
| } else { |
| part->disk_specific = NULL; |
| } |
| return part; |
| |
| ped_free (pc98_data); |
| error_free_part: |
| ped_free (part); |
| error: |
| return 0; |
| } |
| |
| static PedPartition* |
| pc98_partition_duplicate (const PedPartition* part) |
| { |
| PedPartition* new_part; |
| PC98PartitionData* new_pc98_data; |
| PC98PartitionData* old_pc98_data; |
| |
| new_part = ped_partition_new (part->disk, part->type, |
| part->fs_type, part->geom.start, |
| part->geom.end); |
| if (!new_part) |
| return NULL; |
| new_part->num = part->num; |
| |
| old_pc98_data = (PC98PartitionData*) part->disk_specific; |
| new_pc98_data = (PC98PartitionData*) new_part->disk_specific; |
| |
| /* ugly, but C is ugly :p */ |
| memcpy (new_pc98_data, old_pc98_data, sizeof (PC98PartitionData)); |
| return new_part; |
| } |
| |
| static void |
| pc98_partition_destroy (PedPartition* part) |
| { |
| PED_ASSERT (part != NULL, return); |
| |
| if (ped_partition_is_active (part)) |
| ped_free (part->disk_specific); |
| ped_free (part); |
| } |
| |
| static int |
| pc98_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type) |
| { |
| PC98PartitionData* pc98_data = part->disk_specific; |
| |
| part->fs_type = fs_type; |
| |
| pc98_data->system = 0x2062; |
| if (fs_type) { |
| if (!strcmp (fs_type->name, "fat16")) { |
| if (part->geom.length * 512 >= 32 * 1024 * 1024) |
| pc98_data->system = 0x2021; |
| else |
| pc98_data->system = 0x2011; |
| } else if (!strcmp (fs_type->name, "fat32")) { |
| pc98_data->system = 0x2061; |
| } else if (!strcmp (fs_type->name, "ntfs")) { |
| pc98_data->system = 0x2031; |
| } else if (!strncmp (fs_type->name, "ufs", 3)) { |
| pc98_data->system = 0x2044; |
| } else { /* ext2, reiser, xfs, etc. */ |
| /* ext2 partitions must be marked boot */ |
| pc98_data->boot = 1; |
| pc98_data->system = 0xa062; |
| } |
| } |
| |
| if (pc98_data->boot) |
| pc98_data->system |= 0x8000; |
| if (!pc98_data->hidden) |
| pc98_data->system |= 0x0080; |
| return 1; |
| } |
| |
| static int |
| pc98_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state) |
| { |
| PC98PartitionData* pc98_data; |
| |
| PED_ASSERT (part != NULL, return 0); |
| PED_ASSERT (part->disk_specific != NULL, return 0); |
| |
| pc98_data = part->disk_specific; |
| |
| switch (flag) { |
| case PED_PARTITION_HIDDEN: |
| pc98_data->hidden = state; |
| return ped_partition_set_system (part, part->fs_type); |
| |
| case PED_PARTITION_BOOT: |
| pc98_data->boot = state; |
| return ped_partition_set_system (part, part->fs_type); |
| |
| default: |
| return 0; |
| } |
| } |
| |
| static int |
| pc98_partition_get_flag (const PedPartition* part, PedPartitionFlag flag) |
| { |
| PC98PartitionData* pc98_data; |
| |
| PED_ASSERT (part != NULL, return 0); |
| PED_ASSERT (part->disk_specific != NULL, return 0); |
| |
| pc98_data = part->disk_specific; |
| switch (flag) { |
| case PED_PARTITION_HIDDEN: |
| return pc98_data->hidden; |
| |
| case PED_PARTITION_BOOT: |
| return pc98_data->boot; |
| |
| default: |
| return 0; |
| } |
| } |
| |
| static int |
| pc98_partition_is_flag_available ( |
| const PedPartition* part, PedPartitionFlag flag) |
| { |
| switch (flag) { |
| case PED_PARTITION_HIDDEN: |
| case PED_PARTITION_BOOT: |
| return 1; |
| |
| default: |
| return 0; |
| } |
| } |
| |
| static void |
| pc98_partition_set_name (PedPartition* part, const char* name) |
| { |
| PC98PartitionData* pc98_data; |
| int i; |
| |
| PED_ASSERT (part != NULL, return); |
| PED_ASSERT (part->disk_specific != NULL, return); |
| pc98_data = part->disk_specific; |
| |
| strncpy (pc98_data->name, name, 16); |
| pc98_data->name [16] = 0; |
| for (i = strlen (pc98_data->name) - 1; pc98_data->name[i] == ' '; i--) |
| pc98_data->name [i] = 0; |
| } |
| |
| static const char* |
| pc98_partition_get_name (const PedPartition* part) |
| { |
| PC98PartitionData* pc98_data; |
| |
| PED_ASSERT (part != NULL, return NULL); |
| PED_ASSERT (part->disk_specific != NULL, return NULL); |
| pc98_data = part->disk_specific; |
| |
| return pc98_data->name; |
| } |
| |
| static PedConstraint* |
| _primary_constraint (PedDisk* disk) |
| { |
| PedDevice* dev = disk->dev; |
| PedAlignment start_align; |
| PedAlignment end_align; |
| PedGeometry max_geom; |
| PedSector cylinder_size; |
| |
| cylinder_size = dev->hw_geom.sectors * dev->hw_geom.heads; |
| |
| if (!ped_alignment_init (&start_align, 0, cylinder_size)) |
| return NULL; |
| if (!ped_alignment_init (&end_align, -1, cylinder_size)) |
| return NULL; |
| if (!ped_geometry_init (&max_geom, dev, cylinder_size, |
| dev->length - cylinder_size)) |
| return NULL; |
| |
| return ped_constraint_new (&start_align, &end_align, &max_geom, |
| &max_geom, 1, dev->length); |
| } |
| |
| static int |
| pc98_partition_align (PedPartition* part, const PedConstraint* constraint) |
| { |
| PED_ASSERT (part != NULL, return 0); |
| |
| if (_ped_partition_attempt_align (part, constraint, |
| _primary_constraint (part->disk))) |
| return 1; |
| |
| #ifndef DISCOVER_ONLY |
| ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Unable to satisfy all constraints on the partition.")); |
| #endif |
| return 0; |
| } |
| |
| static int |
| next_primary (PedDisk* disk) |
| { |
| int i; |
| for (i=1; i<=MAX_PART_COUNT; i++) { |
| if (!ped_disk_get_partition (disk, i)) |
| return i; |
| } |
| return 0; |
| } |
| |
| static int |
| pc98_partition_enumerate (PedPartition* part) |
| { |
| PED_ASSERT (part != NULL, return 0); |
| PED_ASSERT (part->disk != NULL, return 0); |
| |
| /* don't re-number a partition */ |
| if (part->num != -1) |
| return 1; |
| |
| PED_ASSERT (ped_partition_is_active (part), return 0); |
| |
| part->num = next_primary (part->disk); |
| if (!part->num) { |
| ped_exception_throw (PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Can't add another partition.")); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| pc98_alloc_metadata (PedDisk* disk) |
| { |
| PedPartition* new_part; |
| PedConstraint* constraint_any = NULL; |
| PedSector cyl_size; |
| |
| PED_ASSERT (disk != NULL, goto error); |
| PED_ASSERT (disk->dev != NULL, goto error); |
| |
| constraint_any = ped_constraint_any (disk->dev); |
| |
| cyl_size = disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads; |
| new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, |
| 0, cyl_size - 1); |
| if (!new_part) |
| goto error; |
| |
| if (!ped_disk_add_partition (disk, new_part, constraint_any)) { |
| ped_partition_destroy (new_part); |
| goto error; |
| } |
| |
| ped_constraint_destroy (constraint_any); |
| return 1; |
| |
| error: |
| ped_constraint_destroy (constraint_any); |
| return 0; |
| } |
| |
| static int |
| pc98_get_max_primary_partition_count (const PedDisk* disk) |
| { |
| return MAX_PART_COUNT; |
| } |
| |
| static PedDiskOps pc98_disk_ops = { |
| probe: pc98_probe, |
| #ifndef DISCOVER_ONLY |
| clobber: pc98_clobber, |
| #else |
| clobber: NULL, |
| #endif |
| alloc: pc98_alloc, |
| duplicate: pc98_duplicate, |
| free: pc98_free, |
| read: pc98_read, |
| #ifndef DISCOVER_ONLY |
| write: pc98_write, |
| #else |
| write: NULL, |
| #endif |
| |
| partition_new: pc98_partition_new, |
| partition_duplicate: pc98_partition_duplicate, |
| partition_destroy: pc98_partition_destroy, |
| partition_set_system: pc98_partition_set_system, |
| partition_set_flag: pc98_partition_set_flag, |
| partition_get_flag: pc98_partition_get_flag, |
| partition_is_flag_available: pc98_partition_is_flag_available, |
| partition_set_name: pc98_partition_set_name, |
| partition_get_name: pc98_partition_get_name, |
| partition_align: pc98_partition_align, |
| partition_enumerate: pc98_partition_enumerate, |
| |
| alloc_metadata: pc98_alloc_metadata, |
| get_max_primary_partition_count: |
| pc98_get_max_primary_partition_count |
| }; |
| |
| static PedDiskType pc98_disk_type = { |
| next: NULL, |
| name: "pc98", |
| ops: &pc98_disk_ops, |
| features: PED_DISK_TYPE_PARTITION_NAME |
| }; |
| |
| void |
| ped_disk_pc98_init () |
| { |
| PED_ASSERT (sizeof (PC98RawTable) == 512 * 2, return); |
| ped_disk_type_register (&pc98_disk_type); |
| } |
| |
| void |
| ped_disk_pc98_done () |
| { |
| ped_disk_type_unregister (&pc98_disk_type); |
| } |