OSDN Git Service

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