OSDN Git Service

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