OSDN Git Service

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