/* * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #include "amiga_rdb.h" #include #include #include #include #ifdef _BOOT_MODE # include #else # include #endif #include #include #include //#define TRACE_AMIGA_RDB #ifdef TRACE_AMIGA_RDB # define TRACE(x) dprintf x #else # define TRACE(x) ; #endif #define AMIGA_PARTITION_MODULE_NAME "partitioning_systems/amiga_rdb/v1" template bool validate_check_sum(Type *type) { if (type->SummedLongs() != sizeof(*type) / sizeof(uint32)) return false; // check checksum uint32 *longs = (uint32 *)type; uint32 sum = 0; for (uint32 i = 0; i < type->SummedLongs(); i++) sum += B_BENDIAN_TO_HOST_INT32(longs[i]); #ifdef TRACE_AMIGA_RDB if (sum != 0) TRACE(("search_rdb: check sum is incorrect!\n")); #endif return sum == 0; } #ifdef TRACE_AMIGA_RDB static char * get_tupel(uint32 id) { static unsigned char tupel[5]; tupel[0] = 0xff & (id >> 24); tupel[1] = 0xff & (id >> 16); tupel[2] = 0xff & (id >> 8); tupel[3] = 0xff & (id); tupel[4] = 0; for (int16 i = 0;i < 4;i++) { if (tupel[i] < ' ' || tupel[i] > 128) tupel[i] = '.'; } return (char *)tupel; } #endif static status_t get_next_partition(int fd, rigid_disk_block &rdb, uint32 &cookie, partition_block &partition) { if (cookie == 0) { // first entry cookie = rdb.FirstPartition(); } else if (cookie == 0xffffffff) { // last entry return B_ENTRY_NOT_FOUND; } ssize_t bytesRead = read_pos(fd, (off_t)cookie * rdb.BlockSize(), (void *)&partition, sizeof(partition_block)); if (bytesRead < (ssize_t)sizeof(partition_block)) return B_ERROR; // TODO: Should we retry with the next block if the following test fails, as // long as this we find partition_blocks within a reasonable range? if (partition.ID() != RDB_PARTITION_ID || !validate_check_sum(&partition)) return B_BAD_DATA; cookie = partition.Next(); return B_OK; } static bool search_rdb(int fd, rigid_disk_block **_rdb) { for (int32 sector = 0; sector < RDB_LOCATION_LIMIT; sector++) { uint8 buffer[512]; ssize_t bytesRead = read_pos(fd, sector * 512, buffer, sizeof(buffer)); if (bytesRead < (ssize_t)sizeof(buffer)) { TRACE(("search_rdb: read error: %ld\n", bytesRead)); return false; } rigid_disk_block *rdb = (rigid_disk_block *)buffer; if (rdb->ID() == RDB_DISK_ID && validate_check_sum(rdb)) { // copy the RDB to a new piece of memory rdb = new rigid_disk_block(); memcpy(rdb, buffer, sizeof(rigid_disk_block)); *_rdb = rdb; return true; } } return false; } // #pragma mark - public module interface static status_t amiga_rdb_std_ops(int32 op, ...) { switch (op) { case B_MODULE_INIT: case B_MODULE_UNINIT: return B_OK; } return B_ERROR; } static float amiga_rdb_identify_partition(int fd, partition_data *partition, void **_cookie) { rigid_disk_block *rdb; if (!search_rdb(fd, &rdb)) return B_ERROR; *_cookie = (void *)rdb; return 0.5f; } static status_t amiga_rdb_scan_partition(int fd, partition_data *partition, void *_cookie) { TRACE(("amiga_rdb_scan_partition(cookie = %p)\n", _cookie)); rigid_disk_block &rdb = *(rigid_disk_block *)_cookie; partition->status = B_PARTITION_VALID; partition->flags |= B_PARTITION_PARTITIONING_SYSTEM | B_PARTITION_READ_ONLY; partition->content_size = partition->size; // scan all children partition_block partitionBlock; uint32 index = 0, cookie = 0; status_t status; while ((status = get_next_partition(fd, rdb, cookie, partitionBlock)) == B_OK) { disk_environment &environment = *(disk_environment *)&partitionBlock.environment[0]; TRACE(("amiga_rdb: file system: %s\n", get_tupel(B_BENDIAN_TO_HOST_INT32(environment.dos_type)))); if (environment.Start() + environment.Size() > (uint64)partition->size) { TRACE(("amiga_rdb: child partition exceeds existing space (%lld " "bytes)\n", environment.Size())); continue; } partition_data *child = create_child_partition(partition->id, index++, partition->offset + environment.Start(), environment.Size(), -1); if (child == NULL) { TRACE(("amiga_rdb: Creating child at index %ld failed\n", index - 1)); return B_ERROR; } child->block_size = environment.BlockSize(); } if (status == B_ENTRY_NOT_FOUND) return B_OK; return status; } static void amiga_rdb_free_identify_partition_cookie(partition_data *partition, void *_cookie) { delete (rigid_disk_block *)_cookie; } #ifndef _BOOT_MODE static partition_module_info sAmigaPartitionModule = { #else partition_module_info gAmigaPartitionModule = { #endif { AMIGA_PARTITION_MODULE_NAME, 0, amiga_rdb_std_ops }, "amiga", // short_name AMIGA_PARTITION_NAME, // pretty_name 0, // flags // scanning amiga_rdb_identify_partition, amiga_rdb_scan_partition, amiga_rdb_free_identify_partition_cookie, NULL, }; #ifndef _BOOT_MODE partition_module_info *modules[] = { &sAmigaPartitionModule, NULL }; #endif