| /* |
| libparted - a library for manipulating disk partitions |
| Copyright (C) 2000, 2002, 2004, 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 */ |
| |
| /* struct's hacked from Linux source: fs/partitions/mac.h |
| * I believe it was originally written by Paul Mackerras (from comments in |
| * Quik source) |
| * |
| * See also: |
| * http://developer.apple.com/documentation/mac/Devices/Devices-126.html |
| * http://developer.apple.com/documentation/mac/Devices/Devices-121.html |
| * http://devworld.apple.com/technotes/tn/tn1189.html |
| * |
| * Partition types: |
| * Apple_Bootstrap new-world (HFS) boot partition |
| * Apple_partition_map partition map (table) |
| * Apple_Driver device driver |
| * Apple_Driver43 SCSI Manager 4.3 device driver |
| * Apple_MFS original Macintosh File System |
| * Apple_HFS Hierarchical File System (and +) |
| * Apple_HFSX HFS+ with case sensitivity and more |
| * Apple_UNIX_SVR2 UNIX file system (UFS?) |
| * Apple_PRODOS ProDOS file system |
| * Apple_Free unused space |
| * Apple_Scratch empty |
| * Apple_Void padding for iso9660 |
| * Apple_Extra an unused partition map entry |
| * |
| * Quick explanation: |
| * ------------------ |
| * Terminology: |
| * |
| * Parted Apple |
| * ------ ----- |
| * device disk/device |
| * disk no equivalent. |
| * partition volume or partition |
| * sector block |
| * |
| * * All space must be accounted for, except block 0 (driver block) and |
| * block 1-X (the partition map: i.e. lots of MacRawPartitions) |
| * |
| * * It's really hard to grow/shrink the number of MacRawPartition |
| * entries in the partition map, because the first partition starts |
| * immediately after the partition map. When we can move the start of |
| * HFS and ext2 partitions, this problem will disappear ;-) |
| */ |
| |
| #define MAC_PARTITION_MAGIC_1 0x5453 /* old */ |
| #define MAC_PARTITION_MAGIC_2 0x504d |
| #define MAC_DISK_MAGIC 0x4552 |
| |
| #define MAC_STATUS_BOOTABLE 8 /* partition is bootable */ |
| |
| typedef struct _MacRawPartition MacRawPartition; |
| typedef struct _MacRawDisk MacRawDisk; |
| typedef struct _MacDeviceDriver MacDeviceDriver; |
| typedef struct _MacPartitionData MacPartitionData; |
| typedef struct _MacDiskData MacDiskData; |
| |
| struct __attribute__ ((packed)) _MacRawPartition { |
| uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */ |
| uint16_t res1; |
| uint32_t map_count; /* # blocks in partition map */ |
| uint32_t start_block; /* absolute starting block # of partition */ |
| uint32_t block_count; /* number of blocks in partition */ |
| char name[32]; /* partition name */ |
| char type[32]; /* string type description */ |
| uint32_t data_start; /* rel block # of first data block */ |
| uint32_t data_count; /* number of data blocks */ |
| uint32_t status; /* partition status bits */ |
| uint32_t boot_start; |
| uint32_t boot_count; |
| uint32_t boot_load; |
| uint32_t boot_load2; |
| uint32_t boot_entry; |
| uint32_t boot_entry2; |
| uint32_t boot_cksum; |
| char processor[16]; /* Contains 680x0, x=0,2,3,4; or empty */ |
| uint32_t driver_sig; |
| char _padding[372]; |
| }; |
| |
| /* Driver descriptor structure, in block 0 */ |
| struct __attribute__ ((packed)) _MacRawDisk { |
| uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */ |
| uint16_t block_size; /* physical sector size */ |
| uint32_t block_count; /* size of device in blocks */ |
| uint16_t dev_type; /* reserved */ |
| uint16_t dev_id; /* reserved */ |
| uint32_t data; /* reserved */ |
| uint16_t driver_count; /* # of driver descriptor entries */ |
| uint8_t driverlist[488];/* info about available drivers */ |
| uint16_t padding[3]; /* pad to 512 bytes */ |
| }; |
| |
| struct __attribute__ ((packed)) _MacDeviceDriver { |
| uint32_t block; /* startblock in MacRawDisk->block_size units */ |
| uint16_t size; /* size in 512 byte units */ |
| uint16_t type; /* operating system type (MacOS = 1) */ |
| }; |
| |
| struct _MacPartitionData { |
| char volume_name[33]; /* eg: "Games" */ |
| char system_name[33]; /* eg: "Apple_Unix_SVR2" */ |
| char processor_name[17]; |
| |
| int is_boot; |
| int is_driver; |
| int has_driver; |
| int is_root; |
| int is_swap; |
| int is_lvm; |
| int is_raid; |
| |
| PedSector data_region_length; |
| PedSector boot_region_length; |
| |
| uint32_t boot_base_address; |
| uint32_t boot_entry_address; |
| uint32_t boot_checksum; |
| |
| uint32_t status; |
| uint32_t driver_sig; |
| }; |
| |
| struct _MacDiskData { |
| int ghost_size; /* sectors per "driver" block */ |
| int part_map_entry_count; /* # entries (incl. ghost) */ |
| int part_map_entry_num; /* partition map location */ |
| |
| int active_part_entry_count; /* # real partitions */ |
| int free_part_entry_count; /* # free space */ |
| int last_part_entry_num; /* last entry number */ |
| |
| uint16_t block_size; /* physical sector size */ |
| uint16_t driver_count; |
| MacDeviceDriver driverlist[1 + 60]; /* 488 bytes */ |
| }; |
| |
| static PedDiskType mac_disk_type; |
| |
| static int |
| _check_signature (MacRawDisk* raw_disk) |
| { |
| if (PED_BE16_TO_CPU (raw_disk->signature) != MAC_DISK_MAGIC) { |
| #ifdef DISCOVER_ONLY |
| return 0; |
| #else |
| return ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_IGNORE_CANCEL, |
| _("Invalid signature %x for Mac disk labels."), |
| (int) PED_BE16_TO_CPU (raw_disk->signature)) |
| == PED_EXCEPTION_IGNORE; |
| #endif |
| } |
| |
| return 1; |
| } |
| |
| static int |
| _rawpart_check_signature (MacRawPartition* raw_part) |
| { |
| int sig = (int) PED_BE16_TO_CPU (raw_part->signature); |
| return sig == MAC_PARTITION_MAGIC_1 || sig == MAC_PARTITION_MAGIC_2; |
| } |
| |
| static int |
| mac_probe (const PedDevice * dev) |
| { |
| MacRawDisk buf; |
| |
| PED_ASSERT (dev != NULL, return 0); |
| |
| if (dev->sector_size != 512) |
| return 0; |
| |
| if (!ped_device_read (dev, &buf, 0, 1)) |
| return 0; |
| |
| return _check_signature (&buf); |
| } |
| |
| static int |
| _disk_add_part_map_entry (PedDisk* disk, int warn) |
| { |
| MacDiskData* mac_disk_data = disk->disk_specific; |
| PedPartition* new_part; |
| MacPartitionData* mac_part_data; |
| PedSector part_map_size; |
| PedConstraint* constraint_any = ped_constraint_any (disk->dev); |
| |
| #ifndef DISCOVER_ONLY |
| if (warn && ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL, |
| _("Partition map has no partition map entry!")) |
| != PED_EXCEPTION_FIX) |
| goto error; |
| #endif /* !DISCOVER_ONLY */ |
| |
| part_map_size |
| = ped_round_up_to (mac_disk_data->last_part_entry_num, 64); |
| if (part_map_size == 0) |
| part_map_size = 64; |
| |
| new_part = ped_partition_new (disk, 0, NULL, 1, part_map_size - 1); |
| if (!new_part) |
| goto error; |
| |
| mac_part_data = new_part->disk_specific; |
| strcpy (mac_part_data->volume_name, "Apple"); |
| strcpy (mac_part_data->system_name, "Apple_partition_map"); |
| |
| if (!ped_disk_add_partition (disk, new_part, constraint_any)) |
| goto error_destroy_new_part; |
| |
| mac_disk_data->part_map_entry_num = new_part->num; |
| mac_disk_data->part_map_entry_count |
| = new_part->geom.end - mac_disk_data->ghost_size; |
| ped_constraint_destroy (constraint_any); |
| return 1; |
| |
| error_destroy_new_part: |
| ped_partition_destroy (new_part); |
| error: |
| ped_constraint_destroy (constraint_any); |
| return 0; |
| } |
| |
| static PedDisk* |
| mac_alloc (const PedDevice* dev) |
| { |
| PedDisk* disk; |
| MacDiskData* mac_disk_data; |
| |
| PED_ASSERT (dev != NULL, return NULL); |
| |
| #ifndef DISCOVER_ONLY |
| if (dev->length < 256) { |
| ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("%s is too small for a Mac disk label!"), |
| dev->path); |
| goto error; |
| } |
| #endif |
| |
| disk = _ped_disk_alloc (dev, &mac_disk_type); |
| if (!disk) |
| goto error; |
| |
| mac_disk_data = (MacDiskData*) ped_malloc (sizeof (MacDiskData)); |
| if (!mac_disk_data) |
| goto error_free_disk; |
| disk->disk_specific = mac_disk_data; |
| mac_disk_data->ghost_size = disk->dev->sector_size / 512; |
| mac_disk_data->active_part_entry_count = 0; |
| mac_disk_data->free_part_entry_count = 1; |
| mac_disk_data->last_part_entry_num = 1; |
| mac_disk_data->block_size = 0; |
| mac_disk_data->driver_count = 0; |
| memset(&mac_disk_data->driverlist[0], 0, sizeof(mac_disk_data->driverlist)); |
| |
| if (!_disk_add_part_map_entry (disk, 0)) |
| goto error_free_disk; |
| return disk; |
| |
| error_free_disk: |
| _ped_disk_free (disk); |
| error: |
| return NULL; |
| } |
| |
| static PedDisk* |
| mac_duplicate (const PedDisk* disk) |
| { |
| PedDisk* new_disk; |
| MacDiskData* new_mac_data; |
| MacDiskData* old_mac_data = (MacDiskData*) disk->disk_specific; |
| PedPartition* partition_map; |
| |
| new_disk = ped_disk_new_fresh (disk->dev, &mac_disk_type); |
| if (!new_disk) |
| goto error; |
| |
| new_mac_data = (MacDiskData*) new_disk->disk_specific; |
| |
| /* remove the partition map partition - it will be duplicated |
| * later. |
| */ |
| partition_map = ped_disk_get_partition_by_sector (new_disk, 1); |
| PED_ASSERT (partition_map != NULL, return 0); |
| ped_disk_remove_partition (new_disk, partition_map); |
| |
| /* ugly, but C is ugly :p */ |
| memcpy (new_mac_data, old_mac_data, sizeof (MacDiskData)); |
| return new_disk; |
| |
| _ped_disk_free (new_disk); |
| error: |
| return NULL; |
| } |
| |
| static void |
| mac_free (PedDisk* disk) |
| { |
| MacDiskData* mac_disk_data = disk->disk_specific; |
| |
| _ped_disk_free (disk); |
| ped_free (mac_disk_data); |
| } |
| |
| #ifndef DISCOVER_ONLY |
| static int |
| _clobber_part_map (PedDevice* dev) |
| { |
| MacRawPartition raw_part; |
| PedSector sector; |
| |
| for (sector=1; 1; sector++) { |
| if (!ped_device_read (dev, &raw_part, sector, 1)) |
| return 0; |
| if (!_rawpart_check_signature (&raw_part)) |
| return 1; |
| memset (&raw_part, 0, 512); |
| if (!ped_device_write (dev, &raw_part, sector, 1)) |
| return 0; |
| } |
| } |
| |
| static int |
| mac_clobber (PedDevice* dev) |
| { |
| MacRawDisk raw_disk; |
| |
| if (!ped_device_read (dev, &raw_disk, 0, 1)) |
| return 0; |
| if (!_check_signature (&raw_disk)) |
| return 0; |
| memset (&raw_disk, 0, 512); |
| if (!ped_device_write (dev, &raw_disk, 0, 1)) |
| return 0; |
| |
| return _clobber_part_map (dev); |
| } |
| #endif /* !DISCOVER_ONLY */ |
| |
| static int |
| _rawpart_cmp_type (MacRawPartition* raw_part, char* type) |
| { |
| return strncasecmp (raw_part->type, type, 32) == 0; |
| } |
| |
| static int |
| _rawpart_cmp_name (MacRawPartition* raw_part, char* name) |
| { |
| return strncasecmp (raw_part->name, name, 32) == 0; |
| } |
| |
| static int |
| _rawpart_is_partition_map (MacRawPartition* raw_part) |
| { |
| return _rawpart_cmp_type (raw_part, "Apple_partition_map"); |
| } |
| |
| static int |
| strncasestr (const char* haystack, const char* needle, int n) |
| { |
| int needle_size = strlen (needle); |
| int i; |
| |
| for (i = 0; haystack[i] && i < n - needle_size; i++) { |
| if (strncasecmp (haystack + i, needle, needle_size) == 0) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| _rawpart_is_boot (MacRawPartition* raw_part) |
| { |
| if (!strcasecmp(raw_part->type, "Apple_Bootstrap")) |
| return 1; |
| |
| if (!strcasecmp(raw_part->type, "Apple_Boot")) |
| return 1; |
| |
| return 0; |
| } |
| |
| static int |
| _rawpart_is_driver (MacRawPartition* raw_part) |
| { |
| if (strncmp (raw_part->type, "Apple_", 6) != 0) |
| return 0; |
| if (!strncasestr (raw_part->type, "driver", 32)) |
| return 0; |
| return 1; |
| } |
| |
| static int |
| _rawpart_has_driver (MacRawPartition* raw_part, MacDiskData* mac_disk_data) |
| { |
| MacDeviceDriver *driverlist; |
| uint16_t i, bsz; |
| uint32_t driver_bs, driver_be, part_be; |
| |
| driverlist = &mac_disk_data->driverlist[0]; |
| bsz = mac_disk_data->block_size / 512; |
| for (i = 0; i < mac_disk_data->driver_count; i++) { |
| driver_bs = driverlist->block * bsz; |
| driver_be = driver_bs + driverlist->size; |
| part_be = raw_part->start_block + raw_part->block_count; |
| if (driver_bs >= raw_part->start_block && driver_be <= part_be) |
| return 1; |
| driverlist++; |
| } |
| return 0; |
| } |
| |
| static int |
| _rawpart_is_root (MacRawPartition* raw_part) |
| { |
| if (!_rawpart_cmp_type (raw_part, "Apple_UNIX_SVR2")) |
| return 0; |
| if (strcmp (raw_part->name, "root") != 0) |
| return 0; |
| return 1; |
| } |
| |
| static int |
| _rawpart_is_swap (MacRawPartition* raw_part) |
| { |
| if (!_rawpart_cmp_type (raw_part, "Apple_UNIX_SVR2")) |
| return 0; |
| if (strcmp (raw_part->name, "swap") != 0) |
| return 0; |
| return 1; |
| } |
| |
| static int |
| _rawpart_is_lvm (MacRawPartition* raw_part) |
| { |
| if (strcmp (raw_part->type, "Linux_LVM") != 0) |
| return 0; |
| return 1; |
| } |
| |
| static int |
| _rawpart_is_raid (MacRawPartition* raw_part) |
| { |
| if (strcmp (raw_part->type, "Linux_RAID") != 0) |
| return 0; |
| return 1; |
| } |
| |
| static int |
| _rawpart_is_void (MacRawPartition* raw_part) |
| { |
| return _rawpart_cmp_type (raw_part, "Apple_Void"); |
| } |
| |
| /* returns 1 if the raw_part represents a partition that is "unused space", or |
| * doesn't represent a partition at all. NOTE: some people make Apple_Free |
| * partitions with MacOS, because they can't select another type. So, if the |
| * name is anything other than "Extra" or "", it is treated as a "real" |
| * partition. |
| */ |
| static int |
| _rawpart_is_active (MacRawPartition* raw_part) |
| { |
| if (_rawpart_cmp_type (raw_part, "Apple_Free") |
| && (_rawpart_cmp_name (raw_part, "Extra") |
| || _rawpart_cmp_name (raw_part, ""))) |
| return 0; |
| if (_rawpart_cmp_type (raw_part, "Apple_Void")) |
| return 0; |
| if (_rawpart_cmp_type (raw_part, "Apple_Scratch")) |
| return 0; |
| if (_rawpart_cmp_type (raw_part, "Apple_Extra")) |
| return 0; |
| |
| return 1; |
| } |
| |
| static PedPartition* |
| _rawpart_analyse (MacRawPartition* raw_part, PedDisk* disk, int num) |
| { |
| MacDiskData* mac_disk_data; |
| PedPartition* part; |
| MacPartitionData* mac_part_data; |
| PedSector block_size; |
| PedSector start, length; |
| |
| if (!_rawpart_check_signature (raw_part)) { |
| #ifndef DISCOVER_ONLY |
| if (ped_exception_throw ( |
| PED_EXCEPTION_WARNING, |
| PED_EXCEPTION_IGNORE_CANCEL, |
| _("Partition %d has an invalid signature %x."), |
| num, |
| (int) PED_BE16_TO_CPU (raw_part->signature)) |
| != PED_EXCEPTION_IGNORE) |
| #endif |
| goto error; |
| } |
| |
| mac_disk_data = (MacDiskData*) disk->disk_specific; |
| block_size = disk->dev->sector_size / 512; |
| |
| start = PED_BE32_TO_CPU (raw_part->start_block) * block_size; |
| length = PED_BE32_TO_CPU (raw_part->block_count) * block_size; |
| if (length == 0) { |
| #ifndef DISCOVER_ONLY |
| ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Partition %d has an invalid length of 0 bytes!"), |
| num); |
| #endif |
| return NULL; |
| } |
| part = ped_partition_new (disk, 0, NULL, start, start + length - 1); |
| if (!part) |
| goto error; |
| |
| mac_part_data = part->disk_specific; |
| |
| strncpy (mac_part_data->volume_name, raw_part->name, 32); |
| strncpy (mac_part_data->system_name, raw_part->type, 32); |
| strncpy (mac_part_data->processor_name, raw_part->processor, 16); |
| |
| mac_part_data->is_boot = _rawpart_is_boot (raw_part); |
| mac_part_data->is_driver = _rawpart_is_driver (raw_part); |
| if (mac_part_data->is_driver) |
| mac_part_data->has_driver = _rawpart_has_driver(raw_part, mac_disk_data); |
| mac_part_data->is_root = _rawpart_is_root (raw_part); |
| mac_part_data->is_swap = _rawpart_is_swap (raw_part); |
| mac_part_data->is_lvm = _rawpart_is_lvm (raw_part); |
| mac_part_data->is_raid = _rawpart_is_raid (raw_part); |
| |
| /* "data" region */ |
| #ifndef DISCOVER_ONLY |
| if (raw_part->data_start) { |
| ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("The data region doesn't start at the start " |
| "of the partition.")); |
| goto error_destroy_part; |
| } |
| #endif /* !DISCOVER_ONLY */ |
| mac_part_data->data_region_length |
| = PED_BE32_TO_CPU (raw_part->data_count) * block_size; |
| |
| /* boot region - we have no idea what this is for, but Mac OSX |
| * seems to put garbage here, and doesn't pay any attention to |
| * it afterwards. [clausen, dan burcaw] |
| */ |
| #if 0 |
| if (raw_part->boot_start) { |
| ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("The boot region doesn't start at the start " |
| "of the partition.")); |
| goto error_destroy_part; |
| } |
| #endif |
| mac_part_data->boot_region_length |
| = PED_BE32_TO_CPU (raw_part->boot_count) * block_size; |
| |
| #ifndef DISCOVER_ONLY |
| if (mac_part_data->has_driver) { |
| if (mac_part_data->boot_region_length < part->geom.length) { |
| if (ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_IGNORE_CANCEL, |
| _("The partition's boot region doesn't occupy " |
| "the entire partition.")) |
| != PED_EXCEPTION_IGNORE) |
| goto error_destroy_part; |
| } |
| } else { |
| if (mac_part_data->data_region_length < part->geom.length && |
| !mac_part_data->is_boot) { |
| if (ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_IGNORE_CANCEL, |
| _("The partition's data region doesn't occupy " |
| "the entire partition.")) |
| != PED_EXCEPTION_IGNORE) |
| goto error_destroy_part; |
| } |
| } |
| #endif /* !DISCOVER_ONLY */ |
| |
| mac_part_data->boot_base_address |
| = PED_BE32_TO_CPU (raw_part->boot_load); |
| mac_part_data->boot_entry_address |
| = PED_BE32_TO_CPU (raw_part->boot_entry); |
| mac_part_data->boot_checksum |
| = PED_BE32_TO_CPU (raw_part->boot_cksum); |
| |
| mac_part_data->status = PED_BE32_TO_CPU (raw_part->status); |
| mac_part_data->driver_sig = PED_BE32_TO_CPU (raw_part->driver_sig); |
| |
| return part; |
| |
| error_destroy_part: |
| ped_partition_destroy (part); |
| error: |
| return NULL; |
| } |
| |
| /* looks at the partition map size field in a mac raw partition, and calculates |
| * what the size of the partition map should be, from it |
| */ |
| static int |
| _rawpart_get_partmap_size (MacRawPartition* raw_part, PedDisk* disk) |
| { |
| MacDiskData* mac_disk_data = disk->disk_specific; |
| PedSector sector_size = disk->dev->sector_size / 512; |
| PedSector part_map_start; |
| PedSector part_map_end; |
| |
| part_map_start = mac_disk_data->ghost_size; |
| part_map_end = sector_size * PED_BE32_TO_CPU (raw_part->map_count); |
| |
| return part_map_end - part_map_start + 1; |
| } |
| |
| static int |
| _disk_analyse_block_size (PedDisk* disk, MacRawDisk* raw_disk) |
| { |
| PedSector block_size; |
| |
| if (PED_BE16_TO_CPU (raw_disk->block_size) % 512) { |
| #ifndef DISCOVER_ONLY |
| ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Weird block size on device descriptor: %d bytes is " |
| "not divisible by 512."), |
| (int) PED_BE16_TO_CPU (raw_disk->block_size)); |
| #endif |
| goto error; |
| } |
| |
| block_size = PED_BE16_TO_CPU (raw_disk->block_size) / 512; |
| if (block_size != disk->dev->sector_size / 512) { |
| #ifndef DISCOVER_ONLY |
| if (ped_exception_throw ( |
| PED_EXCEPTION_WARNING, |
| PED_EXCEPTION_IGNORE_CANCEL, |
| _("The driver descriptor says the physical block size " |
| "is %d bytes, but Linux says it is %d bytes."), |
| (int) block_size * 512, |
| (int) disk->dev->sector_size) |
| != PED_EXCEPTION_IGNORE) |
| goto error; |
| #endif |
| disk->dev->sector_size = block_size * 512; |
| } |
| |
| return 1; |
| |
| error: |
| return 0; |
| } |
| |
| /* Tries to figure out the block size used by the drivers, for the ghost |
| * partitioning scheme. Ghost partitioning works like this: the OpenFirmware |
| * (OF) sees 512 byte blocks, but some drivers use 2048 byte blocks (and, |
| * perhaps, some other number?). To remain compatible, the partition map |
| * only has "real" partition map entries on ghost-aligned block numbers (and |
| * the others are padded with Apple_Void partitions). This function tries |
| * to figure out what the "ghost-aligned" size is... (which, believe-it-or-not, |
| * doesn't always equal 2048!!!) |
| */ |
| static int |
| _disk_analyse_ghost_size (PedDisk* disk) |
| { |
| MacDiskData* mac_disk_data = disk->disk_specific; |
| MacRawPartition raw_part; |
| int i; |
| |
| for (i = 1; i < 64; i *= 2) { |
| if (!ped_device_read (disk->dev, &raw_part, i, 1)) |
| return 0; |
| if (_rawpart_check_signature (&raw_part) |
| && !_rawpart_is_void (&raw_part)) { |
| mac_disk_data->ghost_size = i; |
| PED_ASSERT (i <= disk->dev->sector_size / 512, |
| return 0); |
| return 1; |
| } |
| } |
| |
| #ifndef DISCOVER_ONLY |
| ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("No valid partition map found.")); |
| #endif |
| return 0; |
| } |
| |
| static int |
| mac_read (PedDisk* disk) |
| { |
| MacRawDisk raw_disk; |
| MacRawPartition raw_part; |
| MacDiskData* mac_disk_data; |
| PedPartition* part; |
| int num; |
| PedSector ghost_size; |
| PedConstraint* constraint_exact; |
| int last_part_entry_num = 0; |
| |
| PED_ASSERT (disk != NULL, return 0); |
| |
| mac_disk_data = disk->disk_specific; |
| mac_disk_data->part_map_entry_num = 0; /* 0 == none */ |
| |
| if (!ped_device_read (disk->dev, &raw_disk, 0, 1)) |
| goto error; |
| if (!_check_signature (&raw_disk)) |
| goto error; |
| |
| if (!_disk_analyse_block_size (disk, &raw_disk)) |
| goto error; |
| if (!_disk_analyse_ghost_size (disk)) |
| goto error; |
| ghost_size = mac_disk_data->ghost_size; |
| |
| if (!ped_disk_delete_all (disk)) |
| goto error; |
| |
| if (raw_disk.driver_count && raw_disk.driver_count < 62) { |
| memcpy(&mac_disk_data->driverlist[0], &raw_disk.driverlist[0], |
| sizeof(mac_disk_data->driverlist)); |
| mac_disk_data->driver_count = raw_disk.driver_count; |
| mac_disk_data->block_size = raw_disk.block_size; |
| } |
| |
| for (num=1; num==1 || num <= last_part_entry_num; num++) { |
| if (!ped_device_read (disk->dev, &raw_part, |
| num * ghost_size, 1)) |
| goto error_delete_all; |
| |
| if (!_rawpart_check_signature (&raw_part)) |
| continue; |
| |
| if (num == 1) |
| last_part_entry_num |
| = _rawpart_get_partmap_size (&raw_part, disk); |
| if (_rawpart_get_partmap_size (&raw_part, disk) |
| != last_part_entry_num) { |
| if (ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_IGNORE_CANCEL, |
| _("Conflicting partition map entry sizes! " |
| "Entry 1 says it is %d, but entry %d says " |
| "it is %d!"), |
| last_part_entry_num, |
| _rawpart_get_partmap_size (&raw_part, disk)) |
| != PED_EXCEPTION_IGNORE) |
| goto error_delete_all; |
| } |
| |
| if (!_rawpart_is_active (&raw_part)) |
| continue; |
| |
| part = _rawpart_analyse (&raw_part, disk, num); |
| if (!part) |
| goto error_delete_all; |
| part->num = num; |
| part->fs_type = ped_file_system_probe (&part->geom); |
| constraint_exact = ped_constraint_exact (&part->geom); |
| if (!ped_disk_add_partition (disk, part, constraint_exact)) |
| goto error_delete_all; |
| ped_constraint_destroy (constraint_exact); |
| |
| if (_rawpart_is_partition_map (&raw_part)) { |
| if (mac_disk_data->part_map_entry_num |
| && ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_IGNORE_CANCEL, |
| _("Weird! There are 2 partitions " |
| "map entries!")) |
| != PED_EXCEPTION_IGNORE) |
| goto error_delete_all; |
| |
| mac_disk_data->part_map_entry_num = num; |
| mac_disk_data->part_map_entry_count |
| = part->geom.end - ghost_size + 1; |
| } |
| } |
| |
| if (!mac_disk_data->part_map_entry_num) { |
| if (!_disk_add_part_map_entry (disk, 1)) |
| goto error_delete_all; |
| ped_disk_commit_to_dev (disk); |
| } |
| return 1; |
| |
| error_delete_all: |
| ped_disk_delete_all (disk); |
| error: |
| return 0; |
| } |
| |
| #ifndef DISCOVER_ONLY |
| /* The Ghost partition: is a blank entry, used to pad out each block (where |
| * there physical block size > 512 bytes). This is because OpenFirmware uses |
| * 512 byte blocks, but device drivers Think Different TM, with a different |
| * lbock size, so we need to do this to avoid a clash (!) |
| */ |
| static int |
| _pad_raw_part (PedDisk* disk, int num, MacRawPartition* part_map) |
| { |
| MacDiskData* mac_disk_data = disk->disk_specific; |
| MacRawPartition ghost_entry; |
| int i; |
| |
| memset (&ghost_entry, 0, sizeof (ghost_entry)); |
| ghost_entry.signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2); |
| strcpy (ghost_entry.type, "Apple_Void"); |
| ghost_entry.map_count |
| = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num); |
| |
| for (i=0; i < mac_disk_data->ghost_size - 1; i++) |
| memcpy (&part_map [i + (num - 1) * mac_disk_data->ghost_size], |
| &ghost_entry, sizeof (MacRawPartition)); |
| |
| return 1; |
| } |
| |
| static void |
| _update_driver_count (MacRawPartition* part_map_entry, |
| MacDiskData *mac_driverdata, const MacDiskData* mac_disk_data) |
| { |
| uint16_t i, count_orig, count_cur, bsz; |
| uint32_t driver_bs, driver_be, part_be; |
| |
| bsz = mac_disk_data->block_size / 512; |
| count_cur = mac_driverdata->driver_count; |
| count_orig = mac_disk_data->driver_count; |
| for (i = 0; i < count_orig; i++) { |
| driver_bs = mac_disk_data->driverlist[i].block * bsz; |
| driver_be = driver_bs + mac_disk_data->driverlist[i].size; |
| part_be = part_map_entry->start_block + part_map_entry->block_count; |
| if (driver_bs >= part_map_entry->start_block |
| && driver_be <= part_be) { |
| mac_driverdata->driverlist[count_cur].block |
| = mac_disk_data->driverlist[i].block; |
| mac_driverdata->driverlist[count_cur].size |
| = mac_disk_data->driverlist[i].size; |
| mac_driverdata->driverlist[count_cur].type |
| = mac_disk_data->driverlist[i].type; |
| mac_driverdata->driver_count++; |
| break; |
| } |
| } |
| } |
| |
| static int |
| _generate_raw_part (PedDisk* disk, PedPartition* part, |
| MacRawPartition* part_map, MacDiskData *mac_driverdata) |
| { |
| MacDiskData* mac_disk_data; |
| MacPartitionData* mac_part_data; |
| MacRawPartition* part_map_entry; |
| PedSector block_size = disk->dev->sector_size / 512; |
| |
| PED_ASSERT (part->num > 0, goto error); |
| |
| mac_disk_data = disk->disk_specific; |
| mac_part_data = part->disk_specific; |
| |
| part_map_entry = &part_map [part->num * mac_disk_data->ghost_size - 1]; |
| |
| part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2); |
| part_map_entry->map_count |
| = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num); |
| part_map_entry->start_block |
| = PED_CPU_TO_BE32 (part->geom.start / block_size); |
| part_map_entry->block_count |
| = PED_CPU_TO_BE32 (part->geom.length / block_size); |
| strcpy (part_map_entry->name, mac_part_data->volume_name); |
| strcpy (part_map_entry->type, mac_part_data->system_name); |
| |
| if (mac_part_data->is_driver) { |
| mac_part_data->boot_region_length = part->geom.length; |
| if (mac_part_data->has_driver) |
| _update_driver_count(part_map_entry, mac_driverdata, |
| mac_disk_data); |
| } else |
| mac_part_data->data_region_length = part->geom.length; |
| part_map_entry->data_count = PED_CPU_TO_BE32 ( |
| mac_part_data->data_region_length / block_size); |
| part_map_entry->boot_count = PED_CPU_TO_BE32 ( |
| mac_part_data->boot_region_length / block_size); |
| part_map_entry->status = PED_CPU_TO_BE32 (mac_part_data->status); |
| part_map_entry->driver_sig |
| = PED_CPU_TO_BE32 (mac_part_data->driver_sig); |
| |
| part_map_entry->boot_load = |
| PED_CPU_TO_BE32 (mac_part_data->boot_base_address); |
| part_map_entry->boot_entry = |
| PED_CPU_TO_BE32 (mac_part_data->boot_entry_address); |
| part_map_entry->boot_cksum = |
| PED_CPU_TO_BE32 (mac_part_data->boot_checksum); |
| |
| strncpy (part_map_entry->processor, mac_part_data->processor_name, 16); |
| |
| if (!_pad_raw_part (disk, part->num, part_map)) |
| goto error; |
| |
| return 1; |
| |
| error: |
| return 0; |
| } |
| |
| static int |
| _generate_raw_freespace_part (PedDisk* disk, PedGeometry* geom, int num, |
| MacRawPartition* part_map) |
| { |
| MacDiskData* mac_disk_data = disk->disk_specific; |
| MacRawPartition* part_map_entry; |
| PedSector block_size = disk->dev->sector_size / 512; |
| |
| PED_ASSERT (num > 0, goto error); |
| |
| part_map_entry = &part_map [num * mac_disk_data->ghost_size - 1]; |
| |
| part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2); |
| part_map_entry->map_count |
| = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num); |
| part_map_entry->start_block |
| = PED_CPU_TO_BE32 (geom->start / block_size); |
| part_map_entry->block_count |
| = PED_CPU_TO_BE32 (geom->length / block_size); |
| strcpy (part_map_entry->name, "Extra"); |
| strcpy (part_map_entry->type, "Apple_Free"); |
| |
| part_map_entry->data_count = PED_CPU_TO_BE32 (geom->length); |
| part_map_entry->status = 0; |
| part_map_entry->driver_sig = 0; |
| |
| if (!_pad_raw_part (disk, num, part_map)) |
| goto error; |
| |
| return 1; |
| |
| error: |
| return 0; |
| } |
| |
| static int |
| _generate_empty_part (PedDisk* disk, int num, MacRawPartition* part_map) |
| { |
| MacDiskData* mac_disk_data = disk->disk_specific; |
| MacRawPartition* part_map_entry; |
| |
| PED_ASSERT (num > 0, return 0); |
| |
| part_map_entry = &part_map [num * mac_disk_data->ghost_size - 1]; |
| part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2); |
| part_map_entry->map_count |
| = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num); |
| strcpy (part_map_entry->type, "Apple_Void"); |
| |
| return _pad_raw_part (disk, num, part_map); |
| } |
| |
| /* returns the first empty entry in the partition map */ |
| static int |
| _get_first_empty_part_entry (PedDisk* disk, MacRawPartition* part_map) |
| { |
| MacDiskData* mac_disk_data = disk->disk_specific; |
| int i; |
| |
| for (i=1; i <= mac_disk_data->last_part_entry_num; i++) { |
| if (!part_map[i * mac_disk_data->ghost_size - 1].signature) |
| return i; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| write_block_zero (PedDisk* disk, MacDiskData* mac_driverdata) |
| { |
| PedDevice* dev = disk->dev; |
| MacRawDisk raw_disk; |
| |
| if (!ped_device_read (dev, &raw_disk, 0, 1)) |
| return 0; |
| |
| raw_disk.signature = PED_CPU_TO_BE16 (MAC_DISK_MAGIC); |
| raw_disk.block_size = PED_CPU_TO_BE16 (dev->sector_size); |
| raw_disk.block_count |
| = PED_CPU_TO_BE32 (dev->length / (dev->sector_size / 512)); |
| |
| raw_disk.driver_count = mac_driverdata->driver_count; |
| memcpy(&raw_disk.driverlist[0], &mac_driverdata->driverlist[0], |
| sizeof(raw_disk.driverlist)); |
| |
| return ped_device_write (dev, &raw_disk, 0, 1); |
| } |
| |
| static int |
| mac_write (PedDisk* disk) |
| { |
| MacRawPartition* part_map; |
| MacDiskData* mac_disk_data; |
| MacDiskData* mac_driverdata; /* updated driver list */ |
| PedPartition* part; |
| int num; |
| |
| PED_ASSERT (disk != NULL, return 0); |
| PED_ASSERT (disk->disk_specific != NULL, return 0); |
| PED_ASSERT (disk->dev != NULL, return 0); |
| PED_ASSERT (!disk->update_mode, return 0); |
| |
| mac_disk_data = disk->disk_specific; |
| |
| if (!ped_disk_get_partition (disk, mac_disk_data->part_map_entry_num)) { |
| if (!_disk_add_part_map_entry (disk, 1)) |
| goto error; |
| } |
| |
| mac_driverdata = ped_malloc(sizeof(MacDiskData)); |
| if (!mac_driverdata) |
| goto error; |
| memset (mac_driverdata, 0, sizeof(MacDiskData)); |
| |
| part_map = (MacRawPartition*) |
| ped_malloc (mac_disk_data->part_map_entry_count * 512); |
| if (!part_map) |
| goto error_free_driverdata; |
| memset (part_map, 0, mac_disk_data->part_map_entry_count * 512); |
| |
| /* write (to memory) the "real" partitions */ |
| for (part = ped_disk_next_partition (disk, NULL); part; |
| part = ped_disk_next_partition (disk, part)) { |
| if (!ped_partition_is_active (part)) |
| continue; |
| if (!_generate_raw_part (disk, part, part_map, mac_driverdata)) |
| goto error_free_part_map; |
| } |
| |
| /* write the "free space" partitions */ |
| for (part = ped_disk_next_partition (disk, NULL); part; |
| part = ped_disk_next_partition (disk, part)) { |
| if (part->type != PED_PARTITION_FREESPACE) |
| continue; |
| num = _get_first_empty_part_entry (disk, part_map); |
| if (!_generate_raw_freespace_part (disk, &part->geom, num, |
| part_map)) |
| goto error_free_part_map; |
| } |
| |
| /* write the "void" (empty) partitions */ |
| for (num = _get_first_empty_part_entry (disk, part_map); num; |
| num = _get_first_empty_part_entry (disk, part_map)) |
| _generate_empty_part (disk, num, part_map); |
| |
| /* write to disk */ |
| if (!ped_device_write (disk->dev, part_map, 1, |
| mac_disk_data->part_map_entry_count)) |
| goto error_free_part_map; |
| ped_free (part_map); |
| return write_block_zero (disk, mac_driverdata); |
| |
| error_free_part_map: |
| ped_free (part_map); |
| error_free_driverdata: |
| ped_free (mac_driverdata); |
| error: |
| return 0; |
| } |
| #endif /* !DISCOVER_ONLY */ |
| |
| static PedPartition* |
| mac_partition_new ( |
| const PedDisk* disk, PedPartitionType part_type, |
| const PedFileSystemType* fs_type, PedSector start, PedSector end) |
| { |
| PedPartition* part; |
| MacPartitionData* mac_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 |
| = mac_data = ped_malloc (sizeof (MacPartitionData)); |
| if (!mac_data) |
| goto error_free_part; |
| |
| memset (mac_data, 0, sizeof (MacPartitionData)); |
| strcpy (mac_data->volume_name, "untitled"); |
| } else { |
| part->disk_specific = NULL; |
| } |
| return part; |
| |
| ped_free (mac_data); |
| error_free_part: |
| ped_free (part); |
| error: |
| return 0; |
| } |
| |
| static PedPartition* |
| mac_partition_duplicate (const PedPartition* part) |
| { |
| PedPartition* new_part; |
| MacPartitionData* new_mac_data; |
| MacPartitionData* old_mac_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_mac_data = (MacPartitionData*) part->disk_specific; |
| new_mac_data = (MacPartitionData*) new_part->disk_specific; |
| |
| /* ugly, but C is ugly :p */ |
| memcpy (new_mac_data, old_mac_data, sizeof (MacPartitionData)); |
| return new_part; |
| } |
| |
| static void |
| mac_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 |
| mac_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type) |
| { |
| MacPartitionData* mac_data = part->disk_specific; |
| |
| part->fs_type = fs_type; |
| |
| if (fs_type && !strcmp (fs_type->name, "linux-swap")) |
| ped_partition_set_flag (part, PED_PARTITION_SWAP, 1); |
| |
| if (mac_data->is_boot) { |
| strcpy (mac_data->system_name, "Apple_Bootstrap"); |
| mac_data->status = 0x33; |
| return 1; |
| } |
| |
| if (fs_type && (!strcmp (fs_type->name, "hfs") |
| || !strcmp (fs_type->name, "hfs+"))) { |
| strcpy (mac_data->system_name, "Apple_HFS"); |
| mac_data->status |= 0x7f; |
| } else if (fs_type && !strcmp (fs_type->name, "hfsx")) { |
| strcpy (mac_data->system_name, "Apple_HFSX"); |
| mac_data->status |= 0x7f; |
| } else { |
| strcpy (mac_data->system_name, "Apple_UNIX_SVR2"); |
| mac_data->status = 0x33; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| mac_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state) |
| { |
| MacPartitionData* mac_data; |
| |
| PED_ASSERT (part != NULL, return 0); |
| PED_ASSERT (part->disk_specific != NULL, return 0); |
| |
| mac_data = part->disk_specific; |
| |
| switch (flag) { |
| case PED_PARTITION_BOOT: |
| mac_data->is_boot = state; |
| |
| if (part->fs_type) |
| return mac_partition_set_system (part, part->fs_type); |
| |
| if (state) { |
| strcpy (mac_data->system_name, "Apple_Bootstrap"); |
| mac_data->status = 0x33; |
| } |
| return 1; |
| |
| case PED_PARTITION_ROOT: |
| if (state) { |
| strcpy (mac_data->volume_name, "root"); |
| mac_data->is_swap = 0; |
| } else { |
| if (mac_data->is_root) |
| strcpy (mac_data->volume_name, "untitled"); |
| } |
| mac_data->is_root = state; |
| return 1; |
| |
| case PED_PARTITION_SWAP: |
| if (state) { |
| strcpy (mac_data->volume_name, "swap"); |
| mac_data->is_root = 0; |
| } else { |
| if (mac_data->is_swap) |
| strcpy (mac_data->volume_name, "untitled"); |
| } |
| mac_data->is_swap = state; |
| return 1; |
| |
| case PED_PARTITION_LVM: |
| if (state) { |
| strcpy (mac_data->system_name, "Linux_LVM"); |
| mac_data->is_lvm = state; |
| } else { |
| if (mac_data->is_lvm) |
| mac_partition_set_system (part, part->fs_type); |
| } |
| return 1; |
| |
| case PED_PARTITION_RAID: |
| if (state) { |
| strcpy (mac_data->system_name, "Linux_RAID"); |
| mac_data->is_raid = state; |
| } else { |
| if (mac_data->is_raid) |
| mac_partition_set_system (part, part->fs_type); |
| } |
| return 1; |
| |
| default: |
| return 0; |
| } |
| } |
| |
| static int |
| mac_partition_get_flag (const PedPartition* part, PedPartitionFlag flag) |
| { |
| MacPartitionData* mac_data; |
| |
| PED_ASSERT (part != NULL, return 0); |
| PED_ASSERT (part->disk_specific != NULL, return 0); |
| |
| mac_data = part->disk_specific; |
| switch (flag) { |
| case PED_PARTITION_BOOT: |
| return mac_data->is_boot; |
| |
| case PED_PARTITION_ROOT: |
| return mac_data->is_root; |
| |
| case PED_PARTITION_SWAP: |
| return mac_data->is_swap; |
| |
| case PED_PARTITION_LVM: |
| return mac_data->is_lvm; |
| |
| case PED_PARTITION_RAID: |
| return mac_data->is_raid; |
| |
| default: |
| return 0; |
| } |
| } |
| |
| static int |
| mac_partition_is_flag_available ( |
| const PedPartition* part, PedPartitionFlag flag) |
| { |
| switch (flag) { |
| case PED_PARTITION_BOOT: |
| case PED_PARTITION_ROOT: |
| case PED_PARTITION_SWAP: |
| case PED_PARTITION_LVM: |
| case PED_PARTITION_RAID: |
| return 1; |
| |
| default: |
| return 0; |
| } |
| } |
| |
| static void |
| mac_partition_set_name (PedPartition* part, const char* name) |
| { |
| MacPartitionData* mac_data; |
| int i; |
| |
| PED_ASSERT (part != NULL, return); |
| PED_ASSERT (part->disk_specific != NULL, return); |
| mac_data = part->disk_specific; |
| |
| #ifndef DISCOVER_ONLY |
| if (mac_data->is_root || mac_data->is_swap) { |
| if (ped_exception_throw ( |
| PED_EXCEPTION_WARNING, |
| PED_EXCEPTION_IGNORE_CANCEL, |
| _("Changing the name of a root or swap partition " |
| "will prevent Linux from recognising it as such.")) |
| != PED_EXCEPTION_IGNORE) |
| return; |
| mac_data->is_root = mac_data->is_swap = 0; |
| } |
| #endif |
| |
| strncpy (mac_data->volume_name, name, 32); |
| mac_data->volume_name [32] = 0; |
| for (i = strlen (mac_data->volume_name) - 1; |
| mac_data->volume_name[i] == ' '; i--) |
| mac_data->volume_name [i] = 0; |
| } |
| |
| static const char* |
| mac_partition_get_name (const PedPartition* part) |
| { |
| MacPartitionData* mac_data; |
| |
| PED_ASSERT (part != NULL, return NULL); |
| PED_ASSERT (part->disk_specific != NULL, return NULL); |
| mac_data = part->disk_specific; |
| |
| return mac_data->volume_name; |
| } |
| |
| static PedConstraint* |
| _primary_constraint (PedDisk* disk) |
| { |
| PedAlignment start_align; |
| PedAlignment end_align; |
| PedGeometry max_geom; |
| PedSector sector_size; |
| |
| sector_size = disk->dev->sector_size / 512; |
| |
| if (!ped_alignment_init (&start_align, 0, sector_size)) |
| return NULL; |
| if (!ped_alignment_init (&end_align, -1, sector_size)) |
| return NULL; |
| if (!ped_geometry_init (&max_geom, disk->dev, 1, disk->dev->length - 1)) |
| return NULL; |
| |
| return ped_constraint_new (&start_align, &end_align, &max_geom, |
| &max_geom, 1, disk->dev->length); |
| } |
| |
| static int |
| mac_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 |
| mac_partition_enumerate (PedPartition* part) |
| { |
| PedDisk* disk; |
| MacDiskData* mac_disk_data; |
| int i; |
| int max_part_count; |
| |
| PED_ASSERT (part != NULL, return 0); |
| PED_ASSERT (part->disk != NULL, return 0); |
| |
| disk = part->disk; |
| mac_disk_data = (MacDiskData*) disk->disk_specific; |
| |
| max_part_count = ped_disk_get_max_primary_partition_count (disk); |
| |
| if (part->num > 0 && part->num <= mac_disk_data->part_map_entry_count) |
| return 1; |
| |
| for (i = 1; i <= max_part_count; i++) { |
| if (!ped_disk_get_partition (disk, i)) { |
| part->num = i; |
| return 1; |
| } |
| } |
| |
| #ifndef DISCOVER_ONLY |
| ped_exception_throw ( |
| PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Can't add another partition -- the partition map is too " |
| "small!")); |
| #endif |
| |
| return 0; |
| } |
| |
| static int |
| _disk_count_partitions (PedDisk* disk) |
| { |
| MacDiskData* mac_disk_data = disk->disk_specific; |
| PedPartition* part = NULL; |
| PedPartition* last = NULL; |
| |
| PED_ASSERT (disk->update_mode, return 0); |
| |
| mac_disk_data->active_part_entry_count = 0; |
| mac_disk_data->free_part_entry_count = 0; |
| mac_disk_data->last_part_entry_num = 0; |
| |
| /* subtle: we only care about free space after the partition map. |
| * the partition map is an "active" partition, BTW... */ |
| for (part = ped_disk_next_partition (disk, part); part; |
| part = ped_disk_next_partition (disk, part)) { |
| if (!ped_partition_is_active (part)) |
| continue; |
| |
| mac_disk_data->active_part_entry_count++; |
| if (last && last->geom.end + 1 < part->geom.start) |
| mac_disk_data->free_part_entry_count++; |
| mac_disk_data->last_part_entry_num |
| = PED_MAX (mac_disk_data->last_part_entry_num, |
| part->num); |
| |
| last = part; |
| } |
| |
| if (last && last->geom.end < disk->dev->length - 1) |
| mac_disk_data->free_part_entry_count++; |
| |
| mac_disk_data->last_part_entry_num |
| = PED_MAX (mac_disk_data->last_part_entry_num, |
| mac_disk_data->active_part_entry_count |
| + mac_disk_data->free_part_entry_count); |
| return 1; |
| } |
| |
| static int |
| add_metadata_part (PedDisk* disk, PedSector start, PedSector end) |
| { |
| PedPartition* new_part; |
| PedConstraint* constraint_any = ped_constraint_any (disk->dev); |
| |
| PED_ASSERT (disk != NULL, return 0); |
| |
| new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, |
| start, end); |
| if (!new_part) |
| goto error; |
| if (!ped_disk_add_partition (disk, new_part, constraint_any)) |
| goto error_destroy_new_part; |
| |
| ped_constraint_destroy (constraint_any); |
| return 1; |
| |
| error_destroy_new_part: |
| ped_partition_destroy (new_part); |
| error: |
| ped_constraint_destroy (constraint_any); |
| return 0; |
| } |
| |
| static int |
| mac_alloc_metadata (PedDisk* disk) |
| { |
| MacDiskData* mac_disk_data; |
| |
| PED_ASSERT (disk != NULL, return 0); |
| PED_ASSERT (disk->disk_specific != NULL, return 0); |
| PED_ASSERT (disk->dev != NULL, return 0); |
| |
| mac_disk_data = disk->disk_specific; |
| |
| if (!add_metadata_part (disk, 0, disk->dev->sector_size / 512 - 1)) |
| return 0; |
| |
| /* hack: this seems to be a good place, to update the partition map |
| * entry count, since mac_alloc_metadata() gets called during |
| * _disk_pop_update_mode() |
| */ |
| return _disk_count_partitions (disk); |
| } |
| |
| static int |
| mac_get_max_primary_partition_count (const PedDisk* disk) |
| { |
| MacDiskData* mac_disk_data = disk->disk_specific; |
| PedPartition* part_map_partition; |
| |
| part_map_partition = ped_disk_get_partition (disk, |
| mac_disk_data->part_map_entry_num); |
| |
| /* HACK: if we haven't found the partition map partition (yet), |
| * we return this. |
| */ |
| if (!part_map_partition) { |
| mac_disk_data->part_map_entry_num = 0; |
| return 65536; |
| } |
| |
| /* HACK: since Mac labels need an entry for free-space regions, we |
| * must allow half plus 1 entries for free-space partitions. I hate |
| * this, but things get REALLY complicated, otherwise. |
| * (I'm prepared to complicate things later, but I want to get |
| * everything working, first) |
| */ |
| return mac_disk_data->part_map_entry_count / mac_disk_data->ghost_size |
| - mac_disk_data->free_part_entry_count + 1; |
| } |
| |
| static PedDiskOps mac_disk_ops = { |
| probe: mac_probe, |
| #ifndef DISCOVER_ONLY |
| clobber: mac_clobber, |
| #else |
| clobber: NULL, |
| #endif |
| alloc: mac_alloc, |
| duplicate: mac_duplicate, |
| free: mac_free, |
| read: mac_read, |
| #ifndef DISCOVER_ONLY |
| /* FIXME: remove this cast, once mac_write is fixed not to |
| modify its *DISK parameter. */ |
| write: (int (*) (const PedDisk*)) mac_write, |
| #else |
| write: NULL, |
| #endif |
| |
| partition_new: mac_partition_new, |
| partition_duplicate: mac_partition_duplicate, |
| partition_destroy: mac_partition_destroy, |
| partition_set_system: mac_partition_set_system, |
| partition_set_flag: mac_partition_set_flag, |
| partition_get_flag: mac_partition_get_flag, |
| partition_is_flag_available: mac_partition_is_flag_available, |
| partition_set_name: mac_partition_set_name, |
| partition_get_name: mac_partition_get_name, |
| partition_align: mac_partition_align, |
| partition_enumerate: mac_partition_enumerate, |
| |
| alloc_metadata: mac_alloc_metadata, |
| get_max_primary_partition_count: |
| mac_get_max_primary_partition_count |
| }; |
| |
| static PedDiskType mac_disk_type = { |
| next: NULL, |
| name: "mac", |
| ops: &mac_disk_ops, |
| features: PED_DISK_TYPE_PARTITION_NAME |
| }; |
| |
| void |
| ped_disk_mac_init () |
| { |
| PED_ASSERT (sizeof (MacRawPartition) == 512, return); |
| PED_ASSERT (sizeof (MacRawDisk) == 512, return); |
| |
| ped_disk_type_register (&mac_disk_type); |
| } |
| |
| void |
| ped_disk_mac_done () |
| { |
| ped_disk_type_unregister (&mac_disk_type); |
| } |
| |