OSDN Git Service

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