Refactor CgptAdd and CgptPrioitize to remove gpt-specific code

- Refactor cgpt_prioitize.c to completely remove gpt-specific code.
- Refactor cgpt_add.c to isolate gpt-dependence to one helper function
and the backup/restore logic
- Change several common apis to take a struct drive* rather than a GptData*,
this provides a path to cleanly implement mtd versions

BUG=chromium:221745
TEST=no functional changes, existing tests cover this
BRANCH=none

Change-Id: I27ed166aae390aa5dc83062f62939e45122edc76
Original-Change-Id: I1b0a73509efbf22411c4ae5cf044feede0a49a33
Reviewed-on: https://gerrit.chromium.org/gerrit/46548
Tested-by: Albert Chaulk <achaulk@chromium.org>
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Commit-Queue: Albert Chaulk <achaulk@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/49788
diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h
index 3d09fb9..e55c32f 100644
--- a/cgpt/cgpt.h
+++ b/cgpt/cgpt.h
@@ -92,22 +92,31 @@
 void PrintTypes(void);
 void EntryDetails(GptEntry *entry, uint32_t index, int raw);
 
-uint32_t GetNumberOfEntries(const GptData *gpt);
+uint32_t GetNumberOfEntries(const struct drive *drive);
 GptEntry *GetEntry(GptData *gpt, int secondary, uint32_t entry_index);
-void SetPriority(GptData *gpt, int secondary, uint32_t entry_index,
+void SetPriority(struct drive *drive, int secondary, uint32_t entry_index,
                  int priority);
-int GetPriority(GptData *gpt, int secondary, uint32_t entry_index);
-void SetTries(GptData *gpt, int secondary, uint32_t entry_index, int tries);
-int GetTries(GptData *gpt, int secondary, uint32_t entry_index);
-void SetSuccessful(GptData *gpt, int secondary, uint32_t entry_index,
+int GetPriority(struct drive *drive, int secondary, uint32_t entry_index);
+void SetTries(struct drive *drive, int secondary, uint32_t entry_index,
+              int tries);
+int GetTries(struct drive *drive, int secondary, uint32_t entry_index);
+void SetSuccessful(struct drive *drive, int secondary, uint32_t entry_index,
                    int success);
-int GetSuccessful(GptData *gpt, int secondary, uint32_t entry_index);
+int GetSuccessful(struct drive *drive, int secondary, uint32_t entry_index);
+
+void SetRaw(struct drive *drive, int secondary, uint32_t entry_index,
+           uint32_t raw);
+
+void UpdateAllEntries(struct drive *drive);
 
 uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers);
 uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries);
 void UpdateCrc(GptData *gpt);
 int IsSynonymous(const GptHeader* a, const GptHeader* b);
 
+int IsUnused(struct drive *drive, int secondary, uint32_t index);
+int IsKernel(struct drive *drive, int secondary, uint32_t index);
+
 // For usage and error messages.
 extern const char* progname;
 extern const char* command;
diff --git a/cgpt/cgpt_add.c b/cgpt/cgpt_add.c
index eaf0b73..8d4dd55 100644
--- a/cgpt/cgpt_add.c
+++ b/cgpt/cgpt_add.c
@@ -64,74 +64,133 @@
   return buf;
 }
 
-// This is an internal helper function which assumes no NULL args are passed.
-// It sets the given attribute values for a single entry at the given index.
-static void set_entry_attributes(struct drive drive,
-                                 GptEntry *entry,
+// This is the implementation-specific helper function.
+static int GptSetEntryAttributes(struct drive *drive,
                                  uint32_t index,
                                  CgptAddParams *params) {
+  GptEntry *entry;
+
+  entry = GetEntry(&drive->gpt, PRIMARY, index);
+  if (params->set_begin)
+    entry->starting_lba = params->begin;
+  if (params->set_size)
+    entry->ending_lba = entry->starting_lba + params->size - 1;
+  if (params->set_unique) {
+    memcpy(&entry->unique, &params->unique_guid, sizeof(Guid));
+  } else if (GuidIsZero(&entry->type)) {
+    if (!uuid_generator) {
+      Error("Unable to generate new GUID. uuid_generator not set.\n");
+      return -1;
+    }
+    (*uuid_generator)((uint8_t *)&entry->unique);
+  }
+  if (params->set_type)
+    memcpy(&entry->type, &params->type_guid, sizeof(Guid));
+  if (params->label) {
+    if (CGPT_OK != UTF8ToUTF16((uint8_t *)params->label, entry->name,
+                               sizeof(entry->name) / sizeof(entry->name[0]))) {
+      Error("The label cannot be converted to UTF16.\n");
+      return -1;
+    }
+  }
+  return 0;
+}
+
+// This is an internal helper function which assumes no NULL args are passed.
+// It sets the given attribute values for a single entry at the given index.
+static int SetEntryAttributes(struct drive *drive,
+                              uint32_t index,
+                              CgptAddParams *params) {
   if (params->set_raw) {
-    entry->attrs.fields.gpt_att = params->raw_value;
+    SetRaw(drive, PRIMARY, index, params->raw_value);
   } else {
     if (params->set_successful)
-      SetSuccessful(&drive.gpt, PRIMARY, index, params->successful);
+      SetSuccessful(drive, PRIMARY, index, params->successful);
     if (params->set_tries)
-      SetTries(&drive.gpt, PRIMARY, index, params->tries);
+      SetTries(drive, PRIMARY, index, params->tries);
     if (params->set_priority)
-      SetPriority(&drive.gpt, PRIMARY, index, params->priority);
+      SetPriority(drive, PRIMARY, index, params->priority);
+  }
+
+  // New partitions must specify type, begin, and size.
+  if (IsUnused(drive, PRIMARY, index)) {
+    if (!params->set_begin || !params->set_size || !params->set_type) {
+      Error("-t, -b, and -s options are required for new partitions\n");
+      return -1;
+    }
+    if (GuidIsZero(&params->type_guid)) {
+      Error("New partitions must have a type other than \"unused\"\n");
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+static int CgptCheckAddValidity(struct drive *drive) {
+  int gpt_retval;
+  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive->gpt))) {
+    Error("GptSanityCheck() returned %d: %s\n",
+          gpt_retval, GptError(gpt_retval));
+    return -1;
+  }
+
+  if (((drive->gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
+      ((drive->gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
+    Error("one of the GPT header/entries is invalid.\n"
+          "please run 'cgpt repair' before adding anything.\n");
+    return -1;
+  }
+  return 0;
+}
+
+static int CgptGetUnusedPartition(struct drive *drive, uint32_t *index,
+                                  CgptAddParams *params) {
+  uint32_t i;
+  uint32_t max_part = GetNumberOfEntries(drive);
+  if (params->partition) {
+    if (params->partition > max_part) {
+      Error("invalid partition number: %d\n", params->partition);
+      return -1;
+    }
+    *index = params->partition - 1;
+    return 0;
+  } else {
+    // Find next empty partition.
+    for (i = 0; i < max_part; i++) {
+      if (IsUnused(drive, PRIMARY, i)) {
+        params->partition = i + 1;
+        *index = i;
+        return 0;
+      }
+    }
+    Error("no unused partitions available\n");
+    return -1;
   }
 }
 
-// Set the attributes such as is_successful, num_tries_left, priority, etc.
-// from the given values in params.
 int CgptSetAttributes(CgptAddParams *params) {
   struct drive drive;
 
-  int gpt_retval;
-  GptEntry *entry;
-  uint32_t index;
-
   if (params == NULL)
     return CGPT_FAILED;
 
   if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR))
     return CGPT_FAILED;
 
-  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
-    Error("GptSanityCheck() returned %d: %s\n",
-          gpt_retval, GptError(gpt_retval));
+  if (CgptCheckAddValidity(&drive)) {
     goto bad;
   }
 
-  if (((drive.gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
-      ((drive.gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
-    Error("one of the GPT header/entries is invalid.\n"
-          "please run 'cgpt repair' before adding anything.\n");
-    goto bad;
-  }
-
-  if (params->partition == 0) {
+  if (params->partition == 0 ||
+      params->partition >= GetNumberOfEntries(&drive)) {
     Error("invalid partition number: %d\n", params->partition);
     goto bad;
   }
 
-  uint32_t max_part = GetNumberOfEntries(&drive.gpt);
-  if (params->partition > max_part) {
-    Error("invalid partition number: %d\n", params->partition);
-    goto bad;
-  }
+  SetEntryAttributes(&drive, params->partition - 1, params);
 
-  index = params->partition - 1;
-  entry = GetEntry(&drive.gpt, PRIMARY, index);
-
-  set_entry_attributes(drive, entry, index, params);
-
-  RepairEntries(&drive.gpt, MASK_PRIMARY);
-  RepairHeader(&drive.gpt, MASK_PRIMARY);
-
-  drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
-                         GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
-  UpdateCrc(&drive.gpt);
+  UpdateAllEntries(&drive);
 
   // Write it all out.
   return DriveClose(&drive, 1);
@@ -147,79 +206,57 @@
 // fields of params.
 int CgptGetPartitionDetails(CgptAddParams *params) {
   struct drive drive;
-
-  int gpt_retval;
-  GptEntry *entry;
-  uint32_t index;
   int result = CGPT_FAILED;
+  int index;
 
   if (params == NULL)
-    return result;
+    return CGPT_FAILED;
 
-  if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR)) {
-    Error("Unable to open drive: %s\n", params->drive_name);
-    return result;
-  }
+  if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR))
+    return CGPT_FAILED;
 
-  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
-    Error("GptSanityCheck() returned %d: %s\n",
-          gpt_retval, GptError(gpt_retval));
+  if (CgptCheckAddValidity(&drive)) {
     goto bad;
   }
 
-  if (((drive.gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
-      ((drive.gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
-    Error("one of the GPT header/entries is invalid.\n"
-          "please run 'cgpt repair' before adding anything.\n");
-    goto bad;
-  }
-
-  uint32_t max_part = GetNumberOfEntries(&drive.gpt);
-
-  if (params->partition) {
-    if (params->partition > max_part) {
+  int max_part = GetNumberOfEntries(&drive);
+  if (params->partition > 0) {
+    if (params->partition >= max_part) {
       Error("invalid partition number: %d\n", params->partition);
       goto bad;
     }
-
-    // A valid partition number has been specified, so get the entry directly.
-    index = params->partition - 1;
-    entry = GetEntry(&drive.gpt, PRIMARY, index);
   } else {
-    // Partition number is not specified, try looking up by the unique id.
     if (!params->set_unique) {
       Error("either partition or unique_id must be specified\n");
       goto bad;
     }
-
-    // A unique id is specified. find the entry that matches it.
     for (index = 0; index < max_part; index++) {
-      entry = GetEntry(&drive.gpt, PRIMARY, index);
+      GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
       if (GuidEqual(&entry->unique, &params->unique_guid)) {
         params->partition = index + 1;
         break;
       }
     }
-
     if (index >= max_part) {
       Error("no partitions with the given unique id available\n");
       goto bad;
     }
   }
+  index = params->partition - 1;
 
-  // At this point, irrespective of whether a partition number is specified
-  // or a unique id is specified, we have valid non-null values for all these:
-  // index, entry, params->partition.
+  {
+    // GPT-specific code
+    GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
+    params->begin = entry->starting_lba;
+    params->size =  entry->ending_lba - entry->starting_lba + 1;
+    memcpy(&params->type_guid, &entry->type, sizeof(Guid));
+    memcpy(&params->unique_guid, &entry->unique, sizeof(Guid));
+    params->raw_value = entry->attrs.fields.gpt_att;
+  }
 
-  params->begin = entry->starting_lba;
-  params->size =  entry->ending_lba - entry->starting_lba + 1;
-  memcpy(&params->type_guid, &entry->type, sizeof(Guid));
-  memcpy(&params->unique_guid, &entry->unique, sizeof(Guid));
-
-  params->raw_value = entry->attrs.fields.gpt_att;
-  params->successful = GetSuccessful(&drive.gpt, PRIMARY, index);
-  params->tries = GetTries(&drive.gpt, PRIMARY, index);
-  params->priority = GetPriority(&drive.gpt, PRIMARY, index);
+  params->successful = GetSuccessful(&drive, PRIMARY, index);
+  params->tries = GetTries(&drive, PRIMARY, index);
+  params->priority = GetPriority(&drive, PRIMARY, index);
   result = CGPT_OK;
 
 bad:
@@ -227,11 +264,9 @@
   return result;
 }
 
-
 int CgptAdd(CgptAddParams *params) {
   struct drive drive;
 
-  int gpt_retval;
   GptEntry *entry, backup;
   uint32_t index;
   int rv;
@@ -242,85 +277,24 @@
   if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR))
     return CGPT_FAILED;
 
-  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
-    Error("GptSanityCheck() returned %d: %s\n",
-          gpt_retval, GptError(gpt_retval));
+  if (CgptCheckAddValidity(&drive)) {
     goto bad;
   }
 
-  if (((drive.gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
-      ((drive.gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
-    Error("one of the GPT header/entries is invalid.\n"
-          "please run 'cgpt repair' before adding anything.\n");
+  if (CgptGetUnusedPartition(&drive, &index, params)) {
     goto bad;
   }
 
-  uint32_t max_part = GetNumberOfEntries(&drive.gpt);
-  if (params->partition) {
-    if (params->partition > max_part) {
-      Error("invalid partition number: %d\n", params->partition);
-      goto bad;
-    }
-    index = params->partition - 1;
-    entry = GetEntry(&drive.gpt, PRIMARY, index);
-  } else {
-    // Find next empty partition.
-    for (index = 0; index < max_part; index++) {
-      entry = GetEntry(&drive.gpt, PRIMARY, index);
-      if (GuidIsZero(&entry->type)) {
-        params->partition = index + 1;
-        break;
-      }
-    }
-    if (index >= max_part) {
-      Error("no unused partitions available\n");
-      goto bad;
-    }
-  }
+  entry = GetEntry(&drive.gpt, PRIMARY, index);
   memcpy(&backup, entry, sizeof(backup));
 
-  // New partitions must specify type, begin, and size.
-  if (GuidIsZero(&entry->type)) {
-    if (!params->set_begin || !params->set_size || !params->set_type) {
-      Error("-t, -b, and -s options are required for new partitions\n");
-      goto bad;
-    }
-    if (GuidIsZero(&params->type_guid)) {
-      Error("New partitions must have a type other than \"unused\"\n");
-      goto bad;
-    }
-    if (!params->set_unique)
-      if (!uuid_generator) {
-        Error("Unable to generate new GUID. uuid_generator not set.\n");
-        goto bad;
-      }
-      (*uuid_generator)((uint8_t *)&entry->unique);
+  if (SetEntryAttributes(&drive, index, params) ||
+      GptSetEntryAttributes(&drive, index, params)) {
+    memcpy(entry, &backup, sizeof(*entry));
+    goto bad;
   }
 
-  if (params->set_begin)
-    entry->starting_lba = params->begin;
-  if (params->set_size)
-    entry->ending_lba = entry->starting_lba + params->size - 1;
-  if (params->set_type)
-    memcpy(&entry->type, &params->type_guid, sizeof(Guid));
-  if (params->set_unique)
-    memcpy(&entry->unique, &params->unique_guid, sizeof(Guid));
-  if (params->label) {
-    if (CGPT_OK != UTF8ToUTF16((uint8_t *)params->label, entry->name,
-                               sizeof(entry->name) / sizeof(entry->name[0]))) {
-      Error("The label cannot be converted to UTF16.\n");
-      goto bad;
-    }
-  }
-
-  set_entry_attributes(drive, entry, index, params);
-
-  RepairEntries(&drive.gpt, MASK_PRIMARY);
-  RepairHeader(&drive.gpt, MASK_PRIMARY);
-
-  drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
-                         GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
-  UpdateCrc(&drive.gpt);
+  UpdateAllEntries(&drive);
 
   rv = CheckEntries((GptEntry*)drive.gpt.primary_entries,
                     (GptHeader*)drive.gpt.primary_header);
diff --git a/cgpt/cgpt_boot.c b/cgpt/cgpt_boot.c
index 00b783f..386c4f4 100644
--- a/cgpt/cgpt_boot.c
+++ b/cgpt/cgpt_boot.c
@@ -40,7 +40,7 @@
   char buf[GUID_STRLEN];
   GuidToStr(&drive.pmbr.boot_guid, buf, sizeof(buf));
 
-  int numEntries = GetNumberOfEntries(&drive.gpt);
+  int numEntries = GetNumberOfEntries(&drive);
   int i;
   for(i = 0; i < numEntries; i++) {
       GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, i);
@@ -110,7 +110,7 @@
       goto done;
     }
 
-    if (params->partition > GetNumberOfEntries(&drive.gpt)) {
+    if (params->partition > GetNumberOfEntries(&drive)) {
       Error("invalid partition number: %d\n", params->partition);
       goto done;
     }
diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c
index dec26d1..b4f71f7 100644
--- a/cgpt/cgpt_common.c
+++ b/cgpt/cgpt_common.c
@@ -621,33 +621,29 @@
   printf("\n");
 }
 
-uint32_t GetNumberOfEntries(const GptData *gpt) {
-  GptHeader *header = 0;
+GptHeader* GetGptHeader(const GptData *gpt) {
   if (gpt->valid_headers & MASK_PRIMARY)
-    header = (GptHeader*)gpt->primary_header;
+    return (GptHeader*)gpt->primary_header;
   else if (gpt->valid_headers & MASK_SECONDARY)
-    header = (GptHeader*)gpt->secondary_header;
+    return (GptHeader*)gpt->secondary_header;
   else
     return 0;
+}
+
+uint32_t GetNumberOfEntries(const struct drive *drive) {
+  GptHeader *header = GetGptHeader(&drive->gpt);
+  if (!header)
+    return 0;
   return header->number_of_entries;
 }
 
-static uint32_t GetSizeOfEntries(const GptData *gpt) {
-  GptHeader *header = 0;
-  if (gpt->valid_headers & MASK_PRIMARY)
-    header = (GptHeader*)gpt->primary_header;
-  else if (gpt->valid_headers & MASK_SECONDARY)
-    header = (GptHeader*)gpt->secondary_header;
-  else
-    return 0;
-  return header->size_of_entry;
-}
 
 GptEntry *GetEntry(GptData *gpt, int secondary, uint32_t entry_index) {
+  GptHeader *header = GetGptHeader(gpt);
   uint8_t *entries;
-  uint32_t stride = GetSizeOfEntries(gpt);
+  uint32_t stride = header->size_of_entry;
   require(stride);
-  require(entry_index < GetNumberOfEntries(gpt));
+  require(entry_index < header->number_of_entries);
 
   if (secondary == PRIMARY) {
     entries = gpt->primary_entries;
@@ -666,52 +662,75 @@
   return (GptEntry*)(&entries[stride * entry_index]);
 }
 
-void SetPriority(GptData *gpt, int secondary, uint32_t entry_index,
+void SetPriority(struct drive *drive, int secondary, uint32_t entry_index,
                  int priority) {
   GptEntry *entry;
-  entry = GetEntry(gpt, secondary, entry_index);
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
   require(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY);
-  entry->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_PRIORITY_MASK;
-  entry->attrs.fields.gpt_att |= priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET;
+  SetEntryPriority(entry, priority);
 }
 
-int GetPriority(GptData *gpt, int secondary, uint32_t entry_index) {
+int GetPriority(struct drive *drive, int secondary, uint32_t entry_index) {
   GptEntry *entry;
-  entry = GetEntry(gpt, secondary, entry_index);
-  return (entry->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
-      CGPT_ATTRIBUTE_PRIORITY_OFFSET;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  return GetEntryPriority(entry);
 }
 
-void SetTries(GptData *gpt, int secondary, uint32_t entry_index, int tries) {
+void SetTries(struct drive *drive, int secondary, uint32_t entry_index,
+              int tries) {
   GptEntry *entry;
-  entry = GetEntry(gpt, secondary, entry_index);
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
   require(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES);
-  entry->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_TRIES_MASK;
-  entry->attrs.fields.gpt_att |= tries << CGPT_ATTRIBUTE_TRIES_OFFSET;
+  SetEntryTries(entry, tries);
 }
 
-int GetTries(GptData *gpt, int secondary, uint32_t entry_index) {
+int GetTries(struct drive *drive, int secondary, uint32_t entry_index) {
   GptEntry *entry;
-  entry = GetEntry(gpt, secondary, entry_index);
-  return (entry->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >>
-      CGPT_ATTRIBUTE_TRIES_OFFSET;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  return GetEntryTries(entry);
 }
 
-void SetSuccessful(GptData *gpt, int secondary, uint32_t entry_index,
+void SetSuccessful(struct drive *drive, int secondary, uint32_t entry_index,
                    int success) {
   GptEntry *entry;
-  entry = GetEntry(gpt, secondary, entry_index);
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
 
   require(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL);
-  entry->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
-  entry->attrs.fields.gpt_att |= success << CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
+  SetEntrySuccessful(entry, success);
 }
 
-int GetSuccessful(GptData *gpt, int secondary, uint32_t entry_index) {
+int GetSuccessful(struct drive *drive, int secondary, uint32_t entry_index) {
   GptEntry *entry;
-  entry = GetEntry(gpt, secondary, entry_index);
-  return (entry->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
-         CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  return GetEntrySuccessful(entry);
+}
+
+void SetRaw(struct drive *drive, int secondary, uint32_t entry_index,
+           uint32_t raw) {
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  entry->attrs.fields.gpt_att = (uint16_t)raw;
+}
+
+void UpdateAllEntries(struct drive *drive) {
+  RepairEntries(&drive->gpt, MASK_PRIMARY);
+  RepairHeader(&drive->gpt, MASK_PRIMARY);
+
+  drive->gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
+                         GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
+  UpdateCrc(&drive->gpt);
+}
+
+int IsUnused(struct drive *drive, int secondary, uint32_t index) {
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, index);
+  return GuidIsZero(&entry->type);
+}
+
+int IsKernel(struct drive *drive, int secondary, uint32_t index) {
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, index);
+  return GuidEqual(&entry->type, &guid_chromeos_kernel);
 }
 
 
diff --git a/cgpt/cgpt_find.c b/cgpt/cgpt_find.c
index c7c77b0..a8d3186 100644
--- a/cgpt/cgpt_find.c
+++ b/cgpt/cgpt_find.c
@@ -102,7 +102,7 @@
     return 0;
   }
 
-  for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) {
+  for (i = 0; i < GetNumberOfEntries(&drive); ++i) {
     entry = GetEntry(&drive.gpt, ANY_VALID, i);
 
     if (GuidIsZero(&entry->type))
diff --git a/cgpt/cgpt_prioritize.c b/cgpt/cgpt_prioritize.c
index 7cd73c0..4502306 100644
--- a/cgpt/cgpt_prioritize.c
+++ b/cgpt/cgpt_prioritize.c
@@ -97,7 +97,6 @@
   int priority;
 
   int gpt_retval;
-  GptEntry *entry;
   uint32_t index;
   uint32_t max_part;
   int num_kernels;
@@ -116,7 +115,7 @@
     return CGPT_FAILED;
   }
 
-  max_part = GetNumberOfEntries(&drive.gpt);
+  max_part = GetNumberOfEntries(&drive);
 
   if (params->set_partition) {
     if (params->set_partition < 1 || params->set_partition > max_part) {
@@ -126,8 +125,7 @@
     }
     index = params->set_partition - 1;
     // it must be a kernel
-    entry = GetEntry(&drive.gpt, PRIMARY, index);
-    if (!GuidEqual(&entry->type, &guid_chromeos_kernel)) {
+    if (!IsKernel(&drive, PRIMARY, index)) {
       Error("partition %d is not a ChromeOS kernel\n", params->set_partition);
       goto bad;
     }
@@ -136,8 +134,7 @@
   // How many kernel partitions do I have?
   num_kernels = 0;
   for (i = 0; i < max_part; i++) {
-    entry = GetEntry(&drive.gpt, PRIMARY, i);
-    if (GuidEqual(&entry->type, &guid_chromeos_kernel))
+    if (IsKernel(&drive, PRIMARY, i))
       num_kernels++;
   }
 
@@ -145,11 +142,10 @@
     // Determine the current priority groups
     groups = NewGroupList(num_kernels);
     for (i = 0; i < max_part; i++) {
-      entry = GetEntry(&drive.gpt, PRIMARY, i);
-      if (!GuidEqual(&entry->type, &guid_chromeos_kernel))
+      if (!IsKernel(&drive, PRIMARY, i))
         continue;
 
-      priority = GetPriority(&drive.gpt, PRIMARY, i);
+      priority = GetPriority(&drive, PRIMARY, i);
 
       // Is this partition special?
       if (params->set_partition && (i+1 == params->set_partition)) {
@@ -194,19 +190,14 @@
     // Now apply the ranking to the GPT
     for (i=0; i<groups->num_groups; i++)
       for (j=0; j<groups->group[i].num_parts; j++)
-        SetPriority(&drive.gpt, PRIMARY,
+        SetPriority(&drive, PRIMARY,
                     groups->group[i].part[j], groups->group[i].priority);
 
     FreeGroups(groups);
   }
 
   // Write it all out
-  RepairEntries(&drive.gpt, MASK_PRIMARY);
-  RepairHeader(&drive.gpt, MASK_PRIMARY);
-
-  drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
-                         GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
-  UpdateCrc(&drive.gpt);
+  UpdateAllEntries(&drive);
 
   return DriveClose(&drive, 1);
 
diff --git a/cgpt/cgpt_show.c b/cgpt/cgpt_show.c
index cb5e275..351c9ce 100644
--- a/cgpt/cgpt_show.c
+++ b/cgpt/cgpt_show.c
@@ -150,12 +150,12 @@
 }
 
 
-void EntriesDetails(GptData *gpt, const int secondary, int raw) {
+void EntriesDetails(struct drive *drive, const int secondary, int raw) {
   uint32_t i;
 
-  for (i = 0; i < GetNumberOfEntries(gpt); ++i) {
+  for (i = 0; i < GetNumberOfEntries(drive); ++i) {
     GptEntry *entry;
-    entry = GetEntry(gpt, secondary, i);
+    entry = GetEntry(&drive->gpt, secondary, i);
 
     if (GuidIsZero(&entry->type))
       continue;
@@ -183,7 +183,7 @@
   }
 
   params->num_partitions = 0;
-  int numEntries = GetNumberOfEntries(&drive.gpt);
+  int numEntries = GetNumberOfEntries(&drive);
   int i;
   for(i = 0; i < numEntries; i++) {
       GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, i);
@@ -218,7 +218,7 @@
 
   if (params->partition) {                      // show single partition
 
-    if (params->partition > GetNumberOfEntries(&drive.gpt)) {
+    if (params->partition > GetNumberOfEntries(&drive)) {
       Error("invalid partition number: %d\n", params->partition);
       return CGPT_FAILED;
     }
@@ -249,13 +249,13 @@
         printf("%s\n", buf);
         break;
       case 'S':
-        printf("%d\n", GetSuccessful(&drive.gpt, ANY_VALID, index));
+        printf("%d\n", GetSuccessful(&drive, ANY_VALID, index));
         break;
       case 'T':
-        printf("%d\n", GetTries(&drive.gpt, ANY_VALID, index));
+        printf("%d\n", GetTries(&drive, ANY_VALID, index));
         break;
       case 'P':
-        printf("%d\n", GetPriority(&drive.gpt, ANY_VALID, index));
+        printf("%d\n", GetPriority(&drive, ANY_VALID, index));
         break;
       case 'A':
         printf("0x%x\n", entry->attrs.fields.gpt_att);
@@ -271,7 +271,7 @@
     GptEntry *entry;
     char type[GUID_STRLEN];
 
-    for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) {
+    for (i = 0; i < GetNumberOfEntries(&drive); ++i) {
       entry = GetEntry(&drive.gpt, ANY_VALID, i);
 
       if (GuidIsZero(&entry->type))
@@ -324,7 +324,7 @@
 
     if (params->debug ||
         (drive.gpt.valid_entries & MASK_PRIMARY))
-      EntriesDetails(&drive.gpt, PRIMARY, params->numeric);
+      EntriesDetails(&drive, PRIMARY, params->numeric);
 
     /****************************** Secondary *************************/
     printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR -
@@ -342,7 +342,7 @@
          (!(drive.gpt.valid_entries & MASK_PRIMARY) ||
           memcmp(drive.gpt.primary_entries, drive.gpt.secondary_entries,
                  TOTAL_ENTRIES_SIZE)))) {
-      EntriesDetails(&drive.gpt, SECONDARY, params->numeric);
+      EntriesDetails(&drive, SECONDARY, params->numeric);
     }
 
     if (drive.gpt.valid_headers & MASK_SECONDARY)
diff --git a/host/include/cgpt_params.h b/host/include/cgpt_params.h
index c8567e5..14e380a 100644
--- a/host/include/cgpt_params.h
+++ b/host/include/cgpt_params.h
@@ -29,7 +29,7 @@
   int successful;
   int tries;
   int priority;
-  uint16_t raw_value;
+  uint32_t raw_value;
   int set_begin;
   int set_size;
   int set_type;