OSDN Git Service

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