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 35template<typename Type> bool 36validate_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 57static char * 58get_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 77static status_t 78get_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 106static bool 107search_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 136static status_t 137amiga_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 149static float 150amiga_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 161static status_t 162amiga_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 211static void 212amiga_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 220static partition_module_info sAmigaPartitionModule = { 221#else 222partition_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 241partition_module_info *modules[] = { 242 &sAmigaPartitionModule, 243 NULL 244}; 245#endif 246 247