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