Esempio n. 1
0
int CgptRepair(CgptRepairParams *params) {
  struct drive drive;

  if (params == NULL)
    return CGPT_FAILED;

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

  int gpt_retval = GptSanityCheck(&drive.gpt);
  if (params->verbose)
    printf("GptSanityCheck() returned %d: %s\n",
           gpt_retval, GptError(gpt_retval));

  GptRepair(&drive.gpt);
  if (drive.gpt.modified & GPT_MODIFIED_HEADER1)
    printf("Primary Header is updated.\n");
  if (drive.gpt.modified & GPT_MODIFIED_ENTRIES1)
    printf("Primary Entries is updated.\n");
  if (drive.gpt.modified & GPT_MODIFIED_ENTRIES2)
    printf("Secondary Entries is updated.\n");
  if (drive.gpt.modified & GPT_MODIFIED_HEADER2)
    printf("Secondary Header is updated.\n");

  return DriveClose(&drive, 1);
}
Esempio n. 2
0
void GptModified(GptData *gpt) {
	GptHeader *header = (GptHeader *)gpt->primary_header;

	/* Update the CRCs */
	header->entries_crc32 = Crc32(gpt->primary_entries,
				      header->size_of_entry *
				      header->number_of_entries);
	header->header_crc32 = HeaderCrc(header);
	gpt->modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;

	/*
	 * Use the repair function to update the other copy of the GPT.  This
	 * is a tad inefficient, but is much faster than the disk I/O to update
	 * the GPT on disk so it doesn't matter.
	 */
	gpt->valid_headers = MASK_PRIMARY;
	gpt->valid_entries = MASK_PRIMARY;
	GptRepair(gpt);
}
int CgptRepair(CgptRepairParams *params) {
  struct drive drive;

  if (params == NULL)
    return CGPT_FAILED;

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

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

  int gpt_retval = GptSanityCheck(&drive.gpt);
  if (params->verbose)
    printf("GptSanityCheck() returned %d: %s\n",
           gpt_retval, GptError(gpt_retval));

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

  if (drive.gpt.modified & GPT_MODIFIED_HEADER1)
    printf("Primary Header is updated.\n");
  if (drive.gpt.modified & GPT_MODIFIED_ENTRIES1)
    printf("Primary Entries is updated.\n");
  if (drive.gpt.modified & GPT_MODIFIED_ENTRIES2)
    printf("Secondary Entries is updated.\n");
  if (drive.gpt.modified & GPT_MODIFIED_HEADER2)
    printf("Secondary Header is updated.\n");

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

  return DriveClose(&drive, 1);
}
Esempio n. 4
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;
}