1/*
2** Copyright 2003-2004, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3** Distributed under the terms of the MIT License.
4*/
5
6
7#include "apple.h"
8
9#include <ddm_modules.h>
10#include <disk_device_types.h>
11#include <KernelExport.h>
12#ifdef _BOOT_MODE
13#	include <boot/partitions.h>
14#else
15#	include <DiskDeviceTypes.h>
16#endif
17#include <util/kernel_cpp.h>
18
19#include <unistd.h>
20#include <string.h>
21
22
23#define TRACE_APPLE 0
24#if TRACE_APPLE
25#	define TRACE(x) dprintf x
26#else
27#	define TRACE(x) ;
28#endif
29
30#define APPLE_PARTITION_MODULE_NAME "partitioning_systems/apple/v1"
31
32static const char *kApplePartitionTypes[] = {
33	"partition_map",	// the partition map itself
34	"Driver",			// contains a device driver
35	"Driver43",			// the SCSI 4.3 manager
36	"MFS",				// Macintosh File System
37	"HFS",				// Hierarchical File System (HFS/HFS+)
38	"Unix_SVR2",		// UFS
39	"PRODOS",
40	"Free",				// unused partition
41	"Scratch",			// empty partition
42	"Driver_ATA",		// the device driver for an ATA device
43	"Driver_ATAPI",		// the device driver for an ATAPI device
44	"Driver43_CD",		// an SCSI CD-ROM driver suitable for booting
45	"FWDriver",			// a FireWire driver for the device
46	"Void",				// dummy partition map entry (used to align entries for CD-ROM)
47	"Patches",
48	NULL
49};
50#if 0
51static const char *kOtherPartitionTypes[] = {
52	"Be_BFS",			// Be's BFS (not specified endian)
53};
54#endif
55
56static status_t
57get_next_partition(int fd, apple_driver_descriptor &descriptor, uint32 &cookie,
58	apple_partition_map &partition)
59{
60	uint32 block = cookie;
61
62	// find first partition map if this is the first call,
63	// or else, just load the next block
64	do {
65		ssize_t bytesRead = read_pos(fd, (off_t)block * descriptor.BlockSize(),
66					(void *)&partition, sizeof(apple_partition_map));
67		if (bytesRead < (ssize_t)sizeof(apple_partition_map))
68			return B_ERROR;
69
70		block++;
71	} while (cookie == 0 && block < 64 && !partition.HasValidSignature());
72
73	if (!partition.HasValidSignature()) {
74		if (cookie)
75			return B_ENTRY_NOT_FOUND;
76
77		// we searched for the first partition map entry and failed
78		return B_ERROR;
79	}
80
81	// the first partition map entry must be of type Apple_partition_map
82	if (!cookie && (strncmp(partition.type, "Apple_", 6)
83		|| strcmp(partition.type + 6, kApplePartitionTypes[0])))
84		return B_ERROR;
85
86	// ToDo: warn about unknown types?
87
88	cookie = block;
89	return B_OK;
90}
91
92
93//	#pragma mark -
94//	Apple public module interface
95
96
97static status_t
98apple_std_ops(int32 op, ...)
99{
100	switch (op) {
101		case B_MODULE_INIT:
102		case B_MODULE_UNINIT:
103			return B_OK;
104	}
105
106	return B_ERROR;
107}
108
109
110static float
111apple_identify_partition(int fd, partition_data *partition, void **_cookie)
112{
113	struct apple_driver_descriptor *descriptor;
114	uint8 buffer[512];
115
116	if (read_pos(fd, 0, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer))
117		return B_ERROR;
118
119	descriptor = (apple_driver_descriptor *)buffer;
120
121	TRACE(("apple: read first chunk (signature = %x)\n", descriptor->signature));
122
123	if (!descriptor->HasValidSignature())
124		return B_ERROR;
125
126	TRACE(("apple: valid partition descriptor!\n"));
127
128	// ToDo: Should probably call get_next_partition() once to know if there
129	//		are any partitions on this disk
130
131	// copy the relevant part of the first block
132	descriptor = new apple_driver_descriptor();
133	memcpy(descriptor, buffer, sizeof(apple_driver_descriptor));
134
135	*_cookie = (void *)descriptor;
136
137	// ToDo: reevaluate the priority with ISO-9660 and others in mind
138	//		(for CD-ROM only, as far as I can tell)
139	return 0.5f;
140}
141
142
143static status_t
144apple_scan_partition(int fd, partition_data *partition, void *_cookie)
145{
146	TRACE(("apple_scan_partition(cookie = %p)\n", _cookie));
147
148	apple_driver_descriptor &descriptor = *(apple_driver_descriptor *)_cookie;
149
150	partition->status = B_PARTITION_VALID;
151	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
152						| B_PARTITION_READ_ONLY;
153	partition->content_size = descriptor.BlockSize() * descriptor.BlockCount();
154
155	// scan all children
156
157	apple_partition_map partitionMap;
158	uint32 index = 0, cookie = 0;
159	status_t status;
160
161	while ((status = get_next_partition(fd, descriptor, cookie, partitionMap)) == B_OK) {
162		TRACE(("apple: found partition: name = \"%s\", type = \"%s\"\n",
163			partitionMap.name, partitionMap.type));
164
165		if (partitionMap.Start(descriptor) + partitionMap.Size(descriptor) > (uint64)partition->size) {
166			TRACE(("apple: child partition exceeds existing space (%lld bytes)\n",
167				partitionMap.Size(descriptor)));
168			continue;
169		}
170
171		partition_data *child = create_child_partition(partition->id, index++,
172			partition->offset + partitionMap.Start(descriptor),
173			partitionMap.Size(descriptor), -1);
174		if (child == NULL) {
175			TRACE(("apple: Creating child at index %ld failed\n", index - 1));
176			return B_ERROR;
177		}
178
179		child->block_size = partition->block_size;
180	}
181
182	if (status == B_ENTRY_NOT_FOUND)
183		return B_OK;
184
185	return status;
186}
187
188
189static void
190apple_free_identify_partition_cookie(partition_data *partition, void *_cookie)
191{
192	delete (apple_driver_descriptor *)_cookie;
193}
194
195
196#ifndef _BOOT_MODE
197static partition_module_info sApplePartitionModule = {
198#else
199partition_module_info gApplePartitionModule = {
200#endif
201	{
202		APPLE_PARTITION_MODULE_NAME,
203		0,
204		apple_std_ops
205	},
206	"apple",							// short_name
207	APPLE_PARTITION_NAME,				// pretty_name
208	0,									// flags
209
210	// scanning
211	apple_identify_partition,			// identify_partition
212	apple_scan_partition,				// scan_partition
213	apple_free_identify_partition_cookie,	// free_identify_partition_cookie
214	NULL,
215};
216
217#ifndef _BOOT_MODE
218partition_module_info *modules[] = {
219	&sApplePartitionModule,
220	NULL
221};
222#endif
223