diff options
Diffstat (limited to 'cgpt/cgpt_add.c')
-rw-r--r-- | cgpt/cgpt_add.c | 188 |
1 files changed, 172 insertions, 16 deletions
diff --git a/cgpt/cgpt_add.c b/cgpt/cgpt_add.c index f989fe4d..5a3aeec7 100644 --- a/cgpt/cgpt_add.c +++ b/cgpt/cgpt_add.c @@ -9,8 +9,27 @@ #include "cgptlib_internal.h" #include "cgpt_params.h" -int cgpt_add(CgptAddParams *params) { +// 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, + uint32_t index, + CgptAddParams *params) { + if (params->set_raw) { + entry->attrs.fields.gpt_att = params->raw_value; + } else { + if (params->set_successful) + SetSuccessful(&drive.gpt, PRIMARY, index, params->successful); + if (params->set_tries) + SetTries(&drive.gpt, PRIMARY, index, params->tries); + if (params->set_priority) + SetPriority(&drive.gpt, PRIMARY, index, params->priority); + } +} +// Set the attributes such as is_successful, num_tries_left, priority, etc. +// from the given values in params. +int cgpt_set_attributes(CgptAddParams *params) { struct drive drive; int gpt_retval; @@ -20,20 +39,164 @@ int cgpt_add(CgptAddParams *params) { if (params == NULL) return CGPT_FAILED; - if (CGPT_OK != DriveOpen(params->driveName, &drive)) + if (CGPT_OK != DriveOpen(params->drive_name, &drive)) return CGPT_FAILED; if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { Error("GptSanityCheck() returned %d: %s\n", gpt_retval, GptError(gpt_retval)); - return CGPT_FAILED; + 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) { + 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; + } + + 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); + + // Write it all out. + return DriveClose(&drive, 1); + +bad: + DriveClose(&drive, 0); + return CGPT_FAILED; +} + +// This method gets the partition details such as the attributes, the +// guids of the partitions, etc. Input is the partition number or the +// unique id of the partition. Output is populated in the respective +// fields of params. +int cgpt_get_partition_details(CgptAddParams *params) { + struct drive drive; + + int gpt_retval; + GptEntry *entry; + uint32_t index; + int result = CGPT_FAILED; + + if (params == NULL) + return result; + + if (CGPT_OK != DriveOpen(params->drive_name, &drive)) { + Error("Unable to open drive: %s\n", params->drive_name); + return result; + } + + if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { + Error("GptSanityCheck() returned %d: %s\n", + gpt_retval, GptError(gpt_retval)); + 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) { + 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); + if (GuidEqual(&entry->unique, ¶ms->unique_guid)) { + params->partition = index + 1; + break; + } + } + + if (index >= max_part) { + Error("no partitions with the given unique id available\n"); + goto bad; + } + } + + // 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. + + params->begin = entry->starting_lba; + params->size = entry->ending_lba - entry->starting_lba + 1; + memcpy(¶ms->type_guid, &entry->type, sizeof(Guid)); + memcpy(¶ms->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); + result = CGPT_OK; + +bad: + DriveClose(&drive, 0); + return result; +} + + +int cgpt_add(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)) return CGPT_FAILED; + + if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { + Error("GptSanityCheck() returned %d: %s\n", + gpt_retval, GptError(gpt_retval)); + 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); @@ -45,7 +208,7 @@ int cgpt_add(CgptAddParams *params) { index = params->partition - 1; entry = GetEntry(&drive.gpt, PRIMARY, index); } else { - // find next empty partition + // Find next empty partition. for (index = 0; index < max_part; index++) { entry = GetEntry(&drive.gpt, PRIMARY, index); if (IsZero(&entry->type)) { @@ -88,16 +251,8 @@ int cgpt_add(CgptAddParams *params) { goto bad; } } - if (params->set_raw) { - entry->attrs.fields.gpt_att = params->raw_value; - } else { - if (params->set_successful) - SetSuccessful(&drive.gpt, PRIMARY, index, params->successful); - if (params->set_tries) - SetTries(&drive.gpt, PRIMARY, index, params->tries); - if (params->set_priority) - SetPriority(&drive.gpt, PRIMARY, index, params->priority); - } + + set_entry_attributes(drive, entry, index, params); RepairEntries(&drive.gpt, MASK_PRIMARY); RepairHeader(&drive.gpt, MASK_PRIMARY); @@ -106,10 +261,11 @@ int cgpt_add(CgptAddParams *params) { GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2); UpdateCrc(&drive.gpt); - // Write it all out + // Write it all out. return DriveClose(&drive, 1); bad: - (void) DriveClose(&drive, 0); + DriveClose(&drive, 0); return CGPT_FAILED; } + |