1 /*
   2     libparted - a library for manipulating disk partitions
   3     Copyright (C) 2000, 2002, 2004, 2007 Free Software Foundation, Inc.
   4 
   5     This program is free software; you can redistribute it and/or modify
   6     it under the terms of the GNU General Public License as published by
   7     the Free Software Foundation; either version 3 of the License, or
   8     (at your option) any later version.
   9 
  10     This program is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13     GNU General Public License for more details.
  14 
  15     You should have received a copy of the GNU General Public License
  16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 */
  18 
  19 #include <config.h>
  20 
  21 #include <parted/parted.h>
  22 #include <parted/debug.h>
  23 #include <parted/endian.h>
  24 
  25 #if ENABLE_NLS
  26 #  include <libintl.h>
  27 #  define _(String) dgettext (PACKAGE, String)
  28 #else
  29 #  define _(String) (String)
  30 #endif /* ENABLE_NLS */
  31 
  32 /* struct's hacked from Linux source:  fs/partitions/mac.h
  33  * I believe it was originally written by Paul Mackerras (from comments in
  34  * Quik source)
  35  *
  36  * See also:
  37  *      http://developer.apple.com/documentation/mac/Devices/Devices-126.html
  38  *      http://developer.apple.com/documentation/mac/Devices/Devices-121.html
  39  *      http://devworld.apple.com/technotes/tn/tn1189.html
  40  *
  41  * Partition types:
  42  *      Apple_Bootstrap         new-world (HFS) boot partition
  43  *      Apple_partition_map     partition map (table)
  44  *      Apple_Driver            device driver
  45  *      Apple_Driver43          SCSI Manager 4.3 device driver
  46  *      Apple_MFS               original Macintosh File System 
  47  *      Apple_HFS               Hierarchical File System (and +)
  48  *      Apple_HFSX              HFS+ with case sensitivity and more
  49  *      Apple_UNIX_SVR2         UNIX file system (UFS?)
  50  *      Apple_PRODOS            ProDOS file system 
  51  *      Apple_Free              unused space
  52  *      Apple_Scratch           empty
  53  *      Apple_Void              padding for iso9660
  54  *      Apple_Extra             an unused partition map entry
  55  *
  56  * Quick explanation:
  57  * ------------------
  58  * Terminology:
  59  *
  60  *      Parted                  Apple
  61  *      ------                  -----
  62  *      device                  disk/device
  63  *      disk                    no equivalent.
  64  *      partition               volume or partition
  65  *      sector                  block
  66  *
  67  *      * All space must be accounted for, except block 0 (driver block) and
  68  *      block 1-X (the partition map: i.e. lots of MacRawPartitions)
  69  *
  70  *      * It's really hard to grow/shrink the number of MacRawPartition
  71  *      entries in the partition map, because the first partition starts
  72  *      immediately after the partition map.  When we can move the start of
  73  *      HFS and ext2 partitions, this problem will disappear ;-)
  74  */
  75 
  76 #define MAC_PARTITION_MAGIC_1   0x5453          /* old */
  77 #define MAC_PARTITION_MAGIC_2   0x504d
  78 #define MAC_DISK_MAGIC          0x4552
  79 
  80 #define MAC_STATUS_BOOTABLE     8       /* partition is bootable */
  81 
  82 typedef struct _MacRawPartition     MacRawPartition;
  83 typedef struct _MacRawDisk          MacRawDisk;
  84 typedef struct _MacDeviceDriver     MacDeviceDriver;
  85 typedef struct _MacPartitionData    MacPartitionData;
  86 typedef struct _MacDiskData         MacDiskData;
  87 
  88 #ifdef __sun
  89 #define __attribute__(X)        /*nothing*/
  90 #endif /* __sun */
  91 
  92 #ifdef __sun
  93 #pragma pack(1)
  94 #endif
  95 struct __attribute__ ((packed)) _MacRawPartition {
  96         uint16_t        signature;      /* expected to be MAC_PARTITION_MAGIC */
  97         uint16_t        res1;
  98         uint32_t        map_count;      /* # blocks in partition map */
  99         uint32_t        start_block;    /* absolute starting block # of partition */
 100         uint32_t        block_count;    /* number of blocks in partition */
 101         char            name[32];       /* partition name */
 102         char            type[32];       /* string type description */
 103         uint32_t        data_start;     /* rel block # of first data block */
 104         uint32_t        data_count;     /* number of data blocks */
 105         uint32_t        status;         /* partition status bits */
 106         uint32_t        boot_start;
 107         uint32_t        boot_count;
 108         uint32_t        boot_load;
 109         uint32_t        boot_load2;
 110         uint32_t        boot_entry;
 111         uint32_t        boot_entry2;
 112         uint32_t        boot_cksum;
 113         char            processor[16];  /* Contains 680x0, x=0,2,3,4; or empty */
 114         uint32_t        driver_sig;
 115         char            _padding[372];
 116 };
 117 
 118 /* Driver descriptor structure, in block 0 */
 119 struct __attribute__ ((packed)) _MacRawDisk {
 120         uint16_t        signature;      /* expected to be MAC_DRIVER_MAGIC */
 121         uint16_t        block_size;     /* physical sector size */
 122         uint32_t        block_count;    /* size of device in blocks */
 123         uint16_t        dev_type;       /* reserved */
 124         uint16_t        dev_id;         /* reserved */
 125         uint32_t        data;           /* reserved */
 126         uint16_t        driver_count;   /* # of driver descriptor entries */
 127         uint8_t         driverlist[488];/* info about available drivers */
 128         uint16_t        padding[3];     /* pad to 512 bytes */
 129 };
 130 
 131 struct __attribute__ ((packed)) _MacDeviceDriver {
 132         uint32_t        block;          /* startblock in MacRawDisk->block_size units */
 133         uint16_t        size;           /* size in 512 byte units */
 134         uint16_t        type;           /* operating system type (MacOS = 1) */
 135 };
 136 #ifdef __sun
 137 #pragma pack()
 138 #endif
 139 
 140 struct _MacPartitionData {
 141         char            volume_name[33];        /* eg: "Games" */
 142         char            system_name[33];        /* eg: "Apple_Unix_SVR2" */
 143         char            processor_name[17];
 144 
 145         int             is_boot;
 146         int             is_driver;
 147         int             has_driver;
 148         int             is_root;
 149         int             is_swap;
 150         int             is_lvm;
 151         int             is_raid;
 152 
 153         PedSector       data_region_length;
 154         PedSector       boot_region_length;
 155 
 156         uint32_t        boot_base_address;
 157         uint32_t        boot_entry_address;
 158         uint32_t        boot_checksum;
 159 
 160         uint32_t        status;
 161         uint32_t        driver_sig;
 162 };
 163 
 164 struct _MacDiskData {
 165         int             ghost_size;             /* sectors per "driver" block */
 166         int             part_map_entry_count;   /* # entries (incl. ghost) */
 167         int             part_map_entry_num;     /* partition map location */
 168 
 169         int             active_part_entry_count;        /* # real partitions */
 170         int             free_part_entry_count;          /* # free space */
 171         int             last_part_entry_num;            /* last entry number */
 172 
 173         uint16_t        block_size;             /* physical sector size */
 174         uint16_t        driver_count;
 175         MacDeviceDriver driverlist[1 + 60];     /* 488 bytes */
 176 };
 177 
 178 static PedDiskType mac_disk_type;
 179 
 180 static int
 181 _check_signature (MacRawDisk* raw_disk)
 182 {
 183         if (PED_BE16_TO_CPU (raw_disk->signature) != MAC_DISK_MAGIC) {
 184 #ifdef DISCOVER_ONLY
 185                 return 0;
 186 #else
 187                 return ped_exception_throw (
 188                         PED_EXCEPTION_ERROR,
 189                         PED_EXCEPTION_IGNORE_CANCEL,
 190                         _("Invalid signature %x for Mac disk labels."),
 191                         (int) PED_BE16_TO_CPU (raw_disk->signature))
 192                         == PED_EXCEPTION_IGNORE;
 193 #endif
 194         }
 195 
 196         return 1;
 197 }
 198 
 199 static int
 200 _rawpart_check_signature (MacRawPartition* raw_part)
 201 {
 202         int     sig = (int) PED_BE16_TO_CPU (raw_part->signature);
 203         return sig == MAC_PARTITION_MAGIC_1 || sig == MAC_PARTITION_MAGIC_2;
 204 }
 205 
 206 static int
 207 mac_probe (const PedDevice * dev)
 208 {
 209         MacRawDisk      buf;
 210 
 211         PED_ASSERT (dev != NULL, return 0);
 212 
 213         if (dev->sector_size != 512)
 214                 return 0;
 215 
 216         if (!ped_device_read (dev, &buf, 0, 1))
 217                 return 0;
 218 
 219         return _check_signature (&buf);
 220 }
 221 
 222 static int
 223 _disk_add_part_map_entry (PedDisk* disk, int warn)
 224 {
 225         MacDiskData*            mac_disk_data = disk->disk_specific;
 226         PedPartition*           new_part;
 227         MacPartitionData*       mac_part_data;
 228         PedSector               part_map_size;
 229         PedConstraint*          constraint_any = ped_constraint_any (disk->dev);
 230 
 231 #ifndef DISCOVER_ONLY
 232         if (warn && ped_exception_throw (
 233                 PED_EXCEPTION_ERROR,
 234                 PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
 235                 _("Partition map has no partition map entry!"))
 236                         != PED_EXCEPTION_FIX)
 237                 goto error;
 238 #endif /* !DISCOVER_ONLY */
 239 
 240         part_map_size
 241                 = ped_round_up_to (mac_disk_data->last_part_entry_num, 64);
 242         if (part_map_size == 0)
 243                 part_map_size = 64;
 244 
 245         new_part = ped_partition_new (disk, 0, NULL, 1, part_map_size - 1);
 246         if (!new_part)
 247                 goto error;
 248 
 249         mac_part_data = new_part->disk_specific;
 250         strcpy (mac_part_data->volume_name, "Apple");
 251         strcpy (mac_part_data->system_name, "Apple_partition_map");
 252 
 253         if (!ped_disk_add_partition (disk, new_part, constraint_any))
 254                 goto error_destroy_new_part;
 255 
 256         mac_disk_data->part_map_entry_num = new_part->num;
 257         mac_disk_data->part_map_entry_count
 258                 = new_part->geom.end - mac_disk_data->ghost_size;
 259         ped_constraint_destroy (constraint_any);
 260         return 1;
 261 
 262 error_destroy_new_part:
 263         ped_partition_destroy (new_part);
 264 error:
 265         ped_constraint_destroy (constraint_any);
 266         return 0;
 267 }
 268 
 269 static PedDisk*
 270 mac_alloc (const PedDevice* dev)
 271 {
 272         PedDisk*                disk;
 273         MacDiskData*            mac_disk_data;
 274 
 275         PED_ASSERT (dev != NULL, return NULL);
 276 
 277 #ifndef DISCOVER_ONLY
 278         if (dev->length < 256) {
 279                 ped_exception_throw (
 280                         PED_EXCEPTION_ERROR,
 281                         PED_EXCEPTION_CANCEL,
 282                         _("%s is too small for a Mac disk label!"),
 283                         dev->path);
 284                 goto error;
 285         }
 286 #endif
 287 
 288         disk = _ped_disk_alloc (dev, &mac_disk_type);
 289         if (!disk)
 290                 goto error;
 291 
 292         mac_disk_data = (MacDiskData*) ped_malloc (sizeof (MacDiskData));
 293         if (!mac_disk_data)
 294                 goto error_free_disk;
 295         disk->disk_specific = mac_disk_data;
 296         mac_disk_data->ghost_size = disk->dev->sector_size / 512;
 297         mac_disk_data->active_part_entry_count = 0;
 298         mac_disk_data->free_part_entry_count = 1;
 299         mac_disk_data->last_part_entry_num = 1;
 300         mac_disk_data->block_size = 0;
 301         mac_disk_data->driver_count = 0;
 302         memset(&mac_disk_data->driverlist[0], 0, sizeof(mac_disk_data->driverlist));
 303 
 304         if (!_disk_add_part_map_entry (disk, 0))
 305                 goto error_free_disk;
 306         return disk;
 307 
 308 error_free_disk:
 309         _ped_disk_free (disk);
 310 error:
 311         return NULL;
 312 }
 313 
 314 static PedDisk*
 315 mac_duplicate (const PedDisk* disk)
 316 {
 317         PedDisk*        new_disk;
 318         MacDiskData*    new_mac_data;
 319         MacDiskData*    old_mac_data = (MacDiskData*) disk->disk_specific;
 320         PedPartition*   partition_map;
 321        
 322         new_disk = ped_disk_new_fresh (disk->dev, &mac_disk_type);
 323         if (!new_disk)
 324                 goto error;
 325 
 326         new_mac_data = (MacDiskData*) new_disk->disk_specific;
 327 
 328         /* remove the partition map partition - it will be duplicated
 329          * later.
 330          */
 331         partition_map = ped_disk_get_partition_by_sector (new_disk, 1);
 332         PED_ASSERT (partition_map != NULL, return 0);
 333         ped_disk_remove_partition (new_disk, partition_map);
 334 
 335         /* ugly, but C is ugly :p */
 336         memcpy (new_mac_data, old_mac_data, sizeof (MacDiskData));
 337         return new_disk;
 338 
 339         _ped_disk_free (new_disk);
 340 error:
 341         return NULL;
 342 }
 343 
 344 static void
 345 mac_free (PedDisk* disk)
 346 {
 347         MacDiskData*    mac_disk_data = disk->disk_specific;
 348 
 349         _ped_disk_free (disk);
 350         ped_free (mac_disk_data);
 351 }
 352 
 353 #ifndef DISCOVER_ONLY
 354 static int
 355 _clobber_part_map (PedDevice* dev)
 356 {
 357         MacRawPartition         raw_part;
 358         PedSector               sector;
 359 
 360         for (sector=1; 1; sector++) {
 361                 if (!ped_device_read (dev, &raw_part, sector, 1))
 362                         return 0;
 363                 if (!_rawpart_check_signature (&raw_part))
 364                         return 1;
 365                 memset (&raw_part, 0, 512);
 366                 if (!ped_device_write (dev, &raw_part, sector, 1))
 367                         return 0;
 368         }
 369 }
 370 
 371 static int
 372 mac_clobber (PedDevice* dev)
 373 {
 374         MacRawDisk              raw_disk;
 375 
 376         if (!ped_device_read (dev, &raw_disk, 0, 1))
 377                 return 0;
 378         if (!_check_signature (&raw_disk))
 379                 return 0;
 380         memset (&raw_disk, 0, 512);
 381         if (!ped_device_write (dev, &raw_disk, 0, 1))
 382                 return 0;
 383 
 384         return _clobber_part_map (dev);
 385 }
 386 #endif /* !DISCOVER_ONLY */
 387 
 388 static int
 389 _rawpart_cmp_type (MacRawPartition* raw_part, char* type)
 390 {
 391         return strncasecmp (raw_part->type, type, 32) == 0;
 392 }
 393 
 394 static int
 395 _rawpart_cmp_name (MacRawPartition* raw_part, char* name)
 396 {
 397         return strncasecmp (raw_part->name, name, 32) == 0;
 398 }
 399 
 400 static int
 401 _rawpart_is_partition_map (MacRawPartition* raw_part)
 402 {
 403         return _rawpart_cmp_type (raw_part, "Apple_partition_map");
 404 }
 405 
 406 static int
 407 strncasestr (const char* haystack, const char* needle, int n)
 408 {
 409         int     needle_size = strlen (needle);
 410         int     i;
 411 
 412         for (i = 0; haystack[i] && i < n - needle_size; i++) {
 413                 if (strncasecmp (haystack + i, needle, needle_size) == 0)
 414                         return 1;
 415         }
 416 
 417         return 0;
 418 }
 419 
 420 static int
 421 _rawpart_is_boot (MacRawPartition* raw_part)
 422 {
 423         if (!strcasecmp(raw_part->type, "Apple_Bootstrap"))
 424                 return 1;
 425 
 426         if (!strcasecmp(raw_part->type, "Apple_Boot"))
 427                 return 1;
 428 
 429         return 0;
 430 }
 431 
 432 static int
 433 _rawpart_is_driver (MacRawPartition* raw_part)
 434 {
 435         if (strncmp (raw_part->type, "Apple_", 6) != 0)
 436                 return 0;
 437         if (!strncasestr (raw_part->type, "driver", 32))
 438                 return 0;
 439         return 1;
 440 }
 441 
 442 static int
 443 _rawpart_has_driver (MacRawPartition* raw_part, MacDiskData* mac_disk_data)
 444 {
 445         MacDeviceDriver *driverlist;
 446         uint16_t i, bsz;
 447         uint32_t driver_bs, driver_be, part_be;
 448 
 449         driverlist = &mac_disk_data->driverlist[0];
 450         bsz = mac_disk_data->block_size / 512;
 451         for (i = 0; i < mac_disk_data->driver_count; i++) {
 452                 driver_bs = driverlist->block * bsz;
 453                 driver_be = driver_bs + driverlist->size;
 454                 part_be = raw_part->start_block + raw_part->block_count;
 455                 if (driver_bs >= raw_part->start_block && driver_be <= part_be)
 456                         return 1;
 457                 driverlist++;
 458         }
 459         return 0;
 460 }
 461 
 462 static int
 463 _rawpart_is_root (MacRawPartition* raw_part)
 464 {
 465         if (!_rawpart_cmp_type (raw_part, "Apple_UNIX_SVR2"))
 466                 return 0;
 467         if (strcmp (raw_part->name, "root") != 0)
 468                 return 0;
 469         return 1;
 470 }
 471 
 472 static int
 473 _rawpart_is_swap (MacRawPartition* raw_part)
 474 {
 475         if (!_rawpart_cmp_type (raw_part, "Apple_UNIX_SVR2"))
 476                 return 0;
 477         if (strcmp (raw_part->name, "swap") != 0)
 478                 return 0;
 479         return 1;
 480 }
 481 
 482 static int
 483 _rawpart_is_lvm (MacRawPartition* raw_part)
 484 {
 485         if (strcmp (raw_part->type, "Linux_LVM") != 0)
 486                 return 0;
 487         return 1;
 488 }
 489 
 490 static int
 491 _rawpart_is_raid (MacRawPartition* raw_part)
 492 {
 493         if (strcmp (raw_part->type, "Linux_RAID") != 0)
 494                 return 0;
 495         return 1;
 496 }
 497 
 498 static int
 499 _rawpart_is_void (MacRawPartition* raw_part)
 500 {
 501         return _rawpart_cmp_type (raw_part, "Apple_Void");
 502 }
 503 
 504 /* returns 1 if the raw_part represents a partition that is "unused space", or
 505  * doesn't represent a partition at all.  NOTE: some people make Apple_Free
 506  * partitions with MacOS, because they can't select another type.  So, if the
 507  * name is anything other than "Extra" or "", it is treated as a "real"
 508  * partition.
 509  */
 510 static int
 511 _rawpart_is_active (MacRawPartition* raw_part)
 512 {
 513         if (_rawpart_cmp_type (raw_part, "Apple_Free")
 514             && (_rawpart_cmp_name (raw_part, "Extra")
 515                 || _rawpart_cmp_name (raw_part, "")))
 516                 return 0;
 517         if (_rawpart_cmp_type (raw_part, "Apple_Void"))
 518                 return 0;
 519         if (_rawpart_cmp_type (raw_part, "Apple_Scratch"))
 520                 return 0;
 521         if (_rawpart_cmp_type (raw_part, "Apple_Extra"))
 522                 return 0;
 523 
 524         return 1;
 525 }
 526 
 527 static PedPartition*
 528 _rawpart_analyse (MacRawPartition* raw_part, PedDisk* disk, int num)
 529 {
 530         MacDiskData*            mac_disk_data;
 531         PedPartition*           part;
 532         MacPartitionData*       mac_part_data;
 533         PedSector               block_size;
 534         PedSector               start, length;
 535 
 536         if (!_rawpart_check_signature (raw_part)) {
 537 #ifndef DISCOVER_ONLY
 538                 if (ped_exception_throw (
 539                         PED_EXCEPTION_WARNING,
 540                         PED_EXCEPTION_IGNORE_CANCEL,
 541                         _("Partition %d has an invalid signature %x."),
 542                         num,
 543                         (int) PED_BE16_TO_CPU (raw_part->signature))
 544                                 != PED_EXCEPTION_IGNORE)
 545 #endif
 546                         goto error;
 547         }
 548 
 549         mac_disk_data = (MacDiskData*) disk->disk_specific;
 550         block_size = disk->dev->sector_size / 512;
 551 
 552         start = PED_BE32_TO_CPU (raw_part->start_block) * block_size;
 553         length = PED_BE32_TO_CPU (raw_part->block_count) * block_size;
 554         if (length == 0) {
 555 #ifndef DISCOVER_ONLY
 556                 ped_exception_throw (
 557                         PED_EXCEPTION_ERROR,
 558                         PED_EXCEPTION_CANCEL,
 559                         _("Partition %d has an invalid length of 0 bytes!"),
 560                         num);
 561 #endif
 562                 return NULL;
 563         }
 564         part = ped_partition_new (disk, 0, NULL, start, start + length - 1);
 565         if (!part)
 566                 goto error;
 567 
 568         mac_part_data = part->disk_specific;
 569 
 570         strncpy (mac_part_data->volume_name, raw_part->name, 32);
 571         strncpy (mac_part_data->system_name, raw_part->type, 32);
 572         strncpy (mac_part_data->processor_name, raw_part->processor, 16);
 573 
 574         mac_part_data->is_boot = _rawpart_is_boot (raw_part);
 575         mac_part_data->is_driver = _rawpart_is_driver (raw_part);
 576         if (mac_part_data->is_driver)
 577                 mac_part_data->has_driver = _rawpart_has_driver(raw_part, mac_disk_data);
 578         mac_part_data->is_root = _rawpart_is_root (raw_part);
 579         mac_part_data->is_swap = _rawpart_is_swap (raw_part);
 580         mac_part_data->is_lvm = _rawpart_is_lvm (raw_part);
 581         mac_part_data->is_raid = _rawpart_is_raid (raw_part);
 582 
 583         /* "data" region */
 584 #ifndef DISCOVER_ONLY
 585         if (raw_part->data_start) {
 586                 ped_exception_throw (
 587                         PED_EXCEPTION_ERROR,
 588                         PED_EXCEPTION_CANCEL,
 589                         _("The data region doesn't start at the start "
 590                           "of the partition."));
 591                 goto error_destroy_part;
 592         }
 593 #endif /* !DISCOVER_ONLY */
 594         mac_part_data->data_region_length
 595                 = PED_BE32_TO_CPU (raw_part->data_count) * block_size;
 596 
 597         /* boot region - we have no idea what this is for, but Mac OSX
 598          * seems to put garbage here, and doesn't pay any attention to
 599          * it afterwards.  [clausen, dan burcaw]
 600          */
 601 #if 0
 602         if (raw_part->boot_start) {
 603                 ped_exception_throw (
 604                         PED_EXCEPTION_ERROR,
 605                         PED_EXCEPTION_CANCEL,
 606                         _("The boot region doesn't start at the start "
 607                           "of the partition."));
 608                 goto error_destroy_part;
 609         }
 610 #endif
 611         mac_part_data->boot_region_length
 612                 = PED_BE32_TO_CPU (raw_part->boot_count) * block_size;
 613 
 614 #ifndef DISCOVER_ONLY
 615         if (mac_part_data->has_driver) {
 616                 if (mac_part_data->boot_region_length < part->geom.length) {
 617                         if (ped_exception_throw (
 618                                 PED_EXCEPTION_ERROR,
 619                                 PED_EXCEPTION_IGNORE_CANCEL,
 620                                 _("The partition's boot region doesn't occupy "
 621                                   "the entire partition."))
 622                                         != PED_EXCEPTION_IGNORE)
 623                                 goto error_destroy_part;
 624                 }
 625         } else {
 626                 if (mac_part_data->data_region_length < part->geom.length &&
 627                     !mac_part_data->is_boot) {
 628                         if (ped_exception_throw (
 629                                 PED_EXCEPTION_ERROR,
 630                                 PED_EXCEPTION_IGNORE_CANCEL,
 631                                 _("The partition's data region doesn't occupy "
 632                                   "the entire partition."))
 633                                         != PED_EXCEPTION_IGNORE)
 634                                 goto error_destroy_part;
 635                 }
 636         }
 637 #endif /* !DISCOVER_ONLY */
 638 
 639         mac_part_data->boot_base_address
 640                 = PED_BE32_TO_CPU (raw_part->boot_load);
 641         mac_part_data->boot_entry_address
 642                 = PED_BE32_TO_CPU (raw_part->boot_entry);
 643         mac_part_data->boot_checksum
 644                 = PED_BE32_TO_CPU (raw_part->boot_cksum);
 645 
 646         mac_part_data->status = PED_BE32_TO_CPU (raw_part->status);
 647         mac_part_data->driver_sig = PED_BE32_TO_CPU (raw_part->driver_sig);
 648 
 649         return part;
 650 
 651 error_destroy_part:
 652         ped_partition_destroy (part);
 653 error:
 654         return NULL;
 655 }
 656 
 657 /* looks at the partition map size field in a mac raw partition, and calculates
 658  * what the size of the partition map should be, from it
 659  */
 660 static int
 661 _rawpart_get_partmap_size (MacRawPartition* raw_part, PedDisk* disk)
 662 {
 663         MacDiskData*    mac_disk_data = disk->disk_specific;
 664         PedSector       sector_size = disk->dev->sector_size / 512;
 665         PedSector       part_map_start;
 666         PedSector       part_map_end;
 667 
 668         part_map_start = mac_disk_data->ghost_size;
 669         part_map_end = sector_size * PED_BE32_TO_CPU (raw_part->map_count);
 670 
 671         return part_map_end - part_map_start + 1;
 672 }
 673 
 674 static int
 675 _disk_analyse_block_size (PedDisk* disk, MacRawDisk* raw_disk)
 676 {
 677         PedSector       block_size;
 678 
 679         if (PED_BE16_TO_CPU (raw_disk->block_size) % 512) {
 680 #ifndef DISCOVER_ONLY
 681                 ped_exception_throw (
 682                         PED_EXCEPTION_ERROR,
 683                         PED_EXCEPTION_CANCEL,
 684                         _("Weird block size on device descriptor: %d bytes is "
 685                           "not divisible by 512."),
 686                         (int) PED_BE16_TO_CPU (raw_disk->block_size));
 687 #endif
 688                 goto error;
 689         }
 690 
 691         block_size = PED_BE16_TO_CPU (raw_disk->block_size) / 512;
 692         if (block_size != disk->dev->sector_size / 512) {
 693 #ifndef DISCOVER_ONLY
 694                 if (ped_exception_throw (
 695                         PED_EXCEPTION_WARNING,
 696                         PED_EXCEPTION_IGNORE_CANCEL,
 697                         _("The driver descriptor says the physical block size "
 698                           "is %d bytes, but Linux says it is %d bytes."),
 699                         (int) block_size * 512,
 700                         (int) disk->dev->sector_size)
 701                                 != PED_EXCEPTION_IGNORE)
 702                         goto error;
 703 #endif
 704                 disk->dev->sector_size = block_size * 512;
 705         }
 706 
 707         return 1;
 708 
 709 error:
 710         return 0;
 711 }
 712 
 713 /* Tries to figure out the block size used by the drivers, for the ghost
 714  * partitioning scheme.  Ghost partitioning works like this: the OpenFirmware
 715  * (OF) sees 512 byte blocks, but some drivers use 2048 byte blocks (and,
 716  * perhaps, some other number?).  To remain compatible, the partition map
 717  * only has "real" partition map entries on ghost-aligned block numbers (and
 718  * the others are padded with Apple_Void partitions).  This function tries
 719  * to figure out what the "ghost-aligned" size is... (which, believe-it-or-not,
 720  * doesn't always equal 2048!!!)
 721  */
 722 static int
 723 _disk_analyse_ghost_size (PedDisk* disk)
 724 {
 725         MacDiskData*            mac_disk_data = disk->disk_specific;
 726         MacRawPartition         raw_part;
 727         int                     i;
 728 
 729         for (i = 1; i < 64; i *= 2) {
 730                 if (!ped_device_read (disk->dev, &raw_part, i, 1))
 731                         return 0;
 732                 if (_rawpart_check_signature (&raw_part)
 733                     && !_rawpart_is_void (&raw_part)) {
 734                         mac_disk_data->ghost_size = i;
 735                         PED_ASSERT (i <= disk->dev->sector_size / 512,
 736                                     return 0);
 737                         return 1;
 738                 }
 739         }
 740 
 741 #ifndef DISCOVER_ONLY
 742         ped_exception_throw (
 743                 PED_EXCEPTION_ERROR,
 744                 PED_EXCEPTION_CANCEL,
 745                 _("No valid partition map found."));
 746 #endif
 747         return 0;
 748 }
 749 
 750 static int
 751 mac_read (PedDisk* disk)
 752 {
 753         MacRawDisk              raw_disk;
 754         MacRawPartition         raw_part;
 755         MacDiskData*            mac_disk_data;
 756         PedPartition*           part;
 757         int                     num;
 758         PedSector               ghost_size;
 759         PedConstraint*          constraint_exact;
 760         int                     last_part_entry_num = 0;
 761 
 762         PED_ASSERT (disk != NULL, return 0);
 763 
 764         mac_disk_data = disk->disk_specific;
 765         mac_disk_data->part_map_entry_num = 0;               /* 0 == none */
 766 
 767         if (!ped_device_read (disk->dev, &raw_disk, 0, 1))
 768                 goto error;
 769         if (!_check_signature (&raw_disk))
 770                 goto error;
 771 
 772         if (!_disk_analyse_block_size (disk, &raw_disk))
 773                 goto error;
 774         if (!_disk_analyse_ghost_size (disk))
 775                 goto error;
 776         ghost_size = mac_disk_data->ghost_size;
 777 
 778         if (!ped_disk_delete_all (disk))
 779                 goto error;
 780 
 781         if (raw_disk.driver_count && raw_disk.driver_count < 62) {
 782                 memcpy(&mac_disk_data->driverlist[0], &raw_disk.driverlist[0],
 783                                 sizeof(mac_disk_data->driverlist));
 784                 mac_disk_data->driver_count = raw_disk.driver_count;
 785                 mac_disk_data->block_size = raw_disk.block_size;
 786         }
 787 
 788         for (num=1; num==1 || num <= last_part_entry_num; num++) {
 789                 if (!ped_device_read (disk->dev, &raw_part,
 790                                       num * ghost_size, 1))
 791                         goto error_delete_all;
 792 
 793                 if (!_rawpart_check_signature (&raw_part))
 794                         continue;
 795 
 796                 if (num == 1)
 797                         last_part_entry_num
 798                                 = _rawpart_get_partmap_size (&raw_part, disk);
 799                 if (_rawpart_get_partmap_size (&raw_part, disk)
 800                                 != last_part_entry_num) {
 801                         if (ped_exception_throw (
 802                                 PED_EXCEPTION_ERROR,
 803                                 PED_EXCEPTION_IGNORE_CANCEL,
 804                                 _("Conflicting partition map entry sizes!  "
 805                                   "Entry 1 says it is %d, but entry %d says "
 806                                   "it is %d!"),
 807                                 last_part_entry_num,
 808                                 _rawpart_get_partmap_size (&raw_part, disk))
 809                                         != PED_EXCEPTION_IGNORE)
 810                                 goto error_delete_all;
 811                 }
 812 
 813                 if (!_rawpart_is_active (&raw_part))
 814                         continue;
 815 
 816                 part = _rawpart_analyse (&raw_part, disk, num);
 817                 if (!part)
 818                         goto error_delete_all;
 819                 part->num = num;
 820                 part->fs_type = ped_file_system_probe (&part->geom);
 821                 constraint_exact = ped_constraint_exact (&part->geom);
 822                 if (!ped_disk_add_partition (disk, part, constraint_exact))
 823                         goto error_delete_all;
 824                 ped_constraint_destroy (constraint_exact);
 825 
 826                 if (_rawpart_is_partition_map (&raw_part)) {
 827                         if (mac_disk_data->part_map_entry_num
 828                             && ped_exception_throw (
 829                                         PED_EXCEPTION_ERROR,
 830                                         PED_EXCEPTION_IGNORE_CANCEL,
 831                                         _("Weird!  There are 2 partitions "
 832                                           "map entries!"))
 833                             != PED_EXCEPTION_IGNORE)
 834                                 goto error_delete_all;
 835 
 836                         mac_disk_data->part_map_entry_num = num;
 837                         mac_disk_data->part_map_entry_count
 838                                 = part->geom.end - ghost_size + 1;
 839                 }
 840         }
 841 
 842         if (!mac_disk_data->part_map_entry_num) {
 843                 if (!_disk_add_part_map_entry (disk, 1))
 844                         goto error_delete_all;
 845                 ped_disk_commit_to_dev (disk);
 846         }
 847         return 1;
 848 
 849 error_delete_all:
 850         ped_disk_delete_all (disk);
 851 error:
 852         return 0;
 853 }
 854 
 855 #ifndef DISCOVER_ONLY
 856 /* The Ghost partition: is a blank entry, used to pad out each block (where
 857  * there physical block size > 512 bytes).  This is because OpenFirmware uses
 858  * 512 byte blocks, but device drivers Think Different TM, with a different
 859  * lbock size, so we need to do this to avoid a clash (!)
 860  */
 861 static int
 862 _pad_raw_part (PedDisk* disk, int num, MacRawPartition* part_map)
 863 {
 864         MacDiskData*            mac_disk_data = disk->disk_specific;
 865         MacRawPartition         ghost_entry;
 866         int                     i;
 867 
 868         memset (&ghost_entry, 0, sizeof (ghost_entry));
 869         ghost_entry.signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
 870         strcpy (ghost_entry.type, "Apple_Void");
 871         ghost_entry.map_count
 872                 = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
 873 
 874         for (i=0; i < mac_disk_data->ghost_size - 1; i++)
 875                 memcpy (&part_map [i + (num - 1) * mac_disk_data->ghost_size],
 876                         &ghost_entry, sizeof (MacRawPartition));
 877 
 878         return 1;
 879 }
 880 
 881 static void
 882 _update_driver_count (MacRawPartition* part_map_entry,
 883                       MacDiskData *mac_driverdata, const MacDiskData* mac_disk_data)
 884 {
 885         uint16_t        i, count_orig, count_cur, bsz;
 886         uint32_t        driver_bs, driver_be, part_be;
 887 
 888         bsz = mac_disk_data->block_size / 512;
 889         count_cur = mac_driverdata->driver_count;
 890         count_orig = mac_disk_data->driver_count;
 891         for (i = 0; i < count_orig; i++) {
 892                 driver_bs = mac_disk_data->driverlist[i].block * bsz;
 893                 driver_be = driver_bs + mac_disk_data->driverlist[i].size;
 894                 part_be = part_map_entry->start_block + part_map_entry->block_count;
 895                 if (driver_bs >= part_map_entry->start_block
 896                                 && driver_be <= part_be) {
 897                         mac_driverdata->driverlist[count_cur].block
 898                                 = mac_disk_data->driverlist[i].block;
 899                         mac_driverdata->driverlist[count_cur].size
 900                                 = mac_disk_data->driverlist[i].size;
 901                         mac_driverdata->driverlist[count_cur].type
 902                                 = mac_disk_data->driverlist[i].type;
 903                         mac_driverdata->driver_count++;
 904                         break;
 905                 }
 906         }
 907 }
 908 
 909 static int
 910 _generate_raw_part (PedDisk* disk, PedPartition* part,
 911                     MacRawPartition* part_map, MacDiskData *mac_driverdata)
 912 {
 913         MacDiskData*            mac_disk_data;
 914         MacPartitionData*       mac_part_data;
 915         MacRawPartition*        part_map_entry;
 916         PedSector               block_size = disk->dev->sector_size / 512;
 917 
 918         PED_ASSERT (part->num > 0, goto error);
 919 
 920         mac_disk_data = disk->disk_specific;
 921         mac_part_data = part->disk_specific;
 922 
 923         part_map_entry = &part_map [part->num * mac_disk_data->ghost_size - 1];
 924 
 925         part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
 926         part_map_entry->map_count
 927                 = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
 928         part_map_entry->start_block
 929                 = PED_CPU_TO_BE32 (part->geom.start / block_size);
 930         part_map_entry->block_count
 931                 = PED_CPU_TO_BE32 (part->geom.length / block_size);
 932         strcpy (part_map_entry->name, mac_part_data->volume_name);
 933         strcpy (part_map_entry->type, mac_part_data->system_name);
 934 
 935         if (mac_part_data->is_driver) {
 936                 mac_part_data->boot_region_length = part->geom.length;
 937                 if (mac_part_data->has_driver)
 938                         _update_driver_count(part_map_entry, mac_driverdata,
 939                                         mac_disk_data);
 940         } else
 941                 mac_part_data->data_region_length = part->geom.length;
 942         part_map_entry->data_count = PED_CPU_TO_BE32 (
 943                         mac_part_data->data_region_length / block_size);
 944         part_map_entry->boot_count = PED_CPU_TO_BE32 (
 945                         mac_part_data->boot_region_length / block_size);
 946         part_map_entry->status = PED_CPU_TO_BE32 (mac_part_data->status);
 947         part_map_entry->driver_sig
 948                 = PED_CPU_TO_BE32 (mac_part_data->driver_sig);
 949 
 950         part_map_entry->boot_load =
 951                 PED_CPU_TO_BE32 (mac_part_data->boot_base_address);
 952         part_map_entry->boot_entry =
 953                 PED_CPU_TO_BE32 (mac_part_data->boot_entry_address);
 954         part_map_entry->boot_cksum =
 955                 PED_CPU_TO_BE32 (mac_part_data->boot_checksum);
 956 
 957         strncpy (part_map_entry->processor, mac_part_data->processor_name, 16);
 958 
 959         if (!_pad_raw_part (disk, part->num, part_map))
 960                 goto error;
 961 
 962         return 1;
 963 
 964 error:
 965         return 0;       
 966 }
 967 
 968 static int
 969 _generate_raw_freespace_part (PedDisk* disk, PedGeometry* geom, int num,
 970                               MacRawPartition* part_map)
 971 {
 972         MacDiskData*            mac_disk_data = disk->disk_specific;
 973         MacRawPartition*        part_map_entry;
 974         PedSector               block_size = disk->dev->sector_size / 512;
 975 
 976         PED_ASSERT (num > 0, goto error);
 977 
 978         part_map_entry = &part_map [num * mac_disk_data->ghost_size - 1];
 979 
 980         part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
 981         part_map_entry->map_count
 982                 = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
 983         part_map_entry->start_block
 984                 = PED_CPU_TO_BE32 (geom->start / block_size);
 985         part_map_entry->block_count
 986                 = PED_CPU_TO_BE32 (geom->length / block_size);
 987         strcpy (part_map_entry->name, "Extra");
 988         strcpy (part_map_entry->type, "Apple_Free");
 989 
 990         part_map_entry->data_count = PED_CPU_TO_BE32 (geom->length);
 991         part_map_entry->status = 0;
 992         part_map_entry->driver_sig = 0;
 993 
 994         if (!_pad_raw_part (disk, num, part_map))
 995                 goto error;
 996 
 997         return 1;
 998 
 999 error:
1000         return 0;       
1001 }
1002 
1003 static int
1004 _generate_empty_part (PedDisk* disk, int num, MacRawPartition* part_map)
1005 {
1006         MacDiskData*            mac_disk_data = disk->disk_specific;
1007         MacRawPartition*        part_map_entry;
1008 
1009         PED_ASSERT (num > 0, return 0);
1010 
1011         part_map_entry = &part_map [num * mac_disk_data->ghost_size - 1];
1012         part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
1013         part_map_entry->map_count
1014                 = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
1015         strcpy (part_map_entry->type, "Apple_Void");
1016 
1017         return _pad_raw_part (disk, num, part_map);
1018 }
1019 
1020 /* returns the first empty entry in the partition map */
1021 static int
1022 _get_first_empty_part_entry (PedDisk* disk, MacRawPartition* part_map)
1023 {
1024         MacDiskData*    mac_disk_data = disk->disk_specific;
1025         int             i;
1026 
1027         for (i=1; i <= mac_disk_data->last_part_entry_num; i++) {
1028                 if (!part_map[i * mac_disk_data->ghost_size - 1].signature)
1029                         return i;
1030         }
1031 
1032         return 0;
1033 }
1034 
1035 static int
1036 write_block_zero (PedDisk* disk, MacDiskData* mac_driverdata)
1037 {
1038         PedDevice*      dev = disk->dev;
1039         MacRawDisk      raw_disk;
1040 
1041         if (!ped_device_read (dev, &raw_disk, 0, 1))
1042                 return 0;
1043 
1044         raw_disk.signature = PED_CPU_TO_BE16 (MAC_DISK_MAGIC);
1045         raw_disk.block_size = PED_CPU_TO_BE16 (dev->sector_size);
1046         raw_disk.block_count
1047                 = PED_CPU_TO_BE32 (dev->length / (dev->sector_size / 512));
1048 
1049         raw_disk.driver_count = mac_driverdata->driver_count;
1050         memcpy(&raw_disk.driverlist[0], &mac_driverdata->driverlist[0],
1051                         sizeof(raw_disk.driverlist));
1052 
1053         return ped_device_write (dev, &raw_disk, 0, 1);
1054 }
1055 
1056 static int
1057 mac_write (PedDisk* disk)
1058 {
1059         MacRawPartition*        part_map;
1060         MacDiskData*            mac_disk_data;
1061         MacDiskData*            mac_driverdata; /* updated driver list */
1062         PedPartition*           part;
1063         int                     num;
1064 
1065         PED_ASSERT (disk != NULL, return 0);
1066         PED_ASSERT (disk->disk_specific != NULL, return 0);
1067         PED_ASSERT (disk->dev != NULL, return 0);
1068         PED_ASSERT (!disk->update_mode, return 0);
1069 
1070         mac_disk_data = disk->disk_specific;
1071 
1072         if (!ped_disk_get_partition (disk, mac_disk_data->part_map_entry_num)) {
1073                 if (!_disk_add_part_map_entry (disk, 1))
1074                         goto error;
1075         }
1076 
1077         mac_driverdata = ped_malloc(sizeof(MacDiskData));
1078         if (!mac_driverdata)
1079                 goto error;
1080         memset (mac_driverdata, 0, sizeof(MacDiskData));
1081 
1082         part_map = (MacRawPartition*)
1083                         ped_malloc (mac_disk_data->part_map_entry_count * 512);
1084         if (!part_map)
1085                 goto error_free_driverdata;
1086         memset (part_map, 0, mac_disk_data->part_map_entry_count * 512);
1087 
1088 /* write (to memory) the "real" partitions */
1089         for (part = ped_disk_next_partition (disk, NULL); part;
1090              part = ped_disk_next_partition (disk, part)) {
1091                 if (!ped_partition_is_active (part))
1092                         continue;
1093                 if (!_generate_raw_part (disk, part, part_map, mac_driverdata))
1094                         goto error_free_part_map;
1095         }
1096 
1097 /* write the "free space" partitions */
1098         for (part = ped_disk_next_partition (disk, NULL); part;
1099              part = ped_disk_next_partition (disk, part)) {
1100                 if (part->type != PED_PARTITION_FREESPACE)
1101                         continue;
1102                 num = _get_first_empty_part_entry (disk, part_map);
1103                 if (!_generate_raw_freespace_part (disk, &part->geom, num,
1104                                                    part_map))
1105                         goto error_free_part_map;
1106         }
1107 
1108 /* write the "void" (empty) partitions */
1109         for (num = _get_first_empty_part_entry (disk, part_map); num;
1110              num = _get_first_empty_part_entry (disk, part_map))
1111                 _generate_empty_part (disk, num, part_map);
1112 
1113 /* write to disk */
1114         if (!ped_device_write (disk->dev, part_map, 1,
1115                                mac_disk_data->part_map_entry_count))
1116                 goto error_free_part_map;
1117         ped_free (part_map);
1118         return write_block_zero (disk, mac_driverdata);
1119 
1120 error_free_part_map:
1121         ped_free (part_map);
1122 error_free_driverdata:
1123         ped_free (mac_driverdata);
1124 error:
1125         return 0;
1126 }
1127 #endif /* !DISCOVER_ONLY */
1128 
1129 static PedPartition*
1130 mac_partition_new (
1131         const PedDisk* disk, PedPartitionType part_type,
1132         const PedFileSystemType* fs_type, PedSector start, PedSector end)
1133 {
1134         PedPartition*           part;
1135         MacPartitionData*       mac_data;
1136 
1137         part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1138         if (!part)
1139                 goto error;
1140 
1141         if (ped_partition_is_active (part)) {
1142                 part->disk_specific
1143                         = mac_data = ped_malloc (sizeof (MacPartitionData));
1144                 if (!mac_data)
1145                         goto error_free_part;
1146 
1147                 memset (mac_data, 0, sizeof (MacPartitionData));
1148                 strcpy (mac_data->volume_name, "untitled");
1149         } else {
1150                 part->disk_specific = NULL;
1151         }
1152         return part;
1153 
1154         ped_free (mac_data);
1155 error_free_part:
1156         ped_free (part);
1157 error:
1158         return 0;
1159 }
1160 
1161 static PedPartition*
1162 mac_partition_duplicate (const PedPartition* part)
1163 {
1164         PedPartition*           new_part;
1165         MacPartitionData*       new_mac_data;
1166         MacPartitionData*       old_mac_data;
1167 
1168         new_part = ped_partition_new (part->disk, part->type,
1169                                       part->fs_type, part->geom.start,
1170                                       part->geom.end);
1171         if (!new_part)
1172                 return NULL;
1173         new_part->num = part->num;
1174 
1175         old_mac_data = (MacPartitionData*) part->disk_specific;
1176         new_mac_data = (MacPartitionData*) new_part->disk_specific;
1177 
1178         /* ugly, but C is ugly :p */
1179         memcpy (new_mac_data, old_mac_data, sizeof (MacPartitionData));
1180         return new_part;
1181 }
1182 
1183 static void
1184 mac_partition_destroy (PedPartition* part)
1185 {
1186         PED_ASSERT (part != NULL, return);
1187 
1188         if (ped_partition_is_active (part))
1189                 ped_free (part->disk_specific);
1190         ped_free (part);
1191 }
1192 
1193 static int
1194 mac_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1195 {
1196         MacPartitionData* mac_data = part->disk_specific;
1197 
1198         part->fs_type = fs_type;
1199 
1200         if (fs_type && !strcmp (fs_type->name, "linux-swap"))
1201                 ped_partition_set_flag (part, PED_PARTITION_SWAP, 1);
1202 
1203         if (mac_data->is_boot) {
1204                 strcpy (mac_data->system_name, "Apple_Bootstrap");
1205                 mac_data->status = 0x33;
1206                 return 1;
1207         }
1208 
1209         if (fs_type && (!strcmp (fs_type->name, "hfs")
1210                         || !strcmp (fs_type->name, "hfs+"))) {
1211                 strcpy (mac_data->system_name, "Apple_HFS");
1212                 mac_data->status |= 0x7f;
1213         } else if (fs_type && !strcmp (fs_type->name, "hfsx")) {
1214                 strcpy (mac_data->system_name, "Apple_HFSX");
1215                 mac_data->status |= 0x7f;
1216         } else {
1217                 strcpy (mac_data->system_name, "Apple_UNIX_SVR2");
1218                 mac_data->status = 0x33;
1219         }
1220 
1221         return 1;
1222 }
1223 
1224 static int
1225 mac_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
1226 {
1227         MacPartitionData*       mac_data;
1228 
1229         PED_ASSERT (part != NULL, return 0);
1230         PED_ASSERT (part->disk_specific != NULL, return 0);
1231 
1232         mac_data = part->disk_specific;
1233 
1234         switch (flag) {
1235         case PED_PARTITION_BOOT:
1236                 mac_data->is_boot = state;
1237 
1238                 if (part->fs_type)
1239                         return mac_partition_set_system (part, part->fs_type);
1240 
1241                 if (state) {
1242                         strcpy (mac_data->system_name, "Apple_Bootstrap");
1243                         mac_data->status = 0x33;
1244                 }
1245                 return 1;
1246 
1247         case PED_PARTITION_ROOT:
1248                 if (state) {
1249                         strcpy (mac_data->volume_name, "root");
1250                         mac_data->is_swap = 0;
1251                 } else {
1252                         if (mac_data->is_root)
1253                                 strcpy (mac_data->volume_name, "untitled");
1254                 }
1255                 mac_data->is_root = state;
1256                 return 1;
1257 
1258         case PED_PARTITION_SWAP:
1259                 if (state) {
1260                         strcpy (mac_data->volume_name, "swap");
1261                         mac_data->is_root = 0;
1262                 } else {
1263                         if (mac_data->is_swap)
1264                                 strcpy (mac_data->volume_name, "untitled");
1265                 }
1266                 mac_data->is_swap = state;
1267                 return 1;
1268 
1269         case PED_PARTITION_LVM:
1270                 if (state) {
1271                         strcpy (mac_data->system_name, "Linux_LVM");
1272                         mac_data->is_lvm = state;
1273                 } else {
1274                         if (mac_data->is_lvm)
1275                                 mac_partition_set_system (part, part->fs_type);
1276                 }
1277                 return 1;
1278 
1279         case PED_PARTITION_RAID:
1280                 if (state) {
1281                         strcpy (mac_data->system_name, "Linux_RAID");
1282                         mac_data->is_raid = state;
1283                 } else {
1284                         if (mac_data->is_raid)
1285                                 mac_partition_set_system (part, part->fs_type);
1286                 }
1287                 return 1;
1288 
1289         default:
1290                 return 0;
1291         }
1292 }
1293 
1294 static int
1295 mac_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
1296 {
1297         MacPartitionData*       mac_data;
1298 
1299         PED_ASSERT (part != NULL, return 0);
1300         PED_ASSERT (part->disk_specific != NULL, return 0);
1301 
1302         mac_data = part->disk_specific;
1303         switch (flag) {
1304         case PED_PARTITION_BOOT:
1305                 return mac_data->is_boot;
1306 
1307         case PED_PARTITION_ROOT:
1308                 return mac_data->is_root;
1309 
1310         case PED_PARTITION_SWAP:
1311                 return mac_data->is_swap;
1312 
1313         case PED_PARTITION_LVM:
1314                 return mac_data->is_lvm;
1315 
1316         case PED_PARTITION_RAID:
1317                 return mac_data->is_raid;
1318 
1319         default:
1320                 return 0;
1321         }
1322 }
1323 
1324 static int
1325 mac_partition_is_flag_available (
1326         const PedPartition* part, PedPartitionFlag flag)
1327 {
1328         switch (flag) {
1329         case PED_PARTITION_BOOT:
1330         case PED_PARTITION_ROOT:
1331         case PED_PARTITION_SWAP:
1332         case PED_PARTITION_LVM:
1333         case PED_PARTITION_RAID:
1334                 return 1;
1335 
1336         default:
1337                 return 0;
1338         }
1339 }
1340 
1341 static void
1342 mac_partition_set_name (PedPartition* part, const char* name)
1343 {
1344         MacPartitionData*       mac_data;
1345         int                     i;
1346 
1347         PED_ASSERT (part != NULL, return);
1348         PED_ASSERT (part->disk_specific != NULL, return);
1349         mac_data = part->disk_specific;
1350 
1351 #ifndef DISCOVER_ONLY
1352         if (mac_data->is_root || mac_data->is_swap) {
1353                 if (ped_exception_throw (
1354                         PED_EXCEPTION_WARNING,
1355                         PED_EXCEPTION_IGNORE_CANCEL,
1356                         _("Changing the name of a root or swap partition "
1357                           "will prevent Linux from recognising it as such."))
1358                                 != PED_EXCEPTION_IGNORE)
1359                         return;
1360                 mac_data->is_root = mac_data->is_swap = 0;
1361         }
1362 #endif
1363 
1364         strncpy (mac_data->volume_name, name, 32);
1365         mac_data->volume_name [32] = 0;
1366         for (i = strlen (mac_data->volume_name) - 1;
1367                         mac_data->volume_name[i] == ' '; i--)
1368                 mac_data->volume_name [i] = 0;
1369 }
1370 
1371 static const char*
1372 mac_partition_get_name (const PedPartition* part)
1373 {
1374         MacPartitionData*       mac_data;
1375 
1376         PED_ASSERT (part != NULL, return NULL);
1377         PED_ASSERT (part->disk_specific != NULL, return NULL);
1378         mac_data = part->disk_specific;
1379 
1380         return mac_data->volume_name;
1381 }
1382 
1383 static PedConstraint*
1384 _primary_constraint (PedDisk* disk)
1385 {
1386         PedAlignment    start_align;
1387         PedAlignment    end_align;
1388         PedGeometry     max_geom;
1389         PedSector       sector_size;
1390 
1391         sector_size = disk->dev->sector_size / 512;
1392 
1393         if (!ped_alignment_init (&start_align, 0, sector_size))
1394                 return NULL;
1395         if (!ped_alignment_init (&end_align, -1, sector_size))
1396                 return NULL;
1397         if (!ped_geometry_init (&max_geom, disk->dev, 1, disk->dev->length - 1))
1398                 return NULL;
1399 
1400         return ped_constraint_new (&start_align, &end_align, &max_geom,
1401                                    &max_geom, 1, disk->dev->length);
1402 }
1403 
1404 static int
1405 mac_partition_align (PedPartition* part, const PedConstraint* constraint)
1406 {
1407         PED_ASSERT (part != NULL, return 0);
1408 
1409         if (_ped_partition_attempt_align (part, constraint,
1410                                           _primary_constraint (part->disk)))
1411                 return 1;
1412 
1413 #ifndef DISCOVER_ONLY
1414         ped_exception_throw (
1415                 PED_EXCEPTION_ERROR,
1416                 PED_EXCEPTION_CANCEL,
1417                 _("Unable to satisfy all constraints on the partition."));
1418 #endif
1419         return 0;
1420 }
1421 
1422 static int
1423 mac_partition_enumerate (PedPartition* part)
1424 {
1425         PedDisk*                disk;
1426         MacDiskData*            mac_disk_data;
1427         int                     i;
1428         int                     max_part_count;
1429 
1430         PED_ASSERT (part != NULL, return 0);
1431         PED_ASSERT (part->disk != NULL, return 0);
1432 
1433         disk = part->disk;
1434         mac_disk_data = (MacDiskData*) disk->disk_specific;
1435 
1436         max_part_count = ped_disk_get_max_primary_partition_count (disk);
1437 
1438         if (part->num > 0 && part->num <= mac_disk_data->part_map_entry_count)
1439                 return 1;
1440 
1441         for (i = 1; i <= max_part_count; i++) {
1442                 if (!ped_disk_get_partition (disk, i)) {
1443                         part->num = i;
1444                         return 1;
1445                 }
1446         }
1447 
1448 #ifndef DISCOVER_ONLY
1449         ped_exception_throw (
1450                 PED_EXCEPTION_ERROR,
1451                 PED_EXCEPTION_CANCEL,
1452                 _("Can't add another partition -- the partition map is too "
1453                   "small!"));
1454 #endif
1455 
1456         return 0;
1457 }
1458 
1459 static int
1460 _disk_count_partitions (PedDisk* disk)
1461 {
1462         MacDiskData*            mac_disk_data = disk->disk_specific;
1463         PedPartition*           part = NULL;
1464         PedPartition*           last = NULL;
1465 
1466         PED_ASSERT (disk->update_mode, return 0);
1467 
1468         mac_disk_data->active_part_entry_count = 0;
1469         mac_disk_data->free_part_entry_count = 0;
1470         mac_disk_data->last_part_entry_num = 0;
1471 
1472         /* subtle: we only care about free space after the partition map.
1473          * the partition map is an "active" partition, BTW... */
1474         for (part = ped_disk_next_partition (disk, part); part;
1475              part = ped_disk_next_partition (disk, part)) {
1476                 if (!ped_partition_is_active (part))
1477                         continue;
1478 
1479                 mac_disk_data->active_part_entry_count++;
1480                 if (last && last->geom.end + 1 < part->geom.start)
1481                         mac_disk_data->free_part_entry_count++;
1482                 mac_disk_data->last_part_entry_num
1483                         = PED_MAX (mac_disk_data->last_part_entry_num,
1484                                    part->num);
1485 
1486                 last = part;
1487         }
1488 
1489         if (last && last->geom.end < disk->dev->length - 1)
1490                 mac_disk_data->free_part_entry_count++;
1491 
1492         mac_disk_data->last_part_entry_num
1493                 = PED_MAX (mac_disk_data->last_part_entry_num,
1494                            mac_disk_data->active_part_entry_count
1495                                 + mac_disk_data->free_part_entry_count);
1496         return 1;
1497 }
1498 
1499 static int
1500 add_metadata_part (PedDisk* disk, PedSector start, PedSector end)
1501 {
1502         PedPartition*           new_part;
1503         PedConstraint*          constraint_any = ped_constraint_any (disk->dev);
1504 
1505         PED_ASSERT (disk != NULL, return 0);
1506 
1507         new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1508                                       start, end);
1509         if (!new_part)
1510                 goto error;
1511         if (!ped_disk_add_partition (disk, new_part, constraint_any))
1512                 goto error_destroy_new_part;
1513 
1514         ped_constraint_destroy (constraint_any);
1515         return 1;
1516 
1517 error_destroy_new_part:
1518         ped_partition_destroy (new_part);
1519 error:
1520         ped_constraint_destroy (constraint_any);
1521         return 0;
1522 }
1523 
1524 static int
1525 mac_alloc_metadata (PedDisk* disk)
1526 {
1527         MacDiskData*            mac_disk_data;
1528 
1529         PED_ASSERT (disk != NULL, return 0);
1530         PED_ASSERT (disk->disk_specific != NULL, return 0);
1531         PED_ASSERT (disk->dev != NULL, return 0);
1532 
1533         mac_disk_data = disk->disk_specific;
1534 
1535         if (!add_metadata_part (disk, 0, disk->dev->sector_size / 512 - 1))
1536                 return 0;
1537 
1538         /* hack: this seems to be a good place, to update the partition map
1539          * entry count, since mac_alloc_metadata() gets called during
1540          * _disk_pop_update_mode()
1541          */
1542         return _disk_count_partitions (disk);
1543 }
1544 
1545 static int
1546 mac_get_max_primary_partition_count (const PedDisk* disk)
1547 {
1548         MacDiskData*    mac_disk_data = disk->disk_specific;
1549         PedPartition*   part_map_partition;
1550 
1551         part_map_partition = ped_disk_get_partition (disk,
1552                                         mac_disk_data->part_map_entry_num);
1553 
1554         /* HACK: if we haven't found the partition map partition (yet),
1555          * we return this.
1556          */
1557         if (!part_map_partition) {
1558                 mac_disk_data->part_map_entry_num = 0;
1559                 return 65536;
1560         }
1561 
1562         /* HACK: since Mac labels need an entry for free-space regions, we
1563          * must allow half plus 1 entries for free-space partitions.  I hate
1564          * this, but things get REALLY complicated, otherwise.
1565          *     (I'm prepared to complicate things later, but I want to get
1566          * everything working, first)
1567          */
1568         return mac_disk_data->part_map_entry_count / mac_disk_data->ghost_size
1569                 - mac_disk_data->free_part_entry_count + 1;
1570 }
1571 
1572 static PedDiskOps mac_disk_ops = {
1573         .probe =                mac_probe,
1574 #ifndef DISCOVER_ONLY
1575         .clobber =              mac_clobber,
1576 #else
1577         .clobber =              NULL,
1578 #endif
1579         .alloc =                mac_alloc,
1580         .duplicate =            mac_duplicate,
1581         .free =                 mac_free,
1582         .read =                 mac_read,
1583 #ifndef DISCOVER_ONLY
1584         /* FIXME: remove this cast, once mac_write is fixed not to
1585            modify its *DISK parameter.  */
1586         .write =                (int (*) (const PedDisk*)) mac_write,
1587 #else
1588         .write =                NULL,
1589 #endif
1590 
1591         .partition_new =        mac_partition_new,
1592         .partition_duplicate =  mac_partition_duplicate,
1593         .partition_destroy =    mac_partition_destroy,
1594         .partition_set_system = mac_partition_set_system,
1595         .partition_set_flag =   mac_partition_set_flag,
1596         .partition_get_flag =   mac_partition_get_flag,
1597         .partition_is_flag_available =  mac_partition_is_flag_available,
1598         .partition_set_name =   mac_partition_set_name,
1599         .partition_get_name =   mac_partition_get_name,
1600         .partition_align =      mac_partition_align,
1601         .partition_enumerate =  mac_partition_enumerate,
1602 
1603         .alloc_metadata =       mac_alloc_metadata,
1604         .get_max_primary_partition_count =
1605                                 mac_get_max_primary_partition_count
1606 };
1607 
1608 static PedDiskType mac_disk_type = {
1609         .next =         NULL,
1610         .name =         "mac",
1611         .ops =          &mac_disk_ops,
1612         .features =     PED_DISK_TYPE_PARTITION_NAME
1613 };
1614 
1615 void
1616 ped_disk_mac_init ()
1617 {
1618         PED_ASSERT (sizeof (MacRawPartition) == 512, return);
1619         PED_ASSERT (sizeof (MacRawDisk) == 512, return);
1620 
1621         ped_disk_type_register (&mac_disk_type);
1622 }
1623 
1624 void
1625 ped_disk_mac_done ()
1626 {
1627         ped_disk_type_unregister (&mac_disk_type);
1628 }
1629