summaryrefslogtreecommitdiffstats
path: root/libblkid/src/partitions/mac.c
blob: 36ce74ed3fbb070309865ab954410207dea7a109 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
 * mac partitions parsing code
 *
 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
 *
 * This file may be redistributed under the terms of the
 * GNU Lesser General Public License.
 *
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

#include "partitions.h"

#define MAC_PARTITION_MAGIC		0x504d
#define MAC_PARTITION_MAGIC_OLD		0x5453

/*
 * Mac partition entry
 * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-126.html
 */
struct mac_partition {
	uint16_t	signature;	/* expected to be MAC_PARTITION_MAGIC */
	uint16_t	reserved;	/* reserved */
	uint32_t	map_count;	/* # blocks in partition map */
	uint32_t	start_block;	/* absolute starting block # of partition */
	uint32_t	block_count;	/* number of blocks in partition */
	char		name[32];	/* partition name */
	char		type[32];	/* string type description */
	uint32_t	data_start;	/* rel block # of first data block */
	uint32_t	data_count;	/* number of data blocks */
	uint32_t	status;		/* partition status bits */
	uint32_t	boot_start;	/* first logical block of boot code */
	uint32_t	boot_size;	/* size of boot code, in bytes */
	uint32_t	boot_load;	/* boot code load address */
	uint32_t	boot_load2;	/* reserved */
	uint32_t	boot_entry;	/* boot code entry point */
	uint32_t	boot_entry2;	/* reserved */
	uint32_t	boot_cksum;	/* boot code checksum */
	char		processor[16];	/* identifies ISA of boot */

	/* there is more stuff after this that we don't need */
} __attribute__((packed));

/*
 * Driver descriptor structure, in block 0
 * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-121.html
 */
struct mac_driver_desc {
	uint16_t	signature;	/* expected to be MAC_DRIVER_MAGIC */
	uint16_t	block_size;	/* block size of the device */
	uint32_t	block_count;	/* number of blocks on the device */

	/* there is more stuff after this that we don't need */
} __attribute__((packed));

static inline const unsigned char *get_mac_block(
					blkid_probe pr,
					uint16_t block_size,
					uint32_t num)
{
	return blkid_probe_get_buffer(pr, (uint64_t) num * block_size, block_size);
}

static inline int has_part_signature(struct mac_partition *p)
{
	return	be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC ||
		be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC_OLD;
}

static int probe_mac_pt(blkid_probe pr,
		const struct blkid_idmag *mag __attribute__((__unused__)))
{
	struct mac_driver_desc *md;
	struct mac_partition *p;
	blkid_parttable tab = NULL;
	blkid_partlist ls;
	uint16_t block_size;
	uint16_t ssf;	/* sector size fragment */
	uint32_t nblks, nprts, i;


	/* The driver descriptor record is always located at physical block 0,
	 * the first block on the disk.
	 */
	md = (struct mac_driver_desc *) blkid_probe_get_sector(pr, 0);
	if (!md) {
		if (errno)
			return -errno;
		goto nothing;
	}

	block_size = be16_to_cpu(md->block_size);
	if (block_size < sizeof(struct mac_partition))
		goto nothing;

	/* The partition map always begins at physical block 1,
	 * the second block on the disk.
	 */
	p = (struct mac_partition *) get_mac_block(pr, block_size, 1);
	if (!p) {
		if (errno)
			return -errno;
		goto nothing;
	}

	/* check the first partition signature */
	if (!has_part_signature(p))
		goto nothing;

	if (blkid_partitions_need_typeonly(pr))
		/* caller does not ask for details about partitions */
		return 0;

	ls = blkid_probe_get_partlist(pr);
	if (!ls)
		goto nothing;

	tab = blkid_partlist_new_parttable(ls, "mac", 0);
	if (!tab)
		goto err;

	ssf = block_size / 512;
	nblks = be32_to_cpu(p->map_count);
	if (nblks > 256) {
		nprts = 256;
		DBG(LOWPROBE, ul_debug(
			"mac: map_count too large, entry[0]: %u, "
			"enforcing limit of %u", nblks, nprts));
	} else
		nprts = nblks;

	for (i = 0; i < nprts; ++i) {
		blkid_partition par;
		uint32_t start;
		uint32_t size;

		p = (struct mac_partition *) get_mac_block(pr, block_size, i + 1);
		if (!p) {
			if (errno)
				return -errno;
			goto nothing;
		}
		if (!has_part_signature(p))
			goto nothing;

		if (be32_to_cpu(p->map_count) != nblks) {
			DBG(LOWPROBE, ul_debug(
				"mac: inconsistent map_count in partition map, "
				"entry[0]: %u, entry[%u]: %u",
				nblks, i,
				be32_to_cpu(p->map_count)));
		}

		/*
		 * note that libparted ignores some mac partitions according to
		 * the partition name (e.g. "Apple_Free" or "Apple_Void"). We
		 * follows Linux kernel and all partitions are visible
		 */

		start = be32_to_cpu(p->start_block) * ssf;
		size = be32_to_cpu(p->block_count) * ssf;

		par = blkid_partlist_add_partition(ls, tab, start, size);
		if (!par)
			goto err;

		blkid_partition_set_name(par, (unsigned char *) p->name,
						sizeof(p->name));

		blkid_partition_set_type_string(par, (unsigned char *) p->type,
						sizeof(p->type));
	}

	return BLKID_PROBE_OK;

nothing:
	return BLKID_PROBE_NONE;
err:
	return -ENOMEM;
}

/*
 * Mac disk always begin with "Driver Descriptor Record"
 * (struct mac_driver_desc) and magic 0x4552.
 */
const struct blkid_idinfo mac_pt_idinfo =
{
	.name		= "mac",
	.probefunc	= probe_mac_pt,
	.magics		=
	{
		/* big-endian magic string */
		{ .magic = "\x45\x52", .len = 2 },
		{ NULL }
	}
};