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