btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / add-ons / kernel / partitioning_systems / amiga / amiga_rdb.cpp
blob924462df0e53a26ccc09203cb9176360487ab982
1 /*
2 * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "amiga_rdb.h"
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>
20 #include <unistd.h>
21 #include <string.h>
24 //#define TRACE_AMIGA_RDB
25 #ifdef TRACE_AMIGA_RDB
26 # define TRACE(x) dprintf x
27 #else
28 # define TRACE(x) ;
29 #endif
32 #define AMIGA_PARTITION_MODULE_NAME "partitioning_systems/amiga_rdb/v1"
35 template<typename Type> bool
36 validate_check_sum(Type *type)
38 if (type->SummedLongs() != sizeof(*type) / sizeof(uint32))
39 return false;
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]);
47 #ifdef TRACE_AMIGA_RDB
48 if (sum != 0)
49 TRACE(("search_rdb: check sum is incorrect!\n"));
50 #endif
52 return sum == 0;
56 #ifdef TRACE_AMIGA_RDB
57 static char *
58 get_tupel(uint32 id)
60 static unsigned char tupel[5];
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] = '.';
72 return (char *)tupel;
74 #endif
77 static status_t
78 get_next_partition(int fd, rigid_disk_block &rdb, uint32 &cookie,
79 partition_block &partition)
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;
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;
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?
97 if (partition.ID() != RDB_PARTITION_ID
98 || !validate_check_sum<partition_block>(&partition))
99 return B_BAD_DATA;
101 cookie = partition.Next();
102 return B_OK;
106 static bool
107 search_rdb(int fd, rigid_disk_block **_rdb)
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;
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));
124 *_rdb = rdb;
125 return true;
129 return false;
133 // #pragma mark - public module interface
136 static status_t
137 amiga_rdb_std_ops(int32 op, ...)
139 switch (op) {
140 case B_MODULE_INIT:
141 case B_MODULE_UNINIT:
142 return B_OK;
145 return B_ERROR;
149 static float
150 amiga_rdb_identify_partition(int fd, partition_data *partition, void **_cookie)
152 rigid_disk_block *rdb;
153 if (!search_rdb(fd, &rdb))
154 return B_ERROR;
156 *_cookie = (void *)rdb;
157 return 0.5f;
161 static status_t
162 amiga_rdb_scan_partition(int fd, partition_data *partition, void *_cookie)
164 TRACE(("amiga_rdb_scan_partition(cookie = %p)\n", _cookie));
166 rigid_disk_block &rdb = *(rigid_disk_block *)_cookie;
168 partition->status = B_PARTITION_VALID;
169 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
170 | B_PARTITION_READ_ONLY;
171 partition->content_size = partition->size;
173 // scan all children
175 partition_block partitionBlock;
176 uint32 index = 0, cookie = 0;
177 status_t status;
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))));
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;
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;
201 child->block_size = environment.BlockSize();
204 if (status == B_ENTRY_NOT_FOUND)
205 return B_OK;
207 return status;
211 static void
212 amiga_rdb_free_identify_partition_cookie(partition_data *partition,
213 void *_cookie)
215 delete (rigid_disk_block *)_cookie;
219 #ifndef _BOOT_MODE
220 static partition_module_info sAmigaPartitionModule = {
221 #else
222 partition_module_info gAmigaPartitionModule = {
223 #endif
225 AMIGA_PARTITION_MODULE_NAME,
227 amiga_rdb_std_ops
229 "amiga", // short_name
230 AMIGA_PARTITION_NAME, // pretty_name
231 0, // flags
233 // scanning
234 amiga_rdb_identify_partition,
235 amiga_rdb_scan_partition,
236 amiga_rdb_free_identify_partition_cookie,
237 NULL,
240 #ifndef _BOOT_MODE
241 partition_module_info *modules[] = {
242 &sAmigaPartitionModule,
243 NULL
245 #endif