OSDN Git Service

start to make things work with 2048-byte sector size.
[android-x86/external-parted.git] / libparted / labels / rdb.c
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-2009 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 #include "misc.h"
41
42 /* String manipulation */
43 static void _amiga_set_bstr (const char *cstr, char *bstr, int maxsize) {
44         int size = strlen (cstr);
45         int i;
46
47         if (size >= maxsize) return;
48         bstr[0] = size;
49         for (i = 0; i<size; i++) bstr[i+1] = cstr[i];
50 }
51 static const char * _amiga_get_bstr (char * bstr) {
52         char * cstr = bstr + 1;
53         int size = bstr[0];
54
55         cstr[size] = '\0';
56         return cstr;
57 }
58
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
66
67 static const char *
68 _amiga_block_id (uint32_t id) {
69         switch (id) {
70                 case IDNAME_RIGIDDISK :
71                         return "RDSK";
72                 case IDNAME_BADBLOCK :
73                         return "BADB";
74                 case IDNAME_PARTITION :
75                         return "PART";
76                 case IDNAME_FILESYSHEADER :
77                         return "FSHD";
78                 case IDNAME_LOADSEG :
79                         return "LSEG";
80                 case IDNAME_BOOT :
81                         return "BOOT";
82                 case IDNAME_FREE :
83                         return "<free>";
84                 default :
85                         return "<unknown>";
86         }
87 }
88
89 struct AmigaIds {
90         uint32_t ID;
91         struct AmigaIds *next;
92 };
93
94 static struct AmigaIds *
95 _amiga_add_id (uint32_t id, struct AmigaIds *ids) {
96         struct AmigaIds *newid;
97
98         if ((newid=ped_malloc(sizeof (struct AmigaIds)))==NULL)
99                 return 0;
100         newid->ID = id;
101         newid->next = ids;
102         return newid;
103 }
104
105 static void
106 _amiga_free_ids (struct AmigaIds *ids) {
107         struct AmigaIds *current, *next;
108
109         for (current = ids; current != NULL; current = next) {
110                 next = current->next;
111                 free (current);
112         }
113 }
114 static int
115 _amiga_id_in_list (uint32_t id, struct AmigaIds *ids) {
116         struct AmigaIds *current;
117
118         for (current = ids; current != NULL; current = current->next) {
119                 if (id == current->ID)
120                         return 1;
121         }
122         return 0;
123 }
124
125 struct AmigaBlock {
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 */
129 };
130 #define AMIGA(pos) ((struct AmigaBlock *)(pos))
131
132 static int
133 _amiga_checksum (struct AmigaBlock *blk) {
134         uint32_t *rdb = (uint32_t *) blk;
135         uint32_t sum;
136         int i, end;
137
138         sum = PED_BE32_TO_CPU (rdb[0]);
139         end = PED_BE32_TO_CPU (rdb[1]);
140
141         if (end > PED_SECTOR_SIZE_DEFAULT) end = PED_SECTOR_SIZE_DEFAULT;
142
143         for (i = 1; i < end; i++) sum += PED_BE32_TO_CPU (rdb[i]);
144
145         return sum;
146 }
147
148 static void
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));
153         return;
154 }
155
156 static struct AmigaBlock *
157 _amiga_read_block (const PedDevice *dev, struct AmigaBlock *blk,
158                    PedSector block, struct AmigaIds *ids)
159 {
160         if (!ped_device_read (dev, blk, block, 1))
161                 return NULL;
162         if (ids && !_amiga_id_in_list(PED_BE32_TO_CPU(blk->amiga_ID), ids))
163                 return NULL;
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))))
169                 {
170                         case PED_EXCEPTION_CANCEL :
171                                 return NULL;
172                         case PED_EXCEPTION_FIX :
173                                 _amiga_calculate_checksum(AMIGA(blk));
174                                 if (!ped_device_write ((PedDevice*)dev, blk, block, 1))
175                                         return NULL;
176                         case PED_EXCEPTION_IGNORE :
177                         case PED_EXCEPTION_UNHANDLED :
178                         default :
179                                 return blk;
180                 }
181         }
182         return blk;
183 }
184
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];
228 };
229
230 #define RDSK(pos) ((struct RigidDiskBlock *)(pos))
231
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)
236
237 static uint32_t
238 _amiga_find_rdb (const PedDevice *dev, struct RigidDiskBlock *rdb) {
239         int i;
240         struct AmigaIds *ids;
241
242         ids = _amiga_add_id (IDNAME_RIGIDDISK, NULL);
243
244         for (i = 0; i<RDB_LOCATION_LIMIT; i++) {
245                 if (!_amiga_read_block (dev, AMIGA(rdb), i, ids)) {
246                         continue;
247                 }
248                 if (PED_BE32_TO_CPU (rdb->rdb_ID) == IDNAME_RIGIDDISK) {
249                         _amiga_free_ids (ids);
250                         return i;
251                 }
252         }
253         _amiga_free_ids (ids);
254         return AMIGA_RDB_NOT_FOUND;
255 }
256
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];
291 };
292
293 #define PART(pos) ((struct PartitionBlock *)(pos))
294
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 */
303
304
305 struct LinkedBlock {
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 */
311 };
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 */
320 };
321 #define LINK_END        (uint32_t)0xffffffff
322 #define LNK(pos)        ((struct LinkedBlock *)(pos))
323 #define LNK2(pos)       ((struct Linked2Block *)(pos))
324
325
326 static PedDiskType amiga_disk_type;
327
328 static int
329 amiga_probe (const PedDevice *dev)
330 {
331         struct RigidDiskBlock *rdb;
332         uint32_t found;
333         PED_ASSERT(dev != NULL, return 0);
334
335         if ((rdb=RDSK(ped_malloc(dev->sector_size)))==NULL)
336                 return 0;
337         found = _amiga_find_rdb (dev, rdb);
338         free (rdb);
339
340         return (found == AMIGA_RDB_NOT_FOUND ? 0 : 1);
341 }
342
343 static PedDisk*
344 amiga_alloc (const PedDevice* dev)
345 {
346         PedDisk *disk;
347         struct RigidDiskBlock *rdb;
348         PedSector cyl_size;
349         int highest_cylinder, highest_block;
350
351         PED_ASSERT(dev != NULL, return NULL);
352         cyl_size = dev->hw_geom.sectors * dev->hw_geom.heads;
353
354         if (!(disk = _ped_disk_alloc (dev, &amiga_disk_type)))
355                 return NULL;
356
357         if (!(disk->disk_specific = ped_malloc (disk->dev->sector_size))) {
358                 free (disk);
359                 return NULL;
360         }
361         rdb = disk->disk_specific;
362
363         memset(rdb, 0, sizeof(struct RigidDiskBlock));
364
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);
370
371         /* Block lists */
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);
377
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);
387
388         highest_cylinder = 1 + MAX_RDB_BLOCK / cyl_size;
389         highest_block = highest_cylinder * cyl_size - 1;
390
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);
400
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);
408
409         /* And calculate the checksum */
410         _amiga_calculate_checksum ((struct AmigaBlock *) rdb);
411
412         return disk;
413 }
414
415 static PedDisk*
416 amiga_duplicate (const PedDisk* disk)
417 {
418         PedDisk*        new_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);
424
425         old_rdb = (struct RigidDiskBlock *) disk->disk_specific;
426
427         if (!(new_disk = ped_disk_new_fresh (disk->dev, &amiga_disk_type)))
428                 return NULL;
429
430         new_rdb = (struct RigidDiskBlock *) new_disk->disk_specific;
431         memcpy (new_rdb, old_rdb, 256);
432         return new_disk;
433 }
434
435 static void
436 amiga_free (PedDisk* disk)
437 {
438         PED_ASSERT(disk != NULL, return);
439         PED_ASSERT(disk->disk_specific != NULL, return);
440
441         free (disk->disk_specific);
442         _ped_disk_free (disk);
443 }
444
445 #ifndef DISCOVER_ONLY
446 static int
447 amiga_clobber (PedDevice* dev)
448 {
449         struct RigidDiskBlock *rdb;
450         uint32_t i;
451         int result = 0;
452         PED_ASSERT(dev != NULL, return 0);
453
454         if ((rdb=RDSK(ped_malloc(dev->sector_size)))==NULL)
455                 return 0;
456
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);
460         }
461
462         free (rdb);
463
464         return result;
465 }
466 #endif /* !DISCOVER_ONLY */
467
468 static int
469 _amiga_loop_check (uint32_t block, uint32_t * blocklist, uint32_t max)
470 {
471         uint32_t i;
472
473         for (i = 0; i < max; i++)
474                 if (block == blocklist[i]) {
475                         /* We are looping, let's stop.  */
476                         return 1;
477                 }
478         blocklist[max] = block;
479         return 0;
480 }
481
482 /* We have already allocated a rdb, we are now reading it from the disk */
483 static int
484 amiga_read (PedDisk* disk)
485 {
486         struct RigidDiskBlock *rdb;
487         struct PartitionBlock *partition;
488         uint32_t partblock;
489         uint32_t partlist[AMIGA_MAX_PARTITIONS];
490         PedSector cylblocks;
491         int i;
492
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,
496                    return 0);
497         PED_ASSERT(disk->disk_specific != NULL, return 0);
498         rdb = RDSK(disk->disk_specific);
499
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__);
503                 return 0;
504         }
505
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);
513
514         /* Remove all partitions in the former in memory table */
515         ped_disk_delete_all (disk);
516
517         /* Let's allocate a partition block */
518         if (!(partition = ped_malloc (disk->dev->sector_size)))
519                 return 0;
520
521         /* We initialize the hardblock free list to detect loops */
522         for (i = 0; i < AMIGA_MAX_PARTITIONS; i++) partlist[i] = LINK_END;
523
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))
527         {
528                 PedPartition *part;
529                 PedSector start, end;
530                 PedConstraint *constraint_exact;
531
532                 /* Let's look for loops in the partition table */
533                 if (_amiga_loop_check(partblock, partlist, i)) {
534                         break;
535                 }
536
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)) {
540                         free(partition);
541                         return 0;
542                 }
543
544                 start = ((PedSector) PED_BE32_TO_CPU (partition->de_LowCyl))
545                         * cylblocks;
546                 end = (((PedSector) PED_BE32_TO_CPU (partition->de_HighCyl))
547                         + 1) * cylblocks - 1;
548
549                 /* We can now construct a new partition */
550                 if (!(part = ped_partition_new (disk, PED_PARTITION_NORMAL,
551                                                 NULL, start, end))) {
552                         free(partition);
553                         return 0;
554                 }
555                 /* And copy over the partition block */
556                 memcpy(part->disk_specific, partition, 256);
557
558                 part->num = i;
559                 part->type = 0;
560                 /* Let's probe what file system is present on the disk */
561                 part->fs_type = ped_file_system_probe (&part->geom);
562
563                 constraint_exact = ped_constraint_exact (&part->geom);
564                 if (!ped_disk_add_partition (disk, part, constraint_exact)) {
565                         ped_partition_destroy(part);
566                         free(partition);
567                         return 0;
568                 }
569                 ped_constraint_destroy (constraint_exact);
570         }
571         free(partition);
572         return 1;
573 }
574
575 static int
576 _amiga_find_free_blocks(const PedDisk *disk, uint32_t *table,
577         struct LinkedBlock *block, uint32_t first, uint32_t type)
578 {
579         PedSector next;
580
581         PED_ASSERT(disk != NULL, return 0);
582         PED_ASSERT(disk->dev != NULL, return 0);
583
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))
589                         {
590                                 case PED_EXCEPTION_CANCEL :
591                                         return 0;
592                                 case PED_EXCEPTION_FIX :
593                                         /* TODO : Need to add fixing code */
594                                 case PED_EXCEPTION_IGNORE :
595                                 case PED_EXCEPTION_UNHANDLED :
596                                 default :
597                                         return 1;
598                         }
599                 }
600
601                 if (!_amiga_read_block (disk->dev, AMIGA(block), next, NULL)) {
602                         return 0;
603                 }
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))
609                         {
610                                 /* TODO : to more subtile things here */
611                                 case PED_EXCEPTION_CANCEL :
612                                 case PED_EXCEPTION_UNHANDLED :
613                                 default :
614                                         return 0;
615                         }
616                 }
617                 table[next] = type;
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;
622                 }
623         }
624         return 1;
625 }
626 static uint32_t
627 _amiga_next_free_block(uint32_t *table, uint32_t start, uint32_t type) {
628         int i;
629
630         for (i = start; table[i] != type && table[i] != IDNAME_FREE; i++);
631         return i;
632 }
633 static PedPartition *
634 _amiga_next_real_partition(const PedDisk *disk, PedPartition *part) {
635         PedPartition *next;
636
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));
640         return next;
641 }
642 #ifndef DISCOVER_ONLY
643 static int
644 amiga_write (const PedDisk* disk)
645 {
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;
651         uint32_t * table;
652         uint32_t i;
653         uint32_t rdb_num, part_num, block_num, next_num;
654
655         PED_ASSERT (disk != NULL, return 0);
656         PED_ASSERT (disk->dev != NULL, return 0);
657         PED_ASSERT (disk->disk_specific != NULL, return 0);
658
659         if (!(rdb = ped_malloc (disk->dev->sector_size)))
660                 return 0;
661
662         /* Let's read the rdb */
663         if ((rdb_num = _amiga_find_rdb (disk->dev, rdb)) == AMIGA_RDB_NOT_FOUND) {
664                 rdb_num = 2;
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);
670         } else {
671                 memcpy (RDSK(disk->disk_specific), rdb, disk->dev->sector_size);
672         }
673         free (rdb);
674         rdb = RDSK(disk->disk_specific);
675
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);
681
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)))
688                 return 0;
689
690         for (i = 0; i <= rdb_num; i++)
691                 table[i] = IDNAME_RIGIDDISK;
692         for (     ; i < tab_size; i++)
693                 table[i] = LINK_END;
694
695         /* Let's allocate a partition block */
696         if (!(block = ped_malloc (disk->dev->sector_size))) {
697                 free (table);
698                 return 0;
699         }
700
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)
704         {
705                 ped_exception_throw(PED_EXCEPTION_ERROR,
706                         PED_EXCEPTION_CANCEL,
707                         _("%s : Failed to list bad blocks."), __func__);
708                 goto error_free_table;
709         }
710         if (_amiga_find_free_blocks(disk, table, block,
711                 PED_BE32_TO_CPU (rdb->rdb_PartitionList), IDNAME_PARTITION) == 0)
712         {
713                 ped_exception_throw(PED_EXCEPTION_ERROR,
714                         PED_EXCEPTION_CANCEL,
715                         _("%s : Failed to list partition blocks."), __func__);
716                 goto error_free_table;
717         }
718         if (_amiga_find_free_blocks(disk, table, block,
719                 PED_BE32_TO_CPU (rdb->rdb_FileSysHeaderList), IDNAME_FILESYSHEADER) == 0)
720         {
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;
725         }
726         if (_amiga_find_free_blocks(disk, table, block,
727                 PED_BE32_TO_CPU (rdb->rdb_BootBlockList), IDNAME_BOOT) == 0)
728         {
729                 ped_exception_throw(PED_EXCEPTION_ERROR,
730                         PED_EXCEPTION_CANCEL,
731                         _("%s : Failed to list boot blocks."), __func__);
732                 goto error_free_table;
733         }
734
735         block_num = next_num = part_num = _amiga_next_free_block(table, rdb_num+1,
736                                                                  IDNAME_PARTITION);
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);
743
744                 next_part = _amiga_next_real_partition(disk, part);
745                 next_num = _amiga_next_free_block(table, block_num+1, IDNAME_PARTITION);
746
747                 partition = PART(part->disk_specific);
748                 if (next_part == NULL)
749                         partition->pb_Next = PED_CPU_TO_BE32(LINK_END);
750                 else
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."),
759                                 block_num);
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. */
767                 }
768         }
769
770         if (block_num > PED_BE32_TO_CPU (rdb->rdb_HighRDSKBlock))
771                 rdb->rdb_HighRDSKBlock = PED_CPU_TO_BE32(block_num);
772
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;
776
777         free (table);
778         free (block);
779         return ped_device_sync (disk->dev);
780
781 error_free_table:
782         free (table);
783         free (block);
784         return 0;
785 }
786 #endif /* !DISCOVER_ONLY */
787
788 static PedPartition*
789 amiga_partition_new (const PedDisk* disk, PedPartitionType part_type,
790                    const PedFileSystemType* fs_type,
791                    PedSector start, PedSector end)
792 {
793         PedPartition *part;
794         PedDevice *dev;
795         PedSector cyl;
796         struct PartitionBlock *partition;
797         struct RigidDiskBlock *rdb;
798
799         PED_ASSERT(disk != NULL, return NULL);
800         PED_ASSERT(disk->dev != NULL, return NULL);
801         PED_ASSERT(disk->disk_specific != NULL, return NULL);
802         dev = disk->dev;
803         cyl = (PedSector) (dev->hw_geom.sectors * dev->hw_geom.heads);
804         rdb = RDSK(disk->disk_specific);
805
806         if (!(part = _ped_partition_alloc (disk, part_type, fs_type, start, end)))
807                 return NULL;
808
809         if (ped_partition_is_active (part)) {
810                 if (!(part->disk_specific = ped_malloc (disk->dev->sector_size))) {
811                         free (part);
812                         return NULL;
813                 }
814                 partition = PART(part->disk_specific);
815                 memset(partition, 0, sizeof(struct PartitionBlock));
816
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);
824
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);
846
847         } else {
848                 part->disk_specific = NULL;
849         }
850         return part;
851 }
852
853 static PedPartition*
854 amiga_partition_duplicate (const PedPartition* part)
855 {
856         PedPartition *new_part;
857         struct PartitionBlock *new_amiga_part;
858         struct PartitionBlock *old_amiga_part;
859
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;
864
865         new_part = ped_partition_new (part->disk, part->type,
866                                       part->fs_type, part->geom.start,
867                                       part->geom.end);
868         if (!new_part)
869                 return NULL;
870
871         new_amiga_part = (struct PartitionBlock *) new_part->disk_specific;
872         memcpy (new_amiga_part, old_amiga_part, 256);
873
874         return new_part;
875 }
876
877 static void
878 amiga_partition_destroy (PedPartition* part)
879 {
880         PED_ASSERT (part != NULL, return);
881
882         if (ped_partition_is_active (part)) {
883                 PED_ASSERT (part->disk_specific != NULL, return);
884                 free (part->disk_specific);
885         }
886         _ped_partition_free (part);
887 }
888
889 static int
890 amiga_partition_set_system (PedPartition* part,
891                             const PedFileSystemType* fs_type)
892 {
893         struct PartitionBlock *partition;
894
895         PED_ASSERT (part != NULL, return 0);
896         PED_ASSERT (part->disk_specific != NULL, return 0);
897         partition = PART(part->disk_specific);
898
899         part->fs_type = fs_type;
900
901         if (!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' */
927         else
928                 partition->de_DosType = PED_CPU_TO_BE32(0x00000000); /* unknown */
929         return 1;
930 }
931
932 static int
933 amiga_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
934 {
935         struct PartitionBlock *partition;
936
937         PED_ASSERT (part != NULL, return 0);
938         PED_ASSERT (part->disk_specific != NULL, return 0);
939
940         partition = PART(part->disk_specific);
941
942         switch (flag) {
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));
946                         return 1;
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));
950                         return 1;
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));
954                         return 1;
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));
958                         return 1;
959                 default:
960                         return 0;
961         }
962 }
963
964 static int
965 amiga_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
966 {
967         struct PartitionBlock *partition;
968
969         PED_ASSERT (part != NULL, return 0);
970         PED_ASSERT (part->disk_specific != NULL, return 0);
971
972         partition = PART(part->disk_specific);
973
974         switch (flag) {
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));
983                 default:
984                         return 0;
985         }
986 }
987
988 static int
989 amiga_partition_is_flag_available (const PedPartition* part,
990                                  PedPartitionFlag flag)
991 {
992         switch (flag) {
993         case PED_PARTITION_BOOT:
994         case PED_PARTITION_HIDDEN:
995         case PED_PARTITION_RAID:
996         case PED_PARTITION_LVM:
997                 return 1;
998         default:
999                 return 0;
1000         }
1001 }
1002
1003 static void
1004 amiga_partition_set_name (PedPartition* part, const char* name)
1005 {
1006         struct PartitionBlock *partition;
1007
1008         PED_ASSERT (part != NULL, return);
1009         PED_ASSERT (part->disk_specific != NULL, return);
1010
1011         partition = PART(part->disk_specific);
1012         _amiga_set_bstr(name, partition->pb_DriveName, 32);
1013 }
1014 static const char*
1015 amiga_partition_get_name (const PedPartition* part)
1016 {
1017         struct PartitionBlock *partition;
1018
1019         PED_ASSERT (part != NULL, return 0);
1020         PED_ASSERT (part->disk_specific != NULL, return 0);
1021
1022         partition = PART(part->disk_specific);
1023
1024         return _amiga_get_bstr(partition->pb_DriveName);
1025 }
1026
1027 static PedConstraint*
1028 _amiga_get_constraint (const PedDisk *disk)
1029 {
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;
1034
1035         if (!ped_alignment_init(&start_align, 0, cyl_size))
1036                 return NULL;
1037         if (!ped_alignment_init(&end_align, -1, cyl_size))
1038                 return NULL;
1039         if (!ped_geometry_init(&max_geom, dev, MAX_RDB_BLOCK + 1,
1040                                dev->length - MAX_RDB_BLOCK - 1))
1041                 return NULL;
1042
1043         return ped_constraint_new (&start_align, &end_align,
1044                 &max_geom, &max_geom, 1, dev->length);
1045 }
1046
1047 static int
1048 amiga_partition_align (PedPartition* part, const PedConstraint* constraint)
1049 {
1050         PED_ASSERT (part != NULL, return 0);
1051         PED_ASSERT (part->disk != NULL, return 0);
1052
1053         if (_ped_partition_attempt_align (part, constraint,
1054                                           _amiga_get_constraint (part->disk)))
1055                 return 1;
1056
1057 #ifndef DISCOVER_ONLY
1058         ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1059                 _("Unable to satisfy all constraints on the partition."));
1060 #endif
1061         return 0;
1062 }
1063
1064 static int
1065 amiga_partition_enumerate (PedPartition* part)
1066 {
1067         int i;
1068         PedPartition* p;
1069
1070         PED_ASSERT (part != NULL, return 0);
1071         PED_ASSERT (part->disk != NULL, return 0);
1072
1073         /* never change the partition numbers */
1074         if (part->num != -1)
1075                 return 1;
1076         for (i = 1; i <= AMIGA_MAX_PARTITIONS; i++) {
1077                 p = ped_disk_get_partition (part->disk, i);
1078                 if (!p) {
1079                         part->num = i;
1080                         return 1;
1081                 }
1082         }
1083
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."));
1088 #endif
1089         return 0;
1090 }
1091
1092 static int
1093 amiga_alloc_metadata (PedDisk* disk)
1094 {
1095         PedPartition*           new_part;
1096         PedConstraint*          constraint_any = NULL;
1097
1098         PED_ASSERT (disk != NULL, goto error);
1099         PED_ASSERT (disk->dev != NULL, goto error);
1100
1101         constraint_any = ped_constraint_any (disk->dev);
1102
1103         /* Allocate space for the RDB */
1104         new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1105                                       0, MAX_RDB_BLOCK);
1106         if (!new_part)
1107                 goto error;
1108
1109         if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
1110                 ped_partition_destroy (new_part);
1111                 goto error;
1112         }
1113
1114         ped_constraint_destroy (constraint_any);
1115         return 1;
1116 error:
1117         ped_constraint_destroy (constraint_any);
1118         return 0;
1119 }
1120
1121 static int
1122 amiga_get_max_primary_partition_count (const PedDisk* disk)
1123 {
1124         return AMIGA_MAX_PARTITIONS;
1125 }
1126
1127 static bool
1128 amiga_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
1129 {
1130         *max_n = AMIGA_MAX_PARTITIONS;
1131         return true;
1132 }
1133
1134 static PedDiskOps amiga_disk_ops = {
1135         probe:                  amiga_probe,
1136 #ifndef DISCOVER_ONLY
1137         clobber:                amiga_clobber,
1138 #else
1139         clobber:                NULL,
1140 #endif
1141         alloc:                  amiga_alloc,
1142         duplicate:              amiga_duplicate,
1143         free:                   amiga_free,
1144         read:                   amiga_read,
1145 #ifndef DISCOVER_ONLY
1146         write:                  amiga_write,
1147 #else
1148         write:                  NULL,
1149 #endif
1150
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,
1163
1164
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
1170 };
1171
1172 static PedDiskType amiga_disk_type = {
1173         next:           NULL,
1174         name:           "amiga",
1175         ops:            &amiga_disk_ops,
1176         features:       PED_DISK_TYPE_PARTITION_NAME
1177 };
1178
1179 void
1180 ped_disk_amiga_init ()
1181 {
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);
1187
1188         ped_disk_type_register (&amiga_disk_type);
1189 }
1190
1191 void
1192 ped_disk_amiga_done ()
1193 {
1194         ped_disk_type_unregister (&amiga_disk_type);
1195 }