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 "atari.h"
8
9#include <ByteOrder.h>
10#include <KernelExport.h>
11#include <ddm_modules.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#include <ctype.h>
22
23#define SECTSZ 512
24
25//#define TRACE_ATARI_PARTITION
26#ifdef TRACE_ATARI_PARTITION
27#	define TRACE(x) dprintf x
28#else
29#	define TRACE(x) ;
30#endif
31
32
33#define ATARI_PARTITION_MODULE_NAME "partitioning_systems/atari/v1"
34#define ATARI_PARTITION_NAME "Atari Partition Map"
35
36
37#if 0
38template<typename Type> bool
39validate_check_sum(Type *type)
40{
41	if (type->SummedLongs() != sizeof(*type) / sizeof(uint32))
42		return false;
43
44	// check checksum
45	uint32 *longs = (uint32 *)type;
46	uint32 sum = 0;
47	for (uint32 i = 0; i < type->SummedLongs(); i++)
48		sum += B_BENDIAN_TO_HOST_INT32(longs[i]);
49
50#ifdef TRACE_ATARI_PARTITION
51	if (sum != 0)
52		TRACE(("search_rdb: check sum is incorrect!\n"));
53#endif
54
55	return sum == 0;
56}
57#endif
58
59
60//	#pragma mark -
61//	Atari Root Block public module interface
62
63
64static status_t
65atari_std_ops(int32 op, ...)
66{
67	switch (op) {
68		case B_MODULE_INIT:
69		case B_MODULE_UNINIT:
70			return B_OK;
71	}
72
73	return B_ERROR;
74}
75
76
77static float
78atari_identify_partition(int fd, partition_data *partition, void **_cookie)
79{
80	uint8 buffer[512];
81	atari_root_block *arb = (atari_root_block *)buffer;
82	float weight = 0.5;
83	int i;
84	ssize_t bytesRead = read_pos(fd, 0, buffer, sizeof(buffer));
85	if (bytesRead < (ssize_t)sizeof(buffer)) {
86		TRACE(("%s: read error: %ld\n", __FUNCTION__, bytesRead));
87		return B_ERROR;
88	}
89	if (partition->offset)
90		return B_ERROR;
91
92	if (arb->Checksum() == 0x55aa)
93		weight -= 0.1; /* possible but likely a PC sector */
94	if (arb->_reserved_1[0] != 0x00)
95		weight -= 10;
96	/* hope so */
97	if (arb->MaxPartitionSize() < 10)
98		weight -= 20;
99
100	if ((arb->BadSectorsStart()+arb->BadSectorsCount())*(off_t)SECTSZ > partition->size)
101		return B_ERROR;
102
103	/* check each partition */
104	for (i = 0; i < 4; i++) {
105		struct atari_partition_entry *p = &arb->partitions[i];
106		if (p->Flags() & ATARI_PART_EXISTS) {
107			/* check for unknown flags */
108			if (p->Flags() & ~ (ATARI_PART_EXISTS|ATARI_PART_BOOTABLE))
109				weight -= 10.0;
110			/* id should be readable */
111			if (!isalnum(p->id[0]))
112				weight -= 1.0;
113			if (!isalnum(p->id[1]))
114				weight -= 1.0;
115			if (!isalnum(p->id[2]))
116				weight -= 1.0;
117			/* make sure partition doesn't overlap bad sector list */
118			if ((arb->BadSectorsStart() < p->Start()) &&
119				((arb->BadSectorsStart() + arb->BadSectorsCount()) > p->Start()))
120				weight -= 10;
121			if ((p->Start()+p->Size())*(off_t)SECTSZ > partition->size)
122				return B_ERROR;
123			/* should check partitions don't overlap each other... */
124		} else {
125			/* empty partition entry, then it must be all null */
126			if (p->Flags() || p->id[0] || p->id[1] || p->id[2] ||
127				p->Start() || p->Size())
128				weight -= 10.0;
129			else
130				weight += 0.1;
131		}
132	}
133	/* not exactly sure */
134	if (arb->Checksum() != ATARI_BOOTABLE_MAGIC)
135		weight -= 0.1;
136
137	if (weight > 1.0)
138		weight = 1.0;
139
140	if (weight > 0.0) {
141		// copy the root block to a new piece of memory
142		arb = new atari_root_block();
143		memcpy(arb, buffer, sizeof(atari_root_block));
144
145		*_cookie = (void *)arb;
146		return weight;
147	}
148
149	return B_ERROR;
150}
151
152
153static status_t
154atari_scan_partition(int fd, partition_data *partition, void *_cookie)
155{
156	TRACE(("atari_scan_partition(cookie = %p)\n", _cookie));
157
158	atari_root_block &arb = *(atari_root_block *)_cookie;
159
160	partition->status = B_PARTITION_VALID;
161	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
162						| B_PARTITION_READ_ONLY;
163	partition->content_size = partition->size;
164
165	// scan all children
166
167	uint32 index = 0;
168	status_t status = B_ENTRY_NOT_FOUND;
169
170	for (index = 0; index < 4; index++) {
171		struct atari_partition_entry *p = &arb.partitions[index];
172		if (!(p->Flags() & ATARI_PART_EXISTS))
173			continue;
174		TRACE(("atari: file system: %.3s\n", p->id));
175		if ((p->Start() + p->Size())*(uint64)SECTSZ > (uint64)partition->size) {
176			TRACE(("atari: child partition exceeds existing space (%lld bytes)\n", p->Size()*SECTSZ));
177			continue;
178		}
179		if (!isalnum(p->id[0]))
180			continue;
181		if (!isalnum(p->id[1]))
182			continue;
183		if (!isalnum(p->id[2]))
184			continue;
185
186		partition_data *child = create_child_partition(partition->id, index,
187			partition->offset + p->Start() * (uint64)SECTSZ,
188			p->Size() * (uint64)SECTSZ, -1);
189		if (child == NULL) {
190			TRACE(("atari: Creating child at index %ld failed\n", index - 1));
191			return B_ERROR;
192		}
193#warning M68K: use a lookup table ?
194		char type[] = "??? Partition";
195		memcpy(type, p->id, 3);
196		child->type = strdup(type);
197		child->block_size = SECTSZ;
198		status = B_OK;
199	}
200
201	if (status == B_ENTRY_NOT_FOUND)
202		return B_OK;
203
204	return status;
205}
206
207
208static void
209atari_free_identify_partition_cookie(partition_data *partition, void *_cookie)
210{
211	delete (atari_root_block *)_cookie;
212}
213
214
215#ifndef _BOOT_MODE
216static partition_module_info sAtariPartitionModule = {
217#else
218partition_module_info gAtariPartitionModule = {
219#endif
220	{
221		ATARI_PARTITION_MODULE_NAME,
222		0,
223		atari_std_ops
224	},
225	"atari",							// short_name
226	ATARI_PARTITION_NAME,				// pretty_name
227	0,									// flags
228
229	// scanning
230	atari_identify_partition,		// identify_partition
231	atari_scan_partition,			// scan_partition
232	atari_free_identify_partition_cookie,	// free_identify_partition_cookie
233	NULL,
234//	atari_free_partition_cookie,			// free_partition_cookie
235//	atari_free_partition_content_cookie,	// free_partition_content_cookie
236};
237
238#ifndef _BOOT_MODE
239partition_module_info *modules[] = {
240	&sAtariPartitionModule,
241	NULL
242};
243#endif
244