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