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