OSDN Git Service

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