OSDN Git Service

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