xref: /haiku/src/add-ons/kernel/partitioning_systems/amiga/amiga_rdb.cpp (revision e79e4e7c9e432c90415f79809b7160e864f79001)
1 /*
2 ** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 ** Distributed under the terms of the OpenBeOS License.
4 */
5 
6 
7 #include "amiga_rdb.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 
22 
23 #define TRACE_AMIGA_RDB 0
24 #if TRACE_AMIGA_RDB
25 #	define TRACE(x) dprintf x
26 #else
27 #	define TRACE(x) ;
28 #endif
29 
30 #ifdef _BOOT_MODE
31 static const char *kPartitionModuleName = "partitioning_systems/amiga_rdb/v1";
32 #else
33 static const char *kPartitionModuleName = NULL;
34 #endif
35 
36 
37 template<typename Type> bool
38 validate_check_sum(Type *type)
39 {
40 	if (type->SummedLongs() != sizeof(*type) / sizeof(uint32))
41 		return false;
42 
43 	// check checksum
44 	uint32 *longs = (uint32 *)type;
45 	uint32 sum = 0;
46 	for (uint32 i = 0; i < type->SummedLongs(); i++)
47 		sum += B_BENDIAN_TO_HOST_INT32(longs[i]);
48 
49 #if TRACE_AMIGA_RDB
50 	if (sum != 0)
51 		TRACE(("search_rdb: check sum is incorrect!\n"));
52 #endif
53 
54 	return sum == 0;
55 }
56 
57 
58 #if TRACE_AMIGA_RDB
59 static char *
60 get_tupel(uint32 id)
61 {
62 	static unsigned char tupel[5];
63 
64 	tupel[0] = 0xff & (id >> 24);
65 	tupel[1] = 0xff & (id >> 16);
66 	tupel[2] = 0xff & (id >> 8);
67 	tupel[3] = 0xff & (id);
68 	tupel[4] = 0;
69 	for (int16 i = 0;i < 4;i++) {
70 		if (tupel[i] < ' ' || tupel[i] > 128)
71 			tupel[i] = '.';
72 	}
73 
74 	return (char *)tupel;
75 }
76 #endif
77 
78 
79 static status_t
80 get_next_partition(int fd, rigid_disk_block &rdb, uint32 &cookie, partition_block &partition)
81 {
82 	if (cookie == 0) {
83 		// first entry
84 		cookie = rdb.FirstPartition();
85 	} else if (cookie == 0xffffffff) {
86 		// last entry
87 		return B_ENTRY_NOT_FOUND;
88 	}
89 
90 	ssize_t bytesRead = read_pos(fd, (off_t)cookie * rdb.BlockSize(), (void *)&partition,
91 							sizeof(partition_block));
92 	if (bytesRead < (ssize_t)sizeof(partition_block))
93 		return B_ERROR;
94 
95 	// ToDo: Should we retry with the next block if the following test fails, as
96 	//		long as this we find partition_blocks within a reasonable range?
97 
98 	if (partition.ID() != RDB_PARTITION_ID || !validate_check_sum<partition_block>(&partition))
99 		return B_BAD_DATA;
100 
101 	cookie = partition.Next();
102 	return B_OK;
103 }
104 
105 
106 static bool
107 search_rdb(int fd, rigid_disk_block **_rdb)
108 {
109 	for (int32 sector = 0; sector < RDB_LOCATION_LIMIT; sector++) {
110 		uint8 buffer[512];
111 		ssize_t bytesRead = read_pos(fd, sector * 512, buffer, sizeof(buffer));
112 		if (bytesRead < (ssize_t)sizeof(buffer)) {
113 			TRACE(("search_rdb: read error: %ld\n", bytesRead));
114 			return false;
115 		}
116 
117 		rigid_disk_block *rdb = (rigid_disk_block *)buffer;
118 		if (rdb->ID() == RDB_DISK_ID && validate_check_sum<rigid_disk_block>(rdb)) {
119 			// copy the RDB to a new piece of memory
120 			rdb = new rigid_disk_block();
121 			memcpy(rdb, buffer, sizeof(rigid_disk_block));
122 
123 			*_rdb = rdb;
124 			return true;
125 		}
126 	}
127 
128 	return false;
129 }
130 
131 
132 //	#pragma mark -
133 //	AmigaRDB public module interface
134 
135 
136 static status_t
137 amiga_rdb_std_ops(int32 op, ...)
138 {
139 	switch (op) {
140 		case B_MODULE_INIT:
141 		case B_MODULE_UNINIT:
142 			return B_OK;
143 	}
144 
145 	return B_ERROR;
146 }
147 
148 
149 static float
150 amiga_rdb_identify_partition(int fd, partition_data *partition, void **_cookie)
151 {
152 	rigid_disk_block *rdb;
153 	if (!search_rdb(fd, &rdb))
154 		return B_ERROR;
155 
156 	*_cookie = (void *)rdb;
157 	return 0.5f;
158 }
159 
160 
161 static status_t
162 amiga_rdb_scan_partition(int fd, partition_data *partition, void *_cookie)
163 {
164 	TRACE(("amiga_rdb_scan_partition(cookie = %p)\n", _cookie));
165 
166 	rigid_disk_block &rdb = *(rigid_disk_block *)_cookie;
167 
168 	partition->status = B_PARTITION_VALID;
169 	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
170 						| B_PARTITION_READ_ONLY;
171 	partition->content_size = partition->size;
172 
173 	// scan all children
174 
175 	partition_block partitionBlock;
176 	uint32 index = 0, cookie = 0;
177 	status_t status;
178 
179 	while ((status = get_next_partition(fd, rdb, cookie, partitionBlock)) == B_OK) {
180 		disk_environment &environment = *(disk_environment *)&partitionBlock.environment[0];
181 		TRACE(("amiga_rdb: file system: %s\n", get_tupel(B_BENDIAN_TO_HOST_INT32(environment.dos_type))));
182 
183 		if (environment.Start() + environment.Size() > (uint64)partition->size) {
184 			TRACE(("amiga_rdb: child partition exceeds existing space (%Ld bytes)\n", environment.Size()));
185 			continue;
186 		}
187 
188 		partition_data *child = create_child_partition(partition->id, index++, -1);
189 		if (child == NULL) {
190 			TRACE(("amiga_rdb: Creating child at index %ld failed\n", index - 1));
191 			return B_ERROR;
192 		}
193 
194 		child->offset = partition->offset + environment.Start();
195 		child->size = environment.Size();
196 		child->block_size = environment.BlockSize();
197 	}
198 
199 	if (status == B_ENTRY_NOT_FOUND)
200 		return B_OK;
201 
202 	return status;
203 }
204 
205 
206 static void
207 amiga_rdb_free_identify_partition_cookie(partition_data *partition, void *_cookie)
208 {
209 	delete (rigid_disk_block *)_cookie;
210 }
211 
212 
213 #ifndef _BOOT_MODE
214 static partition_module_info gAmigaPartitionModule = {
215 #else
216 partition_module_info gAmigaPartitionModule = {
217 #endif
218 	{
219 		kPartitionModuleName,
220 		0,
221 		amiga_rdb_std_ops
222 	},
223 	kPartitionTypeAmiga,				// pretty_name
224 	0,									// flags
225 
226 	// scanning
227 	amiga_rdb_identify_partition,		// identify_partition
228 	amiga_rdb_scan_partition,			// scan_partition
229 	amiga_rdb_free_identify_partition_cookie,	// free_identify_partition_cookie
230 	NULL,
231 //	amiga_rdb_free_partition_cookie,			// free_partition_cookie
232 //	amiga_rdb_free_partition_content_cookie,	// free_partition_content_cookie
233 };
234 
235 #ifndef _BOOT_MODE
236 partition_module_info *modules[] = {
237 	&gAmigaPartitionModule,
238 	NULL
239 };
240 #endif
241 
242