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 (%lld " 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