OSDN Git Service

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