static struct AmigaBlock * _amiga_read_block (const PedDevice *dev, struct AmigaBlock *blk, PedSector block, struct AmigaIds *ids) { if (!ped_device_read (dev, blk, block, 1)) return NULL; if (ids && !_amiga_id_in_list(PED_BE32_TO_CPU(blk->amiga_ID), ids)) return NULL; if (_amiga_checksum (blk) != 0) { switch (ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE | PED_EXCEPTION_CANCEL, _("%s : Bad checksum on block %llu of type %s."), __func__, block, _amiga_block_id(PED_BE32_TO_CPU(blk->amiga_ID)))) { case PED_EXCEPTION_CANCEL : return NULL; case PED_EXCEPTION_FIX : _amiga_calculate_checksum(AMIGA(blk)); if (!ped_device_write ((PedDevice*)dev, blk, block, 1)) return NULL; case PED_EXCEPTION_IGNORE : case PED_EXCEPTION_UNHANDLED : default : return blk; } } return blk; }
static int _amiga_find_free_blocks(const PedDisk *disk, uint32_t *table, struct LinkedBlock *block, uint32_t first, uint32_t type) { PedSector next; PED_ASSERT(disk != NULL); PED_ASSERT(disk->dev != NULL); for (next = first; next != LINK_END; next = PED_BE32_TO_CPU(block->lk_Next)) { if (table[next] != IDNAME_FREE) { switch (ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE | PED_EXCEPTION_CANCEL, _("%s : Loop detected at block %d."), __func__, next)) { case PED_EXCEPTION_CANCEL : return 0; case PED_EXCEPTION_FIX : /* TODO : Need to add fixing code */ case PED_EXCEPTION_IGNORE : case PED_EXCEPTION_UNHANDLED : default : return 1; } } if (!_amiga_read_block (disk->dev, AMIGA(block), next, NULL)) { return 0; } if (PED_BE32_TO_CPU(block->lk_ID) != type) { switch (ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("%s : The %s list seems bad at block %s."), __func__, _amiga_block_id(PED_BE32_TO_CPU(block->lk_ID)), next)) { /* TODO : to more subtile things here */ case PED_EXCEPTION_CANCEL : case PED_EXCEPTION_UNHANDLED : default : return 0; } } table[next] = type; if (PED_BE32_TO_CPU(block->lk_ID) == IDNAME_FILESYSHEADER) { if (_amiga_find_free_blocks(disk, table, block, PED_BE32_TO_CPU(LNK2(block)->lk2_Linked), IDNAME_LOADSEG) == 0) return 0; } } return 1; }
static uint32_t _amiga_find_rdb (PedDevice *dev, struct RigidDiskBlock *rdb) { int i; struct AmigaIds *ids; ids = _amiga_add_id (IDNAME_RIGIDDISK, NULL); for (i = 0; i<RDB_LOCATION_LIMIT; i++) { if (!_amiga_read_block (dev, AMIGA(rdb), i, ids)) { continue; } if (PED_BE32_TO_CPU (rdb->rdb_ID) == IDNAME_RIGIDDISK) { _amiga_free_ids (ids); return i; } } _amiga_free_ids (ids); return AMIGA_RDB_NOT_FOUND; }
static int amiga_write (const PedDisk* disk) { struct RigidDiskBlock *rdb; struct LinkedBlock *block; struct PartitionBlock *partition; PedPartition *part, *next_part; PedSector cylblocks, first_hb, last_hb; uint32_t * table; uint32_t i; uint32_t rdb_num, part_num, block_num, next_num; PED_ASSERT (disk != NULL); PED_ASSERT (disk->dev != NULL); PED_ASSERT (disk->disk_specific != NULL); if (!(rdb = ped_malloc (disk->dev->sector_size))) return 0; /* Let's read the rdb */ if ((rdb_num = _amiga_find_rdb (disk->dev, rdb)) == AMIGA_RDB_NOT_FOUND) { rdb_num = 2; size_t pb_size = sizeof (struct PartitionBlock); /* Initialize only the part that won't be copied over with a partition block in amiga_read. */ memset ((char *)(RDSK(disk->disk_specific)) + pb_size, 0, PED_SECTOR_SIZE_DEFAULT - pb_size); } else { memcpy (RDSK(disk->disk_specific), rdb, disk->dev->sector_size); } free (rdb); rdb = RDSK(disk->disk_specific); cylblocks = (PedSector) PED_BE32_TO_CPU (rdb->rdb_Heads) * (PedSector) PED_BE32_TO_CPU (rdb->rdb_Sectors); first_hb = (PedSector) PED_BE32_TO_CPU (rdb->rdb_RDBBlocksLo); last_hb = (PedSector) PED_BE32_TO_CPU (rdb->rdb_RDBBlocksHi); /* Allocate a free block table and initialize it. There must be room for at least RDB_NUM + 2 entries, since the first RDB_NUM+1 entries get IDNAME_RIGIDDISK, and the following one must have LINK_END to serve as sentinel. */ size_t tab_size = 2 + MAX (last_hb - first_hb, rdb_num); if (!(table = ped_malloc (tab_size * sizeof *table))) return 0; for (i = 0; i <= rdb_num; i++) table[i] = IDNAME_RIGIDDISK; for ( ; i < tab_size; i++) table[i] = LINK_END; /* Let's allocate a partition block */ if (!(block = ped_malloc (disk->dev->sector_size))) { free (table); return 0; } /* And fill the free block table */ if (_amiga_find_free_blocks(disk, table, block, PED_BE32_TO_CPU (rdb->rdb_BadBlockList), IDNAME_BADBLOCK) == 0) { ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("%s : Failed to list bad blocks."), __func__); goto error_free_table; } if (_amiga_find_free_blocks(disk, table, block, PED_BE32_TO_CPU (rdb->rdb_PartitionList), IDNAME_PARTITION) == 0) { ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("%s : Failed to list partition blocks."), __func__); goto error_free_table; } if (_amiga_find_free_blocks(disk, table, block, PED_BE32_TO_CPU (rdb->rdb_FileSysHeaderList), IDNAME_FILESYSHEADER) == 0) { ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("%s : Failed to list file system blocks."), __func__); goto error_free_table; } if (_amiga_find_free_blocks(disk, table, block, PED_BE32_TO_CPU (rdb->rdb_BootBlockList), IDNAME_BOOT) == 0) { ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("%s : Failed to list boot blocks."), __func__); goto error_free_table; } block_num = part_num = _amiga_next_free_block(table, rdb_num+1, IDNAME_PARTITION); part = _amiga_next_real_partition(disk, NULL); rdb->rdb_PartitionList = PED_CPU_TO_BE32(part ? part_num : LINK_END); for (; part != NULL; part = next_part, block_num = next_num) { PED_ASSERT(part->disk_specific != NULL); PED_ASSERT(part->geom.start % cylblocks == 0); PED_ASSERT((part->geom.end + 1) % cylblocks == 0); next_part = _amiga_next_real_partition(disk, part); next_num = _amiga_next_free_block(table, block_num+1, IDNAME_PARTITION); partition = PART(part->disk_specific); if (next_part == NULL) partition->pb_Next = PED_CPU_TO_BE32(LINK_END); else partition->pb_Next = PED_CPU_TO_BE32(next_num); partition->de_LowCyl = PED_CPU_TO_BE32(part->geom.start/cylblocks); partition->de_HighCyl = PED_CPU_TO_BE32((part->geom.end+1)/cylblocks-1); _amiga_calculate_checksum(AMIGA(partition)); if (!ped_device_write (disk->dev, (void*) partition, block_num, 1)) { ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Failed to write partition block at %d."), block_num); goto error_free_table; /* WARNING : If we fail here, we stop everything, * and the partition table is lost. A better * solution should be found, using the second * half of the hardblocks to not overwrite the * old partition table. It becomes problematic * if we use more than half of the hardblocks. */ } } if (block_num > PED_BE32_TO_CPU (rdb->rdb_HighRDSKBlock)) rdb->rdb_HighRDSKBlock = PED_CPU_TO_BE32(block_num); _amiga_calculate_checksum(AMIGA(rdb)); if (!ped_device_write (disk->dev, (void*) disk->disk_specific, rdb_num, 1)) goto error_free_table; free (table); free (block); return ped_device_sync (disk->dev); error_free_table: free (table); free (block); return 0; }
/* We have already allocated a rdb, we are now reading it from the disk */ static int amiga_read (PedDisk* disk) { struct RigidDiskBlock *rdb; struct PartitionBlock *partition; uint32_t partblock; uint32_t partlist[AMIGA_MAX_PARTITIONS]; PedSector cylblocks; int i; PED_ASSERT(disk != NULL); PED_ASSERT(disk->dev != NULL); PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0); PED_ASSERT(disk->disk_specific != NULL); rdb = RDSK(disk->disk_specific); if (_amiga_find_rdb (disk->dev, rdb) == AMIGA_RDB_NOT_FOUND) { ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("%s : Didn't find rdb block, should never happen."), __func__); return 0; } /* Let's copy the rdb read geometry to the dev */ /* FIXME: should this go into disk->dev->bios_geom instead? */ disk->dev->hw_geom.cylinders = PED_BE32_TO_CPU (rdb->rdb_Cylinders); disk->dev->hw_geom.heads = PED_BE32_TO_CPU (rdb->rdb_Heads); disk->dev->hw_geom.sectors = PED_BE32_TO_CPU (rdb->rdb_Sectors); cylblocks = (PedSector) PED_BE32_TO_CPU (rdb->rdb_Heads) * (PedSector) PED_BE32_TO_CPU (rdb->rdb_Sectors); /* Remove all partitions in the former in memory table */ ped_disk_delete_all (disk); /* Let's allocate a partition block */ if (!(partition = ped_malloc (disk->dev->sector_size))) return 0; /* We initialize the hardblock free list to detect loops */ for (i = 0; i < AMIGA_MAX_PARTITIONS; i++) partlist[i] = LINK_END; for (i = 1, partblock = PED_BE32_TO_CPU(rdb->rdb_PartitionList); i < AMIGA_MAX_PARTITIONS && partblock != LINK_END; i++, partblock = PED_BE32_TO_CPU(partition->pb_Next)) { PedPartition *part; PedSector start, end; /* Let's look for loops in the partition table */ if (_amiga_loop_check(partblock, partlist, i)) { break; } /* Let's allocate and read a partition block to get its geometry*/ if (!_amiga_read_block (disk->dev, AMIGA(partition), (PedSector)partblock, NULL)) { free(partition); return 0; } start = ((PedSector) PED_BE32_TO_CPU (partition->de_LowCyl)) * cylblocks; end = (((PedSector) PED_BE32_TO_CPU (partition->de_HighCyl)) + 1) * cylblocks - 1; /* We can now construct a new partition */ if (!(part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL, start, end))) { free(partition); return 0; } /* And copy over the partition block */ memcpy(part->disk_specific, partition, 256); part->num = i; part->type = 0; /* Let's probe what file system is present on the disk */ part->fs_type = ped_file_system_probe (&part->geom); PedConstraint *constraint_exact = ped_constraint_exact (&part->geom); if (constraint_exact == NULL) return 0; bool ok = ped_disk_add_partition (disk, part, constraint_exact); ped_constraint_destroy (constraint_exact); if (!ok) { ped_partition_destroy(part); free(partition); return 0; } } free(partition); return 1; }