123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- #if ENABLE_FEATURE_GPT_LABEL
- /*
- * Copyright (C) 2010 Kevin Cernekee <cernekee@gmail.com>
- *
- * Licensed under GPLv2, see file LICENSE in this source tree.
- */
- #define GPT_MAGIC 0x5452415020494645ULL
- enum {
- LEGACY_GPT_TYPE = 0xee,
- GPT_MAX_PARTS = 256,
- GPT_MAX_PART_ENTRY_LEN = 4096,
- GUID_LEN = 16,
- };
- typedef struct {
- uint64_t magic;
- uint32_t revision;
- uint32_t hdr_size;
- uint32_t hdr_crc32;
- uint32_t reserved;
- uint64_t current_lba;
- uint64_t backup_lba;
- uint64_t first_usable_lba;
- uint64_t last_usable_lba;
- uint8_t disk_guid[GUID_LEN];
- uint64_t first_part_lba;
- uint32_t n_parts;
- uint32_t part_entry_len;
- uint32_t part_array_crc32;
- } gpt_header;
- typedef struct {
- uint8_t type_guid[GUID_LEN];
- uint8_t part_guid[GUID_LEN];
- uint64_t lba_start;
- uint64_t lba_end;
- uint64_t flags;
- uint16_t name36[36];
- } gpt_partition;
- static gpt_header *gpt_hdr;
- static char *part_array;
- static unsigned int n_parts;
- static unsigned int part_entry_len;
- static inline gpt_partition *
- gpt_part(int i)
- {
- if (i >= n_parts) {
- return NULL;
- }
- return (gpt_partition *)&part_array[i * part_entry_len];
- }
- static uint32_t
- gpt_crc32(void *buf, int len)
- {
- return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table);
- }
- static void
- gpt_print_guid(uint8_t *buf)
- {
- printf(
- "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- buf[3], buf[2], buf[1], buf[0],
- buf[5], buf[4],
- buf[7], buf[6],
- buf[8], buf[9],
- buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
- }
- static void
- gpt_print_wide36(uint16_t *s)
- {
- #if ENABLE_UNICODE_SUPPORT
- char buf[37 * 4];
- wchar_t wc[37];
- int i = 0;
- while (i < ARRAY_SIZE(wc)-1) {
- if (s[i] == 0)
- break;
- wc[i] = s[i];
- i++;
- }
- wc[i] = 0;
- if (wcstombs(buf, wc, sizeof(buf)) <= sizeof(buf)-1)
- fputs(printable_string(NULL, buf), stdout);
- #else
- char buf[37];
- int i = 0;
- while (i < ARRAY_SIZE(buf)-1) {
- if (s[i] == 0)
- break;
- buf[i] = (0x20 <= s[i] && s[i] < 0x7f) ? s[i] : '?';
- i++;
- }
- buf[i] = '\0';
- fputs(buf, stdout);
- #endif
- }
- static void
- gpt_list_table(int xtra UNUSED_PARAM)
- {
- int i;
- char numstr6[6];
- smart_ulltoa5(total_number_of_sectors * sector_size, numstr6, " KMGTPEZY")[0] = '\0';
- printf("Disk %s: %llu sectors, %s\n", disk_device,
- (unsigned long long)total_number_of_sectors,
- numstr6);
- printf("Logical sector size: %u\n", sector_size);
- printf("Disk identifier (GUID): ");
- gpt_print_guid(gpt_hdr->disk_guid);
- printf("\nPartition table holds up to %u entries\n",
- (int)SWAP_LE32(gpt_hdr->n_parts));
- printf("First usable sector is %llu, last usable sector is %llu\n\n",
- (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba),
- (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba));
- /* "GPT fdisk" has a concept of 16-bit extension of the original MBR 8-bit type codes,
- * which it displays here: its output columns are ... Size Code Name
- * They are their own invention and are not stored on disk.
- * Looks like they use them to support "hybrid" GPT: for example, they have
- * AddType(0x8307, "69DAD710-2CE4-4E3C-B16C-21A1D49ABED3", "Linux ARM32 root (/)");
- * and then (code>>8) matches what you need to put into MBR's type field for such a partition.
- * To print those codes, we'd need a GUID lookup table. Lets just drop the "Code" column instead:
- */
- puts("Number Start (sector) End (sector) Size Name");
- // 123456 123456789012345 123456789012345 12345 abc
- for (i = 0; i < n_parts; i++) {
- gpt_partition *p = gpt_part(i);
- if (p->lba_start) {
- smart_ulltoa5((1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start)) * sector_size,
- numstr6, " KMGTPEZY")[0] = '\0';
- printf("%6u %15llu %15llu %s ",
- i + 1,
- (unsigned long long)SWAP_LE64(p->lba_start),
- (unsigned long long)SWAP_LE64(p->lba_end),
- numstr6
- );
- gpt_print_wide36(p->name36);
- bb_putchar('\n');
- }
- }
- }
- static int
- check_gpt_label(void)
- {
- unsigned part_array_len;
- struct partition *first = pt_offset(MBRbuffer, 0);
- struct pte pe;
- uint32_t crc;
- /* LBA 0 contains the legacy MBR */
- if (!valid_part_table_flag(MBRbuffer)
- || first->sys_ind != LEGACY_GPT_TYPE
- ) {
- current_label_type = 0;
- return 0;
- }
- /* LBA 1 contains the GPT header */
- read_pte(&pe, 1);
- gpt_hdr = (void *)pe.sectorbuffer;
- if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) {
- current_label_type = 0;
- return 0;
- }
- init_unicode();
- if (!global_crc32_table) {
- global_crc32_table = crc32_filltable(NULL, 0);
- }
- crc = SWAP_LE32(gpt_hdr->hdr_crc32);
- gpt_hdr->hdr_crc32 = 0;
- if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) {
- /* FIXME: read the backup table */
- puts("\nwarning: GPT header CRC is invalid\n");
- }
- n_parts = SWAP_LE32(gpt_hdr->n_parts);
- part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len);
- if (n_parts > GPT_MAX_PARTS
- || part_entry_len > GPT_MAX_PART_ENTRY_LEN
- || SWAP_LE32(gpt_hdr->hdr_size) > sector_size
- ) {
- puts("\nwarning: unable to parse GPT disklabel\n");
- current_label_type = 0;
- return 0;
- }
- part_array_len = n_parts * part_entry_len;
- part_array = xmalloc(part_array_len);
- seek_sector(SWAP_LE64(gpt_hdr->first_part_lba));
- if (full_read(dev_fd, part_array, part_array_len) != part_array_len) {
- fdisk_fatal(unable_to_read);
- }
- if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) {
- /* FIXME: read the backup table */
- puts("\nwarning: GPT array CRC is invalid\n");
- }
- puts("Found valid GPT with protective MBR; using GPT\n");
- current_label_type = LABEL_GPT;
- return 1;
- }
- #endif /* GPT_LABEL */
|