1N/A/*
1N/A libparted - a library for manipulating disk partitions
1N/A Copyright (C) 2000, 2002, 2004, 2007-2010 Free Software Foundation,
1N/A Inc.
1N/A
1N/A This program is free software; you can redistribute it and/or modify
1N/A it under the terms of the GNU General Public License as published by
1N/A the Free Software Foundation; either version 3 of the License, or
1N/A (at your option) any later version.
1N/A
1N/A This program is distributed in the hope that it will be useful,
1N/A but WITHOUT ANY WARRANTY; without even the implied warranty of
1N/A MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A GNU General Public License for more details.
1N/A
1N/A You should have received a copy of the GNU General Public License
1N/A along with this program. If not, see <http://www.gnu.org/licenses/>.
1N/A*/
1N/A
1N/A#include <config.h>
1N/A
1N/A#include <parted/parted.h>
1N/A#include <parted/debug.h>
1N/A#include <parted/endian.h>
1N/A#include <stdbool.h>
1N/A
1N/A#if ENABLE_NLS
1N/A# include <libintl.h>
1N/A# define _(String) dgettext (PACKAGE, String)
1N/A#else
1N/A# define _(String) (String)
1N/A#endif /* ENABLE_NLS */
1N/A
1N/A#include "misc.h"
1N/A#include "pt-tools.h"
1N/A
1N/A/* struct's hacked from Linux source: fs/partitions/mac.h
1N/A * I believe it was originally written by Paul Mackerras (from comments in
1N/A * Quik source)
1N/A *
1N/A * See also:
1N/A * http://developer.apple.com/documentation/mac/Devices/Devices-126.html
1N/A * http://developer.apple.com/documentation/mac/Devices/Devices-121.html
1N/A * http://devworld.apple.com/technotes/tn/tn1189.html
1N/A *
1N/A * Partition types:
1N/A * Apple_Bootstrap new-world (HFS) boot partition
1N/A * Apple_partition_map partition map (table)
1N/A * Apple_Driver device driver
1N/A * Apple_Driver43 SCSI Manager 4.3 device driver
1N/A * Apple_MFS original Macintosh File System
1N/A * Apple_HFS Hierarchical File System (and +)
1N/A * Apple_HFSX HFS+ with case sensitivity and more
1N/A * Apple_UNIX_SVR2 UNIX file system (UFS?)
1N/A * Apple_PRODOS ProDOS file system
1N/A * Apple_Free unused space
1N/A * Apple_Scratch empty
1N/A * Apple_Void padding for iso9660
1N/A * Apple_Extra an unused partition map entry
1N/A *
1N/A * Quick explanation:
1N/A * ------------------
1N/A * Terminology:
1N/A *
1N/A * Parted Apple
1N/A * ------ -----
1N/A * device disk/device
1N/A * disk no equivalent.
1N/A * partition volume or partition
1N/A * sector block
1N/A *
1N/A * * All space must be accounted for, except block 0 (driver block) and
1N/A * block 1-X (the partition map: i.e. lots of MacRawPartitions)
1N/A *
1N/A * * It's really hard to grow/shrink the number of MacRawPartition
1N/A * entries in the partition map, because the first partition starts
1N/A * immediately after the partition map. When we can move the start of
1N/A * HFS and ext2 partitions, this problem will disappear ;-)
1N/A */
1N/A
1N/A#define MAC_PARTITION_MAGIC_1 0x5453 /* old */
1N/A#define MAC_PARTITION_MAGIC_2 0x504d
1N/A#define MAC_DISK_MAGIC 0x4552
1N/A
1N/A#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */
1N/A
1N/Atypedef struct _MacRawPartition MacRawPartition;
1N/Atypedef struct _MacRawDisk MacRawDisk;
1N/Atypedef struct _MacDeviceDriver MacDeviceDriver;
1N/Atypedef struct _MacPartitionData MacPartitionData;
1N/Atypedef struct _MacDiskData MacDiskData;
1N/A
1N/A#ifdef __sun
1N/A#define __attribute__(X) /*nothing*/
1N/A#endif /* __sun */
1N/A
1N/A#ifdef __sun
1N/A#pragma pack(1)
1N/A#endif
1N/Astruct __attribute__ ((packed)) _MacRawPartition {
1N/A uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
1N/A uint16_t res1;
1N/A uint32_t map_count; /* # blocks in partition map */
1N/A uint32_t start_block; /* absolute starting block # of partition */
1N/A uint32_t block_count; /* number of blocks in partition */
1N/A char name[32]; /* partition name */
1N/A char type[32]; /* string type description */
1N/A uint32_t data_start; /* rel block # of first data block */
1N/A uint32_t data_count; /* number of data blocks */
1N/A uint32_t status; /* partition status bits */
1N/A uint32_t boot_start;
1N/A uint32_t boot_count;
1N/A uint32_t boot_load;
1N/A uint32_t boot_load2;
1N/A uint32_t boot_entry;
1N/A uint32_t boot_entry2;
1N/A uint32_t boot_cksum;
1N/A char processor[16]; /* Contains 680x0, x=0,2,3,4; or empty */
1N/A uint32_t driver_sig;
1N/A char _padding[372];
1N/A};
1N/A
1N/A/* Driver descriptor structure, in block 0 */
1N/Astruct __attribute__ ((packed)) _MacRawDisk {
1N/A uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */
1N/A uint16_t block_size; /* physical sector size */
1N/A uint32_t block_count; /* size of device in blocks */
1N/A uint16_t dev_type; /* reserved */
1N/A uint16_t dev_id; /* reserved */
1N/A uint32_t data; /* reserved */
1N/A uint16_t driver_count; /* # of driver descriptor entries */
1N/A uint8_t driverlist[488];/* info about available drivers */
1N/A uint16_t padding[3]; /* pad to 512 bytes */
1N/A};
1N/A
1N/Astruct __attribute__ ((packed)) _MacDeviceDriver {
1N/A uint32_t block; /* startblock in MacRawDisk->block_size units */
1N/A uint16_t size; /* size in 512 byte units */
1N/A uint16_t type; /* operating system type (MacOS = 1) */
1N/A};
1N/A#ifdef __sun
1N/A#pragma pack()
1N/A#endif
1N/A
1N/Astruct _MacPartitionData {
1N/A char volume_name[33]; /* eg: "Games" */
1N/A char system_name[33]; /* eg: "Apple_Unix_SVR2" */
1N/A char processor_name[17];
1N/A
1N/A int is_boot;
1N/A int is_driver;
1N/A int has_driver;
1N/A int is_root;
1N/A int is_swap;
1N/A int is_lvm;
1N/A int is_raid;
1N/A
1N/A PedSector data_region_length;
1N/A PedSector boot_region_length;
1N/A
1N/A uint32_t boot_base_address;
1N/A uint32_t boot_entry_address;
1N/A uint32_t boot_checksum;
1N/A
1N/A uint32_t status;
1N/A uint32_t driver_sig;
1N/A};
1N/A
1N/Astruct _MacDiskData {
1N/A int ghost_size; /* sectors per "driver" block */
1N/A int part_map_entry_count; /* # entries (incl. ghost) */
1N/A int part_map_entry_num; /* partition map location */
1N/A
1N/A int active_part_entry_count; /* # real partitions */
1N/A int free_part_entry_count; /* # free space */
1N/A int last_part_entry_num; /* last entry number */
1N/A
1N/A uint16_t block_size; /* physical sector size */
1N/A uint16_t driver_count;
1N/A MacDeviceDriver driverlist[1 + 60]; /* 488 bytes */
1N/A};
1N/A
1N/Astatic PedDiskType mac_disk_type;
1N/A
1N/Astatic int
1N/A_check_signature (MacRawDisk const *raw_disk)
1N/A{
1N/A if (PED_BE16_TO_CPU (raw_disk->signature) != MAC_DISK_MAGIC) {
1N/A#ifdef DISCOVER_ONLY
1N/A return 0;
1N/A#else
1N/A return ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("Invalid signature %x for Mac disk labels."),
1N/A (int) PED_BE16_TO_CPU (raw_disk->signature))
1N/A == PED_EXCEPTION_IGNORE;
1N/A#endif
1N/A }
1N/A
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_check_signature (MacRawPartition* raw_part)
1N/A{
1N/A int sig = (int) PED_BE16_TO_CPU (raw_part->signature);
1N/A return sig == MAC_PARTITION_MAGIC_1 || sig == MAC_PARTITION_MAGIC_2;
1N/A}
1N/A
1N/Astatic int
1N/Amac_probe (const PedDevice * dev)
1N/A{
1N/A PED_ASSERT (dev != NULL, return 0);
1N/A
1N/A if (dev->sector_size < sizeof (MacRawDisk))
1N/A return 0;
1N/A
1N/A void *label;
1N/A if (!ptt_read_sector (dev, 0, &label))
1N/A return 0;
1N/A
1N/A int valid = _check_signature (label);
1N/A
1N/A free (label);
1N/A return valid;
1N/A}
1N/A
1N/Astatic int
1N/A_disk_add_part_map_entry (PedDisk* disk, int warn)
1N/A{
1N/A MacDiskData* mac_disk_data = disk->disk_specific;
1N/A PedPartition* new_part;
1N/A MacPartitionData* mac_part_data;
1N/A PedSector part_map_size;
1N/A PedConstraint* constraint_any = ped_constraint_any (disk->dev);
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A if (warn && ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
1N/A _("Partition map has no partition map entry!"))
1N/A != PED_EXCEPTION_FIX)
1N/A goto error;
1N/A#endif /* !DISCOVER_ONLY */
1N/A
1N/A part_map_size
1N/A = ped_round_up_to (mac_disk_data->last_part_entry_num, 64);
1N/A if (part_map_size == 0)
1N/A part_map_size = 64;
1N/A
1N/A new_part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
1N/A 1, part_map_size - 1);
1N/A if (!new_part)
1N/A goto error;
1N/A
1N/A mac_part_data = new_part->disk_specific;
1N/A strcpy (mac_part_data->volume_name, "Apple");
1N/A strcpy (mac_part_data->system_name, "Apple_partition_map");
1N/A
1N/A if (!ped_disk_add_partition (disk, new_part, constraint_any))
1N/A goto error_destroy_new_part;
1N/A
1N/A mac_disk_data->part_map_entry_num = new_part->num;
1N/A mac_disk_data->part_map_entry_count
1N/A = new_part->geom.end - mac_disk_data->ghost_size;
1N/A ped_constraint_destroy (constraint_any);
1N/A return 1;
1N/A
1N/Aerror_destroy_new_part:
1N/A ped_partition_destroy (new_part);
1N/Aerror:
1N/A ped_constraint_destroy (constraint_any);
1N/A return 0;
1N/A}
1N/A
1N/Astatic PedDisk*
1N/Amac_alloc (const PedDevice* dev)
1N/A{
1N/A PedDisk* disk;
1N/A MacDiskData* mac_disk_data;
1N/A
1N/A PED_ASSERT (dev != NULL, return NULL);
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A if (dev->length < 256) {
1N/A ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("%s is too small for a Mac disk label!"),
1N/A dev->path);
1N/A goto error;
1N/A }
1N/A#endif
1N/A
1N/A disk = _ped_disk_alloc (dev, &mac_disk_type);
1N/A if (!disk)
1N/A goto error;
1N/A
1N/A mac_disk_data = (MacDiskData*) ped_malloc (sizeof (MacDiskData));
1N/A if (!mac_disk_data)
1N/A goto error_free_disk;
1N/A disk->disk_specific = mac_disk_data;
1N/A mac_disk_data->ghost_size = disk->dev->sector_size / 512;
1N/A mac_disk_data->active_part_entry_count = 0;
1N/A mac_disk_data->free_part_entry_count = 1;
1N/A mac_disk_data->last_part_entry_num = 1;
1N/A mac_disk_data->block_size = 0;
1N/A mac_disk_data->driver_count = 0;
1N/A memset(&mac_disk_data->driverlist[0], 0, sizeof(mac_disk_data->driverlist));
1N/A
1N/A if (!_disk_add_part_map_entry (disk, 0))
1N/A goto error_free_disk;
1N/A return disk;
1N/A
1N/Aerror_free_disk:
1N/A _ped_disk_free (disk);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/Astatic PedDisk*
1N/Amac_duplicate (const PedDisk* disk)
1N/A{
1N/A PedDisk* new_disk;
1N/A MacDiskData* new_mac_data;
1N/A MacDiskData* old_mac_data = (MacDiskData*) disk->disk_specific;
1N/A
1N/A new_disk = ped_disk_new_fresh (disk->dev, &mac_disk_type);
1N/A if (!new_disk)
1N/A return NULL;
1N/A
1N/A new_mac_data = (MacDiskData*) new_disk->disk_specific;
1N/A
1N/A /* remove the partition map partition - it will be duplicated
1N/A * later.
1N/A */
1N/A PedSector first_part_map_sector = old_mac_data->ghost_size;
1N/A PedPartition *partition_map
1N/A = ped_disk_get_partition_by_sector (new_disk, first_part_map_sector);
1N/A PED_ASSERT (partition_map != NULL, return 0);
1N/A
1N/A /* ped_disk_remove_partition may be used only to delete a "normal"
1N/A partition. Trying to delete at least "freespace" or "metadata"
1N/A partitions leads to a violation of assumptions in
1N/A ped_disk_remove_partition, since it calls _disk_push_update_mode,
1N/A which destroys all "freespace" and "metadata" partitions, and
1N/A depends on that destruction not freeing its PART parameter. */
1N/A PED_ASSERT (partition_map->type == PED_PARTITION_NORMAL, return 0);
1N/A ped_disk_remove_partition (new_disk, partition_map);
1N/A
1N/A /* ugly, but C is ugly :p */
1N/A memcpy (new_mac_data, old_mac_data, sizeof (MacDiskData));
1N/A return new_disk;
1N/A}
1N/A
1N/Astatic void
1N/Amac_free (PedDisk* disk)
1N/A{
1N/A MacDiskData* mac_disk_data = disk->disk_specific;
1N/A
1N/A _ped_disk_free (disk);
1N/A free (mac_disk_data);
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_cmp_type (const MacRawPartition* raw_part, const char* type)
1N/A{
1N/A return strncasecmp (raw_part->type, type, 32) == 0;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_cmp_name (const MacRawPartition* raw_part, const char* name)
1N/A{
1N/A return strncasecmp (raw_part->name, name, 32) == 0;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_is_partition_map (const MacRawPartition* raw_part)
1N/A{
1N/A return _rawpart_cmp_type (raw_part, "Apple_partition_map");
1N/A}
1N/A
1N/Astatic int
1N/Astrncasestr (const char* haystack, const char* needle, int n)
1N/A{
1N/A int needle_size = strlen (needle);
1N/A int i;
1N/A
1N/A for (i = 0; haystack[i] && i < n - needle_size; i++) {
1N/A if (strncasecmp (haystack + i, needle, needle_size) == 0)
1N/A return 1;
1N/A }
1N/A
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_is_boot (const MacRawPartition* raw_part)
1N/A{
1N/A if (!strcasecmp(raw_part->type, "Apple_Bootstrap"))
1N/A return 1;
1N/A
1N/A if (!strcasecmp(raw_part->type, "Apple_Boot"))
1N/A return 1;
1N/A
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_is_driver (const MacRawPartition* raw_part)
1N/A{
1N/A if (strncmp (raw_part->type, "Apple_", 6) != 0)
1N/A return 0;
1N/A if (!strncasestr (raw_part->type, "driver", 32))
1N/A return 0;
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_has_driver (const MacRawPartition* raw_part, MacDiskData* mac_disk_data)
1N/A{
1N/A MacDeviceDriver *driverlist;
1N/A uint16_t i, bsz;
1N/A uint32_t driver_bs, driver_be, part_be;
1N/A
1N/A driverlist = &mac_disk_data->driverlist[0];
1N/A bsz = mac_disk_data->block_size / 512;
1N/A for (i = 0; i < mac_disk_data->driver_count; i++) {
1N/A driver_bs = driverlist->block * bsz;
1N/A driver_be = driver_bs + driverlist->size;
1N/A part_be = raw_part->start_block + raw_part->block_count;
1N/A if (driver_bs >= raw_part->start_block && driver_be <= part_be)
1N/A return 1;
1N/A driverlist++;
1N/A }
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_is_root (MacRawPartition* raw_part)
1N/A{
1N/A if (!_rawpart_cmp_type (raw_part, "Apple_UNIX_SVR2"))
1N/A return 0;
1N/A if (strcmp (raw_part->name, "root") != 0)
1N/A return 0;
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_is_swap (MacRawPartition* raw_part)
1N/A{
1N/A if (!_rawpart_cmp_type (raw_part, "Apple_UNIX_SVR2"))
1N/A return 0;
1N/A if (strcmp (raw_part->name, "swap") != 0)
1N/A return 0;
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_is_lvm (MacRawPartition* raw_part)
1N/A{
1N/A if (strcmp (raw_part->type, "Linux_LVM") != 0)
1N/A return 0;
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_is_raid (MacRawPartition* raw_part)
1N/A{
1N/A if (strcmp (raw_part->type, "Linux_RAID") != 0)
1N/A return 0;
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/A_rawpart_is_void (MacRawPartition* raw_part)
1N/A{
1N/A return _rawpart_cmp_type (raw_part, "Apple_Void");
1N/A}
1N/A
1N/A/* returns 1 if the raw_part represents a partition that is "unused space", or
1N/A * doesn't represent a partition at all. NOTE: some people make Apple_Free
1N/A * partitions with MacOS, because they can't select another type. So, if the
1N/A * name is anything other than "Extra" or "", it is treated as a "real"
1N/A * partition.
1N/A */
1N/Astatic int
1N/A_rawpart_is_active (MacRawPartition* raw_part)
1N/A{
1N/A if (_rawpart_cmp_type (raw_part, "Apple_Free")
1N/A && (_rawpart_cmp_name (raw_part, "Extra")
1N/A || _rawpart_cmp_name (raw_part, "")))
1N/A return 0;
1N/A if (_rawpart_cmp_type (raw_part, "Apple_Void"))
1N/A return 0;
1N/A if (_rawpart_cmp_type (raw_part, "Apple_Scratch"))
1N/A return 0;
1N/A if (_rawpart_cmp_type (raw_part, "Apple_Extra"))
1N/A return 0;
1N/A
1N/A return 1;
1N/A}
1N/A
1N/Astatic PedPartition*
1N/A_rawpart_analyse (MacRawPartition* raw_part, PedDisk* disk, int num)
1N/A{
1N/A MacDiskData* mac_disk_data;
1N/A PedPartition* part;
1N/A MacPartitionData* mac_part_data;
1N/A PedSector block_size;
1N/A PedSector start, length;
1N/A
1N/A if (!_rawpart_check_signature (raw_part)) {
1N/A#ifndef DISCOVER_ONLY
1N/A if (ped_exception_throw (
1N/A PED_EXCEPTION_WARNING,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("Partition %d has an invalid signature %x."),
1N/A num,
1N/A (int) PED_BE16_TO_CPU (raw_part->signature))
1N/A != PED_EXCEPTION_IGNORE)
1N/A#endif
1N/A goto error;
1N/A }
1N/A
1N/A mac_disk_data = (MacDiskData*) disk->disk_specific;
1N/A block_size = disk->dev->sector_size / 512;
1N/A
1N/A start = PED_BE32_TO_CPU (raw_part->start_block) * block_size;
1N/A length = PED_BE32_TO_CPU (raw_part->block_count) * block_size;
1N/A if (length == 0) {
1N/A#ifndef DISCOVER_ONLY
1N/A ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("Partition %d has an invalid length of 0 bytes!"),
1N/A num);
1N/A#endif
1N/A return NULL;
1N/A }
1N/A part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
1N/A start, start + length - 1);
1N/A if (!part)
1N/A goto error;
1N/A
1N/A mac_part_data = part->disk_specific;
1N/A
1N/A strncpy (mac_part_data->volume_name, raw_part->name, 32);
1N/A strncpy (mac_part_data->system_name, raw_part->type, 32);
1N/A strncpy (mac_part_data->processor_name, raw_part->processor, 16);
1N/A
1N/A mac_part_data->is_boot = _rawpart_is_boot (raw_part);
1N/A mac_part_data->is_driver = _rawpart_is_driver (raw_part);
1N/A if (mac_part_data->is_driver)
1N/A mac_part_data->has_driver = _rawpart_has_driver(raw_part, mac_disk_data);
1N/A mac_part_data->is_root = _rawpart_is_root (raw_part);
1N/A mac_part_data->is_swap = _rawpart_is_swap (raw_part);
1N/A mac_part_data->is_lvm = _rawpart_is_lvm (raw_part);
1N/A mac_part_data->is_raid = _rawpart_is_raid (raw_part);
1N/A
1N/A /* "data" region */
1N/A#ifndef DISCOVER_ONLY
1N/A if (raw_part->data_start) {
1N/A ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("The data region doesn't start at the start "
1N/A "of the partition."));
1N/A goto error_destroy_part;
1N/A }
1N/A#endif /* !DISCOVER_ONLY */
1N/A mac_part_data->data_region_length
1N/A = PED_BE32_TO_CPU (raw_part->data_count) * block_size;
1N/A
1N/A /* boot region - we have no idea what this is for, but Mac OSX
1N/A * seems to put garbage here, and doesn't pay any attention to
1N/A * it afterwards. [clausen, dan burcaw]
1N/A */
1N/A#if 0
1N/A if (raw_part->boot_start) {
1N/A ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("The boot region doesn't start at the start "
1N/A "of the partition."));
1N/A goto error_destroy_part;
1N/A }
1N/A#endif
1N/A mac_part_data->boot_region_length
1N/A = PED_BE32_TO_CPU (raw_part->boot_count) * block_size;
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A if (mac_part_data->has_driver) {
1N/A if (mac_part_data->boot_region_length < part->geom.length) {
1N/A if (ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("The partition's boot region doesn't occupy "
1N/A "the entire partition."))
1N/A != PED_EXCEPTION_IGNORE)
1N/A goto error_destroy_part;
1N/A }
1N/A } else {
1N/A if (mac_part_data->data_region_length < part->geom.length &&
1N/A !mac_part_data->is_boot) {
1N/A if (ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("The partition's data region doesn't occupy "
1N/A "the entire partition."))
1N/A != PED_EXCEPTION_IGNORE)
1N/A goto error_destroy_part;
1N/A }
1N/A }
1N/A#endif /* !DISCOVER_ONLY */
1N/A
1N/A mac_part_data->boot_base_address
1N/A = PED_BE32_TO_CPU (raw_part->boot_load);
1N/A mac_part_data->boot_entry_address
1N/A = PED_BE32_TO_CPU (raw_part->boot_entry);
1N/A mac_part_data->boot_checksum
1N/A = PED_BE32_TO_CPU (raw_part->boot_cksum);
1N/A
1N/A mac_part_data->status = PED_BE32_TO_CPU (raw_part->status);
1N/A mac_part_data->driver_sig = PED_BE32_TO_CPU (raw_part->driver_sig);
1N/A
1N/A return part;
1N/A
1N/Aerror_destroy_part:
1N/A ped_partition_destroy (part);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/A/* looks at the partition map size field in a mac raw partition, and calculates
1N/A * what the size of the partition map should be, from it
1N/A */
1N/Astatic int
1N/A_rawpart_get_partmap_size (MacRawPartition* raw_part, PedDisk* disk)
1N/A{
1N/A MacDiskData* mac_disk_data = disk->disk_specific;
1N/A PedSector sector_size = disk->dev->sector_size / 512;
1N/A PedSector part_map_start;
1N/A PedSector part_map_end;
1N/A
1N/A part_map_start = mac_disk_data->ghost_size;
1N/A part_map_end = sector_size * PED_BE32_TO_CPU (raw_part->map_count);
1N/A
1N/A return part_map_end - part_map_start + 1;
1N/A}
1N/A
1N/Astatic int
1N/A_disk_analyse_block_size (PedDisk* disk, MacRawDisk* raw_disk)
1N/A{
1N/A PedSector block_size;
1N/A
1N/A if (PED_BE16_TO_CPU (raw_disk->block_size) % 512) {
1N/A#ifndef DISCOVER_ONLY
1N/A ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("Weird block size on device descriptor: %d bytes is "
1N/A "not divisible by 512."),
1N/A (int) PED_BE16_TO_CPU (raw_disk->block_size));
1N/A#endif
1N/A goto error;
1N/A }
1N/A
1N/A block_size = PED_BE16_TO_CPU (raw_disk->block_size) / 512;
1N/A if (block_size != disk->dev->sector_size / 512) {
1N/A#ifndef DISCOVER_ONLY
1N/A if (ped_exception_throw (
1N/A PED_EXCEPTION_WARNING,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("The driver descriptor says the physical block size "
1N/A "is %d bytes, but Linux says it is %d bytes."),
1N/A (int) block_size * 512,
1N/A (int) disk->dev->sector_size)
1N/A != PED_EXCEPTION_IGNORE)
1N/A goto error;
1N/A#endif
1N/A disk->dev->sector_size = block_size * 512;
1N/A }
1N/A
1N/A return 1;
1N/A
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/A/* Tries to figure out the block size used by the drivers, for the ghost
1N/A * partitioning scheme. Ghost partitioning works like this: the OpenFirmware
1N/A * (OF) sees 512 byte blocks, but some drivers use 2048 byte blocks (and,
1N/A * perhaps, some other number?). To remain compatible, the partition map
1N/A * only has "real" partition map entries on ghost-aligned block numbers (and
1N/A * the others are padded with Apple_Void partitions). This function tries
1N/A * to figure out what the "ghost-aligned" size is... (which, believe-it-or-not,
1N/A * doesn't always equal 2048!!!)
1N/A */
1N/Astatic int
1N/A_disk_analyse_ghost_size (PedDisk* disk)
1N/A{
1N/A MacDiskData* mac_disk_data = disk->disk_specific;
1N/A
1N/A void *buf = ped_malloc (disk->dev->sector_size);
1N/A if (!buf)
1N/A return 0;
1N/A
1N/A int i;
1N/A int found = 0;
1N/A for (i = 1; i < 64; i *= 2) {
1N/A if (!ped_device_read (disk->dev, buf, i, 1))
1N/A break;
1N/A if (_rawpart_check_signature (buf)
1N/A && !_rawpart_is_void (buf)) {
1N/A mac_disk_data->ghost_size = i;
1N/A PED_ASSERT (i <= disk->dev->sector_size / 512, break);
1N/A found = 1;
1N/A break;
1N/A }
1N/A }
1N/A free (buf);
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A if (!found)
1N/A ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("No valid partition map found."));
1N/A#endif
1N/A return found;
1N/A}
1N/A
1N/Astatic int
1N/Amac_read (PedDisk* disk)
1N/A{
1N/A MacDiskData* mac_disk_data;
1N/A PedPartition* part;
1N/A int num;
1N/A PedSector ghost_size;
1N/A PedConstraint* constraint_exact;
1N/A int last_part_entry_num = 0;
1N/A
1N/A PED_ASSERT (disk != NULL, return 0);
1N/A
1N/A mac_disk_data = disk->disk_specific;
1N/A mac_disk_data->part_map_entry_num = 0; /* 0 == none */
1N/A
1N/A void *buf;
1N/A if (!ptt_read_sector (disk->dev, 0, &buf))
1N/A return 0;
1N/A
1N/A MacRawDisk *raw_disk = (MacRawDisk *) buf;
1N/A
1N/A if (!_check_signature (raw_disk))
1N/A goto error;
1N/A
1N/A if (!_disk_analyse_block_size (disk, raw_disk))
1N/A goto error;
1N/A if (!_disk_analyse_ghost_size (disk))
1N/A goto error;
1N/A ghost_size = mac_disk_data->ghost_size;
1N/A
1N/A if (!ped_disk_delete_all (disk))
1N/A goto error;
1N/A
1N/A if (raw_disk->driver_count && raw_disk->driver_count < 62) {
1N/A memcpy(&mac_disk_data->driverlist[0], &raw_disk->driverlist[0],
1N/A sizeof(mac_disk_data->driverlist));
1N/A mac_disk_data->driver_count = raw_disk->driver_count;
1N/A mac_disk_data->block_size = raw_disk->block_size;
1N/A }
1N/A
1N/A for (num=1; num==1 || num <= last_part_entry_num; num++) {
1N/A void *raw_part = buf;
1N/A if (!ped_device_read (disk->dev, raw_part,
1N/A num * ghost_size, 1))
1N/A goto error_delete_all;
1N/A
1N/A if (!_rawpart_check_signature (raw_part))
1N/A continue;
1N/A
1N/A if (num == 1)
1N/A last_part_entry_num
1N/A = _rawpart_get_partmap_size (raw_part, disk);
1N/A if (_rawpart_get_partmap_size (raw_part, disk)
1N/A != last_part_entry_num) {
1N/A if (ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("Conflicting partition map entry sizes! "
1N/A "Entry 1 says it is %d, but entry %d says "
1N/A "it is %d!"),
1N/A last_part_entry_num,
1N/A _rawpart_get_partmap_size (raw_part, disk))
1N/A != PED_EXCEPTION_IGNORE)
1N/A goto error_delete_all;
1N/A }
1N/A
1N/A if (!_rawpart_is_active (raw_part))
1N/A continue;
1N/A
1N/A part = _rawpart_analyse (raw_part, disk, num);
1N/A if (!part)
1N/A goto error_delete_all;
1N/A part->num = num;
1N/A part->fs_type = ped_file_system_probe (&part->geom);
1N/A constraint_exact = ped_constraint_exact (&part->geom);
1N/A if (!ped_disk_add_partition (disk, part, constraint_exact))
1N/A goto error_delete_all;
1N/A ped_constraint_destroy (constraint_exact);
1N/A
1N/A if (_rawpart_is_partition_map (raw_part)) {
1N/A if (mac_disk_data->part_map_entry_num
1N/A && ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("Weird! There are 2 partitions "
1N/A "map entries!"))
1N/A != PED_EXCEPTION_IGNORE)
1N/A goto error_delete_all;
1N/A
1N/A mac_disk_data->part_map_entry_num = num;
1N/A mac_disk_data->part_map_entry_count
1N/A = part->geom.end - ghost_size + 1;
1N/A }
1N/A }
1N/A
1N/A if (!mac_disk_data->part_map_entry_num) {
1N/A if (!_disk_add_part_map_entry (disk, 1))
1N/A goto error_delete_all;
1N/A ped_disk_commit_to_dev (disk);
1N/A }
1N/A free (buf);
1N/A return 1;
1N/A
1N/Aerror_delete_all:
1N/A ped_disk_delete_all (disk);
1N/Aerror:
1N/A free (buf);
1N/A return 0;
1N/A}
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A/* The Ghost partition: is a blank entry, used to pad out each block (where
1N/A * there physical block size > 512 bytes). This is because OpenFirmware uses
1N/A * 512 byte blocks, but device drivers Think Different TM, with a different
1N/A * lbock size, so we need to do this to avoid a clash (!)
1N/A */
1N/Astatic int
1N/A_pad_raw_part (PedDisk* disk, int num, MacRawPartition* part_map)
1N/A{
1N/A MacDiskData* mac_disk_data = disk->disk_specific;
1N/A int i;
1N/A
1N/A size_t ss = disk->dev->sector_size;
1N/A void *buf = ped_calloc (ss);
1N/A if (!buf)
1N/A return 0;
1N/A
1N/A MacRawPartition *ghost_entry = buf;
1N/A ghost_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
1N/A strcpy (ghost_entry->type, "Apple_Void");
1N/A ghost_entry->map_count
1N/A = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
1N/A
1N/A for (i=0; i < mac_disk_data->ghost_size - 1; i++) {
1N/A PedSector idx = i + (num - 1) * mac_disk_data->ghost_size;
1N/A memcpy ((char*)part_map + idx * ss, ghost_entry, ss);
1N/A }
1N/A
1N/A free (buf);
1N/A return 1;
1N/A}
1N/A
1N/Astatic void
1N/A_update_driver_count (MacRawPartition* part_map_entry,
1N/A MacDiskData *mac_driverdata, const MacDiskData* mac_disk_data)
1N/A{
1N/A uint16_t i, count_orig, count_cur, bsz;
1N/A uint32_t driver_bs, driver_be, part_be;
1N/A
1N/A bsz = mac_disk_data->block_size / 512;
1N/A count_cur = mac_driverdata->driver_count;
1N/A count_orig = mac_disk_data->driver_count;
1N/A for (i = 0; i < count_orig; i++) {
1N/A driver_bs = mac_disk_data->driverlist[i].block * bsz;
1N/A driver_be = driver_bs + mac_disk_data->driverlist[i].size;
1N/A part_be = part_map_entry->start_block + part_map_entry->block_count;
1N/A if (driver_bs >= part_map_entry->start_block
1N/A && driver_be <= part_be) {
1N/A mac_driverdata->driverlist[count_cur].block
1N/A = mac_disk_data->driverlist[i].block;
1N/A mac_driverdata->driverlist[count_cur].size
1N/A = mac_disk_data->driverlist[i].size;
1N/A mac_driverdata->driverlist[count_cur].type
1N/A = mac_disk_data->driverlist[i].type;
1N/A mac_driverdata->driver_count++;
1N/A break;
1N/A }
1N/A }
1N/A}
1N/A
1N/Astatic MacRawPartition *
1N/Aget_pme (MacRawPartition const *part_map, PedSector i, PedDisk const *disk)
1N/A{
1N/A MacDiskData const *mac_disk_data = disk->disk_specific;
1N/A PedSector idx = i * mac_disk_data->ghost_size - 1;
1N/A return (MacRawPartition *) ((char*)part_map
1N/A + idx * disk->dev->sector_size);
1N/A}
1N/A
1N/A/* Initialize the disk->dev->sector_size bytes of part_map[part->num]. */
1N/Astatic int
1N/A_generate_raw_part (PedDisk* disk, PedPartition* part,
1N/A MacRawPartition* part_map, MacDiskData *mac_driverdata)
1N/A{
1N/A MacDiskData* mac_disk_data;
1N/A MacPartitionData* mac_part_data;
1N/A PedSector block_size = disk->dev->sector_size / 512;
1N/A
1N/A PED_ASSERT (part->num > 0, goto error);
1N/A
1N/A mac_disk_data = disk->disk_specific;
1N/A mac_part_data = part->disk_specific;
1N/A
1N/A MacRawPartition *part_map_entry = get_pme (part_map, part->num, disk);
1N/A memset (part_map_entry, 0, disk->dev->sector_size);
1N/A
1N/A part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
1N/A part_map_entry->map_count
1N/A = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
1N/A part_map_entry->start_block
1N/A = PED_CPU_TO_BE32 (part->geom.start / block_size);
1N/A part_map_entry->block_count
1N/A = PED_CPU_TO_BE32 (part->geom.length / block_size);
1N/A strcpy (part_map_entry->name, mac_part_data->volume_name);
1N/A strcpy (part_map_entry->type, mac_part_data->system_name);
1N/A
1N/A if (mac_part_data->is_driver) {
1N/A mac_part_data->boot_region_length = part->geom.length;
1N/A if (mac_part_data->has_driver)
1N/A _update_driver_count(part_map_entry, mac_driverdata,
1N/A mac_disk_data);
1N/A } else
1N/A mac_part_data->data_region_length = part->geom.length;
1N/A part_map_entry->data_count = PED_CPU_TO_BE32 (
1N/A mac_part_data->data_region_length / block_size);
1N/A part_map_entry->boot_count = PED_CPU_TO_BE32 (
1N/A mac_part_data->boot_region_length / block_size);
1N/A part_map_entry->status = PED_CPU_TO_BE32 (mac_part_data->status);
1N/A part_map_entry->driver_sig
1N/A = PED_CPU_TO_BE32 (mac_part_data->driver_sig);
1N/A
1N/A part_map_entry->boot_load =
1N/A PED_CPU_TO_BE32 (mac_part_data->boot_base_address);
1N/A part_map_entry->boot_entry =
1N/A PED_CPU_TO_BE32 (mac_part_data->boot_entry_address);
1N/A part_map_entry->boot_cksum =
1N/A PED_CPU_TO_BE32 (mac_part_data->boot_checksum);
1N/A
1N/A strncpy (part_map_entry->processor, mac_part_data->processor_name, 16);
1N/A
1N/A if (!_pad_raw_part (disk, part->num, part_map))
1N/A goto error;
1N/A
1N/A return 1;
1N/A
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/A_generate_raw_freespace_part (PedDisk* disk, PedGeometry* geom, int num,
1N/A MacRawPartition* part_map)
1N/A{
1N/A MacDiskData* mac_disk_data = disk->disk_specific;
1N/A PedSector block_size = disk->dev->sector_size / 512;
1N/A
1N/A PED_ASSERT (num > 0, goto error);
1N/A
1N/A MacRawPartition *part_map_entry = get_pme (part_map, num, disk);
1N/A
1N/A part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
1N/A part_map_entry->map_count
1N/A = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
1N/A part_map_entry->start_block
1N/A = PED_CPU_TO_BE32 (geom->start / block_size);
1N/A part_map_entry->block_count
1N/A = PED_CPU_TO_BE32 (geom->length / block_size);
1N/A strcpy (part_map_entry->name, "Extra");
1N/A strcpy (part_map_entry->type, "Apple_Free");
1N/A
1N/A part_map_entry->data_count = PED_CPU_TO_BE32 (geom->length);
1N/A part_map_entry->status = 0;
1N/A part_map_entry->driver_sig = 0;
1N/A
1N/A if (!_pad_raw_part (disk, num, part_map))
1N/A goto error;
1N/A
1N/A return 1;
1N/A
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/A_generate_empty_part (PedDisk* disk, int num, MacRawPartition* part_map)
1N/A{
1N/A MacDiskData* mac_disk_data = disk->disk_specific;
1N/A
1N/A PED_ASSERT (num > 0, return 0);
1N/A
1N/A MacRawPartition *part_map_entry = get_pme (part_map, num, disk);
1N/A part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
1N/A part_map_entry->map_count
1N/A = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
1N/A strcpy (part_map_entry->type, "Apple_Void");
1N/A
1N/A return _pad_raw_part (disk, num, part_map);
1N/A}
1N/A
1N/A/* returns the first empty entry in the partition map */
1N/Astatic int
1N/A_get_first_empty_part_entry (PedDisk* disk, MacRawPartition* part_map)
1N/A{
1N/A MacDiskData* mac_disk_data = disk->disk_specific;
1N/A int i;
1N/A
1N/A for (i=1; i <= mac_disk_data->last_part_entry_num; i++) {
1N/A MacRawPartition *part_map_entry = get_pme (part_map, i, disk);
1N/A if (!part_map_entry->signature)
1N/A return i;
1N/A }
1N/A
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/Awrite_block_zero (PedDisk* disk, MacDiskData* mac_driverdata)
1N/A{
1N/A PedDevice* dev = disk->dev;
1N/A void *s0;
1N/A if (!ptt_read_sector (dev, 0, &s0))
1N/A return 0;
1N/A MacRawDisk *raw_disk = (MacRawDisk *) s0;
1N/A
1N/A raw_disk->signature = PED_CPU_TO_BE16 (MAC_DISK_MAGIC);
1N/A raw_disk->block_size = PED_CPU_TO_BE16 (dev->sector_size);
1N/A raw_disk->block_count
1N/A = PED_CPU_TO_BE32 (dev->length / (dev->sector_size / 512));
1N/A
1N/A raw_disk->driver_count = mac_driverdata->driver_count;
1N/A memcpy(&raw_disk->driverlist[0], &mac_driverdata->driverlist[0],
1N/A sizeof(raw_disk->driverlist));
1N/A
1N/A int write_ok = ped_device_write (dev, raw_disk, 0, 1);
1N/A free (s0);
1N/A return write_ok;
1N/A}
1N/A
1N/Astatic int
1N/Amac_write (PedDisk* disk)
1N/A{
1N/A MacRawPartition* part_map;
1N/A MacDiskData* mac_disk_data;
1N/A MacDiskData* mac_driverdata; /* updated driver list */
1N/A PedPartition* part;
1N/A int num;
1N/A
1N/A PED_ASSERT (disk != NULL, return 0);
1N/A PED_ASSERT (disk->disk_specific != NULL, return 0);
1N/A PED_ASSERT (disk->dev != NULL, return 0);
1N/A PED_ASSERT (!disk->update_mode, return 0);
1N/A
1N/A mac_disk_data = disk->disk_specific;
1N/A
1N/A if (!ped_disk_get_partition (disk, mac_disk_data->part_map_entry_num)) {
1N/A if (!_disk_add_part_map_entry (disk, 1))
1N/A goto error;
1N/A }
1N/A
1N/A mac_driverdata = ped_malloc(sizeof(MacDiskData));
1N/A if (!mac_driverdata)
1N/A goto error;
1N/A memset (mac_driverdata, 0, sizeof(MacDiskData));
1N/A
1N/A size_t pmap_bytes = (mac_disk_data->part_map_entry_count
1N/A * mac_disk_data->ghost_size
1N/A * disk->dev->sector_size);
1N/A part_map = (MacRawPartition*) ped_calloc (pmap_bytes);
1N/A if (!part_map)
1N/A goto error_free_driverdata;
1N/A
1N/A/* write (to memory) the "real" partitions */
1N/A for (part = ped_disk_next_partition (disk, NULL); part;
1N/A part = ped_disk_next_partition (disk, part)) {
1N/A if (!ped_partition_is_active (part))
1N/A continue;
1N/A if (!_generate_raw_part (disk, part, part_map, mac_driverdata))
1N/A goto error_free_part_map;
1N/A }
1N/A
1N/A/* write the "free space" partitions */
1N/A for (part = ped_disk_next_partition (disk, NULL); part;
1N/A part = ped_disk_next_partition (disk, part)) {
1N/A if (part->type != PED_PARTITION_FREESPACE)
1N/A continue;
1N/A num = _get_first_empty_part_entry (disk, part_map);
1N/A if (!_generate_raw_freespace_part (disk, &part->geom, num,
1N/A part_map))
1N/A goto error_free_part_map;
1N/A }
1N/A
1N/A/* write the "void" (empty) partitions */
1N/A for (num = _get_first_empty_part_entry (disk, part_map); num;
1N/A num = _get_first_empty_part_entry (disk, part_map))
1N/A _generate_empty_part (disk, num, part_map);
1N/A
1N/A/* write to disk */
1N/A if (!ped_device_write (disk->dev, part_map, 1,
1N/A mac_disk_data->part_map_entry_count))
1N/A goto error_free_part_map;
1N/A free (part_map);
1N/A int write_ok = write_block_zero (disk, mac_driverdata);
1N/A free (mac_driverdata);
1N/A return write_ok;
1N/A
1N/Aerror_free_part_map:
1N/A free (part_map);
1N/Aerror_free_driverdata:
1N/A free (mac_driverdata);
1N/Aerror:
1N/A return 0;
1N/A}
1N/A#endif /* !DISCOVER_ONLY */
1N/A
1N/Astatic PedPartition*
1N/Amac_partition_new (
1N/A const PedDisk* disk, PedPartitionType part_type,
1N/A const PedFileSystemType* fs_type, PedSector start, PedSector end)
1N/A{
1N/A PedPartition* part;
1N/A MacPartitionData* mac_data;
1N/A
1N/A part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1N/A if (!part)
1N/A goto error;
1N/A
1N/A if (ped_partition_is_active (part)) {
1N/A part->disk_specific
1N/A = mac_data = ped_malloc (sizeof (MacPartitionData));
1N/A if (!mac_data)
1N/A goto error_free_part;
1N/A
1N/A memset (mac_data, 0, sizeof (MacPartitionData));
1N/A strcpy (mac_data->volume_name, "untitled");
1N/A } else {
1N/A part->disk_specific = NULL;
1N/A }
1N/A return part;
1N/A
1N/Aerror_free_part:
1N/A free (part);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/Astatic PedPartition*
1N/Amac_partition_duplicate (const PedPartition* part)
1N/A{
1N/A PedPartition* new_part;
1N/A MacPartitionData* new_mac_data;
1N/A MacPartitionData* old_mac_data;
1N/A
1N/A new_part = ped_partition_new (part->disk, part->type,
1N/A part->fs_type, part->geom.start,
1N/A part->geom.end);
1N/A if (!new_part)
1N/A return NULL;
1N/A new_part->num = part->num;
1N/A
1N/A old_mac_data = (MacPartitionData*) part->disk_specific;
1N/A new_mac_data = (MacPartitionData*) new_part->disk_specific;
1N/A
1N/A /* ugly, but C is ugly :p */
1N/A memcpy (new_mac_data, old_mac_data, sizeof (MacPartitionData));
1N/A return new_part;
1N/A}
1N/A
1N/Astatic void
1N/Amac_partition_destroy (PedPartition* part)
1N/A{
1N/A PED_ASSERT (part != NULL, return);
1N/A
1N/A if (ped_partition_is_active (part))
1N/A free (part->disk_specific);
1N/A free (part);
1N/A}
1N/A
1N/Astatic int
1N/Amac_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1N/A{
1N/A MacPartitionData* mac_data = part->disk_specific;
1N/A
1N/A part->fs_type = fs_type;
1N/A
1N/A if (fs_type && is_linux_swap (fs_type->name))
1N/A ped_partition_set_flag (part, PED_PARTITION_SWAP, 1);
1N/A
1N/A if (mac_data->is_boot) {
1N/A strcpy (mac_data->system_name, "Apple_Bootstrap");
1N/A mac_data->status = 0x33;
1N/A return 1;
1N/A }
1N/A
1N/A if (fs_type && (!strcmp (fs_type->name, "hfs")
1N/A || !strcmp (fs_type->name, "hfs+"))) {
1N/A strcpy (mac_data->system_name, "Apple_HFS");
1N/A mac_data->status |= 0x7f;
1N/A } else if (fs_type && !strcmp (fs_type->name, "hfsx")) {
1N/A strcpy (mac_data->system_name, "Apple_HFSX");
1N/A mac_data->status |= 0x7f;
1N/A } else {
1N/A strcpy (mac_data->system_name, "Apple_UNIX_SVR2");
1N/A mac_data->status = 0x33;
1N/A }
1N/A
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/Amac_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
1N/A{
1N/A MacPartitionData* mac_data;
1N/A
1N/A PED_ASSERT (part != NULL, return 0);
1N/A PED_ASSERT (part->disk_specific != NULL, return 0);
1N/A
1N/A mac_data = part->disk_specific;
1N/A
1N/A switch (flag) {
1N/A case PED_PARTITION_BOOT:
1N/A mac_data->is_boot = state;
1N/A
1N/A if (part->fs_type)
1N/A return mac_partition_set_system (part, part->fs_type);
1N/A
1N/A if (state) {
1N/A strcpy (mac_data->system_name, "Apple_Bootstrap");
1N/A mac_data->status = 0x33;
1N/A }
1N/A return 1;
1N/A
1N/A case PED_PARTITION_ROOT:
1N/A if (state) {
1N/A strcpy (mac_data->volume_name, "root");
1N/A mac_data->is_swap = 0;
1N/A } else {
1N/A if (mac_data->is_root)
1N/A strcpy (mac_data->volume_name, "untitled");
1N/A }
1N/A mac_data->is_root = state;
1N/A return 1;
1N/A
1N/A case PED_PARTITION_SWAP:
1N/A if (state) {
1N/A strcpy (mac_data->volume_name, "swap");
1N/A mac_data->is_root = 0;
1N/A } else {
1N/A if (mac_data->is_swap)
1N/A strcpy (mac_data->volume_name, "untitled");
1N/A }
1N/A mac_data->is_swap = state;
1N/A return 1;
1N/A
1N/A case PED_PARTITION_LVM:
1N/A if (state) {
1N/A strcpy (mac_data->system_name, "Linux_LVM");
1N/A mac_data->is_lvm = state;
1N/A } else {
1N/A if (mac_data->is_lvm)
1N/A mac_partition_set_system (part, part->fs_type);
1N/A }
1N/A return 1;
1N/A
1N/A case PED_PARTITION_RAID:
1N/A if (state) {
1N/A strcpy (mac_data->system_name, "Linux_RAID");
1N/A mac_data->is_raid = state;
1N/A } else {
1N/A if (mac_data->is_raid)
1N/A mac_partition_set_system (part, part->fs_type);
1N/A }
1N/A return 1;
1N/A
1N/A default:
1N/A return 0;
1N/A }
1N/A}
1N/A
1N/Astatic int
1N/Amac_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
1N/A{
1N/A MacPartitionData* mac_data;
1N/A
1N/A PED_ASSERT (part != NULL, return 0);
1N/A PED_ASSERT (part->disk_specific != NULL, return 0);
1N/A
1N/A mac_data = part->disk_specific;
1N/A switch (flag) {
1N/A case PED_PARTITION_BOOT:
1N/A return mac_data->is_boot;
1N/A
1N/A case PED_PARTITION_ROOT:
1N/A return mac_data->is_root;
1N/A
1N/A case PED_PARTITION_SWAP:
1N/A return mac_data->is_swap;
1N/A
1N/A case PED_PARTITION_LVM:
1N/A return mac_data->is_lvm;
1N/A
1N/A case PED_PARTITION_RAID:
1N/A return mac_data->is_raid;
1N/A
1N/A default:
1N/A return 0;
1N/A }
1N/A}
1N/A
1N/Astatic int
1N/Amac_partition_is_flag_available (
1N/A const PedPartition* part, PedPartitionFlag flag)
1N/A{
1N/A switch (flag) {
1N/A case PED_PARTITION_BOOT:
1N/A case PED_PARTITION_ROOT:
1N/A case PED_PARTITION_SWAP:
1N/A case PED_PARTITION_LVM:
1N/A case PED_PARTITION_RAID:
1N/A return 1;
1N/A
1N/A default:
1N/A return 0;
1N/A }
1N/A}
1N/A
1N/Astatic void
1N/Amac_partition_set_name (PedPartition* part, const char* name)
1N/A{
1N/A MacPartitionData* mac_data;
1N/A int i;
1N/A
1N/A PED_ASSERT (part != NULL, return);
1N/A PED_ASSERT (part->disk_specific != NULL, return);
1N/A mac_data = part->disk_specific;
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A if (mac_data->is_root || mac_data->is_swap) {
1N/A if (ped_exception_throw (
1N/A PED_EXCEPTION_WARNING,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("Changing the name of a root or swap partition "
1N/A "will prevent Linux from recognising it as such."))
1N/A != PED_EXCEPTION_IGNORE)
1N/A return;
1N/A mac_data->is_root = mac_data->is_swap = 0;
1N/A }
1N/A#endif
1N/A
1N/A strncpy (mac_data->volume_name, name, 32);
1N/A mac_data->volume_name [32] = 0;
1N/A for (i = strlen (mac_data->volume_name) - 1;
1N/A mac_data->volume_name[i] == ' '; i--)
1N/A mac_data->volume_name [i] = 0;
1N/A}
1N/A
1N/Astatic const char*
1N/Amac_partition_get_name (const PedPartition* part)
1N/A{
1N/A MacPartitionData* mac_data;
1N/A
1N/A PED_ASSERT (part != NULL, return NULL);
1N/A PED_ASSERT (part->disk_specific != NULL, return NULL);
1N/A mac_data = part->disk_specific;
1N/A
1N/A return mac_data->volume_name;
1N/A}
1N/A
1N/Astatic PedAlignment*
1N/Amac_get_partition_alignment(const PedDisk *disk)
1N/A{
1N/A PedSector sector_size = disk->dev->sector_size / 512;
1N/A
1N/A return ped_alignment_new(0, sector_size);
1N/A}
1N/A
1N/Astatic PedConstraint*
1N/A_primary_constraint (PedDisk* disk)
1N/A{
1N/A PedAlignment start_align;
1N/A PedAlignment end_align;
1N/A PedGeometry max_geom;
1N/A PedSector sector_size;
1N/A
1N/A sector_size = disk->dev->sector_size / 512;
1N/A
1N/A if (!ped_alignment_init (&start_align, 0, sector_size))
1N/A return NULL;
1N/A if (!ped_alignment_init (&end_align, -1, sector_size))
1N/A return NULL;
1N/A if (!ped_geometry_init (&max_geom, disk->dev, 1, disk->dev->length - 1))
1N/A return NULL;
1N/A
1N/A return ped_constraint_new (&start_align, &end_align, &max_geom,
1N/A &max_geom, 1, disk->dev->length);
1N/A}
1N/A
1N/Astatic int
1N/Amac_partition_align (PedPartition* part, const PedConstraint* constraint)
1N/A{
1N/A PED_ASSERT (part != NULL, return 0);
1N/A
1N/A if (_ped_partition_attempt_align (part, constraint,
1N/A _primary_constraint (part->disk)))
1N/A return 1;
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("Unable to satisfy all constraints on the partition."));
1N/A#endif
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/Amac_partition_enumerate (PedPartition* part)
1N/A{
1N/A PedDisk* disk;
1N/A MacDiskData* mac_disk_data;
1N/A int i;
1N/A int max_part_count;
1N/A
1N/A PED_ASSERT (part != NULL, return 0);
1N/A PED_ASSERT (part->disk != NULL, return 0);
1N/A
1N/A disk = part->disk;
1N/A mac_disk_data = (MacDiskData*) disk->disk_specific;
1N/A
1N/A max_part_count = ped_disk_get_max_primary_partition_count (disk);
1N/A
1N/A if (part->num > 0 && part->num <= mac_disk_data->part_map_entry_count)
1N/A return 1;
1N/A
1N/A for (i = 1; i <= max_part_count; i++) {
1N/A if (!ped_disk_get_partition (disk, i)) {
1N/A part->num = i;
1N/A return 1;
1N/A }
1N/A }
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A ped_exception_throw (
1N/A PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("Can't add another partition -- the partition map is too "
1N/A "small!"));
1N/A#endif
1N/A
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/A_disk_count_partitions (PedDisk* disk)
1N/A{
1N/A MacDiskData* mac_disk_data = disk->disk_specific;
1N/A PedPartition* part = NULL;
1N/A PedPartition* last = NULL;
1N/A
1N/A PED_ASSERT (disk->update_mode, return 0);
1N/A
1N/A mac_disk_data->active_part_entry_count = 0;
1N/A mac_disk_data->free_part_entry_count = 0;
1N/A mac_disk_data->last_part_entry_num = 0;
1N/A
1N/A /* subtle: we only care about free space after the partition map.
1N/A * the partition map is an "active" partition, BTW... */
1N/A for (part = ped_disk_next_partition (disk, part); part;
1N/A part = ped_disk_next_partition (disk, part)) {
1N/A if (!ped_partition_is_active (part))
1N/A continue;
1N/A
1N/A mac_disk_data->active_part_entry_count++;
1N/A if (last && last->geom.end + 1 < part->geom.start)
1N/A mac_disk_data->free_part_entry_count++;
1N/A mac_disk_data->last_part_entry_num
1N/A = PED_MAX (mac_disk_data->last_part_entry_num,
1N/A part->num);
1N/A
1N/A last = part;
1N/A }
1N/A
1N/A if (last && last->geom.end < disk->dev->length - 1)
1N/A mac_disk_data->free_part_entry_count++;
1N/A
1N/A mac_disk_data->last_part_entry_num
1N/A = PED_MAX (mac_disk_data->last_part_entry_num,
1N/A mac_disk_data->active_part_entry_count
1N/A + mac_disk_data->free_part_entry_count);
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/Aadd_metadata_part (PedDisk* disk, PedSector start, PedSector end)
1N/A{
1N/A PedPartition* new_part;
1N/A PedConstraint* constraint_any = ped_constraint_any (disk->dev);
1N/A
1N/A PED_ASSERT (disk != NULL, return 0);
1N/A
1N/A new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1N/A start, end);
1N/A if (!new_part)
1N/A goto error;
1N/A if (!ped_disk_add_partition (disk, new_part, constraint_any))
1N/A goto error_destroy_new_part;
1N/A
1N/A ped_constraint_destroy (constraint_any);
1N/A return 1;
1N/A
1N/Aerror_destroy_new_part:
1N/A ped_partition_destroy (new_part);
1N/Aerror:
1N/A ped_constraint_destroy (constraint_any);
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/Amac_alloc_metadata (PedDisk* disk)
1N/A{
1N/A PED_ASSERT (disk != NULL, return 0);
1N/A PED_ASSERT (disk->disk_specific != NULL, return 0);
1N/A PED_ASSERT (disk->dev != NULL, return 0);
1N/A
1N/A if (!add_metadata_part (disk, 0, disk->dev->sector_size / 512 - 1))
1N/A return 0;
1N/A
1N/A /* hack: this seems to be a good place, to update the partition map
1N/A * entry count, since mac_alloc_metadata() gets called during
1N/A * _disk_pop_update_mode()
1N/A */
1N/A return _disk_count_partitions (disk);
1N/A}
1N/A
1N/Astatic int
1N/Amac_get_max_primary_partition_count (const PedDisk* disk)
1N/A{
1N/A MacDiskData* mac_disk_data = disk->disk_specific;
1N/A PedPartition* part_map_partition;
1N/A
1N/A part_map_partition = ped_disk_get_partition (disk,
1N/A mac_disk_data->part_map_entry_num);
1N/A
1N/A /* HACK: if we haven't found the partition map partition (yet),
1N/A * we return this.
1N/A */
1N/A if (!part_map_partition) {
1N/A mac_disk_data->part_map_entry_num = 0;
1N/A return 65536;
1N/A }
1N/A
1N/A /* HACK: since Mac labels need an entry for free-space regions, we
1N/A * must allow half plus 1 entries for free-space partitions. I hate
1N/A * this, but things get REALLY complicated, otherwise.
1N/A * (I'm prepared to complicate things later, but I want to get
1N/A * everything working, first)
1N/A */
1N/A return mac_disk_data->part_map_entry_count / mac_disk_data->ghost_size
1N/A - mac_disk_data->free_part_entry_count + 1;
1N/A}
1N/A
1N/Astatic bool
1N/Amac_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
1N/A{
1N/A *max_n = 65536;
1N/A return true;
1N/A}
1N/A
1N/A#include "pt-common.h"
1N/APT_define_limit_functions (mac)
1N/A
1N/Astatic PedDiskOps mac_disk_ops = {
1N/A .clobber = NULL,
1N/A /* FIXME: remove this cast, once mac_write is fixed not to
1N/A modify its *DISK parameter. */
1N/A .write = NULL_IF_DISCOVER_ONLY ((int (*) (const PedDisk*)) mac_write),
1N/A
1N/A .partition_set_name = mac_partition_set_name,
1N/A .partition_get_name = mac_partition_get_name,
1N/A
1N/A .get_partition_alignment = mac_get_partition_alignment,
1N/A
1N/A PT_op_function_initializers (mac)
1N/A};
1N/A
1N/Astatic PedDiskType mac_disk_type = {
1N/A .next = NULL,
1N/A .name = "mac",
1N/A .ops = &mac_disk_ops,
1N/A .features = PED_DISK_TYPE_PARTITION_NAME
1N/A};
1N/A
1N/Avoid
1N/Aped_disk_mac_init ()
1N/A{
1N/A PED_ASSERT (sizeof (MacRawPartition) == 512, return);
1N/A PED_ASSERT (sizeof (MacRawDisk) == 512, return);
1N/A
1N/A ped_disk_type_register (&mac_disk_type);
1N/A}
1N/A
1N/Avoid
1N/Aped_disk_mac_done ()
1N/A{
1N/A ped_disk_type_unregister (&mac_disk_type);
1N/A}