OSDN Git Service

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