OSDN Git Service

mac partitions pass all label+disk tests @1024 & @2048 sector size
[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         PedPartition*   partition_map;
318
319         new_disk = ped_disk_new_fresh (disk->dev, &mac_disk_type);
320         if (!new_disk)
321                 goto error;
322
323         new_mac_data = (MacDiskData*) new_disk->disk_specific;
324
325         /* remove the partition map partition - it will be duplicated
326          * later.
327          */
328         partition_map = ped_disk_get_partition_by_sector (new_disk, 1);
329         PED_ASSERT (partition_map != NULL, return 0);
330         ped_disk_remove_partition (new_disk, partition_map);
331
332         /* ugly, but C is ugly :p */
333         memcpy (new_mac_data, old_mac_data, sizeof (MacDiskData));
334         return new_disk;
335
336         _ped_disk_free (new_disk);
337 error:
338         return NULL;
339 }
340
341 static void
342 mac_free (PedDisk* disk)
343 {
344         MacDiskData*    mac_disk_data = disk->disk_specific;
345
346         _ped_disk_free (disk);
347         free (mac_disk_data);
348 }
349
350 #ifndef DISCOVER_ONLY
351 static int
352 _clobber_part_map (PedDevice* dev)
353 {
354         void *buf = ped_malloc (dev->sector_size);
355         if (!buf)
356                 return 0;
357
358         int ok = 1;
359         PedSector sector;
360         for (sector=1; 1; sector++) {
361                 if (!ped_device_read (dev, buf, sector, 1)) {
362                         ok = 0;
363                         break;
364                 }
365                 if (!_rawpart_check_signature (buf)) {
366                         ok = 1;
367                         break;
368                 }
369                 memset (buf, 0, dev->sector_size);
370                 if (!ped_device_write (dev, buf, sector, 1)) {
371                         ok = 0;
372                         break;
373                 }
374         }
375         free (buf);
376         return ok;
377 }
378
379 static int
380 mac_clobber (PedDevice* dev)
381 {
382         void *buf;
383         if (!ptt_read_sector (dev, 0, &buf))
384                 return 0;
385
386         if (!_check_signature (buf)) {
387                 free (buf);
388                 return 0;
389         }
390
391         memset (buf, 0, dev->sector_size);
392         bool ok = ped_device_write (dev, buf, 0, 1);
393         free (buf);
394         if (!ok)
395                 return 0;
396
397         return _clobber_part_map (dev);
398 }
399 #endif /* !DISCOVER_ONLY */
400
401 static int
402 _rawpart_cmp_type (const MacRawPartition* raw_part, const char* type)
403 {
404         return strncasecmp (raw_part->type, type, 32) == 0;
405 }
406
407 static int
408 _rawpart_cmp_name (const MacRawPartition* raw_part, const char* name)
409 {
410         return strncasecmp (raw_part->name, name, 32) == 0;
411 }
412
413 static int
414 _rawpart_is_partition_map (const MacRawPartition* raw_part)
415 {
416         return _rawpart_cmp_type (raw_part, "Apple_partition_map");
417 }
418
419 static int
420 strncasestr (const char* haystack, const char* needle, int n)
421 {
422         int     needle_size = strlen (needle);
423         int     i;
424
425         for (i = 0; haystack[i] && i < n - needle_size; i++) {
426                 if (strncasecmp (haystack + i, needle, needle_size) == 0)
427                         return 1;
428         }
429
430         return 0;
431 }
432
433 static int
434 _rawpart_is_boot (const MacRawPartition* raw_part)
435 {
436         if (!strcasecmp(raw_part->type, "Apple_Bootstrap"))
437                 return 1;
438
439         if (!strcasecmp(raw_part->type, "Apple_Boot"))
440                 return 1;
441
442         return 0;
443 }
444
445 static int
446 _rawpart_is_driver (const MacRawPartition* raw_part)
447 {
448         if (strncmp (raw_part->type, "Apple_", 6) != 0)
449                 return 0;
450         if (!strncasestr (raw_part->type, "driver", 32))
451                 return 0;
452         return 1;
453 }
454
455 static int
456 _rawpart_has_driver (const MacRawPartition* raw_part, MacDiskData* mac_disk_data)
457 {
458         MacDeviceDriver *driverlist;
459         uint16_t i, bsz;
460         uint32_t driver_bs, driver_be, part_be;
461
462         driverlist = &mac_disk_data->driverlist[0];
463         bsz = mac_disk_data->block_size / 512;
464         for (i = 0; i < mac_disk_data->driver_count; i++) {
465                 driver_bs = driverlist->block * bsz;
466                 driver_be = driver_bs + driverlist->size;
467                 part_be = raw_part->start_block + raw_part->block_count;
468                 if (driver_bs >= raw_part->start_block && driver_be <= part_be)
469                         return 1;
470                 driverlist++;
471         }
472         return 0;
473 }
474
475 static int
476 _rawpart_is_root (MacRawPartition* raw_part)
477 {
478         if (!_rawpart_cmp_type (raw_part, "Apple_UNIX_SVR2"))
479                 return 0;
480         if (strcmp (raw_part->name, "root") != 0)
481                 return 0;
482         return 1;
483 }
484
485 static int
486 _rawpart_is_swap (MacRawPartition* raw_part)
487 {
488         if (!_rawpart_cmp_type (raw_part, "Apple_UNIX_SVR2"))
489                 return 0;
490         if (strcmp (raw_part->name, "swap") != 0)
491                 return 0;
492         return 1;
493 }
494
495 static int
496 _rawpart_is_lvm (MacRawPartition* raw_part)
497 {
498         if (strcmp (raw_part->type, "Linux_LVM") != 0)
499                 return 0;
500         return 1;
501 }
502
503 static int
504 _rawpart_is_raid (MacRawPartition* raw_part)
505 {
506         if (strcmp (raw_part->type, "Linux_RAID") != 0)
507                 return 0;
508         return 1;
509 }
510
511 static int
512 _rawpart_is_void (MacRawPartition* raw_part)
513 {
514         return _rawpart_cmp_type (raw_part, "Apple_Void");
515 }
516
517 /* returns 1 if the raw_part represents a partition that is "unused space", or
518  * doesn't represent a partition at all.  NOTE: some people make Apple_Free
519  * partitions with MacOS, because they can't select another type.  So, if the
520  * name is anything other than "Extra" or "", it is treated as a "real"
521  * partition.
522  */
523 static int
524 _rawpart_is_active (MacRawPartition* raw_part)
525 {
526         if (_rawpart_cmp_type (raw_part, "Apple_Free")
527             && (_rawpart_cmp_name (raw_part, "Extra")
528                 || _rawpart_cmp_name (raw_part, "")))
529                 return 0;
530         if (_rawpart_cmp_type (raw_part, "Apple_Void"))
531                 return 0;
532         if (_rawpart_cmp_type (raw_part, "Apple_Scratch"))
533                 return 0;
534         if (_rawpart_cmp_type (raw_part, "Apple_Extra"))
535                 return 0;
536
537         return 1;
538 }
539
540 static PedPartition*
541 _rawpart_analyse (MacRawPartition* raw_part, PedDisk* disk, int num)
542 {
543         MacDiskData*            mac_disk_data;
544         PedPartition*           part;
545         MacPartitionData*       mac_part_data;
546         PedSector               block_size;
547         PedSector               start, length;
548
549         if (!_rawpart_check_signature (raw_part)) {
550 #ifndef DISCOVER_ONLY
551                 if (ped_exception_throw (
552                         PED_EXCEPTION_WARNING,
553                         PED_EXCEPTION_IGNORE_CANCEL,
554                         _("Partition %d has an invalid signature %x."),
555                         num,
556                         (int) PED_BE16_TO_CPU (raw_part->signature))
557                                 != PED_EXCEPTION_IGNORE)
558 #endif
559                         goto error;
560         }
561
562         mac_disk_data = (MacDiskData*) disk->disk_specific;
563         block_size = disk->dev->sector_size / 512;
564
565         start = PED_BE32_TO_CPU (raw_part->start_block) * block_size;
566         length = PED_BE32_TO_CPU (raw_part->block_count) * block_size;
567         if (length == 0) {
568 #ifndef DISCOVER_ONLY
569                 ped_exception_throw (
570                         PED_EXCEPTION_ERROR,
571                         PED_EXCEPTION_CANCEL,
572                         _("Partition %d has an invalid length of 0 bytes!"),
573                         num);
574 #endif
575                 return NULL;
576         }
577         part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
578                                   start, start + length - 1);
579         if (!part)
580                 goto error;
581
582         mac_part_data = part->disk_specific;
583
584         strncpy (mac_part_data->volume_name, raw_part->name, 32);
585         strncpy (mac_part_data->system_name, raw_part->type, 32);
586         strncpy (mac_part_data->processor_name, raw_part->processor, 16);
587
588         mac_part_data->is_boot = _rawpart_is_boot (raw_part);
589         mac_part_data->is_driver = _rawpart_is_driver (raw_part);
590         if (mac_part_data->is_driver)
591                 mac_part_data->has_driver = _rawpart_has_driver(raw_part, mac_disk_data);
592         mac_part_data->is_root = _rawpart_is_root (raw_part);
593         mac_part_data->is_swap = _rawpart_is_swap (raw_part);
594         mac_part_data->is_lvm = _rawpart_is_lvm (raw_part);
595         mac_part_data->is_raid = _rawpart_is_raid (raw_part);
596
597         /* "data" region */
598 #ifndef DISCOVER_ONLY
599         if (raw_part->data_start) {
600                 ped_exception_throw (
601                         PED_EXCEPTION_ERROR,
602                         PED_EXCEPTION_CANCEL,
603                         _("The data region doesn't start at the start "
604                           "of the partition."));
605                 goto error_destroy_part;
606         }
607 #endif /* !DISCOVER_ONLY */
608         mac_part_data->data_region_length
609                 = PED_BE32_TO_CPU (raw_part->data_count) * block_size;
610
611         /* boot region - we have no idea what this is for, but Mac OSX
612          * seems to put garbage here, and doesn't pay any attention to
613          * it afterwards.  [clausen, dan burcaw]
614          */
615 #if 0
616         if (raw_part->boot_start) {
617                 ped_exception_throw (
618                         PED_EXCEPTION_ERROR,
619                         PED_EXCEPTION_CANCEL,
620                         _("The boot region doesn't start at the start "
621                           "of the partition."));
622                 goto error_destroy_part;
623         }
624 #endif
625         mac_part_data->boot_region_length
626                 = PED_BE32_TO_CPU (raw_part->boot_count) * block_size;
627
628 #ifndef DISCOVER_ONLY
629         if (mac_part_data->has_driver) {
630                 if (mac_part_data->boot_region_length < part->geom.length) {
631                         if (ped_exception_throw (
632                                 PED_EXCEPTION_ERROR,
633                                 PED_EXCEPTION_IGNORE_CANCEL,
634                                 _("The partition's boot region doesn't occupy "
635                                   "the entire partition."))
636                                         != PED_EXCEPTION_IGNORE)
637                                 goto error_destroy_part;
638                 }
639         } else {
640                 if (mac_part_data->data_region_length < part->geom.length &&
641                     !mac_part_data->is_boot) {
642                         if (ped_exception_throw (
643                                 PED_EXCEPTION_ERROR,
644                                 PED_EXCEPTION_IGNORE_CANCEL,
645                                 _("The partition's data region doesn't occupy "
646                                   "the entire partition."))
647                                         != PED_EXCEPTION_IGNORE)
648                                 goto error_destroy_part;
649                 }
650         }
651 #endif /* !DISCOVER_ONLY */
652
653         mac_part_data->boot_base_address
654                 = PED_BE32_TO_CPU (raw_part->boot_load);
655         mac_part_data->boot_entry_address
656                 = PED_BE32_TO_CPU (raw_part->boot_entry);
657         mac_part_data->boot_checksum
658                 = PED_BE32_TO_CPU (raw_part->boot_cksum);
659
660         mac_part_data->status = PED_BE32_TO_CPU (raw_part->status);
661         mac_part_data->driver_sig = PED_BE32_TO_CPU (raw_part->driver_sig);
662
663         return part;
664
665 error_destroy_part:
666         ped_partition_destroy (part);
667 error:
668         return NULL;
669 }
670
671 /* looks at the partition map size field in a mac raw partition, and calculates
672  * what the size of the partition map should be, from it
673  */
674 static int
675 _rawpart_get_partmap_size (MacRawPartition* raw_part, PedDisk* disk)
676 {
677         MacDiskData*    mac_disk_data = disk->disk_specific;
678         PedSector       sector_size = disk->dev->sector_size / 512;
679         PedSector       part_map_start;
680         PedSector       part_map_end;
681
682         part_map_start = mac_disk_data->ghost_size;
683         part_map_end = sector_size * PED_BE32_TO_CPU (raw_part->map_count);
684
685         return part_map_end - part_map_start + 1;
686 }
687
688 static int
689 _disk_analyse_block_size (PedDisk* disk, MacRawDisk* raw_disk)
690 {
691         PedSector       block_size;
692
693         if (PED_BE16_TO_CPU (raw_disk->block_size) % 512) {
694 #ifndef DISCOVER_ONLY
695                 ped_exception_throw (
696                         PED_EXCEPTION_ERROR,
697                         PED_EXCEPTION_CANCEL,
698                         _("Weird block size on device descriptor: %d bytes is "
699                           "not divisible by 512."),
700                         (int) PED_BE16_TO_CPU (raw_disk->block_size));
701 #endif
702                 goto error;
703         }
704
705         block_size = PED_BE16_TO_CPU (raw_disk->block_size) / 512;
706         if (block_size != disk->dev->sector_size / 512) {
707 #ifndef DISCOVER_ONLY
708                 if (ped_exception_throw (
709                         PED_EXCEPTION_WARNING,
710                         PED_EXCEPTION_IGNORE_CANCEL,
711                         _("The driver descriptor says the physical block size "
712                           "is %d bytes, but Linux says it is %d bytes."),
713                         (int) block_size * 512,
714                         (int) disk->dev->sector_size)
715                                 != PED_EXCEPTION_IGNORE)
716                         goto error;
717 #endif
718                 disk->dev->sector_size = block_size * 512;
719         }
720
721         return 1;
722
723 error:
724         return 0;
725 }
726
727 /* Tries to figure out the block size used by the drivers, for the ghost
728  * partitioning scheme.  Ghost partitioning works like this: the OpenFirmware
729  * (OF) sees 512 byte blocks, but some drivers use 2048 byte blocks (and,
730  * perhaps, some other number?).  To remain compatible, the partition map
731  * only has "real" partition map entries on ghost-aligned block numbers (and
732  * the others are padded with Apple_Void partitions).  This function tries
733  * to figure out what the "ghost-aligned" size is... (which, believe-it-or-not,
734  * doesn't always equal 2048!!!)
735  */
736 static int
737 _disk_analyse_ghost_size (PedDisk* disk)
738 {
739         MacDiskData*            mac_disk_data = disk->disk_specific;
740
741         void *buf = ped_malloc (disk->dev->sector_size);
742         if (!buf)
743                 return 0;
744
745         int i;
746         int found = 0;
747         for (i = 1; i < 64; i *= 2) {
748                 if (!ped_device_read (disk->dev, buf, i, 1))
749                         break;
750                 if (_rawpart_check_signature (buf)
751                     && !_rawpart_is_void (buf)) {
752                         mac_disk_data->ghost_size = i;
753                         PED_ASSERT (i <= disk->dev->sector_size / 512, break);
754                         found = 1;
755                         break;
756                 }
757         }
758         free (buf);
759
760 #ifndef DISCOVER_ONLY
761         if (!found)
762                 ped_exception_throw (
763                         PED_EXCEPTION_ERROR,
764                         PED_EXCEPTION_CANCEL,
765                         _("No valid partition map found."));
766 #endif
767         return found;
768 }
769
770 static int
771 mac_read (PedDisk* disk)
772 {
773         MacDiskData*            mac_disk_data;
774         PedPartition*           part;
775         int                     num;
776         PedSector               ghost_size;
777         PedConstraint*          constraint_exact;
778         int                     last_part_entry_num = 0;
779
780         PED_ASSERT (disk != NULL, return 0);
781
782         mac_disk_data = disk->disk_specific;
783         mac_disk_data->part_map_entry_num = 0;          /* 0 == none */
784
785         void *buf;
786         if (!ptt_read_sector (disk->dev, 0, &buf))
787                 return 0;
788
789         MacRawDisk *raw_disk = (MacRawDisk *) buf;
790
791         if (!_check_signature (raw_disk))
792                 goto error;
793
794         if (!_disk_analyse_block_size (disk, raw_disk))
795                 goto error;
796         if (!_disk_analyse_ghost_size (disk))
797                 goto error;
798         ghost_size = mac_disk_data->ghost_size;
799
800         if (!ped_disk_delete_all (disk))
801                 goto error;
802
803         if (raw_disk->driver_count && raw_disk->driver_count < 62) {
804                 memcpy(&mac_disk_data->driverlist[0], &raw_disk->driverlist[0],
805                                 sizeof(mac_disk_data->driverlist));
806                 mac_disk_data->driver_count = raw_disk->driver_count;
807                 mac_disk_data->block_size = raw_disk->block_size;
808         }
809
810         for (num=1; num==1 || num <= last_part_entry_num; num++) {
811                 void *raw_part = buf;
812                 if (!ped_device_read (disk->dev, raw_part,
813                                       num * ghost_size, 1))
814                         goto error_delete_all;
815
816                 if (!_rawpart_check_signature (raw_part))
817                         continue;
818
819                 if (num == 1)
820                         last_part_entry_num
821                                 = _rawpart_get_partmap_size (raw_part, disk);
822                 if (_rawpart_get_partmap_size (raw_part, disk)
823                                 != last_part_entry_num) {
824                         if (ped_exception_throw (
825                                 PED_EXCEPTION_ERROR,
826                                 PED_EXCEPTION_IGNORE_CANCEL,
827                                 _("Conflicting partition map entry sizes!  "
828                                   "Entry 1 says it is %d, but entry %d says "
829                                   "it is %d!"),
830                                 last_part_entry_num,
831                                 _rawpart_get_partmap_size (raw_part, disk))
832                                         != PED_EXCEPTION_IGNORE)
833                                 goto error_delete_all;
834                 }
835
836                 if (!_rawpart_is_active (raw_part))
837                         continue;
838
839                 part = _rawpart_analyse (raw_part, disk, num);
840                 if (!part)
841                         goto error_delete_all;
842                 part->num = num;
843                 part->fs_type = ped_file_system_probe (&part->geom);
844                 constraint_exact = ped_constraint_exact (&part->geom);
845                 if (!ped_disk_add_partition (disk, part, constraint_exact))
846                         goto error_delete_all;
847                 ped_constraint_destroy (constraint_exact);
848
849                 if (_rawpart_is_partition_map (raw_part)) {
850                         if (mac_disk_data->part_map_entry_num
851                             && ped_exception_throw (
852                                         PED_EXCEPTION_ERROR,
853                                         PED_EXCEPTION_IGNORE_CANCEL,
854                                         _("Weird!  There are 2 partitions "
855                                           "map entries!"))
856                             != PED_EXCEPTION_IGNORE)
857                                 goto error_delete_all;
858
859                         mac_disk_data->part_map_entry_num = num;
860                         mac_disk_data->part_map_entry_count
861                                 = part->geom.end - ghost_size + 1;
862                 }
863         }
864
865         if (!mac_disk_data->part_map_entry_num) {
866                 if (!_disk_add_part_map_entry (disk, 1))
867                         goto error_delete_all;
868                 ped_disk_commit_to_dev (disk);
869         }
870         free (buf);
871         return 1;
872
873 error_delete_all:
874         ped_disk_delete_all (disk);
875 error:
876         free (buf);
877         return 0;
878 }
879
880 #ifndef DISCOVER_ONLY
881 /* The Ghost partition: is a blank entry, used to pad out each block (where
882  * there physical block size > 512 bytes).  This is because OpenFirmware uses
883  * 512 byte blocks, but device drivers Think Different TM, with a different
884  * lbock size, so we need to do this to avoid a clash (!)
885  */
886 static int
887 _pad_raw_part (PedDisk* disk, int num, MacRawPartition* part_map)
888 {
889         MacDiskData*            mac_disk_data = disk->disk_specific;
890         int                     i;
891
892         size_t ss = disk->dev->sector_size;
893         void *buf = ped_calloc (ss);
894         if (!buf)
895                 return 0;
896
897         MacRawPartition *ghost_entry = buf;
898         ghost_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
899         strcpy (ghost_entry->type, "Apple_Void");
900         ghost_entry->map_count
901                 = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
902
903         for (i=0; i < mac_disk_data->ghost_size - 1; i++) {
904                 PedSector idx = i + (num - 1) * mac_disk_data->ghost_size;
905                 memcpy ((char*)part_map + idx * ss, ghost_entry, ss);
906         }
907
908         free (buf);
909         return 1;
910 }
911
912 static void
913 _update_driver_count (MacRawPartition* part_map_entry,
914                       MacDiskData *mac_driverdata, const MacDiskData* mac_disk_data)
915 {
916         uint16_t        i, count_orig, count_cur, bsz;
917         uint32_t        driver_bs, driver_be, part_be;
918
919         bsz = mac_disk_data->block_size / 512;
920         count_cur = mac_driverdata->driver_count;
921         count_orig = mac_disk_data->driver_count;
922         for (i = 0; i < count_orig; i++) {
923                 driver_bs = mac_disk_data->driverlist[i].block * bsz;
924                 driver_be = driver_bs + mac_disk_data->driverlist[i].size;
925                 part_be = part_map_entry->start_block + part_map_entry->block_count;
926                 if (driver_bs >= part_map_entry->start_block
927                                 && driver_be <= part_be) {
928                         mac_driverdata->driverlist[count_cur].block
929                                 = mac_disk_data->driverlist[i].block;
930                         mac_driverdata->driverlist[count_cur].size
931                                 = mac_disk_data->driverlist[i].size;
932                         mac_driverdata->driverlist[count_cur].type
933                                 = mac_disk_data->driverlist[i].type;
934                         mac_driverdata->driver_count++;
935                         break;
936                 }
937         }
938 }
939
940 static MacRawPartition *
941 get_pme (MacRawPartition const *part_map, PedSector i, PedDisk const *disk)
942 {
943         MacDiskData const *mac_disk_data = disk->disk_specific;
944         PedSector idx = i * mac_disk_data->ghost_size - 1;
945         return (MacRawPartition *) ((char*)part_map
946                                     + idx * disk->dev->sector_size);
947 }
948
949 /* Initialize the disk->dev->sector_size bytes of part_map[part->num]. */
950 static int
951 _generate_raw_part (PedDisk* disk, PedPartition* part,
952                     MacRawPartition* part_map, MacDiskData *mac_driverdata)
953 {
954         MacDiskData*            mac_disk_data;
955         MacPartitionData*       mac_part_data;
956         PedSector               block_size = disk->dev->sector_size / 512;
957
958         PED_ASSERT (part->num > 0, goto error);
959
960         mac_disk_data = disk->disk_specific;
961         mac_part_data = part->disk_specific;
962
963         MacRawPartition *part_map_entry = get_pme (part_map, part->num, disk);
964         memset (part_map_entry, 0, disk->dev->sector_size);
965
966         part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
967         part_map_entry->map_count
968                 = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
969         part_map_entry->start_block
970                 = PED_CPU_TO_BE32 (part->geom.start / block_size);
971         part_map_entry->block_count
972                 = PED_CPU_TO_BE32 (part->geom.length / block_size);
973         strcpy (part_map_entry->name, mac_part_data->volume_name);
974         strcpy (part_map_entry->type, mac_part_data->system_name);
975
976         if (mac_part_data->is_driver) {
977                 mac_part_data->boot_region_length = part->geom.length;
978                 if (mac_part_data->has_driver)
979                         _update_driver_count(part_map_entry, mac_driverdata,
980                                         mac_disk_data);
981         } else
982                 mac_part_data->data_region_length = part->geom.length;
983         part_map_entry->data_count = PED_CPU_TO_BE32 (
984                         mac_part_data->data_region_length / block_size);
985         part_map_entry->boot_count = PED_CPU_TO_BE32 (
986                         mac_part_data->boot_region_length / block_size);
987         part_map_entry->status = PED_CPU_TO_BE32 (mac_part_data->status);
988         part_map_entry->driver_sig
989                 = PED_CPU_TO_BE32 (mac_part_data->driver_sig);
990
991         part_map_entry->boot_load =
992                 PED_CPU_TO_BE32 (mac_part_data->boot_base_address);
993         part_map_entry->boot_entry =
994                 PED_CPU_TO_BE32 (mac_part_data->boot_entry_address);
995         part_map_entry->boot_cksum =
996                 PED_CPU_TO_BE32 (mac_part_data->boot_checksum);
997
998         strncpy (part_map_entry->processor, mac_part_data->processor_name, 16);
999
1000         if (!_pad_raw_part (disk, part->num, part_map))
1001                 goto error;
1002
1003         return 1;
1004
1005 error:
1006         return 0;
1007 }
1008
1009 static int
1010 _generate_raw_freespace_part (PedDisk* disk, PedGeometry* geom, int num,
1011                               MacRawPartition* part_map)
1012 {
1013         MacDiskData*            mac_disk_data = disk->disk_specific;
1014         PedSector               block_size = disk->dev->sector_size / 512;
1015
1016         PED_ASSERT (num > 0, goto error);
1017
1018         MacRawPartition *part_map_entry = get_pme (part_map, num, disk);
1019
1020         part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
1021         part_map_entry->map_count
1022                 = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
1023         part_map_entry->start_block
1024                 = PED_CPU_TO_BE32 (geom->start / block_size);
1025         part_map_entry->block_count
1026                 = PED_CPU_TO_BE32 (geom->length / block_size);
1027         strcpy (part_map_entry->name, "Extra");
1028         strcpy (part_map_entry->type, "Apple_Free");
1029
1030         part_map_entry->data_count = PED_CPU_TO_BE32 (geom->length);
1031         part_map_entry->status = 0;
1032         part_map_entry->driver_sig = 0;
1033
1034         if (!_pad_raw_part (disk, num, part_map))
1035                 goto error;
1036
1037         return 1;
1038
1039 error:
1040         return 0;
1041 }
1042
1043 static int
1044 _generate_empty_part (PedDisk* disk, int num, MacRawPartition* part_map)
1045 {
1046         MacDiskData*            mac_disk_data = disk->disk_specific;
1047
1048         PED_ASSERT (num > 0, return 0);
1049
1050         MacRawPartition *part_map_entry = get_pme (part_map, num, disk);
1051         part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
1052         part_map_entry->map_count
1053                 = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
1054         strcpy (part_map_entry->type, "Apple_Void");
1055
1056         return _pad_raw_part (disk, num, part_map);
1057 }
1058
1059 /* returns the first empty entry in the partition map */
1060 static int
1061 _get_first_empty_part_entry (PedDisk* disk, MacRawPartition* part_map)
1062 {
1063         MacDiskData*    mac_disk_data = disk->disk_specific;
1064         int             i;
1065
1066         for (i=1; i <= mac_disk_data->last_part_entry_num; i++) {
1067                 MacRawPartition *part_map_entry = get_pme (part_map, i, disk);
1068                 if (!part_map_entry->signature)
1069                         return i;
1070         }
1071
1072         return 0;
1073 }
1074
1075 static int
1076 write_block_zero (PedDisk* disk, MacDiskData* mac_driverdata)
1077 {
1078         PedDevice*      dev = disk->dev;
1079         void *s0;
1080         if (!ptt_read_sector (dev, 0, &s0))
1081                 return 0;
1082         MacRawDisk *raw_disk = (MacRawDisk *) s0;
1083
1084         raw_disk->signature = PED_CPU_TO_BE16 (MAC_DISK_MAGIC);
1085         raw_disk->block_size = PED_CPU_TO_BE16 (dev->sector_size);
1086         raw_disk->block_count
1087                 = PED_CPU_TO_BE32 (dev->length / (dev->sector_size / 512));
1088
1089         raw_disk->driver_count = mac_driverdata->driver_count;
1090         memcpy(&raw_disk->driverlist[0], &mac_driverdata->driverlist[0],
1091                         sizeof(raw_disk->driverlist));
1092
1093         return ped_device_write (dev, raw_disk, 0, 1);
1094 }
1095
1096 static int
1097 mac_write (PedDisk* disk)
1098 {
1099         MacRawPartition*        part_map;
1100         MacDiskData*            mac_disk_data;
1101         MacDiskData*            mac_driverdata; /* updated driver list */
1102         PedPartition*           part;
1103         int                     num;
1104
1105         PED_ASSERT (disk != NULL, return 0);
1106         PED_ASSERT (disk->disk_specific != NULL, return 0);
1107         PED_ASSERT (disk->dev != NULL, return 0);
1108         PED_ASSERT (!disk->update_mode, return 0);
1109
1110         mac_disk_data = disk->disk_specific;
1111
1112         if (!ped_disk_get_partition (disk, mac_disk_data->part_map_entry_num)) {
1113                 if (!_disk_add_part_map_entry (disk, 1))
1114                         goto error;
1115         }
1116
1117         mac_driverdata = ped_malloc(sizeof(MacDiskData));
1118         if (!mac_driverdata)
1119                 goto error;
1120         memset (mac_driverdata, 0, sizeof(MacDiskData));
1121
1122         size_t pmap_bytes = (mac_disk_data->part_map_entry_count
1123                              * mac_disk_data->ghost_size
1124                              * disk->dev->sector_size);
1125         part_map = (MacRawPartition*) ped_calloc (pmap_bytes);
1126         if (!part_map)
1127                 goto error_free_driverdata;
1128
1129 /* write (to memory) the "real" partitions */
1130         for (part = ped_disk_next_partition (disk, NULL); part;
1131              part = ped_disk_next_partition (disk, part)) {
1132                 if (!ped_partition_is_active (part))
1133                         continue;
1134                 if (!_generate_raw_part (disk, part, part_map, mac_driverdata))
1135                         goto error_free_part_map;
1136         }
1137
1138 /* write the "free space" partitions */
1139         for (part = ped_disk_next_partition (disk, NULL); part;
1140              part = ped_disk_next_partition (disk, part)) {
1141                 if (part->type != PED_PARTITION_FREESPACE)
1142                         continue;
1143                 num = _get_first_empty_part_entry (disk, part_map);
1144                 if (!_generate_raw_freespace_part (disk, &part->geom, num,
1145                                                    part_map))
1146                         goto error_free_part_map;
1147         }
1148
1149 /* write the "void" (empty) partitions */
1150         for (num = _get_first_empty_part_entry (disk, part_map); num;
1151              num = _get_first_empty_part_entry (disk, part_map))
1152                 _generate_empty_part (disk, num, part_map);
1153
1154 /* write to disk */
1155         if (!ped_device_write (disk->dev, part_map, 1,
1156                                mac_disk_data->part_map_entry_count))
1157                 goto error_free_part_map;
1158         free (part_map);
1159         return write_block_zero (disk, mac_driverdata);
1160
1161 error_free_part_map:
1162         free (part_map);
1163 error_free_driverdata:
1164         free (mac_driverdata);
1165 error:
1166         return 0;
1167 }
1168 #endif /* !DISCOVER_ONLY */
1169
1170 static PedPartition*
1171 mac_partition_new (
1172         const PedDisk* disk, PedPartitionType part_type,
1173         const PedFileSystemType* fs_type, PedSector start, PedSector end)
1174 {
1175         PedPartition*           part;
1176         MacPartitionData*       mac_data;
1177
1178         part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1179         if (!part)
1180                 goto error;
1181
1182         if (ped_partition_is_active (part)) {
1183                 part->disk_specific
1184                         = mac_data = ped_malloc (sizeof (MacPartitionData));
1185                 if (!mac_data)
1186                         goto error_free_part;
1187
1188                 memset (mac_data, 0, sizeof (MacPartitionData));
1189                 strcpy (mac_data->volume_name, "untitled");
1190         } else {
1191                 part->disk_specific = NULL;
1192         }
1193         return part;
1194
1195 error_free_part:
1196         free (part);
1197 error:
1198         return NULL;
1199 }
1200
1201 static PedPartition*
1202 mac_partition_duplicate (const PedPartition* part)
1203 {
1204         PedPartition*           new_part;
1205         MacPartitionData*       new_mac_data;
1206         MacPartitionData*       old_mac_data;
1207
1208         new_part = ped_partition_new (part->disk, part->type,
1209                                       part->fs_type, part->geom.start,
1210                                       part->geom.end);
1211         if (!new_part)
1212                 return NULL;
1213         new_part->num = part->num;
1214
1215         old_mac_data = (MacPartitionData*) part->disk_specific;
1216         new_mac_data = (MacPartitionData*) new_part->disk_specific;
1217
1218         /* ugly, but C is ugly :p */
1219         memcpy (new_mac_data, old_mac_data, sizeof (MacPartitionData));
1220         return new_part;
1221 }
1222
1223 static void
1224 mac_partition_destroy (PedPartition* part)
1225 {
1226         PED_ASSERT (part != NULL, return);
1227
1228         if (ped_partition_is_active (part))
1229                 free (part->disk_specific);
1230         free (part);
1231 }
1232
1233 static int
1234 mac_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1235 {
1236         MacPartitionData* mac_data = part->disk_specific;
1237
1238         part->fs_type = fs_type;
1239
1240         if (fs_type && is_linux_swap (fs_type->name))
1241                 ped_partition_set_flag (part, PED_PARTITION_SWAP, 1);
1242
1243         if (mac_data->is_boot) {
1244                 strcpy (mac_data->system_name, "Apple_Bootstrap");
1245                 mac_data->status = 0x33;
1246                 return 1;
1247         }
1248
1249         if (fs_type && (!strcmp (fs_type->name, "hfs")
1250                         || !strcmp (fs_type->name, "hfs+"))) {
1251                 strcpy (mac_data->system_name, "Apple_HFS");
1252                 mac_data->status |= 0x7f;
1253         } else if (fs_type && !strcmp (fs_type->name, "hfsx")) {
1254                 strcpy (mac_data->system_name, "Apple_HFSX");
1255                 mac_data->status |= 0x7f;
1256         } else {
1257                 strcpy (mac_data->system_name, "Apple_UNIX_SVR2");
1258                 mac_data->status = 0x33;
1259         }
1260
1261         return 1;
1262 }
1263
1264 static int
1265 mac_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
1266 {
1267         MacPartitionData*       mac_data;
1268
1269         PED_ASSERT (part != NULL, return 0);
1270         PED_ASSERT (part->disk_specific != NULL, return 0);
1271
1272         mac_data = part->disk_specific;
1273
1274         switch (flag) {
1275         case PED_PARTITION_BOOT:
1276                 mac_data->is_boot = state;
1277
1278                 if (part->fs_type)
1279                         return mac_partition_set_system (part, part->fs_type);
1280
1281                 if (state) {
1282                         strcpy (mac_data->system_name, "Apple_Bootstrap");
1283                         mac_data->status = 0x33;
1284                 }
1285                 return 1;
1286
1287         case PED_PARTITION_ROOT:
1288                 if (state) {
1289                         strcpy (mac_data->volume_name, "root");
1290                         mac_data->is_swap = 0;
1291                 } else {
1292                         if (mac_data->is_root)
1293                                 strcpy (mac_data->volume_name, "untitled");
1294                 }
1295                 mac_data->is_root = state;
1296                 return 1;
1297
1298         case PED_PARTITION_SWAP:
1299                 if (state) {
1300                         strcpy (mac_data->volume_name, "swap");
1301                         mac_data->is_root = 0;
1302                 } else {
1303                         if (mac_data->is_swap)
1304                                 strcpy (mac_data->volume_name, "untitled");
1305                 }
1306                 mac_data->is_swap = state;
1307                 return 1;
1308
1309         case PED_PARTITION_LVM:
1310                 if (state) {
1311                         strcpy (mac_data->system_name, "Linux_LVM");
1312                         mac_data->is_lvm = state;
1313                 } else {
1314                         if (mac_data->is_lvm)
1315                                 mac_partition_set_system (part, part->fs_type);
1316                 }
1317                 return 1;
1318
1319         case PED_PARTITION_RAID:
1320                 if (state) {
1321                         strcpy (mac_data->system_name, "Linux_RAID");
1322                         mac_data->is_raid = state;
1323                 } else {
1324                         if (mac_data->is_raid)
1325                                 mac_partition_set_system (part, part->fs_type);
1326                 }
1327                 return 1;
1328
1329         default:
1330                 return 0;
1331         }
1332 }
1333
1334 static int
1335 mac_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
1336 {
1337         MacPartitionData*       mac_data;
1338
1339         PED_ASSERT (part != NULL, return 0);
1340         PED_ASSERT (part->disk_specific != NULL, return 0);
1341
1342         mac_data = part->disk_specific;
1343         switch (flag) {
1344         case PED_PARTITION_BOOT:
1345                 return mac_data->is_boot;
1346
1347         case PED_PARTITION_ROOT:
1348                 return mac_data->is_root;
1349
1350         case PED_PARTITION_SWAP:
1351                 return mac_data->is_swap;
1352
1353         case PED_PARTITION_LVM:
1354                 return mac_data->is_lvm;
1355
1356         case PED_PARTITION_RAID:
1357                 return mac_data->is_raid;
1358
1359         default:
1360                 return 0;
1361         }
1362 }
1363
1364 static int
1365 mac_partition_is_flag_available (
1366         const PedPartition* part, PedPartitionFlag flag)
1367 {
1368         switch (flag) {
1369         case PED_PARTITION_BOOT:
1370         case PED_PARTITION_ROOT:
1371         case PED_PARTITION_SWAP:
1372         case PED_PARTITION_LVM:
1373         case PED_PARTITION_RAID:
1374                 return 1;
1375
1376         default:
1377                 return 0;
1378         }
1379 }
1380
1381 static void
1382 mac_partition_set_name (PedPartition* part, const char* name)
1383 {
1384         MacPartitionData*       mac_data;
1385         int                     i;
1386
1387         PED_ASSERT (part != NULL, return);
1388         PED_ASSERT (part->disk_specific != NULL, return);
1389         mac_data = part->disk_specific;
1390
1391 #ifndef DISCOVER_ONLY
1392         if (mac_data->is_root || mac_data->is_swap) {
1393                 if (ped_exception_throw (
1394                         PED_EXCEPTION_WARNING,
1395                         PED_EXCEPTION_IGNORE_CANCEL,
1396                         _("Changing the name of a root or swap partition "
1397                           "will prevent Linux from recognising it as such."))
1398                                 != PED_EXCEPTION_IGNORE)
1399                         return;
1400                 mac_data->is_root = mac_data->is_swap = 0;
1401         }
1402 #endif
1403
1404         strncpy (mac_data->volume_name, name, 32);
1405         mac_data->volume_name [32] = 0;
1406         for (i = strlen (mac_data->volume_name) - 1;
1407                         mac_data->volume_name[i] == ' '; i--)
1408                 mac_data->volume_name [i] = 0;
1409 }
1410
1411 static const char*
1412 mac_partition_get_name (const PedPartition* part)
1413 {
1414         MacPartitionData*       mac_data;
1415
1416         PED_ASSERT (part != NULL, return NULL);
1417         PED_ASSERT (part->disk_specific != NULL, return NULL);
1418         mac_data = part->disk_specific;
1419
1420         return mac_data->volume_name;
1421 }
1422
1423 static PedConstraint*
1424 _primary_constraint (PedDisk* disk)
1425 {
1426         PedAlignment    start_align;
1427         PedAlignment    end_align;
1428         PedGeometry     max_geom;
1429         PedSector       sector_size;
1430
1431         sector_size = disk->dev->sector_size / 512;
1432
1433         if (!ped_alignment_init (&start_align, 0, sector_size))
1434                 return NULL;
1435         if (!ped_alignment_init (&end_align, -1, sector_size))
1436                 return NULL;
1437         if (!ped_geometry_init (&max_geom, disk->dev, 1, disk->dev->length - 1))
1438                 return NULL;
1439
1440         return ped_constraint_new (&start_align, &end_align, &max_geom,
1441                                    &max_geom, 1, disk->dev->length);
1442 }
1443
1444 static int
1445 mac_partition_align (PedPartition* part, const PedConstraint* constraint)
1446 {
1447         PED_ASSERT (part != NULL, return 0);
1448
1449         if (_ped_partition_attempt_align (part, constraint,
1450                                           _primary_constraint (part->disk)))
1451                 return 1;
1452
1453 #ifndef DISCOVER_ONLY
1454         ped_exception_throw (
1455                 PED_EXCEPTION_ERROR,
1456                 PED_EXCEPTION_CANCEL,
1457                 _("Unable to satisfy all constraints on the partition."));
1458 #endif
1459         return 0;
1460 }
1461
1462 static int
1463 mac_partition_enumerate (PedPartition* part)
1464 {
1465         PedDisk*                disk;
1466         MacDiskData*            mac_disk_data;
1467         int                     i;
1468         int                     max_part_count;
1469
1470         PED_ASSERT (part != NULL, return 0);
1471         PED_ASSERT (part->disk != NULL, return 0);
1472
1473         disk = part->disk;
1474         mac_disk_data = (MacDiskData*) disk->disk_specific;
1475
1476         max_part_count = ped_disk_get_max_primary_partition_count (disk);
1477
1478         if (part->num > 0 && part->num <= mac_disk_data->part_map_entry_count)
1479                 return 1;
1480
1481         for (i = 1; i <= max_part_count; i++) {
1482                 if (!ped_disk_get_partition (disk, i)) {
1483                         part->num = i;
1484                         return 1;
1485                 }
1486         }
1487
1488 #ifndef DISCOVER_ONLY
1489         ped_exception_throw (
1490                 PED_EXCEPTION_ERROR,
1491                 PED_EXCEPTION_CANCEL,
1492                 _("Can't add another partition -- the partition map is too "
1493                   "small!"));
1494 #endif
1495
1496         return 0;
1497 }
1498
1499 static int
1500 _disk_count_partitions (PedDisk* disk)
1501 {
1502         MacDiskData*            mac_disk_data = disk->disk_specific;
1503         PedPartition*           part = NULL;
1504         PedPartition*           last = NULL;
1505
1506         PED_ASSERT (disk->update_mode, return 0);
1507
1508         mac_disk_data->active_part_entry_count = 0;
1509         mac_disk_data->free_part_entry_count = 0;
1510         mac_disk_data->last_part_entry_num = 0;
1511
1512         /* subtle: we only care about free space after the partition map.
1513          * the partition map is an "active" partition, BTW... */
1514         for (part = ped_disk_next_partition (disk, part); part;
1515              part = ped_disk_next_partition (disk, part)) {
1516                 if (!ped_partition_is_active (part))
1517                         continue;
1518
1519                 mac_disk_data->active_part_entry_count++;
1520                 if (last && last->geom.end + 1 < part->geom.start)
1521                         mac_disk_data->free_part_entry_count++;
1522                 mac_disk_data->last_part_entry_num
1523                         = PED_MAX (mac_disk_data->last_part_entry_num,
1524                                    part->num);
1525
1526                 last = part;
1527         }
1528
1529         if (last && last->geom.end < disk->dev->length - 1)
1530                 mac_disk_data->free_part_entry_count++;
1531
1532         mac_disk_data->last_part_entry_num
1533                 = PED_MAX (mac_disk_data->last_part_entry_num,
1534                            mac_disk_data->active_part_entry_count
1535                                 + mac_disk_data->free_part_entry_count);
1536         return 1;
1537 }
1538
1539 static int
1540 add_metadata_part (PedDisk* disk, PedSector start, PedSector end)
1541 {
1542         PedPartition*           new_part;
1543         PedConstraint*          constraint_any = ped_constraint_any (disk->dev);
1544
1545         PED_ASSERT (disk != NULL, return 0);
1546
1547         new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1548                                       start, end);
1549         if (!new_part)
1550                 goto error;
1551         if (!ped_disk_add_partition (disk, new_part, constraint_any))
1552                 goto error_destroy_new_part;
1553
1554         ped_constraint_destroy (constraint_any);
1555         return 1;
1556
1557 error_destroy_new_part:
1558         ped_partition_destroy (new_part);
1559 error:
1560         ped_constraint_destroy (constraint_any);
1561         return 0;
1562 }
1563
1564 static int
1565 mac_alloc_metadata (PedDisk* disk)
1566 {
1567         MacDiskData*            mac_disk_data;
1568
1569         PED_ASSERT (disk != NULL, return 0);
1570         PED_ASSERT (disk->disk_specific != NULL, return 0);
1571         PED_ASSERT (disk->dev != NULL, return 0);
1572
1573         mac_disk_data = disk->disk_specific;
1574
1575         if (!add_metadata_part (disk, 0, disk->dev->sector_size / 512 - 1))
1576                 return 0;
1577
1578         /* hack: this seems to be a good place, to update the partition map
1579          * entry count, since mac_alloc_metadata() gets called during
1580          * _disk_pop_update_mode()
1581          */
1582         return _disk_count_partitions (disk);
1583 }
1584
1585 static int
1586 mac_get_max_primary_partition_count (const PedDisk* disk)
1587 {
1588         MacDiskData*    mac_disk_data = disk->disk_specific;
1589         PedPartition*   part_map_partition;
1590
1591         part_map_partition = ped_disk_get_partition (disk,
1592                                         mac_disk_data->part_map_entry_num);
1593
1594         /* HACK: if we haven't found the partition map partition (yet),
1595          * we return this.
1596          */
1597         if (!part_map_partition) {
1598                 mac_disk_data->part_map_entry_num = 0;
1599                 return 65536;
1600         }
1601
1602         /* HACK: since Mac labels need an entry for free-space regions, we
1603          * must allow half plus 1 entries for free-space partitions.  I hate
1604          * this, but things get REALLY complicated, otherwise.
1605          *     (I'm prepared to complicate things later, but I want to get
1606          * everything working, first)
1607          */
1608         return mac_disk_data->part_map_entry_count / mac_disk_data->ghost_size
1609                 - mac_disk_data->free_part_entry_count + 1;
1610 }
1611
1612 static bool
1613 mac_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
1614 {
1615         *max_n = 65536;
1616         return true;
1617 }
1618
1619 static PedDiskOps mac_disk_ops = {
1620         probe:                  mac_probe,
1621 #ifndef DISCOVER_ONLY
1622         clobber:                mac_clobber,
1623 #else
1624         clobber:                NULL,
1625 #endif
1626         alloc:                  mac_alloc,
1627         duplicate:              mac_duplicate,
1628         free:                   mac_free,
1629         read:                   mac_read,
1630 #ifndef DISCOVER_ONLY
1631         /* FIXME: remove this cast, once mac_write is fixed not to
1632            modify its *DISK parameter.  */
1633         write:                  (int (*) (const PedDisk*)) mac_write,
1634 #else
1635         write:                  NULL,
1636 #endif
1637
1638         partition_new:          mac_partition_new,
1639         partition_duplicate:    mac_partition_duplicate,
1640         partition_destroy:      mac_partition_destroy,
1641         partition_set_system:   mac_partition_set_system,
1642         partition_set_flag:     mac_partition_set_flag,
1643         partition_get_flag:     mac_partition_get_flag,
1644         partition_is_flag_available:    mac_partition_is_flag_available,
1645         partition_set_name:     mac_partition_set_name,
1646         partition_get_name:     mac_partition_get_name,
1647         partition_align:        mac_partition_align,
1648         partition_enumerate:    mac_partition_enumerate,
1649
1650         alloc_metadata:         mac_alloc_metadata,
1651         get_max_primary_partition_count:
1652                                 mac_get_max_primary_partition_count,
1653         get_max_supported_partition_count:
1654                                 mac_get_max_supported_partition_count
1655 };
1656
1657 static PedDiskType mac_disk_type = {
1658         next:           NULL,
1659         name:           "mac",
1660         ops:            &mac_disk_ops,
1661         features:       PED_DISK_TYPE_PARTITION_NAME
1662 };
1663
1664 void
1665 ped_disk_mac_init ()
1666 {
1667         PED_ASSERT (sizeof (MacRawPartition) == 512, return);
1668         PED_ASSERT (sizeof (MacRawDisk) == 512, return);
1669
1670         ped_disk_type_register (&mac_disk_type);
1671 }
1672
1673 void
1674 ped_disk_mac_done ()
1675 {
1676         ped_disk_type_unregister (&mac_disk_type);
1677 }