Ejemplo n.º 1
0
int CgptAdd(CgptAddParams *params) {
  struct drive drive;

  GptEntry *entry, backup;
  uint32_t index;
  int rv;

  if (params == NULL)
    return CGPT_FAILED;

  if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR))
    return CGPT_FAILED;

  if (CgptCheckAddValidity(&drive)) {
    goto bad;
  }

  if (CgptGetUnusedPartition(&drive, &index, params)) {
    goto bad;
  }

  entry = GetEntry(&drive.gpt, PRIMARY, index);
  memcpy(&backup, entry, sizeof(backup));

  if (SetEntryAttributes(&drive, index, params) ||
      GptSetEntryAttributes(&drive, index, params)) {
    memcpy(entry, &backup, sizeof(*entry));
    goto bad;
  }

  UpdateAllEntries(&drive);

  rv = CheckEntries((GptEntry*)drive.gpt.primary_entries,
                    (GptHeader*)drive.gpt.primary_header);

  if (0 != rv) {
    // If the modified entry is illegal, recover it and return error.
    memcpy(entry, &backup, sizeof(*entry));
    Error("%s\n", GptErrorText(rv));
    Error(DumpCgptAddParams(params));
    goto bad;
  }

  // Write it all out.
  return DriveClose(&drive, 1);

bad:
  DriveClose(&drive, 0);
  return CGPT_FAILED;
}
Ejemplo n.º 2
0
/* Resize the partition and notify the kernel.
 * returns:
 *   CGPT_OK for resize successful or nothing to do
 *   CGPT_FAILED on error
 */
static int resize_partition(CgptResizeParams *params, blkid_dev dev) {
  char *disk_devname;
  struct drive drive;
  GptHeader *header;
  GptEntry *entry;
  int gpt_retval, entry_index, entry_count;
  uint64_t free_bytes, last_free_lba, entry_size_lba;

  if ((disk_devname = dev_to_wholedevname(dev)) == NULL) {
    Error("Failed to find whole disk device for %s\n", blkid_dev_devname(dev));
    return CGPT_FAILED;
  }

  if (DriveOpen(disk_devname, &drive, 0, O_RDWR) != CGPT_OK) {
    free(disk_devname);
    return CGPT_FAILED;
  }

  free(disk_devname);

  if (CGPT_OK != ReadPMBR(&drive)) {
    Error("Unable to read PMBR\n");
    goto nope;
  }

  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
    Error("GptSanityCheck() returned %d: %s\n",
          gpt_retval, GptError(gpt_retval));
    goto nope;
  }

  // If either table is bad fix it! (likely if disk was extended)
  GptRepair(&drive.gpt);

  header = (GptHeader*)drive.gpt.primary_header;
  last_free_lba = header->last_usable_lba;
  entry_count = GetNumberOfEntries(&drive);
  entry_index = dev_to_partno(dev) - 1;
  if (entry_index < 0 || entry_index >= entry_count) {
    Error("Kernel and GPT disagree on the number of partitions!\n");
    goto nope;
  }
  entry = GetEntry(&drive.gpt, PRIMARY, entry_index);

  // Scan entire table to determine if entry can grow.
  for (int i = 0; i < entry_count; i++) {
    GptEntry *other = GetEntry(&drive.gpt, PRIMARY, i);

    if (GuidIsZero(&other->type))
      continue;

    if (other->starting_lba > entry->ending_lba &&
        other->starting_lba - 1 < last_free_lba) {
      last_free_lba = other->starting_lba - 1;
    }
  }

  // Exit without doing anything if the size is too small
  free_bytes = (last_free_lba - entry->ending_lba) * drive.gpt.sector_bytes;
  if (entry->ending_lba >= last_free_lba ||
      free_bytes < params->min_resize_bytes) {
    if (DriveClose(&drive, 0) != CGPT_OK)
      return CGPT_FAILED;
    else
      return CGPT_OK;
  }

  // Update and test partition table in memory
  entry->ending_lba = last_free_lba;
  entry_size_lba = entry->ending_lba - entry->starting_lba;
  UpdateAllEntries(&drive);
  gpt_retval = CheckEntries((GptEntry*)drive.gpt.primary_entries,
                            (GptHeader*)drive.gpt.primary_header);
  if (gpt_retval != GPT_SUCCESS) {
    Error("CheckEntries() returned %d: %s\n",
          gpt_retval, GptError(gpt_retval));
    goto nope;
  }

  // Notify kernel of new partition size via an ioctl.
  if (blkpg_resize_partition(drive.fd, dev_to_partno(dev),
                             entry->starting_lba * drive.gpt.sector_bytes,
                             entry_size_lba * drive.gpt.sector_bytes) < 0) {
    Error("Failed to notify kernel of new partition size: %s\n"
          "Leaving existing partition table in place.\n", strerror(errno));
    goto nope;
  }

  UpdatePMBR(&drive, PRIMARY);
  if (WritePMBR(&drive) != CGPT_OK) {
    Error("Failed to write legacy MBR.\n");
    goto nope;
  }

  // Whew! we made it! Flush to disk.
  return DriveClose(&drive, 1);

nope:
  DriveClose(&drive, 0);
  return CGPT_FAILED;
}
Ejemplo n.º 3
0
int GptSanityCheck(GptData *gpt)
{
	int retval;
	GptHeader *header1 = (GptHeader *)(gpt->primary_header);
	GptHeader *header2 = (GptHeader *)(gpt->secondary_header);
	GptEntry *entries1 = (GptEntry *)(gpt->primary_entries);
	GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries);
	GptHeader *goodhdr = NULL;

	gpt->valid_headers = 0;
	gpt->valid_entries = 0;

	retval = CheckParameters(gpt);
	if (retval != GPT_SUCCESS)
		return retval;

	/* Check both headers; we need at least one valid header. */
	if (0 == CheckHeader(header1, 0, gpt->streaming_drive_sectors,
			     gpt->gpt_drive_sectors, gpt->flags)) {
		gpt->valid_headers |= MASK_PRIMARY;
		goodhdr = header1;
	}
	if (0 == CheckHeader(header2, 1, gpt->streaming_drive_sectors,
			     gpt->gpt_drive_sectors, gpt->flags)) {
		gpt->valid_headers |= MASK_SECONDARY;
		if (!goodhdr)
			goodhdr = header2;
	}

	if (!gpt->valid_headers)
		return GPT_ERROR_INVALID_HEADERS;

	/*
	 * Check if entries are valid.
	 *
	 * Note that we use the same header in both checks.  This way we'll
	 * catch the case where (header1,entries1) and (header2,entries2) are
	 * both valid, but (entries1 != entries2).
	 */
	if (0 == CheckEntries(entries1, goodhdr))
		gpt->valid_entries |= MASK_PRIMARY;
	if (0 == CheckEntries(entries2, goodhdr))
		gpt->valid_entries |= MASK_SECONDARY;

	/*
	 * If both headers are good but neither entries were good, check the
	 * entries with the secondary header.
	 */
	if (MASK_BOTH == gpt->valid_headers && !gpt->valid_entries) {
		if (0 == CheckEntries(entries1, header2))
			gpt->valid_entries |= MASK_PRIMARY;
		if (0 == CheckEntries(entries2, header2))
			gpt->valid_entries |= MASK_SECONDARY;
		if (gpt->valid_entries) {
			/*
			 * Sure enough, header2 had a good CRC for one of the
			 * entries.  Mark header1 invalid, so we'll update its
			 * entries CRC.
			 */
			gpt->valid_headers &= ~MASK_PRIMARY;
			goodhdr = header2;
		}
	}

	if (!gpt->valid_entries)
		return GPT_ERROR_INVALID_ENTRIES;

	/*
	 * Now that we've determined which header contains a good CRC for
	 * the entries, make sure the headers are otherwise identical.
	 */
	if (MASK_BOTH == gpt->valid_headers &&
	    0 != HeaderFieldsSame(header1, header2))
		gpt->valid_headers &= ~MASK_SECONDARY;

	return GPT_SUCCESS;
}