/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- libparted - a library for manipulating disk partitions atari.c - libparted module to manipulate Atari partition tables. Copyright (C) 2000-2001, 2004, 2007-2014, 2019-2022 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Contributor: Guillaume Knispel John Paul Adrian Glaubitz */ /* Documentation : README file of atari-fdisk atari-fdisk source code Linux atari partitions parser source code ( fs/partitions/atari.[ch] ) */ #include #include #include #include #include #include #include #include #include #include #include "pt-tools.h" #if ENABLE_NLS # include # define _(String) dgettext (PACKAGE, String) #else # define _(String) (String) #endif /* ENABLE_NLS */ /********************** Atari data and structure stuff **********************/ #define BOOTABLE_CKSUM 0x1234 #define NONBOOT_CKSUM 0x4321 #define GEM_MAX ((32*1024*1024)/PED_SECTOR_SIZE_DEFAULT) #define PART_FLAG_USED 0x01 #define PART_FLAG_BOOT_GEM 0x80 /* GEMDOS */ #define PART_FLAG_BOOT_ASV 0x40 /* Atari System V */ #define PART_FLAG_BOOT_BSD 0x20 /* Net(?)BSD */ #define PART_FLAG_BOOT_LNX 0x10 /* Linux */ #define PART_FLAG_BOOT_UNK 0x08 /* unknown / other */ #define N_AHDI 4 #define N_ICD 8 #define MAXIMUM_PARTS 64 /* what we put instead of id, start and size in empty */ /* partition tables, to be able to detect it */ #define SIGNATURE_EMPTY_TABLE "PARTEDATARI" #define SIGNATURE_EMPTY_SIZE 11 /* to be compared to the last two bytes of 1st sector (Big Endian) */ static const uint16_t atr_forbidden_sign[] = { 0x55AA, 0 }; static const char *atr_known_icd_pid[] = { "BGM", "GEM", "LNX", "SWP", "RAW", NULL }; /* static const char *atr_known_pid[] = { */ /* "BGM", "GEM", "LNX", "MAC", "MIX", "MNX", "RAW", "SWP", "UNX", */ /* "F32", "SV4", NULL */ /* }; */ struct _AtariPartID2BootFlag { const char pid[4]; uint8_t flag; }; typedef struct _AtariPartID2BootFlag AtariPartID2BootFlag; static AtariPartID2BootFlag atr_pid2bf[] = { { "GEM", PART_FLAG_BOOT_GEM }, { "BGM", PART_FLAG_BOOT_GEM }, { "UNX", PART_FLAG_BOOT_ASV }, { "LNX", PART_FLAG_BOOT_LNX }, { "", PART_FLAG_BOOT_UNK }, }; struct _AtariFS2PartId { const char* fs; const char pid[4]; PedSector max_sectors; }; typedef struct _AtariFS2PartId AtariFS2PartId; static AtariFS2PartId atr_fs2pid[] = { /* Other ID are available : MIX MNX <= minix UNX <= Atari SysV Unix SV4 <= Univ System 4 */ { "ext2", "LNX", INT32_MAX }, { "ext3", "LNX", INT32_MAX }, { "fat16", "GEM", GEM_MAX }, /* small partitions */ { "fat16", "BGM", INT32_MAX }, /* big partitions */ { "fat32", "F32", INT32_MAX }, { "hfs", "MAC", INT32_MAX }, { "hfs+", "MAC", INT32_MAX }, { "hfsx", "MAC", INT32_MAX }, { "jfs", "LNX", INT32_MAX }, { "linux-swap", "SWP", INT32_MAX }, { "reiserfs", "LNX", INT32_MAX }, { "hp-ufs", "LNX", INT32_MAX }, { "sun-ufs", "LNX", INT32_MAX }, { "xfs", "LNX", INT32_MAX }, { "ntfs", "RAW", INT32_MAX }, { "", "RAW", INT32_MAX }, /* default entry */ { NULL, "" , 0 } /* end of list */ }; struct __attribute__ ((packed)) _AtariRawPartition { uint8_t flag; /* bit 0: active; bit 7: bootable */ union { uint8_t empty[11]; /* Empty table */ struct __attribute__ ((packed)) { uint8_t id[3]; /* "GEM", "BGM", "XGM", ... */ uint32_t start; /* start of partition */ uint32_t size; /* length of partition */ }; }; }; typedef struct _AtariRawPartition AtariRawPartition; struct __attribute__ ((packed,aligned(2))) _AtariRawTable { uint8_t boot_code[0x156]; /* room for boot code */ AtariRawPartition icd_part[N_ICD]; /* info for ICD-partitions 5..12 */ uint8_t unused[0xc]; uint32_t hd_size; /* size of disk in blocks */ AtariRawPartition part[N_AHDI]; /* the four primary partitions */ uint32_t bsl_start; /* start of bad sector list */ uint32_t bsl_count; /* length of bad sector list */ uint16_t checksum; /* checksum for bootable disks */ }; typedef struct _AtariRawTable AtariRawTable; typedef enum { FMT_AHDI = 0, /* AHDI v1 compatible, no ICD and no XGM */ FMT_XGM = 1, /* AHDI v3 with XGM / this disable ICD */ FMT_ICD = 2 /* ICD detected / requested because more than 4 prim */ /* no XGM allowed */ } AtrFmt; struct _AtariDisk { AtrFmt format; int has_been_read; /* actually means has been read or written... */ uint32_t bsl_start; /* first sector of the Bad Sectors List */ uint32_t bsl_count; /* number of sectors of the BSL */ uint8_t HDX_comp; /* if set to one, atari_write will initialize */ /* the bsl area */ }; typedef struct _AtariDisk AtariDisk; struct _AtariPart { char part_id[4]; /* ASCIIZ */ char icd_id[4]; /* Linux only parse a limited set of ID */ /* in ICD (why???), so everything else */ /* is translated to RAW. */ uint8_t flag; /* without bit 0 (entry used) */ }; typedef struct _AtariPart AtariPart; /* set by initialisation code to C locale */ static locale_t atr_c_locale; static PedDiskType atari_disk_type; /******************************** Atari Code ********************************/ #define ATARI_DISK(disk) ((AtariDisk*)((disk)->disk_specific)) #define ATARI_PART(part) ((AtariPart*)((part)->disk_specific)) #define atr_pid_eq(a,b) (!memcmp( (a), (b), 3 )) #define atr_pid_assign(a, b) (memcpy ( (a), (b), 3 )) #define atr_part_used(part) (((part)->flag) & PART_FLAG_USED) static int atr_start_size_correct (uint32_t start, uint32_t size, uint32_t hd_size) { uint32_t end = start + size; return end >= start && 0 < start && start <= hd_size && 0 < size && size <= hd_size && 0 < end && end <= hd_size; } static int atr_part_correct (AtariRawPartition* part, uint32_t hd_size) { uint32_t start, size; start = PED_BE32_TO_CPU (part->start); size = PED_BE32_TO_CPU (part->size); return isalnum_l(part->id[0], atr_c_locale) && isalnum_l(part->id[1], atr_c_locale) && isalnum_l(part->id[2], atr_c_locale) && atr_start_size_correct (start, size, hd_size); } static int _GL_ATTRIBUTE_PURE atr_pid_known (const char* pid, const char** pid_list) { for (; *pid_list; pid_list++) { if (atr_pid_eq(pid, *pid_list)) return 1; } return 0; } /* Recognize Parted signature in an AHDI entry, used to * identify empty Atari partition tables */ static int atr_is_signature_entry (AtariRawPartition* part) { return part->flag == 0 && !memcmp (part->empty, SIGNATURE_EMPTY_TABLE, SIGNATURE_EMPTY_SIZE ); } /* Set Parted signature in an AHDI entry */ static void atr_put_signature_entry (AtariRawPartition* part) { part->flag = 0; memcpy (part->empty, SIGNATURE_EMPTY_TABLE, SIGNATURE_EMPTY_SIZE); } #define atr_part_known(part, pid_list) (atr_pid_known ((part)->id, pid_list)) #define atr_part_valid(part, sz) (atr_part_used(part)\ && atr_part_correct((part), (sz))) #define atr_part_trash(part, sz) (atr_part_used(part)\ && !atr_part_correct((part), (sz))) /* Check if this device can be used with an Atari label */ static int atr_can_use_dev (const PedDevice *dev) { /* i really don't know how atari behave with non 512 bytes */ /* sectors... */ if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Can't use Atari partition tables on disks with a " "sector size not equal to %d bytes."), (int)PED_SECTOR_SIZE_DEFAULT ); return 0; } /* the format isn't well defined enough to support > 0x7FFFFFFF */ /* sectors */ if (dev->length > INT32_MAX) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Can't use Atari partition tables on disks with more " "than %d sectors."), INT32_MAX ); return 0; } return 1; } /* * The Atari disk label doesn't have any magic id * so we must completely parse the layout to be sure * we are really dealing with it. */ static int atari_probe (const PedDevice *dev) { AtariRawTable table; uint32_t rs_hd_size, parts, exts; int valid_count, xgm_part, xgm_num, i; int num_sign, total_count = 0; PED_ASSERT (dev != NULL); PED_ASSERT (sizeof(table) == 512); /* Device Spec ok for Atari label? */ if (!atr_can_use_dev (dev)) return 0; /* read the root sector */ if (!ped_device_read (dev, &table, 0, 1)) return 0; /* number of sectors stored in the root sector > device length ? */ /* => just reject the Atari disk label */ rs_hd_size = PED_BE32_TO_CPU (table.hd_size); if (rs_hd_size > dev->length || rs_hd_size < 2) return 0; /* check the BSL fields */ if ((table.bsl_start || table.bsl_count) && !atr_start_size_correct (PED_BE32_TO_CPU (table.bsl_start), PED_BE32_TO_CPU (table.bsl_count), rs_hd_size ) ) return 0; /* scan the main AHDI fields */ num_sign = 0; xgm_num = 0; valid_count = 0; xgm_part = 0; for (i = 0; i < N_AHDI; i++) { if (atr_part_valid (&table.part[i], rs_hd_size)) { valid_count++; total_count++; if (atr_pid_eq(table.part[i].id, "XGM")) { xgm_part++; xgm_num = i; } } else if (atr_part_trash (&table.part[i], rs_hd_size)) { return 0; } if (atr_is_signature_entry (&table.part[i])) num_sign++; } /* no way to reliably detect empty Atari disk labels if * they aren't using parted signature in 4 prim fields * && reject multi XGM labels because Parted can't handle * multiple extended partitions * && reject if xgm partition in slot 0 because not allowed */ if ((!valid_count && num_sign != N_AHDI) || xgm_part > 1 || (xgm_part == 1 && xgm_num == 0) ) return 0; /* check coherency of each logical partitions and ARS */ if (xgm_part) { /* ! WARNING ! reuses "table" */ /* we must allow empty ext partition even if they're */ /* not valid because parted write the layout to the HD */ /* at each operation, and we can't create ext and log */ /* at the same time */ int empty_ars_allowed = 1; parts = exts = PED_BE32_TO_CPU (table.part[xgm_num].start); while (1) { if (!ped_device_read (dev, &table, parts, 1)) return 0; for (i = 0; i < N_AHDI-1; ++i) { if (atr_part_used (&table.part[i])) break; } /* we allow the ext part to be empty (see above) */ if (i == N_AHDI-1 && empty_ars_allowed) break; /* data partition must be in slot 0, 1 or 2 */ if (i == N_AHDI-1 || !atr_part_correct (&table.part[i], rs_hd_size - parts ) || atr_pid_eq (table.part[i].id, "XGM")) return 0; /* If there is at least one logical partition */ /* then next ARS should not be empty */ empty_ars_allowed = 0; total_count++; if (total_count > MAXIMUM_PARTS) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Too many Atari partitions detected. " " Maybe there is a loop in the XGM " "linked list. Aborting.") ); return 0; } /* end of logical partitions? */ if (!atr_part_used (&table.part[i+1])) break; /* is this really the descriptor of the next ARS? */ if (!atr_part_correct (&table.part[i+1], rs_hd_size - exts ) || !atr_pid_eq (table.part[i+1].id, "XGM")) return 0; parts = exts + PED_BE32_TO_CPU (table.part[i+1].start); } } /* no XGM so try ICD */ else if (atr_part_valid (&table.icd_part[0], rs_hd_size) && atr_part_known (&table.icd_part[0], atr_known_icd_pid)) { for (i = 1; i < N_ICD; i++) { if (atr_part_trash (&table.icd_part[i], rs_hd_size)) return 0; } } return 1; } static void atr_disk_reset (AtariDisk* atr_disk) { /* Empty partition table => only AHDI needed right now */ atr_disk->format = FMT_AHDI; /* The disk is not in sync with the actual content of the label */ atr_disk->has_been_read = 0; /* Create an empty BSL for HDX compatibility */ atr_disk->bsl_start = 1; atr_disk->bsl_count = 1; atr_disk->HDX_comp = 1; } /* * Must set up the PedDisk and the associated AtariDisk as if * the user is doing mklabel, since in this case atari_alloc * is called alone whereas when reading an existing partition * table atari_read is called after atari_alloc and can overwrite * the settings. */ static PedDisk* atari_alloc (const PedDevice* dev) { PedDisk* disk; AtariDisk* atr_disk; PED_ASSERT (dev != NULL); if (!atr_can_use_dev (dev) || !(disk = _ped_disk_alloc (dev, &atari_disk_type))) return NULL; if (!(disk->disk_specific = atr_disk = ped_malloc (sizeof (AtariDisk)))) goto error_free_disk; atr_disk_reset (atr_disk); return disk; error_free_disk: free (disk); return NULL; } static PedDisk* atari_duplicate (const PedDisk* disk) { PedDisk* new_disk; AtariDisk* old_atr_dsk; AtariDisk* new_atr_dsk; PED_ASSERT (disk != NULL); PED_ASSERT (disk->dev != NULL); PED_ASSERT (disk->disk_specific != NULL); old_atr_dsk = ATARI_DISK (disk); if (!(new_disk = ped_disk_new_fresh (disk->dev, &atari_disk_type))) return NULL; new_atr_dsk = ATARI_DISK (new_disk); memcpy (new_atr_dsk, old_atr_dsk, sizeof(*old_atr_dsk)); return new_disk; } static void atari_free (PedDisk* disk) { AtariDisk* atr_disk; PED_ASSERT (disk != NULL); PED_ASSERT (disk->disk_specific != NULL); atr_disk = ATARI_DISK (disk); _ped_disk_free (disk); free (atr_disk); } /* Warning : ID not ASCIIZ but 3 chars long */ static void atr_part_sysraw (PedPartition* part, const char* id, uint8_t flag) { AtariPart* atr_part = ATARI_PART (part); atr_part->flag = flag & ~PART_FLAG_USED; atr_pid_assign (atr_part->part_id, id); atr_part->part_id[3] = 0; if (atr_pid_known (id, atr_known_icd_pid)) { atr_pid_assign (atr_part->icd_id, id); atr_part->icd_id[3] = 0; } else { atr_pid_assign (atr_part->icd_id, "RAW"); atr_part->icd_id[3] = 0; } } static int atr_parse_add_rawpart (PedDisk* disk, PedPartitionType type, PedSector st_off, int num, const AtariRawPartition* rawpart ) { PedSector start, end; PedPartition* part; PedConstraint* const_exact; int added; start = st_off + PED_BE32_TO_CPU (rawpart->start); end = start + PED_BE32_TO_CPU (rawpart->size) - 1; part = ped_partition_new (disk, type, NULL, start, end); if (!part) return 0; /*part->num = num;*/ /* Enumeration will take care of that */ part->num = -1; /* Indeed we can't enumerate here * because the enumerate function uses * -1 do detect new partition being * inserted and update the atrdisk->format */ if (type != PED_PARTITION_EXTENDED) part->fs_type = ped_file_system_probe (&part->geom); else part->fs_type = NULL; atr_part_sysraw (part, rawpart->id, rawpart->flag); const_exact = ped_constraint_exact (&part->geom); added = ped_disk_add_partition (disk, part, const_exact); ped_constraint_destroy (const_exact); if (!added) { ped_partition_destroy (part); return 0; } PED_ASSERT (part->num == num); return 1; } /* * Read the chained list of logical partitions. * exts points to the first Auxiliary Root Sector, at the start * of the extended partition. * In each ARS one partition entry describes to the logical partition * (start relative to the ARS position) and the next entry with ID "XGM" * points to the next ARS (start relative to exts). */ static int atr_read_logicals (PedDisk* disk, PedSector exts, int* pnum) { AtariRawTable table; PedSector parts = exts; int i, empty_ars_allowed = 1; while (1) { if (!ped_device_read (disk->dev, &table, parts, 1)) return 0; for (i = 0; i < N_AHDI-1; ++i) if (atr_part_used (&table.part[i])) break; if (i == N_AHDI-1 && empty_ars_allowed) break; /* data partition must be in slot 0, 1 or 2 */ if (i == N_AHDI-1 || atr_pid_eq (table.part[i].id, "XGM")) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("No data partition found in the ARS at " "sector %lli."), parts ); return 0; } empty_ars_allowed = 0; if (!atr_parse_add_rawpart (disk, PED_PARTITION_LOGICAL, parts, *pnum, &table.part[i] ) ) return 0; (*pnum)++; /* end of logical partitions? */ if (!atr_part_used (&table.part[i+1])) break; if (!atr_pid_eq (table.part[i+1].id, "XGM")) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("The entry of the next logical ARS is not of " "type XGM in ARS at sector %lli."), parts ); return 0; } parts = exts + PED_BE32_TO_CPU (table.part[i+1].start); } return 1; } static int atari_read (PedDisk* disk) { AtariRawTable table; AtariDisk* atr_disk; uint32_t rs_hd_size; int i, pnum, xgm, pcount; PED_ASSERT (disk != NULL); PED_ASSERT (disk->dev != NULL); PED_ASSERT (disk->disk_specific != NULL); atr_disk = ATARI_DISK (disk); ped_disk_delete_all (disk); atr_disk_reset (atr_disk); if (!atari_probe (disk->dev)) { if (ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL, _("There doesn't seem to be an Atari partition table " "on this disk (%s), or it is corrupted."), disk->dev->path ) != PED_EXCEPTION_IGNORE) return 0; } if (!ped_device_read (disk->dev, (void*) &table, 0, 1)) goto error; /* We are sure that the layout looks coherent so we don't need to check too much */ rs_hd_size = PED_BE32_TO_CPU (table.hd_size); atr_disk->bsl_start = PED_BE32_TO_CPU (table.bsl_start); atr_disk->bsl_count = PED_BE32_TO_CPU (table.bsl_count); atr_disk->HDX_comp = 0; /* AHDI primary partitions */ pnum = 1; xgm = 0; pcount = 0; for (i = 0; i < N_AHDI; i++) { if (!atr_part_used (&table.part[i])) continue; pcount++; if (atr_pid_eq (table.part[i].id, "XGM")) { atr_disk->format = FMT_XGM; xgm = 1; if (!atr_parse_add_rawpart(disk, PED_PARTITION_EXTENDED, 0, 0, &table.part[i] ) || !atr_read_logicals ( disk, PED_BE32_TO_CPU (table.part[i].start), &pnum ) ) goto error; } else { if (!atr_parse_add_rawpart (disk, PED_PARTITION_NORMAL, 0, pnum, &table.part[i] ) ) goto error; pnum++; } } /* If no XGM partition has been found, the AHDI table is not empty, */ /* the first entry is valid and its ID ok for ICD, then we parse the */ /* ICD table. */ if (!xgm && pcount != 0 && atr_part_valid (&table.icd_part[0], rs_hd_size) && atr_part_known (&table.icd_part[0], atr_known_icd_pid)) for (i = 0; i < N_ICD; i++) { if (!atr_part_known (&table.icd_part[i], atr_known_icd_pid) || !atr_part_used (&table.icd_part[i])) continue; atr_disk->format = FMT_ICD; if (!atr_parse_add_rawpart (disk, PED_PARTITION_NORMAL, 0, pnum, &table.icd_part[i] ) ) goto error; pnum++; } atr_disk->has_been_read = 1; return 1; error: ped_disk_delete_all (disk); atr_disk_reset (atr_disk); return 0; } /* Returns the number of the first logical partition or -1 if not found */ static int atr_find_first_log (const PedDisk* disk) { PedPartition* part; int first_log, last; last = ped_disk_get_last_partition_num (disk); for (first_log = 1; first_log <= last; first_log++) { if ((part = ped_disk_get_partition (disk, first_log)) && (part->type & PED_PARTITION_LOGICAL)) break; } return first_log > last ? -1 : first_log; } #ifndef DISCOVER_ONLY static int atari_clobber (PedDevice* dev) { AtariRawTable table; PED_ASSERT (dev != NULL); PED_ASSERT (atari_probe (dev)); if (!ped_device_read (dev, &table, 0, 1)) return 0; /* clear anything but the boot code and the optional ICD table */ memset (table.boot_code + offsetof (AtariRawTable, hd_size), 0, PED_SECTOR_SIZE_DEFAULT - offsetof (AtariRawTable, hd_size)); return ped_device_write (dev, &table, 0, 1); } /* Computes the checksum of the root sector */ static uint16_t atr_calc_rs_sum (const AtariRawTable* table) { const uint16_t* word = (uint16_t*)(table); const uint16_t* end = (uint16_t*)(table + 1); uint16_t sum; for (sum = 0; word < end; word++) sum += PED_BE16_TO_CPU(*word); return sum; } /* Returns 1 if the root sector is bootable, else returns 0 */ static int atr_is_boot_table (const AtariRawTable* table) { return atr_calc_rs_sum (table) == BOOTABLE_CKSUM; } /* * Returns 1 if sign belongs to a set of `forbidden' signatures. * (e.g.: 55AA which is the MSDOS siganture...) * Only used for non bootable root sector since the signature of * a bootable one is unique. */ static int _GL_ATTRIBUTE_PURE atr_sign_is_forbidden (uint16_t sign) { const uint16_t* forbidden; for (forbidden = atr_forbidden_sign; *forbidden; forbidden++) { if (sign == *forbidden) return 1; } return 0; } /* Updates table->checksum so the RS will be considered bootable (or not) */ static void atr_table_set_boot (AtariRawTable* table, int boot) { uint16_t boot_cksum, noboot_cksum; uint16_t sum; table->checksum = 0; sum = atr_calc_rs_sum (table); boot_cksum = BOOTABLE_CKSUM - sum; if (boot) { table->checksum = PED_CPU_TO_BE16 (boot_cksum); return; } noboot_cksum = NONBOOT_CKSUM - sum; while (atr_sign_is_forbidden (noboot_cksum) || noboot_cksum == boot_cksum) noboot_cksum++; table->checksum = PED_CPU_TO_BE16 (noboot_cksum); } /* Fill an used partition entry */ static void atr_fill_raw_entry (AtariRawPartition* rawpart, uint8_t flag, const char* id, uint32_t start, uint32_t size ) { rawpart->flag = PART_FLAG_USED | flag; atr_pid_assign (rawpart->id, id); rawpart->start = PED_CPU_TO_BE32 (start); rawpart->size = PED_CPU_TO_BE32 (size); } static int atr_write_logicals (const PedDisk* disk) { AtariRawTable table; PedPartition* log_curr; PedPartition* log_next; PedPartition* ext; PedPartition* part; PedSector exts; PedSector parts; AtariPart* atr_part; int first_log, pnum, i; PED_ASSERT (disk != NULL); ext = ped_disk_extended_partition (disk); exts = parts = ext->geom.start; pnum = first_log = atr_find_first_log (disk); while (1) { if (pnum != -1) { log_curr = ped_disk_get_partition (disk, pnum); log_next = ped_disk_get_partition (disk, pnum + 1); } else { log_curr = log_next = NULL; } if (log_curr && !(log_curr->type & PED_PARTITION_LOGICAL)) log_curr = NULL; if (log_next && !(log_next->type & PED_PARTITION_LOGICAL)) log_next = NULL; PED_ASSERT (pnum == first_log || log_curr); part = ped_disk_get_partition_by_sector (disk, parts); if (part && ped_partition_is_active (part)) { if (log_curr) ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("No room at sector %lli to store ARS " "of logical partition %d."), parts, pnum ); else ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("No room at sector %lli to store ARS."), parts ); return 0; } if (!ped_device_read (disk->dev, &table, parts, 1)) return 0; if (!log_curr) { PED_ASSERT (!log_next); for (i = 0; i < N_AHDI; i++) table.part[i].flag &= ~PART_FLAG_USED; } else { atr_part = ATARI_PART (log_curr); atr_fill_raw_entry (&table.part[0], atr_part->flag, atr_part->part_id, log_curr->geom.start - parts, log_curr->geom.length ); for (i = 1; i < N_AHDI; i++) table.part[i].flag &= ~PART_FLAG_USED; if (log_next) { atr_fill_raw_entry (&table.part[1], 0, "XGM", log_next->geom.start - 1 - exts, log_next->geom.length + 1 ); } } /* TODO: check if we can set that bootable, and when */ atr_table_set_boot (&table, 0); if (!ped_device_write (disk->dev, &table, parts, 1)) return 0; if (!log_next) break; parts = log_next->geom.start - 1; pnum++; } return 1; } static int _GL_ATTRIBUTE_PURE _disk_logical_partition_count (const PedDisk* disk) { PedPartition* walk; int count = 0; PED_ASSERT (disk != NULL); for (walk = disk->part_list; walk; walk = ped_disk_next_partition (disk, walk)) { if (ped_partition_is_active (walk) && (walk->type & PED_PARTITION_LOGICAL)) count++; } return count; } /* Load the HD size from the table and ask to fix it if != device size. */ static int atr_load_fix_hdsize (const PedDisk* disk, uint32_t* rs_hd_size, AtariRawTable* table) { AtariDisk* atr_disk = ATARI_DISK (disk); int result = PED_EXCEPTION_UNHANDLED; *rs_hd_size = PED_BE32_TO_CPU (table->hd_size); if (*rs_hd_size != disk->dev->length) { if (atr_disk->has_been_read) { result = ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE_CANCEL, _("The sector count that is stored in the " "partition table does not correspond " "to the size of your device. Do you " "want to fix the partition table?") ); if (result == PED_EXCEPTION_CANCEL) return 0; } if (result == PED_EXCEPTION_UNHANDLED) result = PED_EXCEPTION_FIX; if (result == PED_EXCEPTION_FIX) { *rs_hd_size = disk->dev->length; table->hd_size = PED_CPU_TO_BE32(*rs_hd_size); } } return 1; } /* Try to init the HDX compatibility Bad Sectors List. */ static int atr_empty_init_bsl (const PedDisk* disk) { uint8_t zeros[PED_SECTOR_SIZE_DEFAULT]; PedSector sec; PedPartition* part; AtariDisk* atr_disk = ATARI_DISK (disk); memset (zeros, 0, PED_SECTOR_SIZE_DEFAULT); for (sec = atr_disk->bsl_start; sec < atr_disk->bsl_start + atr_disk->bsl_count; sec++ ) { if (sec == atr_disk->bsl_start) zeros[3] = 0xA5; else zeros[3] = 0; part = ped_disk_get_partition_by_sector (disk, sec); if (part && ped_partition_is_active (part)) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("No room at sector %lli to store BSL."), sec ); return 0; } ped_device_write (disk->dev, zeros, sec, 1); } atr_disk->HDX_comp = 0; return 1; } static int atari_write (const PedDisk* disk) { AtariRawTable table; AtariDisk* atr_disk; AtariPart* atr_part; PedPartition* log; PedPartition* ext_part; PedPartition* part = NULL; uint32_t rs_hd_size; int i, xgm_begin, pnum, append_ext; int put_sign, boot, prim_count, last_num; PED_ASSERT (disk != NULL); PED_ASSERT (disk->dev != NULL); atr_disk = ATARI_DISK (disk); PED_ASSERT (atr_disk != NULL); prim_count = ped_disk_get_primary_partition_count (disk); last_num = ped_disk_get_last_partition_num (disk); ext_part = ped_disk_extended_partition (disk); /* WARNING: similar/related code in atari_enumerate */ xgm_begin = ((log = ped_disk_get_partition (disk, 1)) && (log->type & PED_PARTITION_LOGICAL)); PED_ASSERT (atr_disk->format != FMT_ICD || ext_part == NULL); PED_ASSERT (atr_disk->format != FMT_XGM || prim_count + xgm_begin <= N_AHDI); PED_ASSERT (atr_disk->format != FMT_AHDI || (ext_part == NULL && prim_count + xgm_begin <= N_AHDI)); /* Device Spec ok for Atari label? */ if (!atr_can_use_dev (disk->dev)) goto error; if (!ped_device_read (disk->dev, (void*) &table, 0, 1)) goto error; boot = atr_is_boot_table (&table); table.bsl_start = PED_CPU_TO_BE32 (atr_disk->bsl_start); table.bsl_count = PED_CPU_TO_BE32 (atr_disk->bsl_count); /* Before anything else check the sector count and */ /* fix it if necessary */ if (!atr_load_fix_hdsize (disk, &rs_hd_size, &table)) goto error; append_ext = (ext_part != NULL) && (_disk_logical_partition_count (disk) == 0); /* Fill the AHDI table */ put_sign = (prim_count == 0); pnum = 1; for (i = 0; i < N_AHDI; i++) { if (pnum > last_num) part = NULL; else while (pnum <= last_num && !(part = ped_disk_get_partition (disk, pnum))) pnum++; if (put_sign) { atr_put_signature_entry (&table.part[i]); continue; } if (!part && i != 0 && append_ext) { part = ext_part; append_ext = 0; } if (!part || (i == 0 && xgm_begin)) { table.part[i].flag &= ~PART_FLAG_USED; continue; } if (part->type & PED_PARTITION_LOGICAL) part = ext_part; PED_ASSERT (part != NULL); atr_part = ATARI_PART (part); atr_fill_raw_entry (&table.part[i], atr_part->flag, atr_part->part_id, part->geom.start, part->geom.length ); if (part->type & PED_PARTITION_EXTENDED) { while (pnum <= last_num) { part = ped_disk_get_partition (disk, pnum); if (part && !(part->type & PED_PARTITION_LOGICAL)) break; pnum++; } } else pnum++; } if ((ext_part != NULL || atr_disk->format == FMT_AHDI) && pnum <= last_num) { ped_exception_throw (PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL, _("There were remaining partitions after filling " "the main AHDI table.") ); goto error; } /* Leave XGM or ICD mode if uneeded */ if (pnum > last_num && (atr_disk->format == FMT_ICD || ext_part == NULL)) atr_disk->format = FMT_AHDI; /* If AHDI mode, check that no ICD will be detected */ /* and propose to fix */ if (atr_disk->format == FMT_AHDI && atr_part_valid (&table.icd_part[0], rs_hd_size) && atr_part_known (&table.icd_part[0], atr_known_icd_pid)) { int result = PED_EXCEPTION_UNHANDLED; result = ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_YES_NO_CANCEL, _("The main AHDI table has been filled with all " "partitions but the ICD table is not empty " "so more partitions of unknown size and position " "will be detected by ICD compatible software. Do " "you want to invalidate the ICD table?") ); if (result == PED_EXCEPTION_YES || result == PED_EXCEPTION_UNHANDLED) table.icd_part[0].flag &= ~PART_FLAG_USED; else if (result == PED_EXCEPTION_CANCEL) goto error; } if (put_sign) goto write_to_dev; /* Fill the ICD table */ if (atr_disk->format == FMT_ICD) for (i = 0; i < N_ICD; i++) { if (pnum > last_num) part = NULL; else while (pnum <= last_num && !(part = ped_disk_get_partition (disk, pnum))) pnum++; if (!part) { table.icd_part[i].flag &= ~PART_FLAG_USED; continue; } if (part->type & PED_PARTITION_EXTENDED || part->type & PED_PARTITION_LOGICAL) { ped_exception_throw ( PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL, _("ICD entries can't contain extended or " "logical partitions.") ); goto error; } atr_part = ATARI_PART (part); atr_fill_raw_entry (&table.icd_part[i], atr_part->flag, atr_part->icd_id, part->geom.start, part->geom.length ); pnum++; } /* Write the chained list of logical partitions */ if (atr_disk->format == FMT_XGM) { if (!atr_write_logicals (disk)) goto error; } write_to_dev: if (pnum <= last_num) { ped_exception_throw (PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL, _("There were remaining partitions after filling " "the tables.") ); goto error; } /* Do we need to do that in case of failure too??? */ atr_table_set_boot (&table, boot); /* Commit the root sector... */ if (!ped_device_write (disk->dev, (void*) &table, 0, 1) || !ped_device_sync (disk->dev)) goto error; /* Try to init the HDX compatibility Bad Sectors List if needed. */ if (atr_disk->HDX_comp && !atr_empty_init_bsl (disk)) goto error; atr_disk->has_been_read = 1; return ped_device_sync (disk->dev); error: atr_disk->has_been_read = 0; return 0; } #endif /* If extended partition in ICD mode, generate an error and returns 1 */ /* else returns 0 */ static int atr_xgm_in_icd (const PedDisk* disk, PedPartitionType part_type) { AtariDisk* atrdisk; PED_ASSERT (disk != NULL); if (part_type & PED_PARTITION_EXTENDED) { atrdisk = ATARI_DISK (disk); if (atrdisk->format == FMT_ICD) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("You can't use an extended XGM partition in " "ICD mode (more than %d primary partitions, if " "XGM is the first one it counts for two)."), N_AHDI ); return 1; } } return 0; } static PedPartition* atari_partition_new (const PedDisk* disk, PedPartitionType part_type, const PedFileSystemType* fs_type, PedSector start, PedSector end) { PedPartition* part; AtariPart* atrpart; if (atr_xgm_in_icd(disk, part_type)) return 0; part = _ped_partition_alloc (disk, part_type, fs_type, start, end); if (!part) goto error; if (ped_partition_is_active (part)) { part->disk_specific = atrpart = ped_malloc (sizeof (AtariPart)); if (!atrpart) goto error_free_part; memset (atrpart, 0, sizeof (AtariPart)); } else { part->disk_specific = NULL; } return part; error_free_part: _ped_partition_free (part); error: return NULL; } static PedPartition* atari_partition_duplicate (const PedPartition* part) { PedPartition* new_part; new_part = ped_partition_new (part->disk, part->type, part->fs_type, part->geom.start, part->geom.end); if (!new_part) return NULL; new_part->num = part->num; if (ped_partition_is_active (part)) memcpy (new_part->disk_specific, part->disk_specific, sizeof (AtariPart)); return new_part; } static void atari_partition_destroy (PedPartition* part) { PED_ASSERT (part != NULL); if (ped_partition_is_active (part)) { PED_ASSERT (part->disk_specific != NULL); free (part->disk_specific); } _ped_partition_free (part); } /* Note: fs_type is NULL for extended partitions */ static int atari_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type) { AtariPart* atrpart; AtariFS2PartId* fs2id; PED_ASSERT (part != NULL); atrpart = ATARI_PART (part); PED_ASSERT (atrpart != NULL); part->fs_type = fs_type; if (atr_xgm_in_icd(part->disk, part->type)) return 0; if (part->type & PED_PARTITION_EXTENDED) { strcpy (atrpart->part_id, "XGM"); strcpy (atrpart->icd_id, "XGM"); return 1; } if (!fs_type) { strcpy (atrpart->part_id, "RAW"); strcpy (atrpart->icd_id, "RAW"); return 1; } for (fs2id = atr_fs2pid; fs2id->fs; fs2id++) { if (!*fs2id->fs /* default entry */ || ((!strcmp (fs_type->name, fs2id->fs) && part->geom.length < fs2id->max_sectors))) { strcpy (atrpart->part_id, fs2id->pid); if (atr_pid_known (fs2id->pid, atr_known_icd_pid)) strcpy (atrpart->icd_id, fs2id->pid); else strcpy (atrpart->icd_id, "RAW"); break; } } PED_ASSERT (fs2id->fs != NULL); return 1; } static int atari_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state) { AtariPart* atr_part; AtariPartID2BootFlag* bf; PED_ASSERT (part != NULL); atr_part = ATARI_PART (part); PED_ASSERT (atr_part != NULL); if (flag != PED_PARTITION_BOOT) return 0; if (state == 0) { atr_part->flag = 0; } else { for (bf = atr_pid2bf; *bf->pid; bf++) { if (atr_pid_eq (bf->pid, atr_part->part_id)) break; } atr_part->flag = bf->flag; } return 1; } static int _GL_ATTRIBUTE_PURE atari_partition_get_flag (const PedPartition* part, PedPartitionFlag flag) { AtariPart* atr_part; PED_ASSERT (part != NULL); atr_part = ATARI_PART (part); PED_ASSERT (atr_part != NULL); if (flag != PED_PARTITION_BOOT) return 0; return (atr_part->flag != 0); } static int atari_partition_is_flag_available (const PedPartition* part, PedPartitionFlag flag) { if (flag == PED_PARTITION_BOOT) return 1; return 0; } /* Adapted from disk_dos */ static PedConstraint* atr_log_constraint (const PedPartition* part) { const PedGeometry* geom = &part->geom; PedGeometry safe_space; PedSector min_start; PedSector max_end; PedDisk* disk; PedDevice* dev; PedPartition* ext_part; PedPartition* walk; int first_log, not_first; PED_ASSERT (part->disk != NULL); PED_ASSERT (part->disk->dev != NULL); ext_part = ped_disk_extended_partition (part->disk); PED_ASSERT (ext_part != NULL); dev = (disk = part->disk) -> dev; first_log = atr_find_first_log (disk); if (first_log == -1) first_log = part->num; not_first = (part->num != first_log); walk = ext_part->part_list; min_start = ext_part->geom.start + 1 + not_first; max_end = ext_part->geom.end; while (walk != NULL && ( walk->geom.start - (walk->num != first_log) < geom->start - not_first || walk->geom.start - (walk->num != first_log) < min_start ) ) { if (walk != part && ped_partition_is_active (walk)) min_start = walk->geom.end + 1 + not_first; walk = walk->next; } while (walk && (walk == part || !ped_partition_is_active (walk))) walk = walk->next; if (walk) max_end = walk->geom.start - 1 - (walk->num != first_log); if (min_start >= max_end) return NULL; ped_geometry_init (&safe_space, dev, min_start, max_end - min_start + 1); return ped_constraint_new_from_max (&safe_space); } /* Adapted from disk_dos */ static PedGeometry* art_min_extended_geom (const PedPartition* ext_part) { PedDisk* disk = ext_part->disk; PedPartition* walk; PedGeometry* min_geom; int first_log; first_log = atr_find_first_log (disk); if (first_log == -1) return NULL; walk = ped_disk_get_partition (disk, first_log); PED_ASSERT (walk->type & PED_PARTITION_LOGICAL); min_geom = ped_geometry_duplicate (&walk->geom); if (!min_geom) return NULL; ped_geometry_set_start (min_geom, walk->geom.start - 1); for (walk = ext_part->part_list; walk; walk = walk->next) { if (!ped_partition_is_active (walk) || walk->num == first_log) continue; if (walk->geom.start < min_geom->start) ped_geometry_set_start (min_geom, walk->geom.start - 2); if (walk->geom.end > min_geom->end) ped_geometry_set_end (min_geom, walk->geom.end); } return min_geom; } /* Adapted from disk_dos */ static PedConstraint* atr_ext_constraint (const PedPartition* part) { PedGeometry start_range; PedGeometry end_range; PedConstraint* constraint; PedDevice* dev; PedDisk* disk; PedGeometry* min; PED_ASSERT (part->disk != NULL); PED_ASSERT (part->disk->dev != NULL); dev = (disk = part->disk) -> dev; min = art_min_extended_geom (part); if (min) { ped_geometry_init (&start_range, dev, 1, min->start); ped_geometry_init (&end_range, dev, min->end, dev->length - min->end); ped_geometry_destroy (min); } else { ped_geometry_init (&start_range, dev, 1, dev->length - 1); ped_geometry_init (&end_range, dev, 1, dev->length - 1); } constraint = ped_constraint_new (ped_alignment_any, ped_alignment_any, &start_range, &end_range, 1, dev->length); return constraint; } static PedConstraint* atr_prim_constraint (const PedPartition* part) { PedDevice* dev; PedGeometry max; PED_ASSERT (part->disk != NULL); PED_ASSERT (part->disk->dev != NULL); dev = part->disk->dev; ped_geometry_init (&max, dev, 1, dev->length - 1); return ped_constraint_new_from_max (&max); } /* inspiration from disk_dos */ static PedGeometry* _best_solution (PedGeometry* a, PedGeometry* b) { if (!a) return b; if (!b) return a; if (a->length < b->length) goto choose_b; ped_geometry_destroy (b); return a; choose_b: ped_geometry_destroy (a); return b; } /* copied from disk_dos */ static PedGeometry* _try_constraint (const PedPartition* part, const PedConstraint* external, PedConstraint* internal) { PedConstraint* intersection; PedGeometry* solution; intersection = ped_constraint_intersect (external, internal); ped_constraint_destroy (internal); if (!intersection) return NULL; solution = ped_constraint_solve_nearest (intersection, &part->geom); ped_constraint_destroy (intersection); return solution; } /* * internal is either the primary or extented constraint. * If there's no BSL, the is the only internal constraint considered. * If there's a BSL, try to fit the partition before or after (and * choose the best fit, the one which results in the greatest size...) */ static int atr_prim_align (PedPartition* part, const PedConstraint* constraint, PedConstraint* internal) { PedDevice* dev; AtariDisk* atr_disk; PedConstraint* cut; PedGeometry* solution = NULL; PedGeometry max; PedSector bsl_end; PED_ASSERT (part->disk != NULL); PED_ASSERT (part->disk->dev != NULL); dev = part->disk->dev; atr_disk = ATARI_DISK (part->disk); PED_ASSERT (atr_disk != NULL); /* No BSL */ if (!atr_disk->bsl_start && !atr_disk->bsl_count) { /* Note: _ped_partition_attempt_align will destroy internal */ return _ped_partition_attempt_align(part, constraint, internal); } /* BSL, try to fit before */ if (atr_disk->bsl_start > 1) { ped_geometry_init (&max, dev, 1, atr_disk->bsl_start - 1); cut = ped_constraint_new_from_max (&max); solution = _best_solution (solution, _try_constraint (part, constraint, ped_constraint_intersect (internal, cut))); ped_constraint_destroy (cut); } /* BSL, try to fit after, take the best solution */ bsl_end = atr_disk->bsl_start + atr_disk->bsl_count; if (bsl_end < dev->length) { ped_geometry_init (&max, dev, bsl_end, dev->length - bsl_end); cut = ped_constraint_new_from_max (&max); solution = _best_solution (solution, _try_constraint (part, constraint, ped_constraint_intersect (internal, cut))); ped_constraint_destroy (cut); } ped_constraint_destroy (internal); if (solution) { ped_geometry_set (&part->geom, solution->start, solution->length); ped_geometry_destroy (solution); return 1; } return 0; } static int atari_partition_align (PedPartition* part, const PedConstraint* constraint) { PED_ASSERT (part != NULL); switch (part->type) { case PED_PARTITION_LOGICAL: if (_ped_partition_attempt_align (part, constraint, atr_log_constraint (part) ) ) return 1; break; case PED_PARTITION_EXTENDED: if (atr_prim_align (part, constraint, atr_ext_constraint (part) ) ) return 1; break; default: if (atr_prim_align (part, constraint, atr_prim_constraint (part) ) ) return 1; break; } #ifndef DISCOVER_ONLY ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Unable to satisfy all constraints on the partition.")); #endif return 0; } /* increment numbers of any non logical partition found after the last */ /* logical one, to make room for a new logical partition */ static int art_room_for_logic (PedDisk* disk) { PedPartition* part; int num, last_logic, last; /* too many partitions ? */ last = ped_disk_get_last_partition_num (disk); if (last >= MAXIMUM_PARTS) return 0; /* find the last logical partition */ last_logic = 0; for (num = 1; num <= last; num++) { part = ped_disk_get_partition (disk, num); if (part && ped_partition_is_active (part) && (part->type & PED_PARTITION_LOGICAL)) last_logic = num; } if (!last_logic) return 1; /* increment */ for (num = last; num > last_logic; num--) { part = ped_disk_get_partition (disk, num); if (part && ped_partition_is_active (part) && !(part->type & ( PED_PARTITION_LOGICAL | PED_PARTITION_EXTENDED)) && part->num > 0 ) part->num++; } return 1; } static int atari_partition_enumerate (PedPartition* part) { AtariDisk* atrdisk; PedPartition* ext_part; PedPartition* log; int i, want_icd, want_xgm, num_max, xgm_begin, prim_count; PED_ASSERT (part != NULL); PED_ASSERT (part->disk != NULL); atrdisk = ATARI_DISK (part->disk); PED_ASSERT (atrdisk != NULL); /* WARNING: some similar/related code in atari_write */ /* This is quite a : this function is probably the only way */ /* to know something has been / is going to be modified in the table.*/ /* So we detect the current operation mode (AHDI/XGM/ICD) and report */ /* errors (in which case we refuse to operate...) */ prim_count = ped_disk_get_primary_partition_count (part->disk); ext_part = ped_disk_extended_partition (part->disk); /* : we can't reorder (yet) , so if we begin with */ /* XGM the first slot must be empty */ xgm_begin = ((log = ped_disk_get_partition (part->disk, 1)) && (log->type & PED_PARTITION_LOGICAL)) || ((part->num == -1) && (part->type & PED_PARTITION_LOGICAL) && !ped_disk_get_partition (part->disk, 1)); /* */ PED_ASSERT (atrdisk->format != FMT_ICD || ext_part == NULL); PED_ASSERT (atrdisk->format != FMT_XGM || prim_count + xgm_begin <= N_AHDI); PED_ASSERT (atrdisk->format != FMT_AHDI || (ext_part == NULL && prim_count + xgm_begin <= N_AHDI)); want_icd = ( ( prim_count + xgm_begin + ( (part->num == -1) && !(part->type & PED_PARTITION_LOGICAL) ) ) > N_AHDI ); want_xgm = ( (part->type & PED_PARTITION_EXTENDED) || ext_part != NULL ); if (!want_xgm && !want_icd) atrdisk->format = FMT_AHDI; else if (want_xgm && !want_icd) atrdisk->format = FMT_XGM; else if (!want_xgm && want_icd) atrdisk->format = FMT_ICD; else { if (atr_xgm_in_icd (part->disk, PED_PARTITION_EXTENDED)) return 0; else { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("You can't use more than %d primary partitions " "(ICD mode) if you use an extended XGM " "partition. If XGM is the first partition " "it counts for two."), N_AHDI ); return 0; } } /* End of */ /* Ext will be numbered 0 and will stay 0... */ if (part->num == 0) return 1; if (part->num == -1) { /* Linux don't show the ext part itself for Atari disk labels */ /* so we use number 0 (could use a big number too, but that */ /* would be less cute ;) */ if (part->type & PED_PARTITION_EXTENDED) { part->num = 0; return 1; } switch (atrdisk->format) { case FMT_AHDI: case FMT_ICD: num_max = N_ICD + N_AHDI; break; case FMT_XGM: num_max = MAXIMUM_PARTS; break; default: num_max = 0; PED_ASSERT (0); } /* make room for logical partitions */ if (part->type & PED_PARTITION_LOGICAL) { if (!art_room_for_logic (part->disk)) goto error_alloc_failed; } /* find an unused number */ for (i = 1; i <= num_max; i++) { if (!ped_disk_get_partition (part->disk, i)) { part->num = i; return 1; } } } else { /* find an unused number before or don't re-number */ for (i = 1; i < part->num; i++) { if (!ped_disk_get_partition (part->disk, i)) { part->num = i; } } return 1; } /* failed to allocate a number */ error_alloc_failed: #ifndef DISCOVER_ONLY ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Unable to allocate a partition number.")); #endif return 0; } static int atr_creat_add_metadata (PedDisk* disk, PedSector start, PedSector end, PedPartitionType type ) { PedPartition* new_part; PedConstraint* const_exact; int added; type |= PED_PARTITION_METADATA; new_part = ped_partition_new (disk, type, NULL, start, end); if (!new_part) goto error; const_exact = ped_constraint_exact (&new_part->geom); added = ped_disk_add_partition (disk, new_part, const_exact); ped_constraint_destroy (const_exact); if (!added) goto error_destroy_part; return 1; error_destroy_part: ped_partition_destroy (new_part); error: return 0; } static int atari_alloc_metadata (PedDisk* disk) { PedPartition* ext; PedPartition* log; AtariDisk* atr_disk; int i; PED_ASSERT (disk != NULL); PED_ASSERT (disk->dev != NULL); atr_disk = ATARI_DISK (disk); PED_ASSERT (atr_disk != NULL); /* allocate 1 sector for the disk label at the start */ if (!atr_creat_add_metadata (disk, 0, 0, 0)) return 0; /* allocate the sectors containing the BSL */ if (atr_disk->bsl_start || atr_disk->bsl_count) { if (!atr_creat_add_metadata (disk, atr_disk->bsl_start, atr_disk->bsl_start + atr_disk->bsl_count - 1, 0 ) ) return 0; } ext = ped_disk_extended_partition (disk); if (ext) { if (!atr_creat_add_metadata (disk, ext->geom.start, ext->geom.start, PED_PARTITION_LOGICAL ) ) return 0; /* Find the first logical part */ for (i = 1; i <= ped_disk_get_last_partition_num (disk); i++) if ((log = ped_disk_get_partition (disk, i)) && (log->type & PED_PARTITION_LOGICAL)) break; for (log = ext->part_list; log; log = log->next) { if ((log->type & ( PED_PARTITION_METADATA | PED_PARTITION_FREESPACE)) || log->num == i) continue; if (!atr_creat_add_metadata (disk, log->geom.start-1, log->geom.start-1, PED_PARTITION_LOGICAL ) ) return 0; } } return 1; } static int _GL_ATTRIBUTE_PURE atari_get_max_primary_partition_count (const PedDisk* disk) { AtariDisk* atr_disk; PED_ASSERT (disk != NULL); atr_disk = ATARI_DISK (disk); PED_ASSERT (atr_disk != NULL); return atr_disk->format == FMT_XGM ? N_AHDI : N_AHDI + N_ICD; } static bool atari_get_max_supported_partition_count (const PedDisk* disk, int *max_n) { AtariDisk* atr_disk; PED_ASSERT (disk != NULL); atr_disk = ATARI_DISK (disk); PED_ASSERT (atr_disk != NULL); *max_n = atr_disk->format == FMT_XGM ? N_AHDI : N_AHDI + N_ICD; return true; } #include "pt-common.h" PT_define_limit_functions(atari) static PedDiskOps atari_disk_ops = { clobber: NULL_IF_DISCOVER_ONLY (atari_clobber), write: NULL_IF_DISCOVER_ONLY (atari_write), partition_set_name: NULL, partition_get_name: NULL, PT_op_function_initializers (atari) }; static PedDiskType atari_disk_type = { next: NULL, name: "atari", ops: &atari_disk_ops, features: PED_DISK_TYPE_EXTENDED }; void ped_disk_atari_init () { PED_ASSERT (sizeof (AtariRawPartition) == 12); PED_ASSERT (sizeof (AtariRawTable) == 512); /* GNU Libc doesn't support NULL instead of the locale name */ PED_ASSERT ((atr_c_locale = newlocale(LC_ALL_MASK, "C", NULL)) != NULL); ped_disk_type_register (&atari_disk_type); } void ped_disk_atari_done () { ped_disk_type_unregister (&atari_disk_type); freelocale(atr_c_locale); }