+
+/* Sets endofpart parameter to the last block used by the last GPT partition on the device.
+ * Returns: 1 if successful
+ * -1 for unknown partition type
+ * 0 for other errors
+ */
+static int get_gpt_last_partition_end(int fd, unsigned long long *endofpart)
+{
+ struct GPT gpt;
+ unsigned char buf[512];
+ unsigned char empty_gpt_entry[16]= {0};
+ struct GPT_part_entry *part;
+ unsigned long long curr_part_end;
+ unsigned all_partitions, entry_size;
+ int part_nr;
+
+ *endofpart = 0;
+
+ BUILD_BUG_ON(sizeof(gpt) != 512);
+ /* read GPT header */
+ lseek(fd, 512, SEEK_SET);
+ if (read(fd, &gpt, 512) != 512)
+ return 0;
+
+ /* get the number of partition entries and the entry size */
+ all_partitions = __le32_to_cpu(gpt.part_cnt);
+ entry_size = __le32_to_cpu(gpt.part_size);
+
+ /* Check GPT signature*/
+ if (gpt.magic != GPT_SIGNATURE_MAGIC)
+ return -1;
+
+ /* sanity checks */
+ if (all_partitions > 1024 ||
+ entry_size > 512)
+ return -1;
+
+ /* read first GPT partition entries */
+ if (read(fd, buf, 512) != 512)
+ return 0;
+
+ part = (struct GPT_part_entry*)buf;
+
+ for (part_nr=0; part_nr < all_partitions; part_nr++) {
+ /* is this valid partition? */
+ if (memcmp(part->type_guid, empty_gpt_entry, 16) != 0) {
+ /* check the last lba for the current partition */
+ curr_part_end = __le64_to_cpu(part->ending_lba);
+ if (curr_part_end > *endofpart)
+ *endofpart = curr_part_end;
+ }
+
+ part = (struct GPT_part_entry*)((unsigned char*)part + entry_size);
+
+ if ((unsigned char *)part >= buf + 512) {
+ if (read(fd, buf, 512) != 512)
+ return 0;
+ part = (struct GPT_part_entry*)buf;
+ }
+ }
+ return 1;
+}
+
+/* Sets endofpart parameter to the last block used by the last partition on the device.
+ * Returns: 1 if successful
+ * -1 for unknown partition type
+ * 0 for other errors
+ */
+static int get_last_partition_end(int fd, unsigned long long *endofpart)
+{
+ struct MBR boot_sect;
+ struct MBR_part_record *part;
+ unsigned long long curr_part_end;
+ int part_nr;
+ int retval = 0;
+
+ *endofpart = 0;
+
+ BUILD_BUG_ON(sizeof(boot_sect) != 512);
+ /* read MBR */
+ lseek(fd, 0, 0);
+ if (read(fd, &boot_sect, 512) != 512)
+ goto abort;
+
+ /* check MBP signature */
+ if (boot_sect.magic == MBR_SIGNATURE_MAGIC) {
+ retval = 1;
+ /* found the correct signature */
+ part = boot_sect.parts;
+
+ for (part_nr=0; part_nr < MBR_PARTITIONS; part_nr++) {
+ /* check for GPT type */
+ if (part->part_type == MBR_GPT_PARTITION_TYPE) {
+ retval = get_gpt_last_partition_end(fd, endofpart);
+ break;
+ }
+ /* check the last used lba for the current partition */
+ curr_part_end = __le32_to_cpu(part->first_sect_lba) +
+ __le32_to_cpu(part->blocks_num);
+ if (curr_part_end > *endofpart)
+ *endofpart = curr_part_end;
+
+ part++;
+ }
+ } else {
+ /* Unknown partition table */
+ retval = -1;
+ }
+ abort:
+ return retval;
+}
+
+int check_partitions(int fd, char *dname, unsigned long long freesize)
+{
+ /*
+ * Check where the last partition ends
+ */
+ unsigned long long endofpart;
+ int ret;
+
+ if ((ret = get_last_partition_end(fd, &endofpart)) > 0) {
+ /* There appears to be a partition table here */
+ if (freesize == 0) {
+ /* partitions will not be visible in new device */
+ fprintf(stderr,
+ Name ": partition table exists on %s but will be lost or\n"
+ " meaningless after creating array\n",
+ dname);
+ return 1;
+ } else if (endofpart > freesize) {
+ /* last partition overlaps metadata */
+ fprintf(stderr,
+ Name ": metadata will over-write last partition on %s.\n",
+ dname);
+ return 1;
+ }
+ }
+ return 0;
+}
+