OSDN Git Service

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