xref: /haiku/src/add-ons/kernel/partitioning_systems/amiga/amiga_rdb.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
1 /*
2  * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "amiga_rdb.h"
8 
9 #include <ByteOrder.h>
10 #include <KernelExport.h>
11 #include <disk_device_manager/ddm_modules.h>
12 #include <disk_device_types.h>
13 #ifdef _BOOT_MODE
14 #	include <boot/partitions.h>
15 #else
16 #	include <DiskDeviceTypes.h>
17 #endif
18 #include <util/kernel_cpp.h>
19 
20 #include <unistd.h>
21 #include <string.h>
22 
23 
24 //#define TRACE_AMIGA_RDB
25 #ifdef TRACE_AMIGA_RDB
26 #	define TRACE(x) dprintf x
27 #else
28 #	define TRACE(x) ;
29 #endif
30 
31 
32 #define AMIGA_PARTITION_MODULE_NAME "partitioning_systems/amiga_rdb/v1"
33 
34 
35 template<typename Type> bool
36 validate_check_sum(Type *type)
37 {
38 	if (type->SummedLongs() != sizeof(*type) / sizeof(uint32))
39 		return false;
40 
41 	// check checksum
42 	uint32 *longs = (uint32 *)type;
43 	uint32 sum = 0;
44 	for (uint32 i = 0; i < type->SummedLongs(); i++)
45 		sum += B_BENDIAN_TO_HOST_INT32(longs[i]);
46 
47 #ifdef TRACE_AMIGA_RDB
48 	if (sum != 0)
49 		TRACE(("search_rdb: check sum is incorrect!\n"));
50 #endif
51 
52 	return sum == 0;
53 }
54 
55 
56 #ifdef TRACE_AMIGA_RDB
57 static char *
58 get_tupel(uint32 id)
59 {
60 	static unsigned char tupel[5];
61 
62 	tupel[0] = 0xff & (id >> 24);
63 	tupel[1] = 0xff & (id >> 16);
64 	tupel[2] = 0xff & (id >> 8);
65 	tupel[3] = 0xff & (id);
66 	tupel[4] = 0;
67 	for (int16 i = 0;i < 4;i++) {
68 		if (tupel[i] < ' ' || tupel[i] > 128)
69 			tupel[i] = '.';
70 	}
71 
72 	return (char *)tupel;
73 }
74 #endif
75 
76 
77 static status_t
78 get_next_partition(int fd, rigid_disk_block &rdb, uint32 &cookie,
79 	partition_block &partition)
80 {
81 	if (cookie == 0) {
82 		// first entry
83 		cookie = rdb.FirstPartition();
84 	} else if (cookie == 0xffffffff) {
85 		// last entry
86 		return B_ENTRY_NOT_FOUND;
87 	}
88 
89 	ssize_t bytesRead = read_pos(fd, (off_t)cookie * rdb.BlockSize(),
90 		(void *)&partition, sizeof(partition_block));
91 	if (bytesRead < (ssize_t)sizeof(partition_block))
92 		return B_ERROR;
93 
94 	// TODO: Should we retry with the next block if the following test fails, as
95 	// long as this we find partition_blocks within a reasonable range?
96 
97 	if (partition.ID() != RDB_PARTITION_ID
98 		|| !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
119 			&& validate_check_sum<rigid_disk_block>(rdb)) {
120 			// copy the RDB to a new piece of memory
121 			rdb = new rigid_disk_block();
122 			memcpy(rdb, buffer, sizeof(rigid_disk_block));
123 
124 			*_rdb = rdb;
125 			return true;
126 		}
127 	}
128 
129 	return false;
130 }
131 
132 
133 // #pragma mark - 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))
180 			== B_OK) {
181 		disk_environment &environment
182 			= *(disk_environment *)&partitionBlock.environment[0];
183 		TRACE(("amiga_rdb: file system: %s\n",
184 			get_tupel(B_BENDIAN_TO_HOST_INT32(environment.dos_type))));
185 
186 		if (environment.Start() + environment.Size()
187 				> (uint64)partition->size) {
188 			TRACE(("amiga_rdb: child partition exceeds existing space (%Ld "
189 				"bytes)\n", environment.Size()));
190 			continue;
191 		}
192 
193 		partition_data *child = create_child_partition(partition->id, index++,
194 			partition->offset + environment.Start(), environment.Size(), -1);
195 		if (child == NULL) {
196 			TRACE(("amiga_rdb: Creating child at index %ld failed\n",
197 				index - 1));
198 			return B_ERROR;
199 		}
200 
201 		child->block_size = environment.BlockSize();
202 	}
203 
204 	if (status == B_ENTRY_NOT_FOUND)
205 		return B_OK;
206 
207 	return status;
208 }
209 
210 
211 static void
212 amiga_rdb_free_identify_partition_cookie(partition_data *partition,
213 	void *_cookie)
214 {
215 	delete (rigid_disk_block *)_cookie;
216 }
217 
218 
219 #ifndef _BOOT_MODE
220 static partition_module_info sAmigaPartitionModule = {
221 #else
222 partition_module_info gAmigaPartitionModule = {
223 #endif
224 	{
225 		AMIGA_PARTITION_MODULE_NAME,
226 		0,
227 		amiga_rdb_std_ops
228 	},
229 	"amiga",							// short_name
230 	AMIGA_PARTITION_NAME,				// pretty_name
231 	0,									// flags
232 
233 	// scanning
234 	amiga_rdb_identify_partition,
235 	amiga_rdb_scan_partition,
236 	amiga_rdb_free_identify_partition_cookie,
237 	NULL,
238 };
239 
240 #ifndef _BOOT_MODE
241 partition_module_info *modules[] = {
242 	&sAmigaPartitionModule,
243 	NULL
244 };
245 #endif
246 
247