1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
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 Free Software Foundation, Inc.
6
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.
11
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.
16
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/>.
19
20 Contributor: Sven Luther <luther@debian.org>
21 */
22
23 #include <config.h>
24
25 #include <parted/parted.h>
26 #include <parted/debug.h>
27 #include <parted/endian.h>
28
29 #ifndef MAX
30 # define MAX(a,b) ((a) < (b) ? (b) : (a))
31 #endif
32
33 #if ENABLE_NLS
34 # include <libintl.h>
35 # define _(String) dgettext (PACKAGE, String)
36 #else
37 # define _(String) (String)
38 #endif /* ENABLE_NLS */
39
40 /* String manipulation */
41 static void _amiga_set_bstr (const char *cstr, char *bstr, int maxsize) {
42 int size = strlen (cstr);
43 int i;
44
45 if (size >= maxsize) return;
46 bstr[0] = size;
47 for (i = 0; i<size; i++) bstr[i+1] = cstr[i];
48 }
49 static const char * _amiga_get_bstr (char * bstr) {
50 char * cstr = bstr + 1;
51 int size = bstr[0];
52
53 cstr[size] = '\0';
54 return cstr;
55 }
56
57 #define IDNAME_RIGIDDISK (uint32_t)0x5244534B /* 'RDSK' */
58 #define IDNAME_BADBLOCK (uint32_t)0x42414442 /* 'BADB' */
59 #define IDNAME_PARTITION (uint32_t)0x50415254 /* 'PART' */
60 #define IDNAME_FILESYSHEADER (uint32_t)0x46534844 /* 'FSHD' */
61 #define IDNAME_LOADSEG (uint32_t)0x4C534547 /* 'LSEG' */
62 #define IDNAME_BOOT (uint32_t)0x424f4f54 /* 'BOOT' */
63 #define IDNAME_FREE (uint32_t)0xffffffff
64
65 static const char *
66 _amiga_block_id (uint32_t id) {
67 switch (id) {
68 case IDNAME_RIGIDDISK :
69 return "RDSK";
70 case IDNAME_BADBLOCK :
71 return "BADB";
72 case IDNAME_PARTITION :
73 return "PART";
74 case IDNAME_FILESYSHEADER :
75 return "FSHD";
76 case IDNAME_LOADSEG :
77 return "LSEG";
78 case IDNAME_BOOT :
79 return "BOOT";
80 case IDNAME_FREE :
81 return "<free>";
82 default :
83 return "<unknown>";
84 }
85 }
86
87 struct AmigaIds {
88 uint32_t ID;
89 struct AmigaIds *next;
90 };
91
92 static struct AmigaIds *
93 _amiga_add_id (uint32_t id, struct AmigaIds *ids) {
94 struct AmigaIds *newid;
95
96 if ((newid=ped_malloc(sizeof (struct AmigaIds)))==NULL)
97 return 0;
98 newid->ID = id;
99 newid->next = ids;
100 return newid;
101 }
102
103 static void
104 _amiga_free_ids (struct AmigaIds *ids) {
105 struct AmigaIds *current, *next;
106
107 for (current = ids; current != NULL; current = next) {
108 next = current->next;
109 ped_free (current);
110 }
111 }
112 static int
113 _amiga_id_in_list (uint32_t id, struct AmigaIds *ids) {
114 struct AmigaIds *current;
115
116 for (current = ids; current != NULL; current = current->next) {
117 if (id == current->ID)
118 return 1;
119 }
120 return 0;
121 }
122
123 struct AmigaBlock {
124 uint32_t amiga_ID; /* Identifier 32 bit word */
125 uint32_t amiga_SummedLongss; /* Size of the structure for checksums */
126 int32_t amiga_ChkSum; /* Checksum of the structure */
127 };
128 #define AMIGA(pos) ((struct AmigaBlock *)(pos))
129
130 static int
131 _amiga_checksum (struct AmigaBlock *blk) {
132 uint32_t *rdb = (uint32_t *) blk;
133 uint32_t sum;
134 int i, end;
135
136 sum = PED_BE32_TO_CPU (rdb[0]);
137 end = PED_BE32_TO_CPU (rdb[1]);
138
139 if (end > PED_SECTOR_SIZE_DEFAULT) end = PED_SECTOR_SIZE_DEFAULT;
140
141 for (i = 1; i < end; i++) sum += PED_BE32_TO_CPU (rdb[i]);
142
143 return sum;
144 }
145
146 static void
147 _amiga_calculate_checksum (struct AmigaBlock *blk) {
148 blk->amiga_ChkSum = PED_CPU_TO_BE32(
149 PED_BE32_TO_CPU(blk->amiga_ChkSum) -
150 _amiga_checksum((struct AmigaBlock *) blk));
151 return;
152 }
153
154 static struct AmigaBlock *
155 _amiga_read_block (const PedDevice *dev, struct AmigaBlock *blk,
156 PedSector block, struct AmigaIds *ids)
157 {
158 if (!ped_device_read (dev, blk, block, 1))
159 return NULL;
160 if (ids && !_amiga_id_in_list(PED_BE32_TO_CPU(blk->amiga_ID), ids))
161 return NULL;
162 if (_amiga_checksum (blk) != 0) {
163 switch (ped_exception_throw(PED_EXCEPTION_ERROR,
164 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE | PED_EXCEPTION_CANCEL,
165 _("%s : Bad checksum on block %llu of type %s."),
166 __func__, block, _amiga_block_id(PED_BE32_TO_CPU(blk->amiga_ID))))
167 {
168 case PED_EXCEPTION_CANCEL :
169 return NULL;
170 case PED_EXCEPTION_FIX :
171 _amiga_calculate_checksum(AMIGA(blk));
172 if (!ped_device_write ((PedDevice*)dev, blk, block, 1))
173 return NULL;
174 case PED_EXCEPTION_IGNORE :
175 case PED_EXCEPTION_UNHANDLED :
176 default :
177 return blk;
178 }
179 }
180 return blk;
181 }
182
183 struct RigidDiskBlock {
184 uint32_t rdb_ID; /* Identifier 32 bit word : 'RDSK' */
185 uint32_t rdb_SummedLongs; /* Size of the structure for checksums */
186 int32_t rdb_ChkSum; /* Checksum of the structure */
187 uint32_t rdb_HostID; /* SCSI Target ID of host, not really used */
188 uint32_t rdb_BlockBytes; /* Size of disk blocks */
189 uint32_t rdb_Flags; /* RDB Flags */
190 /* block list heads */
191 uint32_t rdb_BadBlockList; /* Bad block list */
192 uint32_t rdb_PartitionList; /* Partition list */
193 uint32_t rdb_FileSysHeaderList; /* File system header list */
194 uint32_t rdb_DriveInit; /* Drive specific init code */
195 uint32_t rdb_BootBlockList; /* Amiga OS 4 Boot Blocks */
196 uint32_t rdb_Reserved1[5]; /* Unused word, need to be set to $ffffffff */
197 /* physical drive characteristics */
198 uint32_t rdb_Cylinders; /* Number of the cylinders of the drive */
199 uint32_t rdb_Sectors; /* Number of sectors of the drive */
200 uint32_t rdb_Heads; /* Number of heads of the drive */
201 uint32_t rdb_Interleave; /* Interleave */
202 uint32_t rdb_Park; /* Head parking cylinder */
203 uint32_t rdb_Reserved2[3]; /* Unused word, need to be set to $ffffffff */
204 uint32_t rdb_WritePreComp; /* Starting cylinder of write precompensation */
205 uint32_t rdb_ReducedWrite; /* Starting cylinder of reduced write current */
206 uint32_t rdb_StepRate; /* Step rate of the drive */
207 uint32_t rdb_Reserved3[5]; /* Unused word, need to be set to $ffffffff */
208 /* logical drive characteristics */
209 uint32_t rdb_RDBBlocksLo; /* low block of range reserved for hardblocks */
210 uint32_t rdb_RDBBlocksHi; /* high block of range for these hardblocks */
211 uint32_t rdb_LoCylinder; /* low cylinder of partitionable disk area */
212 uint32_t rdb_HiCylinder; /* high cylinder of partitionable data area */
213 uint32_t rdb_CylBlocks; /* number of blocks available per cylinder */
214 uint32_t rdb_AutoParkSeconds; /* zero for no auto park */
215 uint32_t rdb_HighRDSKBlock; /* highest block used by RDSK */
216 /* (not including replacement bad blocks) */
217 uint32_t rdb_Reserved4;
218 /* drive identification */
219 char rdb_DiskVendor[8];
220 char rdb_DiskProduct[16];
221 char rdb_DiskRevision[4];
222 char rdb_ControllerVendor[8];
223 char rdb_ControllerProduct[16];
224 char rdb_ControllerRevision[4];
225 uint32_t rdb_Reserved5[10];
226 };
227
228 #define RDSK(pos) ((struct RigidDiskBlock *)(pos))
229
230 #define AMIGA_RDB_NOT_FOUND ((uint32_t)0xffffffff)
231 #define RDB_LOCATION_LIMIT 16
232 #define AMIGA_MAX_PARTITIONS 128
233 #define MAX_RDB_BLOCK (RDB_LOCATION_LIMIT + 2 * AMIGA_MAX_PARTITIONS + 2)
234
235 static uint32_t
236 _amiga_find_rdb (const PedDevice *dev, struct RigidDiskBlock *rdb) {
237 int i;
238 struct AmigaIds *ids;
239
240 ids = _amiga_add_id (IDNAME_RIGIDDISK, NULL);
241
242 for (i = 0; i<RDB_LOCATION_LIMIT; i++) {
243 if (!_amiga_read_block (dev, AMIGA(rdb), i, ids)) {
244 continue;
245 }
246 if (PED_BE32_TO_CPU (rdb->rdb_ID) == IDNAME_RIGIDDISK) {
247 _amiga_free_ids (ids);
248 return i;
249 }
250 }
251 _amiga_free_ids (ids);
252 return AMIGA_RDB_NOT_FOUND;
253 }
254
255 struct PartitionBlock {
256 uint32_t pb_ID; /* Identifier 32 bit word : 'PART' */
257 uint32_t pb_SummedLongs; /* Size of the structure for checksums */
258 int32_t pb_ChkSum; /* Checksum of the structure */
259 uint32_t pb_HostID; /* SCSI Target ID of host, not really used */
260 uint32_t pb_Next; /* Block number of the next PartitionBlock */
261 uint32_t pb_Flags; /* Part Flags (NOMOUNT and BOOTABLE) */
262 uint32_t pb_Reserved1[2];
263 uint32_t pb_DevFlags; /* Preferred flags for OpenDevice */
264 char pb_DriveName[32]; /* Preferred DOS device name: BSTR form */
265 uint32_t pb_Reserved2[15];
266 uint32_t de_TableSize; /* Size of Environment vector */
267 /* Size of the blocks in 32 bit words, usually 128 */
268 uint32_t de_SizeBlock;
269 uint32_t de_SecOrg; /* Not used; must be 0 */
270 uint32_t de_Surfaces; /* Number of heads (surfaces) */
271 /* Disk sectors per block, used with SizeBlock, usually 1 */
272 uint32_t de_SectorPerBlock;
273 uint32_t de_BlocksPerTrack; /* Blocks per track. drive specific */
274 uint32_t de_Reserved; /* DOS reserved blocks at start of partition. */
275 uint32_t de_PreAlloc; /* DOS reserved blocks at end of partition */
276 uint32_t de_Interleave; /* Not used, usually 0 */
277 uint32_t de_LowCyl; /* First cylinder of the partition */
278 uint32_t de_HighCyl; /* Last cylinder of the partition */
279 uint32_t de_NumBuffers; /* Initial # DOS of buffers. */
280 uint32_t de_BufMemType; /* Type of mem to allocate for buffers */
281 uint32_t de_MaxTransfer; /* Max number of bytes to transfer at a time */
282 uint32_t de_Mask; /* Address Mask to block out certain memory */
283 int32_t de_BootPri; /* Boot priority for autoboot */
284 uint32_t de_DosType; /* Dostype of the file system */
285 uint32_t de_Baud; /* Baud rate for serial handler */
286 uint32_t de_Control; /* Control word for handler/filesystem */
287 uint32_t de_BootBlocks; /* Number of blocks containing boot code */
288 uint32_t pb_EReserved[12];
289 };
290
291 #define PART(pos) ((struct PartitionBlock *)(pos))
292
293 #define PBFB_BOOTABLE 0 /* this partition is intended to be bootable */
294 #define PBFF_BOOTABLE 1L /* (expected directories and files exist) */
295 #define PBFB_NOMOUNT 1 /* do not mount this partition (e.g. manually */
296 #define PBFF_NOMOUNT 2L /* mounted, but space reserved here) */
297 #define PBFB_RAID 2 /* this partition is intended to be part of */
298 #define PBFF_RAID 4L /* a RAID array */
299 #define PBFB_LVM 3 /* this partition is intended to be part of */
300 #define PBFF_LVM 8L /* a LVM volume group */
301
302
303 struct LinkedBlock {
304 uint32_t lk_ID; /* Identifier 32 bit word */
305 uint32_t lk_SummedLongs; /* Size of the structure for checksums */
306 int32_t lk_ChkSum; /* Checksum of the structure */
307 uint32_t pb_HostID; /* SCSI Target ID of host, not really used */
308 uint32_t lk_Next; /* Block number of the next PartitionBlock */
309 };
310 struct Linked2Block {
311 uint32_t lk2_ID; /* Identifier 32 bit word */
312 uint32_t lk2_SummedLongs; /* Size of the structure for checksums */
313 int32_t lk2_ChkSum; /* Checksum of the structure */
314 uint32_t lk2_HostID; /* SCSI Target ID of host, not really used */
315 uint32_t lk2_Next; /* Block number of the next PartitionBlock */
316 uint32_t lk2_Reverved[13];
317 uint32_t lk2_Linked; /* Secondary linked list */
318 };
319 #define LINK_END (uint32_t)0xffffffff
320 #define LNK(pos) ((struct LinkedBlock *)(pos))
321 #define LNK2(pos) ((struct Linked2Block *)(pos))
322
323
324 static PedDiskType amiga_disk_type;
325
326 static int
327 amiga_probe (const PedDevice *dev)
328 {
329 struct RigidDiskBlock *rdb;
330 uint32_t found;
331 PED_ASSERT(dev != NULL, return 0);
332
333 if ((rdb=RDSK(ped_malloc(dev->sector_size)))==NULL)
334 return 0;
335 found = _amiga_find_rdb (dev, rdb);
336 ped_free (rdb);
337
338 return (found == AMIGA_RDB_NOT_FOUND ? 0 : 1);
339 }
340
341 static PedDisk*
342 amiga_alloc (const PedDevice* dev)
343 {
344 PedDisk *disk;
345 struct RigidDiskBlock *rdb;
346 PedSector cyl_size;
347 int highest_cylinder, highest_block;
348
349 PED_ASSERT(dev != NULL, return NULL);
350 cyl_size = dev->hw_geom.sectors * dev->hw_geom.heads;
351
352 if (!(disk = _ped_disk_alloc (dev, &amiga_disk_type)))
353 return NULL;
354
355 if (!(disk->disk_specific = ped_malloc (PED_SECTOR_SIZE_DEFAULT))) {
356 ped_free (disk);
357 return NULL;
358 }
359 rdb = disk->disk_specific;
360
361 memset(rdb, 0, sizeof(struct RigidDiskBlock));
362
363 rdb->rdb_ID = PED_CPU_TO_BE32 (IDNAME_RIGIDDISK);
364 rdb->rdb_SummedLongs = PED_CPU_TO_BE32 (64);
365 rdb->rdb_HostID = PED_CPU_TO_BE32 (0);
366 rdb->rdb_BlockBytes = PED_CPU_TO_BE32 (PED_SECTOR_SIZE_DEFAULT);
367 rdb->rdb_Flags = PED_CPU_TO_BE32 (0);
368
369 /* Block lists */
370 rdb->rdb_BadBlockList = PED_CPU_TO_BE32 (LINK_END);
371 rdb->rdb_PartitionList = PED_CPU_TO_BE32 (LINK_END);
372 rdb->rdb_FileSysHeaderList = PED_CPU_TO_BE32 (LINK_END);
373 rdb->rdb_DriveInit = PED_CPU_TO_BE32 (LINK_END);
374 rdb->rdb_BootBlockList = PED_CPU_TO_BE32 (LINK_END);
375
376 /* Physical drive characteristics */
377 rdb->rdb_Cylinders = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
378 rdb->rdb_Sectors = PED_CPU_TO_BE32 (dev->hw_geom.sectors);
379 rdb->rdb_Heads = PED_CPU_TO_BE32 (dev->hw_geom.heads);
380 rdb->rdb_Interleave = PED_CPU_TO_BE32 (0);
381 rdb->rdb_Park = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
382 rdb->rdb_WritePreComp = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
383 rdb->rdb_ReducedWrite = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
384 rdb->rdb_StepRate = PED_CPU_TO_BE32 (0);
385
386 highest_cylinder = 1 + MAX_RDB_BLOCK / cyl_size;
387 highest_block = highest_cylinder * cyl_size - 1;
388
389 /* Logical driver characteristics */
390 rdb->rdb_RDBBlocksLo = PED_CPU_TO_BE32 (0);
391 rdb->rdb_RDBBlocksHi = PED_CPU_TO_BE32 (highest_block);
392 rdb->rdb_LoCylinder = PED_CPU_TO_BE32 (highest_cylinder);
393 rdb->rdb_HiCylinder = PED_CPU_TO_BE32 (dev->hw_geom.cylinders -1);
394 rdb->rdb_CylBlocks = PED_CPU_TO_BE32 (cyl_size);
395 rdb->rdb_AutoParkSeconds = PED_CPU_TO_BE32 (0);
396 /* rdb_HighRDSKBlock will only be set when writing */
397 rdb->rdb_HighRDSKBlock = PED_CPU_TO_BE32 (0);
398
399 /* Driver identification */
400 _amiga_set_bstr("", rdb->rdb_DiskVendor, 8);
401 _amiga_set_bstr(dev->model, rdb->rdb_DiskProduct, 16);
402 _amiga_set_bstr("", rdb->rdb_DiskRevision, 4);
403 _amiga_set_bstr("", rdb->rdb_ControllerVendor, 8);
404 _amiga_set_bstr("", rdb->rdb_ControllerProduct, 16);
405 _amiga_set_bstr("", rdb->rdb_ControllerRevision, 4);
406
407 /* And calculate the checksum */
408 _amiga_calculate_checksum ((struct AmigaBlock *) rdb);
409
410 return disk;
411 }
412
413 static PedDisk*
414 amiga_duplicate (const PedDisk* disk)
415 {
416 PedDisk* new_disk;
417 struct RigidDiskBlock * new_rdb;
418 struct RigidDiskBlock * old_rdb;
419 PED_ASSERT(disk != NULL, return NULL);
420 PED_ASSERT(disk->dev != NULL, return NULL);
421 PED_ASSERT(disk->disk_specific != NULL, return NULL);
422
423 old_rdb = (struct RigidDiskBlock *) disk->disk_specific;
424
425 if (!(new_disk = ped_disk_new_fresh (disk->dev, &amiga_disk_type)))
426 return NULL;
427
428 new_rdb = (struct RigidDiskBlock *) new_disk->disk_specific;
429 memcpy (new_rdb, old_rdb, 256);
430 return new_disk;
431 }
432
433 static void
434 amiga_free (PedDisk* disk)
435 {
436 PED_ASSERT(disk != NULL, return);
437 PED_ASSERT(disk->disk_specific != NULL, return);
438
439 ped_free (disk->disk_specific);
440 _ped_disk_free (disk);
441 }
442
443 #ifndef DISCOVER_ONLY
444 static int
445 amiga_clobber (PedDevice* dev)
446 {
447 struct RigidDiskBlock *rdb;
448 uint32_t i;
449 int result = 0;
450 PED_ASSERT(dev != NULL, return 0);
451
452 if ((rdb=RDSK(ped_malloc(PED_SECTOR_SIZE_DEFAULT)))==NULL)
453 return 0;
454
455 while ((i = _amiga_find_rdb (dev, rdb)) != AMIGA_RDB_NOT_FOUND) {
456 rdb->rdb_ID = PED_CPU_TO_BE32 (0);
457 result = ped_device_write (dev, (void*) rdb, i, 1);
458 }
459
460 ped_free (rdb);
461
462 return result;
463 }
464 #endif /* !DISCOVER_ONLY */
465
466 static int
467 _amiga_loop_check (uint32_t block, uint32_t * blocklist, uint32_t max)
468 {
469 uint32_t i;
470
471 for (i = 0; i < max; i++)
472 if (block == blocklist[i]) {
473 /* We are looping, let's stop. */
474 return 1;
475 }
476 blocklist[max] = block;
477 return 0;
478 }
479
480 /* We have already allocated a rdb, we are now reading it from the disk */
481 static int
482 amiga_read (PedDisk* disk)
483 {
484 struct RigidDiskBlock *rdb;
485 struct PartitionBlock *partition;
486 uint32_t partblock;
487 uint32_t partlist[AMIGA_MAX_PARTITIONS];
488 PedSector cylblocks;
489 int i;
490
491 PED_ASSERT(disk != NULL, return 0);
492 PED_ASSERT(disk->dev != NULL, return 0);
493 PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0,
494 return 0);
495 PED_ASSERT(disk->disk_specific != NULL, return 0);
496 rdb = RDSK(disk->disk_specific);
497
498 if (_amiga_find_rdb (disk->dev, rdb) == AMIGA_RDB_NOT_FOUND) {
499 ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
500 _("%s : Didn't find rdb block, should never happen."), __func__);
501 return 0;
502 }
503
504 /* Let's copy the rdb read geometry to the dev */
505 /* FIXME: should this go into disk->dev->bios_geom instead? */
506 disk->dev->hw_geom.cylinders = PED_BE32_TO_CPU (rdb->rdb_Cylinders);
507 disk->dev->hw_geom.heads = PED_BE32_TO_CPU (rdb->rdb_Heads);
508 disk->dev->hw_geom.sectors = PED_BE32_TO_CPU (rdb->rdb_Sectors);
509 cylblocks = (PedSector) PED_BE32_TO_CPU (rdb->rdb_Heads) *
510 (PedSector) PED_BE32_TO_CPU (rdb->rdb_Sectors);
511
512 /* Remove all partitions in the former in memory table */
513 ped_disk_delete_all (disk);
514
515 /* Let's allocate a partition block */
516 if (!(partition = ped_malloc (disk->dev->sector_size)))
517 return 0;
518
519 /* We initialize the hardblock free list to detect loops */
520 for (i = 0; i < AMIGA_MAX_PARTITIONS; i++) partlist[i] = LINK_END;
521
522 for (i = 1, partblock = PED_BE32_TO_CPU(rdb->rdb_PartitionList);
523 i < AMIGA_MAX_PARTITIONS && partblock != LINK_END;
524 i++, partblock = PED_BE32_TO_CPU(partition->pb_Next))
525 {
526 PedPartition *part;
527 PedSector start, end;
528 PedConstraint *constraint_exact;
529
530 /* Let's look for loops in the partition table */
531 if (_amiga_loop_check(partblock, partlist, i)) {
532 break;
533 }
534
535 /* Let's allocate and read a partition block to get its geometry*/
536 if (!_amiga_read_block (disk->dev, AMIGA(partition),
537 (PedSector)partblock, NULL)) {
538 ped_free(partition);
539 return 0;
540 }
541
542 start = ((PedSector) PED_BE32_TO_CPU (partition->de_LowCyl))
543 * cylblocks;
544 end = (((PedSector) PED_BE32_TO_CPU (partition->de_HighCyl))
545 + 1) * cylblocks - 1;
546
547 /* We can now construct a new partition */
548 if (!(part = ped_partition_new (disk, 0, NULL, start, end))) {
549 ped_free(partition);
550 return 0;
551 }
552 /* And copy over the partition block */
553 memcpy(part->disk_specific, partition, 256);
554
555 part->num = i;
556 part->type = 0;
557 /* Let's probe what file system is present on the disk */
558 part->fs_type = ped_file_system_probe (&part->geom);
559
560 constraint_exact = ped_constraint_exact (&part->geom);
561 if (!ped_disk_add_partition (disk, part, constraint_exact)) {
562 ped_partition_destroy(part);
563 ped_free(partition);
564 return 0;
565 }
566 ped_constraint_destroy (constraint_exact);
567 }
568 ped_free(partition);
569 return 1;
570 }
571
572 static int
573 _amiga_find_free_blocks(const PedDisk *disk, uint32_t *table,
574 struct LinkedBlock *block, uint32_t first, uint32_t type)
575 {
576 PedSector next;
577
578 PED_ASSERT(disk != NULL, return 0);
579 PED_ASSERT(disk->dev != NULL, return 0);
580
581 for (next = first; next != LINK_END; next = PED_BE32_TO_CPU(block->lk_Next)) {
582 if (table[next] != IDNAME_FREE) {
583 switch (ped_exception_throw(PED_EXCEPTION_ERROR,
584 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE | PED_EXCEPTION_CANCEL,
585 _("%s : Loop detected at block %d."), __func__, next))
586 {
587 case PED_EXCEPTION_CANCEL :
588 return 0;
589 case PED_EXCEPTION_FIX :
590 /* TODO : Need to add fixing code */
591 case PED_EXCEPTION_IGNORE :
592 case PED_EXCEPTION_UNHANDLED :
593 default :
594 return 1;
595 }
596 }
597
598 if (!_amiga_read_block (disk->dev, AMIGA(block), next, NULL)) {
599 return 0;
600 }
601 if (PED_BE32_TO_CPU(block->lk_ID) != type) {
602 switch (ped_exception_throw(PED_EXCEPTION_ERROR,
603 PED_EXCEPTION_CANCEL,
604 _("%s : The %s list seems bad at block %s."),
605 __func__, _amiga_block_id(PED_BE32_TO_CPU(block->lk_ID)), next))
606 {
607 /* TODO : to more subtile things here */
608 case PED_EXCEPTION_CANCEL :
609 case PED_EXCEPTION_UNHANDLED :
610 default :
611 return 0;
612 }
613 }
614 table[next] = type;
615 if (PED_BE32_TO_CPU(block->lk_ID) == IDNAME_FILESYSHEADER) {
616 if (_amiga_find_free_blocks(disk, table, block,
617 PED_BE32_TO_CPU(LNK2(block)->lk2_Linked),
618 IDNAME_LOADSEG) == 0) return 0;
619 }
620 }
621 return 1;
622 }
623 static uint32_t
624 _amiga_next_free_block(uint32_t *table, uint32_t start, uint32_t type) {
625 int i;
626
627 for (i = start; table[i] != type && table[i] != IDNAME_FREE; i++);
628 return i;
629 }
630 static PedPartition *
631 _amiga_next_real_partition(const PedDisk *disk, PedPartition *part) {
632 PedPartition *next;
633
634 for (next = ped_disk_next_partition (disk, part);
635 next != NULL && !ped_partition_is_active (next);
636 next = ped_disk_next_partition (disk, next));
637 return next;
638 }
639 #ifndef DISCOVER_ONLY
640 static int
641 amiga_write (const PedDisk* disk)
642 {
643 struct RigidDiskBlock *rdb;
644 struct LinkedBlock *block;
645 struct PartitionBlock *partition;
646 PedPartition *part, *next_part;
647 PedSector cylblocks, first_hb, last_hb, last_used_hb;
648 uint32_t * table;
649 uint32_t i;
650 uint32_t rdb_num, part_num, block_num, next_num;
651
652 PED_ASSERT (disk != NULL, return 0);
653 PED_ASSERT (disk->dev != NULL, return 0);
654 PED_ASSERT (disk->disk_specific != NULL, return 0);
655
656 if (!(rdb = ped_malloc (PED_SECTOR_SIZE_DEFAULT)))
657 return 0;
658
659 /* Let's read the rdb */
660 if ((rdb_num = _amiga_find_rdb (disk->dev, rdb)) == AMIGA_RDB_NOT_FOUND) {
661 rdb_num = 2;
662 size_t pb_size = sizeof (struct PartitionBlock);
663 /* Initialize only the part that won't be copied over
664 with a partition block in amiga_read. */
665 memset ((char *)(RDSK(disk->disk_specific)) + pb_size,
666 0, PED_SECTOR_SIZE_DEFAULT - pb_size);
667 } else {
668 memcpy (RDSK(disk->disk_specific), rdb, PED_SECTOR_SIZE_DEFAULT);
669 }
670 ped_free (rdb);
671 rdb = RDSK(disk->disk_specific);
672
673 cylblocks = (PedSector) PED_BE32_TO_CPU (rdb->rdb_Heads) *
674 (PedSector) PED_BE32_TO_CPU (rdb->rdb_Sectors);
675 first_hb = (PedSector) PED_BE32_TO_CPU (rdb->rdb_RDBBlocksLo);
676 last_hb = (PedSector) PED_BE32_TO_CPU (rdb->rdb_RDBBlocksHi);
677 last_used_hb = (PedSector) PED_BE32_TO_CPU (rdb->rdb_HighRDSKBlock);
678
679 /* Allocate a free block table and initialize it.
680 There must be room for at least RDB_NUM + 2 entries, since
681 the first RDB_NUM+1 entries get IDNAME_RIGIDDISK, and the
682 following one must have LINK_END to serve as sentinel. */
683 size_t tab_size = 2 + MAX (last_hb - first_hb, rdb_num);
684 if (!(table = ped_malloc (tab_size * sizeof *table)))
685 return 0;
686
687 for (i = 0; i <= rdb_num; i++)
688 table[i] = IDNAME_RIGIDDISK;
689 for ( ; i < tab_size; i++)
690 table[i] = LINK_END;
691
692 /* Let's allocate a partition block */
693 if (!(block = ped_malloc (PED_SECTOR_SIZE_DEFAULT))) {
694 ped_free (table);
695 return 0;
696 }
697
698 /* And fill the free block table */
699 if (_amiga_find_free_blocks(disk, table, block,
700 PED_BE32_TO_CPU (rdb->rdb_BadBlockList), IDNAME_BADBLOCK) == 0)
701 {
702 ped_exception_throw(PED_EXCEPTION_ERROR,
703 PED_EXCEPTION_CANCEL,
704 _("%s : Failed to list bad blocks."), __func__);
705 goto error_free_table;
706 }
707 if (_amiga_find_free_blocks(disk, table, block,
708 PED_BE32_TO_CPU (rdb->rdb_PartitionList), IDNAME_PARTITION) == 0)
709 {
710 ped_exception_throw(PED_EXCEPTION_ERROR,
711 PED_EXCEPTION_CANCEL,
712 _("%s : Failed to list partition blocks."), __func__);
713 goto error_free_table;
714 }
715 if (_amiga_find_free_blocks(disk, table, block,
716 PED_BE32_TO_CPU (rdb->rdb_FileSysHeaderList), IDNAME_FILESYSHEADER) == 0)
717 {
718 ped_exception_throw(PED_EXCEPTION_ERROR,
719 PED_EXCEPTION_CANCEL,
720 _("%s : Failed to list file system blocks."), __func__);
721 goto error_free_table;
722 }
723 if (_amiga_find_free_blocks(disk, table, block,
724 PED_BE32_TO_CPU (rdb->rdb_BootBlockList), IDNAME_BOOT) == 0)
725 {
726 ped_exception_throw(PED_EXCEPTION_ERROR,
727 PED_EXCEPTION_CANCEL,
728 _("%s : Failed to list boot blocks."), __func__);
729 goto error_free_table;
730 }
731
732 block_num = next_num = part_num = _amiga_next_free_block(table, rdb_num+1,
733 IDNAME_PARTITION);
734 part = _amiga_next_real_partition(disk, NULL);
735 rdb->rdb_PartitionList = PED_CPU_TO_BE32(part ? part_num : LINK_END);
736 for (; part != NULL; part = next_part, block_num = next_num) {
737 PED_ASSERT(part->disk_specific != NULL, return 0);
738 PED_ASSERT(part->geom.start % cylblocks == 0, return 0);
739 PED_ASSERT((part->geom.end + 1) % cylblocks == 0, return 0);
740
741 next_part = _amiga_next_real_partition(disk, part);
742 next_num = _amiga_next_free_block(table, block_num+1, IDNAME_PARTITION);
743
744 partition = PART(part->disk_specific);
745 if (next_part == NULL)
746 partition->pb_Next = PED_CPU_TO_BE32(LINK_END);
747 else
748 partition->pb_Next = PED_CPU_TO_BE32(next_num);
749 partition->de_LowCyl = PED_CPU_TO_BE32(part->geom.start/cylblocks);
750 partition->de_HighCyl = PED_CPU_TO_BE32((part->geom.end+1)/cylblocks-1);
751 _amiga_calculate_checksum(AMIGA(partition));
752 if (!ped_device_write (disk->dev, (void*) partition, block_num, 1)) {
753 ped_exception_throw(PED_EXCEPTION_ERROR,
754 PED_EXCEPTION_CANCEL,
755 _("Failed to write partition block at %d."),
756 block_num);
757 goto error_free_table;
758 /* WARNING : If we fail here, we stop everything,
759 * and the partition table is lost. A better
760 * solution should be found, using the second
761 * half of the hardblocks to not overwrite the
762 * old partition table. It becomes problematic
763 * if we use more than half of the hardblocks. */
764 }
765 }
766
767 if (block_num > PED_BE32_TO_CPU (rdb->rdb_HighRDSKBlock))
768 rdb->rdb_HighRDSKBlock = PED_CPU_TO_BE32(block_num);
769
770 _amiga_calculate_checksum(AMIGA(rdb));
771 if (!ped_device_write (disk->dev, (void*) disk->disk_specific, rdb_num, 1))
772 goto error_free_table;
773
774 ped_free (table);
775 ped_free (block);
776 return ped_device_sync (disk->dev);
777
778 error_free_table:
779 ped_free (table);
780 ped_free (block);
781 return 0;
782 }
783 #endif /* !DISCOVER_ONLY */
784
785 static PedPartition*
786 amiga_partition_new (const PedDisk* disk, PedPartitionType part_type,
787 const PedFileSystemType* fs_type,
788 PedSector start, PedSector end)
789 {
790 PedPartition *part;
791 PedDevice *dev;
792 PedSector cyl;
793 struct PartitionBlock *partition;
794 struct RigidDiskBlock *rdb;
795
796 PED_ASSERT(disk != NULL, return NULL);
797 PED_ASSERT(disk->dev != NULL, return NULL);
798 PED_ASSERT(disk->disk_specific != NULL, return NULL);
799 dev = disk->dev;
800 cyl = (PedSector) (dev->hw_geom.sectors * dev->hw_geom.heads);
801 rdb = RDSK(disk->disk_specific);
802
803 if (!(part = _ped_partition_alloc (disk, part_type, fs_type, start, end)))
804 return NULL;
805
806 if (ped_partition_is_active (part)) {
807 if (!(part->disk_specific = ped_malloc (PED_SECTOR_SIZE_DEFAULT))) {
808 ped_free (part);
809 return NULL;
810 }
811 partition = PART(part->disk_specific);
812 memset(partition, 0, sizeof(struct PartitionBlock));
813
814 partition->pb_ID = PED_CPU_TO_BE32(IDNAME_PARTITION);
815 partition->pb_SummedLongs = PED_CPU_TO_BE32(64);
816 partition->pb_HostID = rdb->rdb_HostID;
817 partition->pb_Flags = PED_CPU_TO_BE32(0);
818 /* TODO : use a scheme including the device name and the
819 * partition number, if it is possible */
820 _amiga_set_bstr("dhx", partition->pb_DriveName, 32);
821
822 partition->de_TableSize = PED_CPU_TO_BE32(19);
823 partition->de_SizeBlock = PED_CPU_TO_BE32(128);
824 partition->de_SecOrg = PED_CPU_TO_BE32(0);
825 partition->de_Surfaces = PED_CPU_TO_BE32(dev->hw_geom.heads);
826 partition->de_SectorPerBlock = PED_CPU_TO_BE32(1);
827 partition->de_BlocksPerTrack
828 = PED_CPU_TO_BE32(dev->hw_geom.sectors);
829 partition->de_Reserved = PED_CPU_TO_BE32(2);
830 partition->de_PreAlloc = PED_CPU_TO_BE32(0);
831 partition->de_Interleave = PED_CPU_TO_BE32(0);
832 partition->de_LowCyl = PED_CPU_TO_BE32(start/cyl);
833 partition->de_HighCyl = PED_CPU_TO_BE32((end+1)/cyl-1);
834 partition->de_NumBuffers = PED_CPU_TO_BE32(30);
835 partition->de_BufMemType = PED_CPU_TO_BE32(0);
836 partition->de_MaxTransfer = PED_CPU_TO_BE32(0x7fffffff);
837 partition->de_Mask = PED_CPU_TO_BE32(0xffffffff);
838 partition->de_BootPri = PED_CPU_TO_BE32(0);
839 partition->de_DosType = PED_CPU_TO_BE32(0x4c4e5800);
840 partition->de_Baud = PED_CPU_TO_BE32(0);
841 partition->de_Control = PED_CPU_TO_BE32(0);
842 partition->de_BootBlocks = PED_CPU_TO_BE32(0);
843
844 } else {
845 part->disk_specific = NULL;
846 }
847 return part;
848 }
849
850 static PedPartition*
851 amiga_partition_duplicate (const PedPartition* part)
852 {
853 PedPartition *new_part;
854 struct PartitionBlock *new_amiga_part;
855 struct PartitionBlock *old_amiga_part;
856
857 PED_ASSERT(part != NULL, return NULL);
858 PED_ASSERT(part->disk != NULL, return NULL);
859 PED_ASSERT(part->disk_specific != NULL, return NULL);
860 old_amiga_part = (struct PartitionBlock *) part->disk_specific;
861
862 new_part = ped_partition_new (part->disk, part->type,
863 part->fs_type, part->geom.start,
864 part->geom.end);
865 if (!new_part)
866 return NULL;
867
868 new_amiga_part = (struct PartitionBlock *) new_part->disk_specific;
869 memcpy (new_amiga_part, old_amiga_part, 256);
870
871 return new_part;
872 }
873
874 static void
875 amiga_partition_destroy (PedPartition* part)
876 {
877 PED_ASSERT (part != NULL, return);
878
879 if (ped_partition_is_active (part)) {
880 PED_ASSERT (part->disk_specific != NULL, return);
881 ped_free (part->disk_specific);
882 }
883 _ped_partition_free (part);
884 }
885
886 static int
887 amiga_partition_set_system (PedPartition* part,
888 const PedFileSystemType* fs_type)
889 {
890 struct PartitionBlock *partition;
891
892 PED_ASSERT (part != NULL, return 0);
893 PED_ASSERT (part->disk_specific != NULL, return 0);
894 partition = PART(part->disk_specific);
895
896 part->fs_type = fs_type;
897
898 if (!fs_type)
899 partition->de_DosType = PED_CPU_TO_BE32(0x4c4e5800); /* 'LNX\0' */
900 else if (!strcmp (fs_type->name, "ext2"))
901 partition->de_DosType = PED_CPU_TO_BE32(0x4c4e5800); /* 'LNX\0' */
902 else if (!strcmp (fs_type->name, "ext3"))
903 partition->de_DosType = PED_CPU_TO_BE32(0x45585403); /* 'EXT\3' */
904 else if (!strcmp (fs_type->name, "linux-swap"))
905 partition->de_DosType = PED_CPU_TO_BE32(0x53575000); /* 'SWP\0' */
906 else if (!strcmp (fs_type->name, "fat16"))
907 partition->de_DosType = PED_CPU_TO_BE32(0x46415400); /* 'FAT\0' */
908 else if (!strcmp (fs_type->name, "fat32"))
909 partition->de_DosType = PED_CPU_TO_BE32(0x46415401); /* 'FAT\1'*/
910 else if (!strcmp (fs_type->name, "hfs"))
911 partition->de_DosType = PED_CPU_TO_BE32(0x48465300); /* 'HFS\0' */
912 else if (!strcmp (fs_type->name, "jfs"))
913 partition->de_DosType = PED_CPU_TO_BE32(0x4a465300); /* 'JFS\0' */
914 else if (!strcmp (fs_type->name, "ntfs"))
915 partition->de_DosType = PED_CPU_TO_BE32(0x4e544653); /* 'NTFS' */
916 else if (!strcmp (fs_type->name, "reiserfs"))
917 partition->de_DosType = PED_CPU_TO_BE32(0x52465300); /* 'RFS\0' */
918 else if (!strcmp (fs_type->name, "sun-ufs"))
919 partition->de_DosType = PED_CPU_TO_BE32(0x53554653); /* 'SUFS' */
920 else if (!strcmp (fs_type->name, "hp-ufs"))
921 partition->de_DosType = PED_CPU_TO_BE32(0x48554653); /* 'HUFS' */
922 else if (!strcmp (fs_type->name, "xfs"))
923 partition->de_DosType = PED_CPU_TO_BE32(0x58465300); /* 'XFS\0' */
924 else
925 partition->de_DosType = PED_CPU_TO_BE32(0x00000000); /* unknown */
926 return 1;
927 }
928
929 static int
930 amiga_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
931 {
932 struct PartitionBlock *partition;
933
934 PED_ASSERT (part != NULL, return 0);
935 PED_ASSERT (part->disk_specific != NULL, return 0);
936
937 partition = PART(part->disk_specific);
938
939 switch (flag) {
940 case PED_PARTITION_BOOT:
941 if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_BOOTABLE);
942 else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_BOOTABLE));
943 return 1;
944 case PED_PARTITION_HIDDEN:
945 if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_NOMOUNT);
946 else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_NOMOUNT));
947 return 1;
948 case PED_PARTITION_RAID:
949 if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_RAID);
950 else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_RAID));
951 return 1;
952 case PED_PARTITION_LVM:
953 if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_LVM);
954 else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_LVM));
955 return 1;
956 default:
957 return 0;
958 }
959 }
960
961 static int
962 amiga_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
963 {
964 struct PartitionBlock *partition;
965
966 PED_ASSERT (part != NULL, return 0);
967 PED_ASSERT (part->disk_specific != NULL, return 0);
968
969 partition = PART(part->disk_specific);
970
971 switch (flag) {
972 case PED_PARTITION_BOOT:
973 return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_BOOTABLE));
974 case PED_PARTITION_HIDDEN:
975 return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_NOMOUNT));
976 case PED_PARTITION_RAID:
977 return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_RAID));
978 case PED_PARTITION_LVM:
979 return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_LVM));
980 default:
981 return 0;
982 }
983 }
984
985 static int
986 amiga_partition_is_flag_available (const PedPartition* part,
987 PedPartitionFlag flag)
988 {
989 switch (flag) {
990 case PED_PARTITION_BOOT:
991 case PED_PARTITION_HIDDEN:
992 case PED_PARTITION_RAID:
993 case PED_PARTITION_LVM:
994 return 1;
995 default:
996 return 0;
997 }
998 }
999
1000 static void
1001 amiga_partition_set_name (PedPartition* part, const char* name)
1002 {
1003 struct PartitionBlock *partition;
1004
1005 PED_ASSERT (part != NULL, return);
1006 PED_ASSERT (part->disk_specific != NULL, return);
1007
1008 partition = PART(part->disk_specific);
1009 _amiga_set_bstr(name, partition->pb_DriveName, 32);
1010 }
1011 static const char*
1012 amiga_partition_get_name (const PedPartition* part)
1013 {
1014 struct PartitionBlock *partition;
1015
1016 PED_ASSERT (part != NULL, return 0);
1017 PED_ASSERT (part->disk_specific != NULL, return 0);
1018
1019 partition = PART(part->disk_specific);
1020
1021 return _amiga_get_bstr(partition->pb_DriveName);
1022 }
1023
1024 static PedConstraint*
1025 _amiga_get_constraint (const PedDisk *disk)
1026 {
1027 PedDevice *dev = disk->dev;
1028 PedAlignment start_align, end_align;
1029 PedGeometry max_geom;
1030 PedSector cyl_size = dev->hw_geom.sectors * dev->hw_geom.heads;
1031
1032 if (!ped_alignment_init(&start_align, 0, cyl_size))
1033 return NULL;
1034 if (!ped_alignment_init(&end_align, -1, cyl_size))
1035 return NULL;
1036 if (!ped_geometry_init(&max_geom, dev, MAX_RDB_BLOCK + 1,
1037 dev->length - MAX_RDB_BLOCK - 1))
1038 return NULL;
1039
1040 return ped_constraint_new (&start_align, &end_align,
1041 &max_geom, &max_geom, 1, dev->length);
1042 }
1043
1044 static int
1045 amiga_partition_align (PedPartition* part, const PedConstraint* constraint)
1046 {
1047 PED_ASSERT (part != NULL, return 0);
1048 PED_ASSERT (part->disk != NULL, return 0);
1049
1050 if (_ped_partition_attempt_align (part, constraint,
1051 _amiga_get_constraint (part->disk)))
1052 return 1;
1053
1054 #ifndef DISCOVER_ONLY
1055 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1056 _("Unable to satisfy all constraints on the partition."));
1057 #endif
1058 return 0;
1059 }
1060
1061 static int
1062 amiga_partition_enumerate (PedPartition* part)
1063 {
1064 int i;
1065 PedPartition* p;
1066
1067 PED_ASSERT (part != NULL, return 0);
1068 PED_ASSERT (part->disk != NULL, return 0);
1069
1070 /* never change the partition numbers */
1071 if (part->num != -1)
1072 return 1;
1073 for (i = 1; i <= AMIGA_MAX_PARTITIONS; i++) {
1074 p = ped_disk_get_partition (part->disk, i);
1075 if (!p) {
1076 part->num = i;
1077 return 1;
1078 }
1079 }
1080
1081 /* failed to allocate a number */
1082 #ifndef DISCOVER_ONLY
1083 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1084 _("Unable to allocate a partition number."));
1085 #endif
1086 return 0;
1087 }
1088
1089 static int
1090 amiga_alloc_metadata (PedDisk* disk)
1091 {
1092 PedPartition* new_part;
1093 PedConstraint* constraint_any = NULL;
1094
1095 PED_ASSERT (disk != NULL, goto error);
1096 PED_ASSERT (disk->dev != NULL, goto error);
1097
1098 constraint_any = ped_constraint_any (disk->dev);
1099
1100 /* Allocate space for the RDB */
1101 new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1102 0, MAX_RDB_BLOCK);
1103 if (!new_part)
1104 goto error;
1105
1106 if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
1107 ped_partition_destroy (new_part);
1108 goto error;
1109 }
1110
1111 ped_constraint_destroy (constraint_any);
1112 return 1;
1113 error:
1114 ped_constraint_destroy (constraint_any);
1115 return 0;
1116 }
1117
1118 static int
1119 amiga_get_max_primary_partition_count (const PedDisk* disk)
1120 {
1121 return AMIGA_MAX_PARTITIONS;
1122 }
1123
1124 static PedDiskOps amiga_disk_ops = {
1125 .probe = amiga_probe,
1126 #ifndef DISCOVER_ONLY
1127 .clobber = amiga_clobber,
1128 #else
1129 .clobber = NULL,
1130 #endif
1131 .alloc = amiga_alloc,
1132 .duplicate = amiga_duplicate,
1133 .free = amiga_free,
1134 .read = amiga_read,
1135 #ifndef DISCOVER_ONLY
1136 .write = amiga_write,
1137 #else
1138 .write = NULL,
1139 #endif
1140
1141 .partition_new = amiga_partition_new,
1142 .partition_duplicate = amiga_partition_duplicate,
1143 .partition_destroy = amiga_partition_destroy,
1144 .partition_set_system = amiga_partition_set_system,
1145 .partition_set_flag = amiga_partition_set_flag,
1146 .partition_get_flag = amiga_partition_get_flag,
1147 .partition_is_flag_available =
1148 amiga_partition_is_flag_available,
1149 .partition_set_name = amiga_partition_set_name,
1150 .partition_get_name = amiga_partition_get_name,
1151 .partition_align = amiga_partition_align,
1152 .partition_enumerate = amiga_partition_enumerate,
1153
1154
1155 .alloc_metadata = amiga_alloc_metadata,
1156 .get_max_primary_partition_count =
1157 amiga_get_max_primary_partition_count
1158 };
1159
1160 static PedDiskType amiga_disk_type = {
1161 .next = NULL,
1162 .name = "amiga",
1163 .ops = &amiga_disk_ops,
1164 .features = PED_DISK_TYPE_PARTITION_NAME
1165 };
1166
1167 void
1168 ped_disk_amiga_init ()
1169 {
1170 PED_ASSERT (sizeof (struct AmigaBlock) != 3, return);
1171 PED_ASSERT (sizeof (struct RigidDiskBlock) != 64, return);
1172 PED_ASSERT (sizeof (struct PartitionBlock) != 64, return);
1173 PED_ASSERT (sizeof (struct LinkedBlock) != 5, return);
1174 PED_ASSERT (sizeof (struct Linked2Block) != 18, return);
1175
1176 ped_disk_type_register (&amiga_disk_type);
1177 }
1178
1179 void
1180 ped_disk_amiga_done ()
1181 {
1182 ped_disk_type_unregister (&amiga_disk_type);
1183 }