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