1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3 libparted - a library for manipulating disk partitions
4 disk_amiga.c - libparted module to manipulate amiga RDB partition tables.
5 Copyright (C) 2000, 2001, 2004, 2007-2009 Free Software Foundation, Inc.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Contributor: Sven Luther <luther@debian.org>
25 #include <parted/parted.h>
26 #include <parted/debug.h>
27 #include <parted/endian.h>
30 # define MAX(a,b) ((a) < (b) ? (b) : (a))
35 # define _(String) dgettext (PACKAGE, String)
37 # define _(String) (String)
38 #endif /* ENABLE_NLS */
42 /* String manipulation */
43 static void _amiga_set_bstr (const char *cstr, char *bstr, int maxsize) {
44 int size = strlen (cstr);
47 if (size >= maxsize) return;
49 for (i = 0; i<size; i++) bstr[i+1] = cstr[i];
51 static const char * _amiga_get_bstr (char * bstr) {
52 char * cstr = bstr + 1;
59 #define IDNAME_RIGIDDISK (uint32_t)0x5244534B /* 'RDSK' */
60 #define IDNAME_BADBLOCK (uint32_t)0x42414442 /* 'BADB' */
61 #define IDNAME_PARTITION (uint32_t)0x50415254 /* 'PART' */
62 #define IDNAME_FILESYSHEADER (uint32_t)0x46534844 /* 'FSHD' */
63 #define IDNAME_LOADSEG (uint32_t)0x4C534547 /* 'LSEG' */
64 #define IDNAME_BOOT (uint32_t)0x424f4f54 /* 'BOOT' */
65 #define IDNAME_FREE (uint32_t)0xffffffff
68 _amiga_block_id (uint32_t id) {
70 case IDNAME_RIGIDDISK :
72 case IDNAME_BADBLOCK :
74 case IDNAME_PARTITION :
76 case IDNAME_FILESYSHEADER :
91 struct AmigaIds *next;
94 static struct AmigaIds *
95 _amiga_add_id (uint32_t id, struct AmigaIds *ids) {
96 struct AmigaIds *newid;
98 if ((newid=ped_malloc(sizeof (struct AmigaIds)))==NULL)
106 _amiga_free_ids (struct AmigaIds *ids) {
107 struct AmigaIds *current, *next;
109 for (current = ids; current != NULL; current = next) {
110 next = current->next;
115 _amiga_id_in_list (uint32_t id, struct AmigaIds *ids) {
116 struct AmigaIds *current;
118 for (current = ids; current != NULL; current = current->next) {
119 if (id == current->ID)
126 uint32_t amiga_ID; /* Identifier 32 bit word */
127 uint32_t amiga_SummedLongss; /* Size of the structure for checksums */
128 int32_t amiga_ChkSum; /* Checksum of the structure */
130 #define AMIGA(pos) ((struct AmigaBlock *)(pos))
133 _amiga_checksum (struct AmigaBlock *blk) {
134 uint32_t *rdb = (uint32_t *) blk;
138 sum = PED_BE32_TO_CPU (rdb[0]);
139 end = PED_BE32_TO_CPU (rdb[1]);
141 if (end > PED_SECTOR_SIZE_DEFAULT) end = PED_SECTOR_SIZE_DEFAULT;
143 for (i = 1; i < end; i++) sum += PED_BE32_TO_CPU (rdb[i]);
149 _amiga_calculate_checksum (struct AmigaBlock *blk) {
150 blk->amiga_ChkSum = PED_CPU_TO_BE32(
151 PED_BE32_TO_CPU(blk->amiga_ChkSum) -
152 _amiga_checksum((struct AmigaBlock *) blk));
156 static struct AmigaBlock *
157 _amiga_read_block (const PedDevice *dev, struct AmigaBlock *blk,
158 PedSector block, struct AmigaIds *ids)
160 if (!ped_device_read (dev, blk, block, 1))
162 if (ids && !_amiga_id_in_list(PED_BE32_TO_CPU(blk->amiga_ID), ids))
164 if (_amiga_checksum (blk) != 0) {
165 switch (ped_exception_throw(PED_EXCEPTION_ERROR,
166 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE | PED_EXCEPTION_CANCEL,
167 _("%s : Bad checksum on block %llu of type %s."),
168 __func__, block, _amiga_block_id(PED_BE32_TO_CPU(blk->amiga_ID))))
170 case PED_EXCEPTION_CANCEL :
172 case PED_EXCEPTION_FIX :
173 _amiga_calculate_checksum(AMIGA(blk));
174 if (!ped_device_write ((PedDevice*)dev, blk, block, 1))
176 case PED_EXCEPTION_IGNORE :
177 case PED_EXCEPTION_UNHANDLED :
185 struct RigidDiskBlock {
186 uint32_t rdb_ID; /* Identifier 32 bit word : 'RDSK' */
187 uint32_t rdb_SummedLongs; /* Size of the structure for checksums */
188 int32_t rdb_ChkSum; /* Checksum of the structure */
189 uint32_t rdb_HostID; /* SCSI Target ID of host, not really used */
190 uint32_t rdb_BlockBytes; /* Size of disk blocks */
191 uint32_t rdb_Flags; /* RDB Flags */
192 /* block list heads */
193 uint32_t rdb_BadBlockList; /* Bad block list */
194 uint32_t rdb_PartitionList; /* Partition list */
195 uint32_t rdb_FileSysHeaderList; /* File system header list */
196 uint32_t rdb_DriveInit; /* Drive specific init code */
197 uint32_t rdb_BootBlockList; /* Amiga OS 4 Boot Blocks */
198 uint32_t rdb_Reserved1[5]; /* Unused word, need to be set to $ffffffff */
199 /* physical drive characteristics */
200 uint32_t rdb_Cylinders; /* Number of the cylinders of the drive */
201 uint32_t rdb_Sectors; /* Number of sectors of the drive */
202 uint32_t rdb_Heads; /* Number of heads of the drive */
203 uint32_t rdb_Interleave; /* Interleave */
204 uint32_t rdb_Park; /* Head parking cylinder */
205 uint32_t rdb_Reserved2[3]; /* Unused word, need to be set to $ffffffff */
206 uint32_t rdb_WritePreComp; /* Starting cylinder of write precompensation */
207 uint32_t rdb_ReducedWrite; /* Starting cylinder of reduced write current */
208 uint32_t rdb_StepRate; /* Step rate of the drive */
209 uint32_t rdb_Reserved3[5]; /* Unused word, need to be set to $ffffffff */
210 /* logical drive characteristics */
211 uint32_t rdb_RDBBlocksLo; /* low block of range reserved for hardblocks */
212 uint32_t rdb_RDBBlocksHi; /* high block of range for these hardblocks */
213 uint32_t rdb_LoCylinder; /* low cylinder of partitionable disk area */
214 uint32_t rdb_HiCylinder; /* high cylinder of partitionable data area */
215 uint32_t rdb_CylBlocks; /* number of blocks available per cylinder */
216 uint32_t rdb_AutoParkSeconds; /* zero for no auto park */
217 uint32_t rdb_HighRDSKBlock; /* highest block used by RDSK */
218 /* (not including replacement bad blocks) */
219 uint32_t rdb_Reserved4;
220 /* drive identification */
221 char rdb_DiskVendor[8];
222 char rdb_DiskProduct[16];
223 char rdb_DiskRevision[4];
224 char rdb_ControllerVendor[8];
225 char rdb_ControllerProduct[16];
226 char rdb_ControllerRevision[4];
227 uint32_t rdb_Reserved5[10];
230 #define RDSK(pos) ((struct RigidDiskBlock *)(pos))
232 #define AMIGA_RDB_NOT_FOUND ((uint32_t)0xffffffff)
233 #define RDB_LOCATION_LIMIT 16
234 #define AMIGA_MAX_PARTITIONS 128
235 #define MAX_RDB_BLOCK (RDB_LOCATION_LIMIT + 2 * AMIGA_MAX_PARTITIONS + 2)
238 _amiga_find_rdb (const PedDevice *dev, struct RigidDiskBlock *rdb) {
240 struct AmigaIds *ids;
242 ids = _amiga_add_id (IDNAME_RIGIDDISK, NULL);
244 for (i = 0; i<RDB_LOCATION_LIMIT; i++) {
245 if (!_amiga_read_block (dev, AMIGA(rdb), i, ids)) {
248 if (PED_BE32_TO_CPU (rdb->rdb_ID) == IDNAME_RIGIDDISK) {
249 _amiga_free_ids (ids);
253 _amiga_free_ids (ids);
254 return AMIGA_RDB_NOT_FOUND;
257 struct PartitionBlock {
258 uint32_t pb_ID; /* Identifier 32 bit word : 'PART' */
259 uint32_t pb_SummedLongs; /* Size of the structure for checksums */
260 int32_t pb_ChkSum; /* Checksum of the structure */
261 uint32_t pb_HostID; /* SCSI Target ID of host, not really used */
262 uint32_t pb_Next; /* Block number of the next PartitionBlock */
263 uint32_t pb_Flags; /* Part Flags (NOMOUNT and BOOTABLE) */
264 uint32_t pb_Reserved1[2];
265 uint32_t pb_DevFlags; /* Preferred flags for OpenDevice */
266 char pb_DriveName[32]; /* Preferred DOS device name: BSTR form */
267 uint32_t pb_Reserved2[15];
268 uint32_t de_TableSize; /* Size of Environment vector */
269 /* Size of the blocks in 32 bit words, usually 128 */
270 uint32_t de_SizeBlock;
271 uint32_t de_SecOrg; /* Not used; must be 0 */
272 uint32_t de_Surfaces; /* Number of heads (surfaces) */
273 /* Disk sectors per block, used with SizeBlock, usually 1 */
274 uint32_t de_SectorPerBlock;
275 uint32_t de_BlocksPerTrack; /* Blocks per track. drive specific */
276 uint32_t de_Reserved; /* DOS reserved blocks at start of partition. */
277 uint32_t de_PreAlloc; /* DOS reserved blocks at end of partition */
278 uint32_t de_Interleave; /* Not used, usually 0 */
279 uint32_t de_LowCyl; /* First cylinder of the partition */
280 uint32_t de_HighCyl; /* Last cylinder of the partition */
281 uint32_t de_NumBuffers; /* Initial # DOS of buffers. */
282 uint32_t de_BufMemType; /* Type of mem to allocate for buffers */
283 uint32_t de_MaxTransfer; /* Max number of bytes to transfer at a time */
284 uint32_t de_Mask; /* Address Mask to block out certain memory */
285 int32_t de_BootPri; /* Boot priority for autoboot */
286 uint32_t de_DosType; /* Dostype of the file system */
287 uint32_t de_Baud; /* Baud rate for serial handler */
288 uint32_t de_Control; /* Control word for handler/filesystem */
289 uint32_t de_BootBlocks; /* Number of blocks containing boot code */
290 uint32_t pb_EReserved[12];
293 #define PART(pos) ((struct PartitionBlock *)(pos))
295 #define PBFB_BOOTABLE 0 /* this partition is intended to be bootable */
296 #define PBFF_BOOTABLE 1L /* (expected directories and files exist) */
297 #define PBFB_NOMOUNT 1 /* do not mount this partition (e.g. manually */
298 #define PBFF_NOMOUNT 2L /* mounted, but space reserved here) */
299 #define PBFB_RAID 2 /* this partition is intended to be part of */
300 #define PBFF_RAID 4L /* a RAID array */
301 #define PBFB_LVM 3 /* this partition is intended to be part of */
302 #define PBFF_LVM 8L /* a LVM volume group */
306 uint32_t lk_ID; /* Identifier 32 bit word */
307 uint32_t lk_SummedLongs; /* Size of the structure for checksums */
308 int32_t lk_ChkSum; /* Checksum of the structure */
309 uint32_t pb_HostID; /* SCSI Target ID of host, not really used */
310 uint32_t lk_Next; /* Block number of the next PartitionBlock */
312 struct Linked2Block {
313 uint32_t lk2_ID; /* Identifier 32 bit word */
314 uint32_t lk2_SummedLongs; /* Size of the structure for checksums */
315 int32_t lk2_ChkSum; /* Checksum of the structure */
316 uint32_t lk2_HostID; /* SCSI Target ID of host, not really used */
317 uint32_t lk2_Next; /* Block number of the next PartitionBlock */
318 uint32_t lk2_Reverved[13];
319 uint32_t lk2_Linked; /* Secondary linked list */
321 #define LINK_END (uint32_t)0xffffffff
322 #define LNK(pos) ((struct LinkedBlock *)(pos))
323 #define LNK2(pos) ((struct Linked2Block *)(pos))
326 static PedDiskType amiga_disk_type;
329 amiga_probe (const PedDevice *dev)
331 struct RigidDiskBlock *rdb;
333 PED_ASSERT(dev != NULL, return 0);
335 if ((rdb=RDSK(ped_malloc(dev->sector_size)))==NULL)
337 found = _amiga_find_rdb (dev, rdb);
340 return (found == AMIGA_RDB_NOT_FOUND ? 0 : 1);
344 amiga_alloc (const PedDevice* dev)
347 struct RigidDiskBlock *rdb;
349 int highest_cylinder, highest_block;
351 PED_ASSERT(dev != NULL, return NULL);
352 cyl_size = dev->hw_geom.sectors * dev->hw_geom.heads;
354 if (!(disk = _ped_disk_alloc (dev, &amiga_disk_type)))
357 if (!(disk->disk_specific = ped_malloc (disk->dev->sector_size))) {
361 rdb = disk->disk_specific;
363 memset(rdb, 0, sizeof(struct RigidDiskBlock));
365 rdb->rdb_ID = PED_CPU_TO_BE32 (IDNAME_RIGIDDISK);
366 rdb->rdb_SummedLongs = PED_CPU_TO_BE32 (64);
367 rdb->rdb_HostID = PED_CPU_TO_BE32 (0);
368 rdb->rdb_BlockBytes = PED_CPU_TO_BE32 (disk->dev->sector_size);
369 rdb->rdb_Flags = PED_CPU_TO_BE32 (0);
372 rdb->rdb_BadBlockList = PED_CPU_TO_BE32 (LINK_END);
373 rdb->rdb_PartitionList = PED_CPU_TO_BE32 (LINK_END);
374 rdb->rdb_FileSysHeaderList = PED_CPU_TO_BE32 (LINK_END);
375 rdb->rdb_DriveInit = PED_CPU_TO_BE32 (LINK_END);
376 rdb->rdb_BootBlockList = PED_CPU_TO_BE32 (LINK_END);
378 /* Physical drive characteristics */
379 rdb->rdb_Cylinders = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
380 rdb->rdb_Sectors = PED_CPU_TO_BE32 (dev->hw_geom.sectors);
381 rdb->rdb_Heads = PED_CPU_TO_BE32 (dev->hw_geom.heads);
382 rdb->rdb_Interleave = PED_CPU_TO_BE32 (0);
383 rdb->rdb_Park = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
384 rdb->rdb_WritePreComp = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
385 rdb->rdb_ReducedWrite = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
386 rdb->rdb_StepRate = PED_CPU_TO_BE32 (0);
388 highest_cylinder = 1 + MAX_RDB_BLOCK / cyl_size;
389 highest_block = highest_cylinder * cyl_size - 1;
391 /* Logical driver characteristics */
392 rdb->rdb_RDBBlocksLo = PED_CPU_TO_BE32 (0);
393 rdb->rdb_RDBBlocksHi = PED_CPU_TO_BE32 (highest_block);
394 rdb->rdb_LoCylinder = PED_CPU_TO_BE32 (highest_cylinder);
395 rdb->rdb_HiCylinder = PED_CPU_TO_BE32 (dev->hw_geom.cylinders -1);
396 rdb->rdb_CylBlocks = PED_CPU_TO_BE32 (cyl_size);
397 rdb->rdb_AutoParkSeconds = PED_CPU_TO_BE32 (0);
398 /* rdb_HighRDSKBlock will only be set when writing */
399 rdb->rdb_HighRDSKBlock = PED_CPU_TO_BE32 (0);
401 /* Driver identification */
402 _amiga_set_bstr("", rdb->rdb_DiskVendor, 8);
403 _amiga_set_bstr(dev->model, rdb->rdb_DiskProduct, 16);
404 _amiga_set_bstr("", rdb->rdb_DiskRevision, 4);
405 _amiga_set_bstr("", rdb->rdb_ControllerVendor, 8);
406 _amiga_set_bstr("", rdb->rdb_ControllerProduct, 16);
407 _amiga_set_bstr("", rdb->rdb_ControllerRevision, 4);
409 /* And calculate the checksum */
410 _amiga_calculate_checksum ((struct AmigaBlock *) rdb);
416 amiga_duplicate (const PedDisk* disk)
419 struct RigidDiskBlock * new_rdb;
420 struct RigidDiskBlock * old_rdb;
421 PED_ASSERT(disk != NULL, return NULL);
422 PED_ASSERT(disk->dev != NULL, return NULL);
423 PED_ASSERT(disk->disk_specific != NULL, return NULL);
425 old_rdb = (struct RigidDiskBlock *) disk->disk_specific;
427 if (!(new_disk = ped_disk_new_fresh (disk->dev, &amiga_disk_type)))
430 new_rdb = (struct RigidDiskBlock *) new_disk->disk_specific;
431 memcpy (new_rdb, old_rdb, 256);
436 amiga_free (PedDisk* disk)
438 PED_ASSERT(disk != NULL, return);
439 PED_ASSERT(disk->disk_specific != NULL, return);
441 free (disk->disk_specific);
442 _ped_disk_free (disk);
445 #ifndef DISCOVER_ONLY
447 amiga_clobber (PedDevice* dev)
449 struct RigidDiskBlock *rdb;
452 PED_ASSERT(dev != NULL, return 0);
454 if ((rdb=RDSK(ped_malloc(dev->sector_size)))==NULL)
457 while ((i = _amiga_find_rdb (dev, rdb)) != AMIGA_RDB_NOT_FOUND) {
458 rdb->rdb_ID = PED_CPU_TO_BE32 (0);
459 result = ped_device_write (dev, (void*) rdb, i, 1);
466 #endif /* !DISCOVER_ONLY */
469 _amiga_loop_check (uint32_t block, uint32_t * blocklist, uint32_t max)
473 for (i = 0; i < max; i++)
474 if (block == blocklist[i]) {
475 /* We are looping, let's stop. */
478 blocklist[max] = block;
482 /* We have already allocated a rdb, we are now reading it from the disk */
484 amiga_read (PedDisk* disk)
486 struct RigidDiskBlock *rdb;
487 struct PartitionBlock *partition;
489 uint32_t partlist[AMIGA_MAX_PARTITIONS];
493 PED_ASSERT(disk != NULL, return 0);
494 PED_ASSERT(disk->dev != NULL, return 0);
495 PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0,
497 PED_ASSERT(disk->disk_specific != NULL, return 0);
498 rdb = RDSK(disk->disk_specific);
500 if (_amiga_find_rdb (disk->dev, rdb) == AMIGA_RDB_NOT_FOUND) {
501 ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
502 _("%s : Didn't find rdb block, should never happen."), __func__);
506 /* Let's copy the rdb read geometry to the dev */
507 /* FIXME: should this go into disk->dev->bios_geom instead? */
508 disk->dev->hw_geom.cylinders = PED_BE32_TO_CPU (rdb->rdb_Cylinders);
509 disk->dev->hw_geom.heads = PED_BE32_TO_CPU (rdb->rdb_Heads);
510 disk->dev->hw_geom.sectors = PED_BE32_TO_CPU (rdb->rdb_Sectors);
511 cylblocks = (PedSector) PED_BE32_TO_CPU (rdb->rdb_Heads) *
512 (PedSector) PED_BE32_TO_CPU (rdb->rdb_Sectors);
514 /* Remove all partitions in the former in memory table */
515 ped_disk_delete_all (disk);
517 /* Let's allocate a partition block */
518 if (!(partition = ped_malloc (disk->dev->sector_size)))
521 /* We initialize the hardblock free list to detect loops */
522 for (i = 0; i < AMIGA_MAX_PARTITIONS; i++) partlist[i] = LINK_END;
524 for (i = 1, partblock = PED_BE32_TO_CPU(rdb->rdb_PartitionList);
525 i < AMIGA_MAX_PARTITIONS && partblock != LINK_END;
526 i++, partblock = PED_BE32_TO_CPU(partition->pb_Next))
529 PedSector start, end;
530 PedConstraint *constraint_exact;
532 /* Let's look for loops in the partition table */
533 if (_amiga_loop_check(partblock, partlist, i)) {
537 /* Let's allocate and read a partition block to get its geometry*/
538 if (!_amiga_read_block (disk->dev, AMIGA(partition),
539 (PedSector)partblock, NULL)) {
544 start = ((PedSector) PED_BE32_TO_CPU (partition->de_LowCyl))
546 end = (((PedSector) PED_BE32_TO_CPU (partition->de_HighCyl))
547 + 1) * cylblocks - 1;
549 /* We can now construct a new partition */
550 if (!(part = ped_partition_new (disk, PED_PARTITION_NORMAL,
551 NULL, start, end))) {
555 /* And copy over the partition block */
556 memcpy(part->disk_specific, partition, 256);
560 /* Let's probe what file system is present on the disk */
561 part->fs_type = ped_file_system_probe (&part->geom);
563 constraint_exact = ped_constraint_exact (&part->geom);
564 if (!ped_disk_add_partition (disk, part, constraint_exact)) {
565 ped_partition_destroy(part);
569 ped_constraint_destroy (constraint_exact);
576 _amiga_find_free_blocks(const PedDisk *disk, uint32_t *table,
577 struct LinkedBlock *block, uint32_t first, uint32_t type)
581 PED_ASSERT(disk != NULL, return 0);
582 PED_ASSERT(disk->dev != NULL, return 0);
584 for (next = first; next != LINK_END; next = PED_BE32_TO_CPU(block->lk_Next)) {
585 if (table[next] != IDNAME_FREE) {
586 switch (ped_exception_throw(PED_EXCEPTION_ERROR,
587 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE | PED_EXCEPTION_CANCEL,
588 _("%s : Loop detected at block %d."), __func__, next))
590 case PED_EXCEPTION_CANCEL :
592 case PED_EXCEPTION_FIX :
593 /* TODO : Need to add fixing code */
594 case PED_EXCEPTION_IGNORE :
595 case PED_EXCEPTION_UNHANDLED :
601 if (!_amiga_read_block (disk->dev, AMIGA(block), next, NULL)) {
604 if (PED_BE32_TO_CPU(block->lk_ID) != type) {
605 switch (ped_exception_throw(PED_EXCEPTION_ERROR,
606 PED_EXCEPTION_CANCEL,
607 _("%s : The %s list seems bad at block %s."),
608 __func__, _amiga_block_id(PED_BE32_TO_CPU(block->lk_ID)), next))
610 /* TODO : to more subtile things here */
611 case PED_EXCEPTION_CANCEL :
612 case PED_EXCEPTION_UNHANDLED :
618 if (PED_BE32_TO_CPU(block->lk_ID) == IDNAME_FILESYSHEADER) {
619 if (_amiga_find_free_blocks(disk, table, block,
620 PED_BE32_TO_CPU(LNK2(block)->lk2_Linked),
621 IDNAME_LOADSEG) == 0) return 0;
627 _amiga_next_free_block(uint32_t *table, uint32_t start, uint32_t type) {
630 for (i = start; table[i] != type && table[i] != IDNAME_FREE; i++);
633 static PedPartition *
634 _amiga_next_real_partition(const PedDisk *disk, PedPartition *part) {
637 for (next = ped_disk_next_partition (disk, part);
638 next != NULL && !ped_partition_is_active (next);
639 next = ped_disk_next_partition (disk, next));
642 #ifndef DISCOVER_ONLY
644 amiga_write (const PedDisk* disk)
646 struct RigidDiskBlock *rdb;
647 struct LinkedBlock *block;
648 struct PartitionBlock *partition;
649 PedPartition *part, *next_part;
650 PedSector cylblocks, first_hb, last_hb, last_used_hb;
653 uint32_t rdb_num, part_num, block_num, next_num;
655 PED_ASSERT (disk != NULL, return 0);
656 PED_ASSERT (disk->dev != NULL, return 0);
657 PED_ASSERT (disk->disk_specific != NULL, return 0);
659 if (!(rdb = ped_malloc (disk->dev->sector_size)))
662 /* Let's read the rdb */
663 if ((rdb_num = _amiga_find_rdb (disk->dev, rdb)) == AMIGA_RDB_NOT_FOUND) {
665 size_t pb_size = sizeof (struct PartitionBlock);
666 /* Initialize only the part that won't be copied over
667 with a partition block in amiga_read. */
668 memset ((char *)(RDSK(disk->disk_specific)) + pb_size,
669 0, PED_SECTOR_SIZE_DEFAULT - pb_size);
671 memcpy (RDSK(disk->disk_specific), rdb, disk->dev->sector_size);
674 rdb = RDSK(disk->disk_specific);
676 cylblocks = (PedSector) PED_BE32_TO_CPU (rdb->rdb_Heads) *
677 (PedSector) PED_BE32_TO_CPU (rdb->rdb_Sectors);
678 first_hb = (PedSector) PED_BE32_TO_CPU (rdb->rdb_RDBBlocksLo);
679 last_hb = (PedSector) PED_BE32_TO_CPU (rdb->rdb_RDBBlocksHi);
680 last_used_hb = (PedSector) PED_BE32_TO_CPU (rdb->rdb_HighRDSKBlock);
682 /* Allocate a free block table and initialize it.
683 There must be room for at least RDB_NUM + 2 entries, since
684 the first RDB_NUM+1 entries get IDNAME_RIGIDDISK, and the
685 following one must have LINK_END to serve as sentinel. */
686 size_t tab_size = 2 + MAX (last_hb - first_hb, rdb_num);
687 if (!(table = ped_malloc (tab_size * sizeof *table)))
690 for (i = 0; i <= rdb_num; i++)
691 table[i] = IDNAME_RIGIDDISK;
692 for ( ; i < tab_size; i++)
695 /* Let's allocate a partition block */
696 if (!(block = ped_malloc (disk->dev->sector_size))) {
701 /* And fill the free block table */
702 if (_amiga_find_free_blocks(disk, table, block,
703 PED_BE32_TO_CPU (rdb->rdb_BadBlockList), IDNAME_BADBLOCK) == 0)
705 ped_exception_throw(PED_EXCEPTION_ERROR,
706 PED_EXCEPTION_CANCEL,
707 _("%s : Failed to list bad blocks."), __func__);
708 goto error_free_table;
710 if (_amiga_find_free_blocks(disk, table, block,
711 PED_BE32_TO_CPU (rdb->rdb_PartitionList), IDNAME_PARTITION) == 0)
713 ped_exception_throw(PED_EXCEPTION_ERROR,
714 PED_EXCEPTION_CANCEL,
715 _("%s : Failed to list partition blocks."), __func__);
716 goto error_free_table;
718 if (_amiga_find_free_blocks(disk, table, block,
719 PED_BE32_TO_CPU (rdb->rdb_FileSysHeaderList), IDNAME_FILESYSHEADER) == 0)
721 ped_exception_throw(PED_EXCEPTION_ERROR,
722 PED_EXCEPTION_CANCEL,
723 _("%s : Failed to list file system blocks."), __func__);
724 goto error_free_table;
726 if (_amiga_find_free_blocks(disk, table, block,
727 PED_BE32_TO_CPU (rdb->rdb_BootBlockList), IDNAME_BOOT) == 0)
729 ped_exception_throw(PED_EXCEPTION_ERROR,
730 PED_EXCEPTION_CANCEL,
731 _("%s : Failed to list boot blocks."), __func__);
732 goto error_free_table;
735 block_num = next_num = part_num = _amiga_next_free_block(table, rdb_num+1,
737 part = _amiga_next_real_partition(disk, NULL);
738 rdb->rdb_PartitionList = PED_CPU_TO_BE32(part ? part_num : LINK_END);
739 for (; part != NULL; part = next_part, block_num = next_num) {
740 PED_ASSERT(part->disk_specific != NULL, return 0);
741 PED_ASSERT(part->geom.start % cylblocks == 0, return 0);
742 PED_ASSERT((part->geom.end + 1) % cylblocks == 0, return 0);
744 next_part = _amiga_next_real_partition(disk, part);
745 next_num = _amiga_next_free_block(table, block_num+1, IDNAME_PARTITION);
747 partition = PART(part->disk_specific);
748 if (next_part == NULL)
749 partition->pb_Next = PED_CPU_TO_BE32(LINK_END);
751 partition->pb_Next = PED_CPU_TO_BE32(next_num);
752 partition->de_LowCyl = PED_CPU_TO_BE32(part->geom.start/cylblocks);
753 partition->de_HighCyl = PED_CPU_TO_BE32((part->geom.end+1)/cylblocks-1);
754 _amiga_calculate_checksum(AMIGA(partition));
755 if (!ped_device_write (disk->dev, (void*) partition, block_num, 1)) {
756 ped_exception_throw(PED_EXCEPTION_ERROR,
757 PED_EXCEPTION_CANCEL,
758 _("Failed to write partition block at %d."),
760 goto error_free_table;
761 /* WARNING : If we fail here, we stop everything,
762 * and the partition table is lost. A better
763 * solution should be found, using the second
764 * half of the hardblocks to not overwrite the
765 * old partition table. It becomes problematic
766 * if we use more than half of the hardblocks. */
770 if (block_num > PED_BE32_TO_CPU (rdb->rdb_HighRDSKBlock))
771 rdb->rdb_HighRDSKBlock = PED_CPU_TO_BE32(block_num);
773 _amiga_calculate_checksum(AMIGA(rdb));
774 if (!ped_device_write (disk->dev, (void*) disk->disk_specific, rdb_num, 1))
775 goto error_free_table;
779 return ped_device_sync (disk->dev);
786 #endif /* !DISCOVER_ONLY */
789 amiga_partition_new (const PedDisk* disk, PedPartitionType part_type,
790 const PedFileSystemType* fs_type,
791 PedSector start, PedSector end)
796 struct PartitionBlock *partition;
797 struct RigidDiskBlock *rdb;
799 PED_ASSERT(disk != NULL, return NULL);
800 PED_ASSERT(disk->dev != NULL, return NULL);
801 PED_ASSERT(disk->disk_specific != NULL, return NULL);
803 cyl = (PedSector) (dev->hw_geom.sectors * dev->hw_geom.heads);
804 rdb = RDSK(disk->disk_specific);
806 if (!(part = _ped_partition_alloc (disk, part_type, fs_type, start, end)))
809 if (ped_partition_is_active (part)) {
810 if (!(part->disk_specific = ped_malloc (disk->dev->sector_size))) {
814 partition = PART(part->disk_specific);
815 memset(partition, 0, sizeof(struct PartitionBlock));
817 partition->pb_ID = PED_CPU_TO_BE32(IDNAME_PARTITION);
818 partition->pb_SummedLongs = PED_CPU_TO_BE32(64);
819 partition->pb_HostID = rdb->rdb_HostID;
820 partition->pb_Flags = PED_CPU_TO_BE32(0);
821 /* TODO : use a scheme including the device name and the
822 * partition number, if it is possible */
823 _amiga_set_bstr("dhx", partition->pb_DriveName, 32);
825 partition->de_TableSize = PED_CPU_TO_BE32(19);
826 partition->de_SizeBlock = PED_CPU_TO_BE32(128);
827 partition->de_SecOrg = PED_CPU_TO_BE32(0);
828 partition->de_Surfaces = PED_CPU_TO_BE32(dev->hw_geom.heads);
829 partition->de_SectorPerBlock = PED_CPU_TO_BE32(1);
830 partition->de_BlocksPerTrack
831 = PED_CPU_TO_BE32(dev->hw_geom.sectors);
832 partition->de_Reserved = PED_CPU_TO_BE32(2);
833 partition->de_PreAlloc = PED_CPU_TO_BE32(0);
834 partition->de_Interleave = PED_CPU_TO_BE32(0);
835 partition->de_LowCyl = PED_CPU_TO_BE32(start/cyl);
836 partition->de_HighCyl = PED_CPU_TO_BE32((end+1)/cyl-1);
837 partition->de_NumBuffers = PED_CPU_TO_BE32(30);
838 partition->de_BufMemType = PED_CPU_TO_BE32(0);
839 partition->de_MaxTransfer = PED_CPU_TO_BE32(0x7fffffff);
840 partition->de_Mask = PED_CPU_TO_BE32(0xffffffff);
841 partition->de_BootPri = PED_CPU_TO_BE32(0);
842 partition->de_DosType = PED_CPU_TO_BE32(0x4c4e5800);
843 partition->de_Baud = PED_CPU_TO_BE32(0);
844 partition->de_Control = PED_CPU_TO_BE32(0);
845 partition->de_BootBlocks = PED_CPU_TO_BE32(0);
848 part->disk_specific = NULL;
854 amiga_partition_duplicate (const PedPartition* part)
856 PedPartition *new_part;
857 struct PartitionBlock *new_amiga_part;
858 struct PartitionBlock *old_amiga_part;
860 PED_ASSERT(part != NULL, return NULL);
861 PED_ASSERT(part->disk != NULL, return NULL);
862 PED_ASSERT(part->disk_specific != NULL, return NULL);
863 old_amiga_part = (struct PartitionBlock *) part->disk_specific;
865 new_part = ped_partition_new (part->disk, part->type,
866 part->fs_type, part->geom.start,
871 new_amiga_part = (struct PartitionBlock *) new_part->disk_specific;
872 memcpy (new_amiga_part, old_amiga_part, 256);
878 amiga_partition_destroy (PedPartition* part)
880 PED_ASSERT (part != NULL, return);
882 if (ped_partition_is_active (part)) {
883 PED_ASSERT (part->disk_specific != NULL, return);
884 free (part->disk_specific);
886 _ped_partition_free (part);
890 amiga_partition_set_system (PedPartition* part,
891 const PedFileSystemType* fs_type)
893 struct PartitionBlock *partition;
895 PED_ASSERT (part != NULL, return 0);
896 PED_ASSERT (part->disk_specific != NULL, return 0);
897 partition = PART(part->disk_specific);
899 part->fs_type = fs_type;
902 partition->de_DosType = PED_CPU_TO_BE32(0x4c4e5800); /* 'LNX\0' */
903 else if (!strcmp (fs_type->name, "ext2"))
904 partition->de_DosType = PED_CPU_TO_BE32(0x4c4e5800); /* 'LNX\0' */
905 else if (!strcmp (fs_type->name, "ext3"))
906 partition->de_DosType = PED_CPU_TO_BE32(0x45585403); /* 'EXT\3' */
907 else if (is_linux_swap (fs_type->name))
908 partition->de_DosType = PED_CPU_TO_BE32(0x53575000); /* 'SWP\0' */
909 else if (!strcmp (fs_type->name, "fat16"))
910 partition->de_DosType = PED_CPU_TO_BE32(0x46415400); /* 'FAT\0' */
911 else if (!strcmp (fs_type->name, "fat32"))
912 partition->de_DosType = PED_CPU_TO_BE32(0x46415401); /* 'FAT\1'*/
913 else if (!strcmp (fs_type->name, "hfs"))
914 partition->de_DosType = PED_CPU_TO_BE32(0x48465300); /* 'HFS\0' */
915 else if (!strcmp (fs_type->name, "jfs"))
916 partition->de_DosType = PED_CPU_TO_BE32(0x4a465300); /* 'JFS\0' */
917 else if (!strcmp (fs_type->name, "ntfs"))
918 partition->de_DosType = PED_CPU_TO_BE32(0x4e544653); /* 'NTFS' */
919 else if (!strcmp (fs_type->name, "reiserfs"))
920 partition->de_DosType = PED_CPU_TO_BE32(0x52465300); /* 'RFS\0' */
921 else if (!strcmp (fs_type->name, "sun-ufs"))
922 partition->de_DosType = PED_CPU_TO_BE32(0x53554653); /* 'SUFS' */
923 else if (!strcmp (fs_type->name, "hp-ufs"))
924 partition->de_DosType = PED_CPU_TO_BE32(0x48554653); /* 'HUFS' */
925 else if (!strcmp (fs_type->name, "xfs"))
926 partition->de_DosType = PED_CPU_TO_BE32(0x58465300); /* 'XFS\0' */
928 partition->de_DosType = PED_CPU_TO_BE32(0x00000000); /* unknown */
933 amiga_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
935 struct PartitionBlock *partition;
937 PED_ASSERT (part != NULL, return 0);
938 PED_ASSERT (part->disk_specific != NULL, return 0);
940 partition = PART(part->disk_specific);
943 case PED_PARTITION_BOOT:
944 if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_BOOTABLE);
945 else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_BOOTABLE));
947 case PED_PARTITION_HIDDEN:
948 if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_NOMOUNT);
949 else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_NOMOUNT));
951 case PED_PARTITION_RAID:
952 if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_RAID);
953 else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_RAID));
955 case PED_PARTITION_LVM:
956 if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_LVM);
957 else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_LVM));
965 amiga_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
967 struct PartitionBlock *partition;
969 PED_ASSERT (part != NULL, return 0);
970 PED_ASSERT (part->disk_specific != NULL, return 0);
972 partition = PART(part->disk_specific);
975 case PED_PARTITION_BOOT:
976 return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_BOOTABLE));
977 case PED_PARTITION_HIDDEN:
978 return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_NOMOUNT));
979 case PED_PARTITION_RAID:
980 return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_RAID));
981 case PED_PARTITION_LVM:
982 return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_LVM));
989 amiga_partition_is_flag_available (const PedPartition* part,
990 PedPartitionFlag flag)
993 case PED_PARTITION_BOOT:
994 case PED_PARTITION_HIDDEN:
995 case PED_PARTITION_RAID:
996 case PED_PARTITION_LVM:
1004 amiga_partition_set_name (PedPartition* part, const char* name)
1006 struct PartitionBlock *partition;
1008 PED_ASSERT (part != NULL, return);
1009 PED_ASSERT (part->disk_specific != NULL, return);
1011 partition = PART(part->disk_specific);
1012 _amiga_set_bstr(name, partition->pb_DriveName, 32);
1015 amiga_partition_get_name (const PedPartition* part)
1017 struct PartitionBlock *partition;
1019 PED_ASSERT (part != NULL, return 0);
1020 PED_ASSERT (part->disk_specific != NULL, return 0);
1022 partition = PART(part->disk_specific);
1024 return _amiga_get_bstr(partition->pb_DriveName);
1027 static PedConstraint*
1028 _amiga_get_constraint (const PedDisk *disk)
1030 PedDevice *dev = disk->dev;
1031 PedAlignment start_align, end_align;
1032 PedGeometry max_geom;
1033 PedSector cyl_size = dev->hw_geom.sectors * dev->hw_geom.heads;
1035 if (!ped_alignment_init(&start_align, 0, cyl_size))
1037 if (!ped_alignment_init(&end_align, -1, cyl_size))
1039 if (!ped_geometry_init(&max_geom, dev, MAX_RDB_BLOCK + 1,
1040 dev->length - MAX_RDB_BLOCK - 1))
1043 return ped_constraint_new (&start_align, &end_align,
1044 &max_geom, &max_geom, 1, dev->length);
1048 amiga_partition_align (PedPartition* part, const PedConstraint* constraint)
1050 PED_ASSERT (part != NULL, return 0);
1051 PED_ASSERT (part->disk != NULL, return 0);
1053 if (_ped_partition_attempt_align (part, constraint,
1054 _amiga_get_constraint (part->disk)))
1057 #ifndef DISCOVER_ONLY
1058 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1059 _("Unable to satisfy all constraints on the partition."));
1065 amiga_partition_enumerate (PedPartition* part)
1070 PED_ASSERT (part != NULL, return 0);
1071 PED_ASSERT (part->disk != NULL, return 0);
1073 /* never change the partition numbers */
1074 if (part->num != -1)
1076 for (i = 1; i <= AMIGA_MAX_PARTITIONS; i++) {
1077 p = ped_disk_get_partition (part->disk, i);
1084 /* failed to allocate a number */
1085 #ifndef DISCOVER_ONLY
1086 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1087 _("Unable to allocate a partition number."));
1093 amiga_alloc_metadata (PedDisk* disk)
1095 PedPartition* new_part;
1096 PedConstraint* constraint_any = NULL;
1098 PED_ASSERT (disk != NULL, goto error);
1099 PED_ASSERT (disk->dev != NULL, goto error);
1101 constraint_any = ped_constraint_any (disk->dev);
1103 /* Allocate space for the RDB */
1104 new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1109 if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
1110 ped_partition_destroy (new_part);
1114 ped_constraint_destroy (constraint_any);
1117 ped_constraint_destroy (constraint_any);
1122 amiga_get_max_primary_partition_count (const PedDisk* disk)
1124 return AMIGA_MAX_PARTITIONS;
1128 amiga_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
1130 *max_n = AMIGA_MAX_PARTITIONS;
1134 static PedDiskOps amiga_disk_ops = {
1136 #ifndef DISCOVER_ONLY
1137 clobber: amiga_clobber,
1142 duplicate: amiga_duplicate,
1145 #ifndef DISCOVER_ONLY
1151 partition_new: amiga_partition_new,
1152 partition_duplicate: amiga_partition_duplicate,
1153 partition_destroy: amiga_partition_destroy,
1154 partition_set_system: amiga_partition_set_system,
1155 partition_set_flag: amiga_partition_set_flag,
1156 partition_get_flag: amiga_partition_get_flag,
1157 partition_is_flag_available:
1158 amiga_partition_is_flag_available,
1159 partition_set_name: amiga_partition_set_name,
1160 partition_get_name: amiga_partition_get_name,
1161 partition_align: amiga_partition_align,
1162 partition_enumerate: amiga_partition_enumerate,
1165 alloc_metadata: amiga_alloc_metadata,
1166 get_max_primary_partition_count:
1167 amiga_get_max_primary_partition_count,
1168 get_max_supported_partition_count:
1169 amiga_get_max_supported_partition_count
1172 static PedDiskType amiga_disk_type = {
1175 ops: &amiga_disk_ops,
1176 features: PED_DISK_TYPE_PARTITION_NAME
1180 ped_disk_amiga_init ()
1182 PED_ASSERT (sizeof (struct AmigaBlock) != 3, return);
1183 PED_ASSERT (sizeof (struct RigidDiskBlock) != 64, return);
1184 PED_ASSERT (sizeof (struct PartitionBlock) != 64, return);
1185 PED_ASSERT (sizeof (struct LinkedBlock) != 5, return);
1186 PED_ASSERT (sizeof (struct Linked2Block) != 18, return);
1188 ped_disk_type_register (&amiga_disk_type);
1192 ped_disk_amiga_done ()
1194 ped_disk_type_unregister (&amiga_disk_type);