]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - libfdisk/src/gpt.c
libfdisk: make it possible to use zero for size and start
[thirdparty/util-linux.git] / libfdisk / src / gpt.c
index 58f27962b396bfa0becf08f043de3a8cd1a48b64..ec6dbd6644099a6a7898a0a24f7b22a4ea40cb80 100644 (file)
@@ -99,16 +99,16 @@ struct gpt_header {
        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 {
@@ -1370,6 +1370,75 @@ static int gpt_entry_attrs_to_string(struct gpt_entry *e, char **res)
        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)
 {
@@ -1470,14 +1539,17 @@ static int gpt_set_partition(struct fdisk_context *cxt, size_t n,
                        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 (pa->start)
+       if (fdisk_partition_has_start(pa))
                e->lba_start = cpu_to_le64(pa->start);
-       if (pa->size)
+       if (fdisk_partition_has_size(pa))
                e->lba_end = cpu_to_le64(gpt_partition_start(e) + pa->size - 1ULL);
 
-       /* TODO: pa->attrs */
-
        gpt_recompute_crc(gpt->pheader, gpt->ents);
        gpt_recompute_crc(gpt->bheader, gpt->ents);
 
@@ -1500,8 +1572,10 @@ static int gpt_list_disklabel(struct fdisk_context *cxt)
 
                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);
-               fdisk_info(cxt, _("Partitions entries LBA: %ju"), h->partition_entry_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);
        }
 
@@ -1878,15 +1952,16 @@ static int gpt_add_partition(
        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 (;;) {
@@ -1919,15 +1994,16 @@ static int gpt_add_partition(
        /* Last sector */
        dflt_l = find_last_free(pheader, ents, user_f);
 
-       if (pa && pa->size) {
+       if (pa && pa->end_follow_default) {
+               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)
+               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)
@@ -1955,7 +2031,9 @@ static int gpt_add_partition(
                                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;
                }
        }
@@ -1967,6 +2045,9 @@ static int gpt_add_partition(
                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);
@@ -1991,6 +2072,8 @@ static int gpt_add_partition(
 
        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,
@@ -2154,31 +2237,6 @@ static int gpt_set_disklabel_id(struct fdisk_context *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_label(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;
@@ -2394,7 +2452,6 @@ static const struct fdisk_label_operations gpt_operations =
        .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,
@@ -2409,7 +2466,6 @@ static const struct fdisk_field gpt_fields[] =
        { 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_CYLINDERS,N_("Cylinders"),  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 */