Hello,

This is a second attempt at my patch to allow creating a GPT with an offset between the GPT header and the partition entries.

This version uses the same gap between the alternate partition header and its partition entries so the gap information can be recovered in the event of a corrupt primary partition header (thanks to Rob Elliot for the idea)

Also at least one bug resulting from using the GPT header structure as if it was in cpu byte order has been squished.

Thanks,
Derek
>From 9a87a772f991f2cd6ae08a426d4c5506f750f299 Mon Sep 17 00:00:00 2001
From: Derek Foreman <[email protected]>
Date: Fri, 5 Apr 2013 12:25:21 -0500
Subject: [PATCH] Add an optional offset for GPT partition entries

---
 include/parted/disk.in.h |    3 ++
 libparted/labels/gpt.c   |  100 ++++++++++++++++++++++++++--------------------
 parted/parted.c          |   18 +++++++++
 3 files changed, 78 insertions(+), 43 deletions(-)

diff --git a/include/parted/disk.in.h b/include/parted/disk.in.h
index aa905c5..f645ef5 100644
--- a/include/parted/disk.in.h
+++ b/include/parted/disk.in.h
@@ -210,6 +210,9 @@ struct _PedDiskOps {
         int (*disk_is_flag_available) (
                 const PedDisk *disk,
                 PedDiskFlag flag);
+        int (*disk_set_partitions_offset) (
+                const PedDisk *disk,
+                PedSector offset);
         /** \todo add label guessing op here */
 
         /* partition operations */
diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c
index 490de70..19ee26c 100644
--- a/libparted/labels/gpt.c
+++ b/libparted/labels/gpt.c
@@ -269,6 +269,7 @@ struct __attribute__ ((packed)) _GPTDiskData
   int entry_count;
   efi_guid_t uuid;
   int pmbr_boot;
+  int partitions_offset;
 };
 
 /* uses libparted's disk_specific field in PedPartition, to store our info */
@@ -529,6 +530,7 @@ gpt_alloc (const PedDevice *dev)
   uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
   swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
   gpt_disk_data->pmbr_boot = 0;
+  gpt_disk_data->partitions_offset = 2;
   return disk;
 
 error_free_disk:
@@ -679,13 +681,14 @@ _header_is_valid (PedDisk const *disk, GuidPartitionTableHeader_t *gpt,
 
 static int
 _parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
-               int *update_needed)
+               int *update_needed, int use_backup)
 {
   GPTDiskData *gpt_disk_data = disk->disk_specific;
   PedSector first_usable;
   PedSector last_usable;
   PedSector last_usable_if_grown, last_usable_min_default;
   static int asked_already;
+  PedSector offset;
 
 #ifndef DISCOVER_ONLY
   if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
@@ -711,14 +714,25 @@ _parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
      If the volume has grown, offer the user the chance to use the new
      space or continue with the current usable area.  Only ask once per
      parted invocation. */
+  if (use_backup)
+    {
+      size_t ss = disk->dev->sector_size;
+      PedSector ptes_bytes = (PED_LE64_TO_CPU (gpt->NumberOfPartitionEntries)
+                              * sizeof (GuidPartitionEntry_t));
+      PedSector ptes_sectors = (ptes_bytes + ss - 1) / ss;
+
+      offset = PED_LE64_TO_CPU (gpt->MyLBA) - ptes_sectors - PED_LE64_TO_CPU (gpt->PartitionEntryLBA) + 1;
+    }
+  else
+      offset = PED_LE64_TO_CPU (gpt->PartitionEntryLBA);
 
   last_usable_if_grown
-    = (disk->dev->length - 2 -
+    = (disk->dev->length - 1 - offset -
        ((PedSector) (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries)) *
         (PedSector) (PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry)) /
         disk->dev->sector_size));
 
-  last_usable_min_default = disk->dev->length - 2 -
+  last_usable_min_default = disk->dev->length - offset -
     GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
 
   if (last_usable_if_grown > last_usable_min_default)
@@ -765,7 +779,7 @@ _parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
   PED_ASSERT (gpt_disk_data->entry_count <= 8192);
 
   gpt_disk_data->uuid = gpt->DiskGUID;
-
+  gpt_disk_data->partitions_offset = offset;
   return 1;
 }
 
@@ -936,6 +950,7 @@ gpt_read (PedDisk *disk)
   GuidPartitionTableHeader_t *primary_gpt;
   GuidPartitionTableHeader_t *backup_gpt;
   PedSector backup_sector_num;
+  int use_backup = 0;
   int read_failure = gpt_read_headers (disk, &primary_gpt, &backup_gpt,
                                        &backup_sector_num);
   if (read_failure)
@@ -1016,11 +1031,12 @@ gpt_read (PedDisk *disk)
         goto error_free_gpt;
 
       gpt = backup_gpt;
+      use_backup = 1;
     }
   backup_gpt = NULL;
   primary_gpt = NULL;
 
-  if (!_parse_header (disk, gpt, &write_back))
+  if (!_parse_header (disk, gpt, &write_back, use_backup))
     goto error_free_gpt;
 
   size_t ptes_bytes;
@@ -1142,27 +1158,27 @@ _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
   gpt->HeaderCRC32 = 0;
   gpt->Reserved1 = 0;
 
+  PedSector ptes_bytes = (gpt_disk_data->entry_count
+		          * sizeof (GuidPartitionEntry_t));
+  size_t ptes_sectors = ped_div_round_up (ptes_bytes,
+                                          disk->dev->sector_size);
   if (alternate)
     {
-      size_t ss = disk->dev->sector_size;
-      PedSector ptes_bytes = (gpt_disk_data->entry_count
-			      * sizeof (GuidPartitionEntry_t));
-      PedSector ptes_sectors = (ptes_bytes + ss - 1) / ss;
 
       gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
       gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
       gpt->PartitionEntryLBA
-        = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_sectors);
+        = PED_CPU_TO_LE64 (disk->dev->length - ptes_sectors - gpt_disk_data->partitions_offset);
     }
   else
     {
       gpt->MyLBA = PED_CPU_TO_LE64 (1);
       gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
-      gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
+      gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (gpt_disk_data->partitions_offset);
     }
 
-  gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
-  gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
+  gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->partitions_offset + ptes_sectors);
+  gpt->LastUsableLBA = PED_CPU_TO_LE64 (disk->dev->length - ptes_sectors - gpt_disk_data->partitions_offset - 1);
   gpt->DiskGUID = gpt_disk_data->uuid;
   gpt->NumberOfPartitionEntries
     = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
@@ -1209,6 +1225,7 @@ gpt_write (const PedDisk *disk)
   uint8_t *pth_raw;
   GuidPartitionTableHeader_t *gpt;
   PedPartition *part;
+  int i;
 
   PED_ASSERT (disk != NULL);
   PED_ASSERT (disk->dev != NULL);
@@ -1239,36 +1256,23 @@ gpt_write (const PedDisk *disk)
   if (!_write_pmbr (disk->dev, gpt_disk_data->pmbr_boot))
     goto error_free_ptes;
 
-  /* Write PTH and PTEs */
-  /* FIXME: Caution: this code is nearly identical to what's just below. */
-  if (_generate_header (disk, 0, ptes_crc, &gpt) != 0)
-    goto error_free_ptes;
-  pth_raw = pth_get_raw (disk->dev, gpt);
-  pth_free (gpt);
-  if (pth_raw == NULL)
-    goto error_free_ptes;
-  int write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
-  free (pth_raw);
-  if (!write_ok)
-    goto error_free_ptes;
-  if (!ped_device_write (disk->dev, ptes, 2, ptes_sectors))
-    goto error_free_ptes;
-
-  /* Write Alternate PTH & PTEs */
-  /* FIXME: Caution: this code is nearly identical to what's just above. */
-  if (_generate_header (disk, 1, ptes_crc, &gpt) != 0)
-    goto error_free_ptes;
-  pth_raw = pth_get_raw (disk->dev, gpt);
-  pth_free (gpt);
-  if (pth_raw == NULL)
-    goto error_free_ptes;
-  write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
-  free (pth_raw);
-  if (!write_ok)
-    goto error_free_ptes;
-  if (!ped_device_write (disk->dev, ptes,
-                         disk->dev->length - 1 - ptes_sectors, ptes_sectors))
-    goto error_free_ptes;
+  /* Write primary and alternate PTH and PTEs */
+  for (i = 0; i < 2; i++)
+    {
+      if (_generate_header (disk, i, ptes_crc, &gpt) != 0)
+        goto error_free_ptes;
+      pth_raw = pth_get_raw (disk->dev, gpt);
+      pth_free (gpt);
+      if (pth_raw == NULL)
+        goto error_free_ptes;
+      int write_ok = ped_device_write (disk->dev, pth_raw, PED_LE64_TO_CPU (gpt->MyLBA), 1);
+      free (pth_raw);
+      if (!write_ok)
+        goto error_free_ptes;
+      if (!ped_device_write (disk->dev, ptes,
+                             PED_LE64_TO_CPU (gpt->PartitionEntryLBA), ptes_sectors))
+        goto error_free_ptes;
+    }
 
   free (ptes);
   return ped_device_sync (disk->dev);
@@ -1872,6 +1876,15 @@ gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
   return 0;
 }
 
+static int
+gpt_disk_set_partitions_offset(const PedDisk *disk, PedSector offset)
+{
+  GPTDiskData *gpt_disk_data = disk->disk_specific;
+
+  gpt_disk_data->partitions_offset = offset;
+  return 1;
+}
+
 #include "pt-common.h"
 PT_define_limit_functions (gpt)
 
@@ -1885,6 +1898,7 @@ static PedDiskOps gpt_disk_ops =
   disk_set_flag:		gpt_disk_set_flag,
   disk_get_flag:		gpt_disk_get_flag,
   disk_is_flag_available:	gpt_disk_is_flag_available,
+  disk_set_partitions_offset:	gpt_disk_set_partitions_offset,
 
   PT_op_function_initializers (gpt)
 };
diff --git a/parted/parted.c b/parted/parted.c
index b20d432..617ea75 100644
--- a/parted/parted.c
+++ b/parted/parted.c
@@ -488,6 +488,10 @@ do_mklabel (PedDevice** dev)
 {
         PedDisk*                disk;
         const PedDiskType*      type = NULL;
+        PedGeometry             *range = NULL;
+        PedSector               offset;
+        char                    *peek_word;
+        int                     set_offset = 0;
 
         ped_exception_fetch_all ();
         disk = ped_disk_new (*dev);
@@ -497,6 +501,17 @@ do_mklabel (PedDevice** dev)
         if (!command_line_get_disk_type (_("New disk label type?"), &type))
                 goto error;
 
+        peek_word = command_line_peek_word ();
+        if (peek_word && isdigit (peek_word[0])) {
+                if (!command_line_get_sector (_("Offset?"), *dev, &offset, &range, NULL))
+                        goto error;
+                else
+                        set_offset = 1;
+        }
+
+        if (set_offset && !type->ops->disk_set_partitions_offset)
+                goto error;
+
         if (disk) {
                 if (!_disk_warn_busy (disk))
                         goto error_destroy_disk;
@@ -510,6 +525,9 @@ do_mklabel (PedDevice** dev)
         if (!disk)
                 goto error;
 
+        if (set_offset && !type->ops->disk_set_partitions_offset(disk, offset))
+                goto error_destroy_disk;
+
         if (!ped_disk_commit (disk))
                 goto error_destroy_disk;
         ped_disk_destroy (disk);
-- 
1.7.10.4

Reply via email to