uint32_t size; /* in bytes */
uint32_t crc32; /* header CRC checksum */
uint32_t reserved1; /* must be 0 */
- uint64_t my_lba; /* LBA that contains this struct (LBA 1) */
+ uint64_t my_lba; /* LBA of block that contains this struct (LBA 1) */
uint64_t alternative_lba; /* backup GPT header */
uint64_t first_usable_lba; /* first usable logical block for partitions */
uint64_t last_usable_lba; /* last usable logical block for partitions */
struct gpt_guid disk_guid; /* unique disk identifier */
- uint64_t partition_entry_lba; /* stat LBA of the partition entry array */
+ uint64_t partition_entry_lba; /* LBA of start of partition entries array */
uint32_t npartition_entries; /* total partition entries - normally 128 */
uint32_t sizeof_partition_entry; /* bytes for each GUID pt */
uint32_t partition_entry_array_crc32; /* partition CRC checksum */
- uint8_t reserved2[512 - 92]; /* must be 0 */
+ uint8_t reserved2[512 - 92]; /* must all be 0 */
} __attribute__ ((packed));
struct gpt_record {
DEF_GUID("AF9B60A0-1431-4F62-BC68-3311714A69AD", N_("Microsoft LDM data")),
DEF_GUID("DE94BBA4-06D1-4D40-A16A-BFD50179D6AC", N_("Windows recovery environment")),
DEF_GUID("37AFFC90-EF7D-4E96-91C3-2D7AE055B174", N_("IBM General Parallel Fs")),
+ DEF_GUID("E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D", N_("Microsoft Storage Spaces")),
/* HP-UX */
DEF_GUID("75894C1E-3AEB-11D3-B7C1-7B03A0000000", N_("HP-UX data")),
return start > end ? 0 : end - start + 1ULL;
}
-#ifdef CONFIG_LIBFDISK_DEBUG
/* prints UUID in the real byte order! */
-static void dbgprint_uuid(const char *mesg, struct gpt_guid *guid)
+static void gpt_debug_uuid(const char *mesg, struct gpt_guid *guid)
{
const unsigned char *uuid = (unsigned char *) guid;
uuid[8], uuid[9],
uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]);
}
-#endif
/*
* UUID is traditionally 16 byte big-endian array, except Intel EFI
char str[37];
guid_to_string(&e->type, str);
- t = fdisk_get_parttype_from_string(cxt, str);
+ t = fdisk_label_get_parttype_from_string(cxt->label, str);
return t ? : fdisk_new_unknown_parttype(0, str);
}
+static void gpt_entry_set_type(struct gpt_entry *e, struct gpt_guid *uuid)
+{
+ e->type = *uuid;
+ DBG(LABEL, gpt_debug_uuid("new type", &(e->type)));
+}
+
+static void gpt_entry_set_name(struct gpt_entry *e, char *str)
+{
+ char name[GPT_PART_NAME_LEN] = { 0 };
+ size_t i, sz = strlen(str);
+
+ if (sz) {
+ if (sz > GPT_PART_NAME_LEN)
+ sz = GPT_PART_NAME_LEN;
+ memcpy(name, str, sz);
+ }
+
+ for (i = 0; i < GPT_PART_NAME_LEN; i++)
+ e->name[i] = cpu_to_le16((uint16_t) name[i]);
+}
+
+static int gpt_entry_set_uuid(struct gpt_entry *e, char *str)
+{
+ struct gpt_guid uuid;
+ int rc;
+
+ rc = string_to_guid(str, &uuid);
+ if (rc)
+ return rc;
+
+ e->partition_guid = uuid;
+ return 0;
+}
static const char *gpt_get_header_revstr(struct gpt_header *header)
static int gpt_mknew_pmbr(struct fdisk_context *cxt)
{
struct gpt_legacy_mbr *pmbr = NULL;
+ int rc;
if (!cxt || !cxt->firstsector)
return -ENOSYS;
- fdisk_zeroize_firstsector(cxt);
+ rc = fdisk_init_firstsector_buffer(cxt);
+ if (rc)
+ return rc;
pmbr = (struct gpt_legacy_mbr *) cxt->firstsector;
struct gpt_header *header, uint64_t lba)
{
uint64_t first, last;
+ int has_id = 0;
if (!cxt || !header)
return -ENOSYS;
header->size = cpu_to_le32(sizeof(struct gpt_header));
/*
- * 128 partitions is the default. It can go behond this, however,
+ * 128 partitions are the default. It can go beyond that, but
* we're creating a de facto header here, so no funny business.
*/
header->npartition_entries = cpu_to_le32(GPT_NPARTITIONS);
header->last_usable_lba = cpu_to_le64(last);
gpt_mknew_header_common(cxt, header, lba);
- uuid_generate_random((unsigned char *) &header->disk_guid);
- swap_efi_guid(&header->disk_guid);
+ if (cxt->script) {
+ const char *id = fdisk_script_get_header(cxt->script, "label-id");
+ if (id && string_to_guid(id, &header->disk_guid) == 0)
+ has_id = 1;
+ }
+
+ if (!has_id) {
+ uuid_generate_random((unsigned char *) &header->disk_guid);
+ swap_efi_guid(&header->disk_guid);
+ }
return 0;
}
static uint64_t last_lba(struct fdisk_context *cxt)
{
struct stat s;
+ uint64_t sectors = 0;
memset(&s, 0, sizeof(s));
if (fstat(cxt->dev_fd, &s) == -1) {
}
if (S_ISBLK(s.st_mode))
- return cxt->total_sectors - 1;
- else if (S_ISREG(s.st_mode)) {
- uint64_t sectors = s.st_size >> cxt->sector_size;
- return (sectors / cxt->sector_size) - 1ULL;
- } else
+ sectors = cxt->total_sectors - 1;
+ else if (S_ISREG(s.st_mode))
+ sectors = ((uint64_t) s.st_size /
+ (uint64_t) cxt->sector_size) - 1ULL;
+ else
fdisk_warnx(cxt, _("gpt: cannot handle files with mode %o"), s.st_mode);
- return 0;
+
+ DBG(LABEL, ul_debug("GPT last LBA: %ju", sectors));
+ return sectors;
}
static ssize_t read_lba(struct fdisk_context *cxt, uint64_t lba,
/* check if first and last usable LBA make sense */
if (lu < fu) {
- DBG(LABEL, dbgprint("error: header last LBA is before first LBA"));
+ DBG(LABEL, ul_debug("error: header last LBA is before first LBA"));
goto done;
}
/* check if first and last usable LBAs with the disk's last LBA */
if (fu > lastlba || lu > lastlba) {
- DBG(LABEL, dbgprint("error: header LBAs are after the disk's last LBA"));
+ DBG(LABEL, ul_debug("error: header LBAs are after the disk's last LBA"));
goto done;
}
/* the header has to be outside usable range */
if (fu < GPT_PRIMARY_PARTITION_TABLE_LBA &&
GPT_PRIMARY_PARTITION_TABLE_LBA < lu) {
- DBG(LABEL, dbgprint("error: header outside of usable range"));
+ DBG(LABEL, ul_debug("error: header outside of usable range"));
goto done;
}
else
free(ents);
- DBG(LABEL, dbgprint("found valid GPT Header on LBA %ju", lba));
+ DBG(LABEL, ul_debug("found valid GPT Header on LBA %ju", lba));
return header;
invalid:
free(header);
free(ents);
- DBG(LABEL, dbgprint("read GPT Header on LBA %ju failed", lba));
+ DBG(LABEL, ul_debug("read GPT Header on LBA %ju failed", lba));
return NULL;
}
}
/*
- * Check if partition e1 overlaps with partition e2
+ * Check if partition e1 overlaps with partition e2.
*/
static inline int partition_overlap(struct gpt_entry *e1, struct gpt_entry *e2)
{
}
/*
- * Find any paritions that overlap.
+ * Find any partitions that overlap.
*/
static uint32_t partition_check_overlaps(struct gpt_header *header, struct gpt_entry *e)
{
partition_unused(&e[j]))
continue;
if (partition_overlap(&e[i], &e[j])) {
- DBG(LABEL, dbgprint("GPT partitions overlap detected [%u vs. %u]", i, j));
+ DBG(LABEL, ul_debug("GPT partitions overlap detected [%u vs. %u]", i, j));
return i + 1;
}
}
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
if (!mbr_type)
goto failed;
- DBG(LABEL, dbgprint("found a %s MBR", mbr_type == GPT_MBR_PROTECTIVE ?
+ DBG(LABEL, ul_debug("found a %s MBR", mbr_type == GPT_MBR_PROTECTIVE ?
"protective" : "hybrid"));
/* primary header */
cxt->label->nparts_cur = partitions_in_use(gpt->pheader, gpt->ents);
return 1;
failed:
- DBG(LABEL, dbgprint("GPT probe failed"));
+ DBG(LABEL, ul_debug("GPT probe failed"));
gpt_deinit(cxt->label);
return 0;
}
return 0;
}
+static int gpt_entry_attrs_from_string(
+ struct fdisk_context *cxt,
+ struct gpt_entry *e,
+ const char *str)
+{
+ const char *p = str;
+ uint64_t attrs = 0;
+ char *bits;
+
+ assert(e);
+ assert(p);
+
+ DBG(LABEL, ul_debug("GPT: parsing string attributes '%s'", p));
+
+ bits = (char *) &attrs;
+
+ while (p && *p) {
+ int bit = -1;
+
+ while (isblank(*p)) p++;
+ if (!*p)
+ break;
+
+ DBG(LABEL, ul_debug(" parsing item '%s'", p));
+
+ if (strncmp(p, "GUID:", 5) == 0) {
+ p += 5;
+ continue;
+ } else if (strncmp(p, GPT_ATTRSTR_REQ,
+ sizeof(GPT_ATTRSTR_REQ) - 1) == 0) {
+ bit = GPT_ATTRBIT_REQ;
+ p += sizeof(GPT_ATTRSTR_REQ) - 1;
+ } else if (strncmp(p, GPT_ATTRSTR_LEGACY,
+ sizeof(GPT_ATTRSTR_LEGACY) - 1) == 0) {
+ bit = GPT_ATTRBIT_LEGACY;
+ p += sizeof(GPT_ATTRSTR_LEGACY) - 1;
+ } else if (strncmp(p, GPT_ATTRSTR_NOBLOCK,
+ sizeof(GPT_ATTRSTR_NOBLOCK) - 1) == 0) {
+ bit = GPT_ATTRBIT_NOBLOCK;
+ p += sizeof(GPT_ATTRSTR_NOBLOCK) - 1;
+ } else if (isdigit((unsigned int) *p)) {
+ char *end = NULL;
+
+ errno = 0;
+ bit = strtol(p, &end, 0);
+ if (errno || !end || end == str
+ || bit < GPT_ATTRBIT_GUID_FIRST
+ || bit >= GPT_ATTRBIT_GUID_FIRST + GPT_ATTRBIT_GUID_COUNT)
+ bit = -1;
+ else
+ p = end;
+ }
+
+ if (bit < 0) {
+ fdisk_warnx(cxt, _("unssuported GPT attribute bit '%s'"), p);
+ return -EINVAL;
+ }
+
+ setbit(bits, bit);
+
+ while (isblank(*p)) p++;
+ if (*p == ',')
+ p++;
+ }
+
+ e->attrs = cpu_to_le64(attrs);
+ return 0;
+}
+
static int gpt_get_partition(struct fdisk_context *cxt, size_t n,
struct fdisk_partition *pa)
{
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
return rc;
}
+
+static int gpt_set_partition(struct fdisk_context *cxt, size_t n,
+ struct fdisk_partition *pa)
+{
+ struct fdisk_gpt_label *gpt;
+ struct gpt_entry *e;
+ int rc = 0;
+
+ assert(cxt);
+ assert(cxt->label);
+ assert(fdisk_is_label(cxt, GPT));
+
+ gpt = self_label(cxt);
+
+ if ((uint32_t) n >= le32_to_cpu(gpt->pheader->npartition_entries))
+ return -EINVAL;
+
+ gpt = self_label(cxt);
+ e = &gpt->ents[n];
+
+ if (pa->uuid) {
+ char new_u[37], old_u[37];
+
+ guid_to_string(&e->partition_guid, old_u);
+ rc = gpt_entry_set_uuid(e, pa->uuid);
+ if (rc)
+ return rc;
+ guid_to_string(&e->partition_guid, new_u);
+ fdisk_sinfo(cxt, FDISK_INFO_SUCCESS,
+ _("Partition UUID changed from %s to %s."),
+ old_u, new_u);
+ }
+
+ if (pa->name) {
+ char *old = encode_to_utf8((unsigned char *)e->name, sizeof(e->name));
+ gpt_entry_set_name(e, pa->name);
+
+ fdisk_sinfo(cxt, FDISK_INFO_SUCCESS,
+ _("Partition name changed from '%s' to '%.*s'."),
+ old, (int) GPT_PART_NAME_LEN, pa->name);
+ free(old);
+ }
+
+ if (pa->type && pa->type->typestr) {
+ struct gpt_guid typeid;
+
+ rc = string_to_guid(pa->type->typestr, &typeid);
+ if (rc)
+ return rc;
+ gpt_entry_set_type(e, &typeid);
+ }
+ if (pa->attrs) {
+ rc = gpt_entry_attrs_from_string(cxt, e, pa->attrs);
+ if (rc)
+ return rc;
+ }
+
+ if (fdisk_partition_has_start(pa))
+ e->lba_start = cpu_to_le64(pa->start);
+ if (fdisk_partition_has_size(pa))
+ e->lba_end = cpu_to_le64(gpt_partition_start(e) + pa->size - 1ULL);
+
+ gpt_recompute_crc(gpt->pheader, gpt->ents);
+ gpt_recompute_crc(gpt->bheader, gpt->ents);
+
+ fdisk_label_set_changed(cxt->label, 1);
+ return rc;
+}
+
+
/*
* List label partitions.
*/
{
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
- if (fdisk_context_display_details(cxt)) {
+ if (fdisk_is_details(cxt)) {
struct gpt_header *h = self_label(cxt)->pheader;
- fdisk_colon(cxt, _("First LBA: %ju"), h->first_usable_lba);
- fdisk_colon(cxt, _("Last LBA: %ju"), h->last_usable_lba);
- fdisk_colon(cxt, _("Alternative LBA: %ju"), h->alternative_lba);
- fdisk_colon(cxt, _("Partitions entries LBA: %ju"), h->partition_entry_lba);
- fdisk_colon(cxt, _("Allocated partition entries: %u"), h->npartition_entries);
+ fdisk_info(cxt, _("First LBA: %ju"), h->first_usable_lba);
+ fdisk_info(cxt, _("Last LBA: %ju"), h->last_usable_lba);
+ /* TRANSLATORS: The LBA (Logical Block Address) of the backup GPT header. */
+ fdisk_info(cxt, _("Alternative LBA: %ju"), h->alternative_lba);
+ /* TRANSLATORS: The start of the array of partition entries. */
+ fdisk_info(cxt, _("Partition entries LBA: %ju"), h->partition_entry_lba);
+ fdisk_info(cxt, _("Allocated partition entries: %u"), h->npartition_entries);
}
return 0;
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
mbr_type = valid_pmbr(cxt);
else if (gpt_write_pmbr(cxt) != 0)
goto err1;
- DBG(LABEL, dbgprint("GPT write success"));
+ DBG(LABEL, ul_debug("GPT write success"));
return 0;
err0:
- DBG(LABEL, dbgprint("GPT write failed: incorrect input"));
+ DBG(LABEL, ul_debug("GPT write failed: incorrect input"));
errno = EINVAL;
return -EINVAL;
err1:
- DBG(LABEL, dbgprint("GPT write failed: %m"));
+ DBG(LABEL, ul_debug("GPT write failed: %m"));
return -errno;
}
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
return 0;
}
-static void gpt_entry_set_type(struct gpt_entry *e, struct gpt_guid *uuid)
-{
- e->type = *uuid;
- DBG(LABEL, dbgprint_uuid("new type", &(e->type)));
-}
-
-/*
- * Create a new GPT partition entry, specified by partnum, and with a range
- * of fsect to lsenct sectors, of type t.
- * Returns 0 on success, or negative upon failure.
- */
-static int gpt_create_new_partition(struct fdisk_context *cxt,
- size_t partnum, uint64_t fsect, uint64_t lsect,
- struct gpt_guid *type,
- struct gpt_entry *entries)
-{
- struct gpt_entry *e = NULL;
- struct fdisk_gpt_label *gpt;
-
- assert(cxt);
- assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
-
- DBG(LABEL, dbgprint("GPT new partition: partno=%zu, start=%ju, end=%ju",
- partnum, fsect, lsect));
-
- gpt = self_label(cxt);
-
- if (fsect > lsect || partnum >= cxt->label->nparts_max)
- return -EINVAL;
-
- e = calloc(1, sizeof(*e));
- if (!e)
- return -ENOMEM;
- e->lba_end = cpu_to_le64(lsect);
- e->lba_start = cpu_to_le64(fsect);
-
- gpt_entry_set_type(e, type);
-
- /*
- * Any time a new partition entry is created a new GUID must be
- * generated for that partition, and every partition is guaranteed
- * to have a unique GUID.
- */
- uuid_generate_random((unsigned char *) &e->partition_guid);
- swap_efi_guid(&e->partition_guid);
-
- memcpy(&entries[partnum], e, sizeof(*e));
-
- gpt_recompute_crc(gpt->pheader, entries);
- gpt_recompute_crc(gpt->bheader, entries);
-
- free(e);
- return 0;
-}
/* Performs logical checks to add a new partition entry */
static int gpt_add_partition(
struct fdisk_context *cxt,
- struct fdisk_partition *pa)
+ struct fdisk_partition *pa,
+ size_t *partno)
{
uint64_t user_f, user_l; /* user input ranges for first and last sectors */
uint64_t disk_f, disk_l; /* first and last available sector ranges on device*/
struct gpt_guid typeid;
struct fdisk_gpt_label *gpt;
struct gpt_header *pheader;
- struct gpt_entry *ents;
+ struct gpt_entry *e, *ents;
struct fdisk_ask *ask = NULL;
size_t partnum;
int rc;
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
pheader = gpt->pheader;
rc = fdisk_partition_next_partno(pa, cxt, &partnum);
if (rc) {
- DBG(LABEL, dbgprint("GPT failed to get next partno"));
+ DBG(LABEL, ul_debug("GPT failed to get next partno"));
return rc;
}
if (!partition_unused(&ents[partnum])) {
dflt_f = fdisk_align_lba_in_range(cxt, dflt_f, dflt_f, dflt_l);
/* first sector */
- if (pa && pa->start) {
+ if (pa && pa->start_follow_default) {
+ user_f = dflt_f;
+
+ } else if (pa && fdisk_partition_has_start(pa)) {
+ DBG(LABEL, ul_debug("first sector defined: %ju", pa->start));
if (pa->start != find_first_available(pheader, ents, pa->start)) {
fdisk_warnx(cxt, _("Sector %ju already used."), pa->start);
return -ERANGE;
}
user_f = pa->start;
- } else if (pa && pa->start_follow_default) {
- user_f = dflt_f;
} else {
/* ask by dialog */
for (;;) {
/* Last sector */
dflt_l = find_last_free(pheader, ents, user_f);
- if (pa && pa->size) {
- user_l = user_f + pa->size;
- user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1;
+ if (pa && pa->end_follow_default) {
+ user_l = dflt_l;
- /* no space for anything useful, use all space
- if (user_l + (cxt->grain / cxt->sector_size) > dflt_l)
- user_l = dflt_l;
- */
+ } else if (pa && fdisk_partition_has_size(pa)) {
+ user_l = user_f + pa->size - 1;
+ DBG(LABEL, ul_debug("size defined: %ju, end: %ju (last possible: %ju)",
+ pa->size, user_l, dflt_l));
+ if (user_l != dflt_l && !pa->size_explicit)
+ user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1;
- } else if (pa && pa->end_follow_default) {
- user_l = dflt_l;
} else {
for (;;) {
if (!ask)
if (user_l + (cxt->grain / cxt->sector_size) > dflt_l)
user_l = dflt_l;
*/
- } if (user_l > user_f && user_l <= disk_l)
+ }
+
+ if (user_l > user_f && user_l <= disk_l)
break;
}
}
- if ((rc = gpt_create_new_partition(cxt, partnum,
- user_f, user_l, &typeid, ents) != 0)) {
+
+ if (user_f > user_l || partnum >= cxt->label->nparts_max) {
fdisk_warnx(cxt, _("Could not create partition %zu"), partnum + 1);
+ rc = -EINVAL;
goto done;
+ }
+
+ assert(!FDISK_IS_UNDEF(user_l));
+ assert(!FDISK_IS_UNDEF(user_f));
+
+ e = &ents[partnum];
+ e->lba_end = cpu_to_le64(user_l);
+ e->lba_start = cpu_to_le64(user_f);
+
+ gpt_entry_set_type(e, &typeid);
+
+ if (pa && pa->uuid) {
+ /* Sometimes it's necessary to create a copy of the PT and
+ * reuse already defined UUID
+ */
+ rc = gpt_entry_set_uuid(e, pa->uuid);
+ if (rc)
+ goto done;
} else {
+ /* Any time a new partition entry is created a new GUID must be
+ * generated for that partition, and every partition is guaranteed
+ * to have a unique GUID.
+ */
+ uuid_generate_random((unsigned char *) &e->partition_guid);
+ swap_efi_guid(&e->partition_guid);
+ }
+
+ if (pa && pa->name && *pa->name)
+ gpt_entry_set_name(e, pa->name);
+ if (pa && pa->attrs)
+ gpt_entry_attrs_from_string(cxt, e, pa->attrs);
+
+ DBG(LABEL, ul_debug("GPT new partition: partno=%zu, start=%ju, end=%ju, size=%ju",
+ partnum,
+ gpt_partition_start(e),
+ gpt_partition_end(e),
+ gpt_partition_size(e)));
+
+ gpt_recompute_crc(gpt->pheader, ents);
+ gpt_recompute_crc(gpt->bheader, ents);
+
+ /* report result */
+ {
struct fdisk_parttype *t;
cxt->label->nparts_cur++;
}
rc = 0;
+ if (partno)
+ *partno = partnum;
done:
fdisk_free_ask(ask);
return rc;
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
assert(cxt);
assert(id);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
guid_to_string(&gpt->pheader->disk_guid, str);
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
if (fdisk_ask_string(cxt,
return 0;
}
-static int gpt_set_partition_type(
- struct fdisk_context *cxt,
- size_t i,
- struct fdisk_parttype *t)
-{
- struct gpt_guid uuid;
- struct fdisk_gpt_label *gpt;
-
- assert(cxt);
- assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
-
- gpt = self_label(cxt);
- if ((uint32_t) i >= le32_to_cpu(gpt->pheader->npartition_entries)
- || !t || !t->typestr || string_to_guid(t->typestr, &uuid) != 0)
- return -EINVAL;
-
- gpt_entry_set_type(&gpt->ents[i], &uuid);
- gpt_recompute_crc(gpt->pheader, gpt->ents);
- gpt_recompute_crc(gpt->bheader, gpt->ents);
-
- fdisk_label_set_changed(cxt->label, 1);
- return 0;
-}
-
static int gpt_part_is_used(struct fdisk_context *cxt, size_t i)
{
struct fdisk_gpt_label *gpt;
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
return !partition_unused(e) || gpt_partition_start(e);
}
-int fdisk_gpt_partition_set_uuid(struct fdisk_context *cxt, size_t i)
-{
- struct fdisk_gpt_label *gpt;
- struct gpt_entry *e;
- struct gpt_guid uuid;
- char *str, new_u[37], old_u[37];
- int rc;
-
- assert(cxt);
- assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
-
- DBG(LABEL, dbgprint("UUID change requested partno=%zu", i));
-
- gpt = self_label(cxt);
-
- if ((uint32_t) i >= le32_to_cpu(gpt->pheader->npartition_entries))
- return -EINVAL;
-
- if (fdisk_ask_string(cxt,
- _("New UUID (in 8-4-4-4-12 format)"), &str))
- return -EINVAL;
-
- rc = string_to_guid(str, &uuid);
- free(str);
-
- if (rc) {
- fdisk_warnx(cxt, _("Failed to parse your UUID."));
- return rc;
- }
-
- e = &gpt->ents[i];
-
- guid_to_string(&e->partition_guid, old_u);
- guid_to_string(&uuid, new_u);
-
- e->partition_guid = uuid;
- gpt_recompute_crc(gpt->pheader, gpt->ents);
- gpt_recompute_crc(gpt->bheader, gpt->ents);
- fdisk_label_set_changed(cxt->label, 1);
-
- fdisk_sinfo(cxt, FDISK_INFO_SUCCESS,
- _("Partition UUID changed from %s to %s."),
- old_u, new_u);
- return 0;
-}
-
-int fdisk_gpt_partition_set_name(struct fdisk_context *cxt, size_t i)
-{
- struct fdisk_gpt_label *gpt;
- struct gpt_entry *e;
- char *str, *old, name[GPT_PART_NAME_LEN] = { 0 };
- size_t sz;
-
- assert(cxt);
- assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
-
- DBG(LABEL, dbgprint("NAME change requested partno=%zu", i));
-
- gpt = self_label(cxt);
-
- if ((uint32_t) i >= le32_to_cpu(gpt->pheader->npartition_entries))
- return -EINVAL;
-
- if (fdisk_ask_string(cxt, _("New name"), &str))
- return -EINVAL;
-
- e = &gpt->ents[i];
- old = encode_to_utf8((unsigned char *)e->name, sizeof(e->name));
-
- sz = strlen(str);
- if (sz) {
- if (sz > GPT_PART_NAME_LEN)
- sz = GPT_PART_NAME_LEN;
- memcpy(name, str, sz);
- }
-
- for (i = 0; i < GPT_PART_NAME_LEN; i++)
- e->name[i] = cpu_to_le16((uint16_t) name[i]);
-
- gpt_recompute_crc(gpt->pheader, gpt->ents);
- gpt_recompute_crc(gpt->bheader, gpt->ents);
-
- fdisk_label_set_changed(cxt->label, 1);
-
- fdisk_sinfo(cxt, FDISK_INFO_SUCCESS,
- _("Partition name changed from '%s' to '%.*s'."),
- old, (int) GPT_PART_NAME_LEN, str);
- free(str);
- free(old);
-
- return 0;
-}
-
int fdisk_gpt_is_hybrid(struct fdisk_context *cxt)
{
assert(cxt);
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
- DBG(LABEL, dbgprint("GPT entry attribute change requested partno=%zu", i));
+ DBG(LABEL, ul_debug("GPT entry attribute change requested partno=%zu", i));
gpt = self_label(cxt);
if ((uint32_t) i >= le32_to_cpu(gpt->pheader->npartition_entries))
return rc;
bit = tmp;
break;
+ default:
+ /* already specified PT_FLAG_GUIDSPECIFIC bit */
+ if (flag >= 48 && flag <= 63) {
+ bit = flag;
+ flag = GPT_FLAG_GUIDSPECIFIC;
+ }
+ break;
}
- if (bit < 0)
+ if (bit < 0) {
+ fdisk_warnx(cxt, _("failed to toggle unsupported bit %lu"), flag);
return -EINVAL;
+ }
if (!isset(bits, bit))
setbit(bits, bit);
return 0;
}
+static int gpt_entry_cmp_start(const void *a, const void *b)
+{
+ struct gpt_entry *ae = (struct gpt_entry *) a,
+ *be = (struct gpt_entry *) b;
+ int au = partition_unused(ae),
+ bu = partition_unused(be);
+
+ if (au && bu)
+ return 0;
+ if (au)
+ return 1;
+ if (bu)
+ return -1;
+
+ return gpt_partition_start(ae) - gpt_partition_start(be);
+}
+
+/* sort partition by start sector */
+static int gpt_reorder(struct fdisk_context *cxt)
+{
+ struct fdisk_gpt_label *gpt;
+ size_t nparts;
+
+ assert(cxt);
+ assert(cxt->label);
+ assert(fdisk_is_label(cxt, GPT));
+
+ gpt = self_label(cxt);
+ nparts = le32_to_cpu(gpt->pheader->npartition_entries);
+
+ qsort(gpt->ents, nparts, sizeof(struct gpt_entry),
+ gpt_entry_cmp_start);
+
+ gpt_recompute_crc(gpt->pheader, gpt->ents);
+ gpt_recompute_crc(gpt->bheader, gpt->ents);
+ fdisk_label_set_changed(cxt->label, 1);
+
+ fdisk_sinfo(cxt, FDISK_INFO_SUCCESS, _("Done."));
+ return 0;
+}
+
static int gpt_reset_alignment(struct fdisk_context *cxt)
{
struct fdisk_gpt_label *gpt;
assert(cxt);
assert(cxt->label);
- assert(fdisk_is_disklabel(cxt, GPT));
+ assert(fdisk_is_label(cxt, GPT));
gpt = self_label(cxt);
h = gpt ? gpt->pheader : NULL;
.create = gpt_create_disklabel,
.list = gpt_list_disklabel,
.locate = gpt_locate_disklabel,
+ .reorder = gpt_reorder,
.get_id = gpt_get_disklabel_id,
.set_id = gpt_set_disklabel_id,
.get_part = gpt_get_partition,
+ .set_part = gpt_set_partition,
.add_part = gpt_add_partition,
-
- .part_delete = gpt_delete_partition,
+ .del_part = gpt_delete_partition,
.part_is_used = gpt_part_is_used,
- .part_set_type = gpt_set_partition_type,
.part_toggle_flag = gpt_toggle_partition_flag,
.deinit = gpt_deinit,
.reset_alignment = gpt_reset_alignment
};
-static const struct fdisk_column gpt_columns[] =
+static const struct fdisk_field gpt_fields[] =
{
/* basic */
- { FDISK_COL_DEVICE, N_("Device"), 10, 0 },
- { FDISK_COL_START, N_("Start"), 5, TT_FL_RIGHT },
- { FDISK_COL_END, N_("End"), 5, TT_FL_RIGHT },
- { FDISK_COL_SECTORS, N_("Sectors"), 5, TT_FL_RIGHT },
- { FDISK_COL_CYLINDERS, N_("Cylinders"), 5, TT_FL_RIGHT },
- { FDISK_COL_SIZE, N_("Size"), 5, TT_FL_RIGHT, FDISK_COLFL_EYECANDY },
- { FDISK_COL_TYPE, N_("Type"), 0.1, TT_FL_TRUNC, FDISK_COLFL_EYECANDY },
+ { FDISK_FIELD_DEVICE, N_("Device"), 10, 0 },
+ { FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER },
+ { FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER },
+ { FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER },
+ { FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_EYECANDY },
+ { FDISK_FIELD_TYPE, N_("Type"), 0.1, FDISK_FIELDFL_EYECANDY },
/* expert */
- { FDISK_COL_TYPEID, N_("Type-UUID"), 36, 0, FDISK_COLFL_DETAIL },
- { FDISK_COL_UUID, N_("UUID"), 36, 0, FDISK_COLFL_DETAIL },
- { FDISK_COL_NAME, N_("Name"), 0.2, TT_FL_TRUNC, FDISK_COLFL_DETAIL },
- { FDISK_COL_ATTR, N_("Attrs"), 0, 0, FDISK_COLFL_DETAIL }
+ { FDISK_FIELD_TYPEID, N_("Type-UUID"), 36, FDISK_FIELDFL_DETAIL },
+ { FDISK_FIELD_UUID, N_("UUID"), 36, FDISK_FIELDFL_DETAIL },
+ { FDISK_FIELD_NAME, N_("Name"), 0.2, FDISK_FIELDFL_DETAIL },
+ { FDISK_FIELD_ATTR, N_("Attrs"), 0, FDISK_FIELDFL_DETAIL }
};
/*
lb->parttypes = gpt_parttypes;
lb->nparttypes = ARRAY_SIZE(gpt_parttypes);
- lb->columns = gpt_columns;
- lb->ncolumns = ARRAY_SIZE(gpt_columns);
+ lb->fields = gpt_fields;
+ lb->nfields = ARRAY_SIZE(gpt_fields);
return lb;
}