Home | History | Annotate | Download | only in cgpt
      1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  *
      5  * Utility for ChromeOS-specific GPT partitions, Please see corresponding .c
      6  * files for more details.
      7  */
      8 
      9 #include <errno.h>
     10 #include <fcntl.h>
     11 #include <getopt.h>
     12 #ifndef HAVE_MACOS
     13 #include <linux/major.h>
     14 #include <mtd/mtd-user.h>
     15 #endif
     16 #include <stdarg.h>
     17 #include <stdint.h>
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include <string.h>
     21 #include <sys/ioctl.h>
     22 #include <sys/mount.h>
     23 #include <sys/stat.h>
     24 #include <sys/types.h>
     25 #include <unistd.h>
     26 
     27 #include "cgpt.h"
     28 #include "cgptlib_internal.h"
     29 #include "crc32.h"
     30 #include "vboot_host.h"
     31 
     32 static const char kErrorTag[] = "ERROR";
     33 static const char kWarningTag[] = "WARNING";
     34 
     35 static void LogToStderr(const char *tag, const char *format, va_list ap) {
     36   fprintf(stderr, "%s: ", tag);
     37   vfprintf(stderr, format, ap);
     38 }
     39 
     40 void Error(const char *format, ...) {
     41   va_list ap;
     42   va_start(ap, format);
     43   LogToStderr(kErrorTag, format, ap);
     44   va_end(ap);
     45 }
     46 
     47 void Warning(const char *format, ...) {
     48   va_list ap;
     49   va_start(ap, format);
     50   LogToStderr(kWarningTag, format, ap);
     51   va_end(ap);
     52 }
     53 
     54 int CheckValid(const struct drive *drive) {
     55   if ((drive->gpt.valid_headers != MASK_BOTH) ||
     56       (drive->gpt.valid_entries != MASK_BOTH)) {
     57     Warning("One of the GPT headers/entries is invalid\n\n");
     58     return CGPT_FAILED;
     59   }
     60   return CGPT_OK;
     61 }
     62 
     63 int Load(struct drive *drive, uint8_t **buf,
     64                 const uint64_t sector,
     65                 const uint64_t sector_bytes,
     66                 const uint64_t sector_count) {
     67   int count;  /* byte count to read */
     68   int nread;
     69 
     70   require(buf);
     71   if (!sector_count || !sector_bytes) {
     72     Error("%s() failed at line %d: sector_count=%ld, sector_bytes=%ld\n",
     73           __FUNCTION__, __LINE__, sector_count, sector_bytes);
     74     return CGPT_FAILED;
     75   }
     76   /* Make sure that sector_bytes * sector_count doesn't roll over. */
     77   if (sector_bytes > (UINT64_MAX / sector_count)) {
     78     Error("%s() failed at line %d: sector_count=%d, sector_bytes=%d\n",
     79           __FUNCTION__, __LINE__, sector_count, sector_bytes);
     80     return CGPT_FAILED;
     81   }
     82   count = sector_bytes * sector_count;
     83   *buf = malloc(count);
     84   require(*buf);
     85 
     86   if (-1 == lseek(drive->fd, sector * sector_bytes, SEEK_SET)) {
     87     Error("Can't seek: %s\n", strerror(errno));
     88     goto error_free;
     89   }
     90 
     91   nread = read(drive->fd, *buf, count);
     92   if (nread < count) {
     93     Error("Can't read enough: %d, not %d\n", nread, count);
     94     goto error_free;
     95   }
     96 
     97   return CGPT_OK;
     98 
     99 error_free:
    100   free(*buf);
    101   *buf = 0;
    102   return CGPT_FAILED;
    103 }
    104 
    105 
    106 int ReadPMBR(struct drive *drive) {
    107   if (-1 == lseek(drive->fd, 0, SEEK_SET))
    108     return CGPT_FAILED;
    109 
    110   int nread = read(drive->fd, &drive->pmbr, sizeof(struct pmbr));
    111   if (nread != sizeof(struct pmbr))
    112     return CGPT_FAILED;
    113 
    114   return CGPT_OK;
    115 }
    116 
    117 int WritePMBR(struct drive *drive) {
    118   if (-1 == lseek(drive->fd, 0, SEEK_SET))
    119     return CGPT_FAILED;
    120 
    121   int nwrote = write(drive->fd, &drive->pmbr, sizeof(struct pmbr));
    122   if (nwrote != sizeof(struct pmbr))
    123     return CGPT_FAILED;
    124 
    125   return CGPT_OK;
    126 }
    127 
    128 int Save(struct drive *drive, const uint8_t *buf,
    129                 const uint64_t sector,
    130                 const uint64_t sector_bytes,
    131                 const uint64_t sector_count) {
    132   int count;  /* byte count to write */
    133   int nwrote;
    134 
    135   require(buf);
    136   count = sector_bytes * sector_count;
    137 
    138   if (-1 == lseek(drive->fd, sector * sector_bytes, SEEK_SET))
    139     return CGPT_FAILED;
    140 
    141   nwrote = write(drive->fd, buf, count);
    142   if (nwrote < count)
    143     return CGPT_FAILED;
    144 
    145   return CGPT_OK;
    146 }
    147 
    148 static int GptLoad(struct drive *drive, uint32_t sector_bytes) {
    149   drive->gpt.sector_bytes = sector_bytes;
    150   if (drive->size % drive->gpt.sector_bytes) {
    151     Error("Media size (%llu) is not a multiple of sector size(%d)\n",
    152           (long long unsigned int)drive->size, drive->gpt.sector_bytes);
    153     return -1;
    154   }
    155   drive->gpt.streaming_drive_sectors = drive->size / drive->gpt.sector_bytes;
    156 
    157   /* TODO(namnguyen): Remove this and totally trust gpt_drive_sectors. */
    158   if (!(drive->gpt.flags & GPT_FLAG_EXTERNAL)) {
    159     drive->gpt.gpt_drive_sectors = drive->gpt.streaming_drive_sectors;
    160   } /* Else, we trust gpt.gpt_drive_sectors. */
    161 
    162   // Read the data.
    163   if (CGPT_OK != Load(drive, &drive->gpt.primary_header,
    164                       GPT_PMBR_SECTORS,
    165                       drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) {
    166     Error("Cannot read primary GPT header\n");
    167     return -1;
    168   }
    169   if (CGPT_OK != Load(drive, &drive->gpt.secondary_header,
    170                       drive->gpt.gpt_drive_sectors - GPT_PMBR_SECTORS,
    171                       drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) {
    172     Error("Cannot read secondary GPT header\n");
    173     return -1;
    174   }
    175   GptHeader* primary_header = (GptHeader*)drive->gpt.primary_header;
    176   if (CheckHeader(primary_header, 0, drive->gpt.streaming_drive_sectors,
    177                   drive->gpt.gpt_drive_sectors,
    178                   drive->gpt.flags) == 0) {
    179     if (CGPT_OK != Load(drive, &drive->gpt.primary_entries,
    180                         primary_header->entries_lba,
    181                         drive->gpt.sector_bytes,
    182                         CalculateEntriesSectors(primary_header))) {
    183       Error("Cannot read primary partition entry array\n");
    184       return -1;
    185     }
    186   } else {
    187     Warning("Primary GPT header is invalid\n");
    188   }
    189   GptHeader* secondary_header = (GptHeader*)drive->gpt.secondary_header;
    190   if (CheckHeader(secondary_header, 1, drive->gpt.streaming_drive_sectors,
    191                   drive->gpt.gpt_drive_sectors,
    192                   drive->gpt.flags) == 0) {
    193     if (CGPT_OK != Load(drive, &drive->gpt.secondary_entries,
    194                         secondary_header->entries_lba,
    195                         drive->gpt.sector_bytes,
    196                         CalculateEntriesSectors(secondary_header))) {
    197       Error("Cannot read secondary partition entry array\n");
    198       return -1;
    199     }
    200   } else {
    201     Warning("Secondary GPT header is invalid\n");
    202   }
    203   return 0;
    204 }
    205 
    206 static int GptSave(struct drive *drive) {
    207   int errors = 0;
    208   if (drive->gpt.modified & GPT_MODIFIED_HEADER1) {
    209     if (CGPT_OK != Save(drive, drive->gpt.primary_header,
    210                         GPT_PMBR_SECTORS,
    211                         drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) {
    212       errors++;
    213       Error("Cannot write primary header: %s\n", strerror(errno));
    214     }
    215   }
    216 
    217   if (drive->gpt.modified & GPT_MODIFIED_HEADER2) {
    218     if(CGPT_OK != Save(drive, drive->gpt.secondary_header,
    219                        drive->gpt.gpt_drive_sectors - GPT_PMBR_SECTORS,
    220                        drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) {
    221       errors++;
    222       Error("Cannot write secondary header: %s\n", strerror(errno));
    223     }
    224   }
    225   GptHeader* primary_header = (GptHeader*)drive->gpt.primary_header;
    226   if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) {
    227     if (CGPT_OK != Save(drive, drive->gpt.primary_entries,
    228                         primary_header->entries_lba,
    229                         drive->gpt.sector_bytes,
    230                         CalculateEntriesSectors(primary_header))) {
    231       errors++;
    232       Error("Cannot write primary entries: %s\n", strerror(errno));
    233     }
    234   }
    235   GptHeader* secondary_header = (GptHeader*)drive->gpt.secondary_header;
    236   if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2) {
    237     if (CGPT_OK != Save(drive, drive->gpt.secondary_entries,
    238                         secondary_header->entries_lba,
    239                         drive->gpt.sector_bytes,
    240                         CalculateEntriesSectors(secondary_header))) {
    241       errors++;
    242       Error("Cannot write secondary entries: %s\n", strerror(errno));
    243     }
    244   }
    245 
    246   if (drive->gpt.primary_header)
    247     free(drive->gpt.primary_header);
    248   drive->gpt.primary_header = 0;
    249   if (drive->gpt.primary_entries)
    250     free(drive->gpt.primary_entries);
    251   drive->gpt.primary_entries = 0;
    252   if (drive->gpt.secondary_header)
    253     free(drive->gpt.secondary_header);
    254   drive->gpt.secondary_header = 0;
    255   if (drive->gpt.secondary_entries)
    256     free(drive->gpt.secondary_entries);
    257   drive->gpt.secondary_entries = 0;
    258   return errors ? -1 : 0;
    259 }
    260 
    261 /*
    262  * Query drive size and bytes per sector. Return zero on success. On error,
    263  * -1 is returned and errno is set appropriately.
    264  */
    265 static int ObtainDriveSize(int fd, uint64_t* size, uint32_t* sector_bytes) {
    266   struct stat stat;
    267   if (fstat(fd, &stat) == -1) {
    268     return -1;
    269   }
    270 #ifndef HAVE_MACOS
    271   if ((stat.st_mode & S_IFMT) != S_IFREG) {
    272     if (ioctl(fd, BLKGETSIZE64, size) < 0) {
    273       return -1;
    274     }
    275     if (ioctl(fd, BLKSSZGET, sector_bytes) < 0) {
    276       return -1;
    277     }
    278   } else {
    279     *sector_bytes = 512;  /* bytes */
    280     *size = stat.st_size;
    281   }
    282 #else
    283   *sector_bytes = 512;  /* bytes */
    284   *size = stat.st_size;
    285 #endif
    286   return 0;
    287 }
    288 
    289 int DriveOpen(const char *drive_path, struct drive *drive, int mode,
    290               uint64_t drive_size) {
    291   uint32_t sector_bytes;
    292 
    293   require(drive_path);
    294   require(drive);
    295 
    296   // Clear struct for proper error handling.
    297   memset(drive, 0, sizeof(struct drive));
    298 
    299   drive->fd = open(drive_path, mode |
    300 #ifndef HAVE_MACOS
    301 		               O_LARGEFILE |
    302 #endif
    303 			       O_NOFOLLOW);
    304   if (drive->fd == -1) {
    305     Error("Can't open %s: %s\n", drive_path, strerror(errno));
    306     return CGPT_FAILED;
    307   }
    308 
    309   sector_bytes = 512;
    310   uint64_t gpt_drive_size;
    311   if (ObtainDriveSize(drive->fd, &gpt_drive_size, &sector_bytes) != 0) {
    312     Error("Can't get drive size and bytes per sector for %s: %s\n",
    313           drive_path, strerror(errno));
    314     goto error_close;
    315   }
    316 
    317   drive->gpt.gpt_drive_sectors = gpt_drive_size / sector_bytes;
    318   if (drive_size == 0) {
    319     drive->size = gpt_drive_size;
    320     drive->gpt.flags = 0;
    321   } else {
    322     drive->size = drive_size;
    323     drive->gpt.flags = GPT_FLAG_EXTERNAL;
    324   }
    325 
    326 
    327   if (GptLoad(drive, sector_bytes)) {
    328     goto error_close;
    329   }
    330 
    331   // We just load the data. Caller must validate it.
    332   return CGPT_OK;
    333 
    334 error_close:
    335   (void) DriveClose(drive, 0);
    336   return CGPT_FAILED;
    337 }
    338 
    339 
    340 int DriveClose(struct drive *drive, int update_as_needed) {
    341   int errors = 0;
    342 
    343   if (update_as_needed) {
    344     if (GptSave(drive)) {
    345         errors++;
    346     }
    347   }
    348 
    349   // Sync early! Only sync file descriptor here, and leave the whole system sync
    350   // outside cgpt because whole system sync would trigger tons of disk accesses
    351   // and timeout tests.
    352   fsync(drive->fd);
    353 
    354   close(drive->fd);
    355 
    356   return errors ? CGPT_FAILED : CGPT_OK;
    357 }
    358 
    359 
    360 /* GUID conversion functions. Accepted format:
    361  *
    362  *   "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
    363  *
    364  * Returns CGPT_OK if parsing is successful; otherwise CGPT_FAILED.
    365  */
    366 int StrToGuid(const char *str, Guid *guid) {
    367   uint32_t time_low;
    368   uint16_t time_mid;
    369   uint16_t time_high_and_version;
    370   unsigned int chunk[11];
    371 
    372   if (11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
    373                    chunk+0,
    374                    chunk+1,
    375                    chunk+2,
    376                    chunk+3,
    377                    chunk+4,
    378                    chunk+5,
    379                    chunk+6,
    380                    chunk+7,
    381                    chunk+8,
    382                    chunk+9,
    383                    chunk+10)) {
    384     printf("FAILED\n");
    385     return CGPT_FAILED;
    386   }
    387 
    388   time_low = chunk[0] & 0xffffffff;
    389   time_mid = chunk[1] & 0xffff;
    390   time_high_and_version = chunk[2] & 0xffff;
    391 
    392   guid->u.Uuid.time_low = htole32(time_low);
    393   guid->u.Uuid.time_mid = htole16(time_mid);
    394   guid->u.Uuid.time_high_and_version = htole16(time_high_and_version);
    395 
    396   guid->u.Uuid.clock_seq_high_and_reserved = chunk[3] & 0xff;
    397   guid->u.Uuid.clock_seq_low = chunk[4] & 0xff;
    398   guid->u.Uuid.node[0] = chunk[5] & 0xff;
    399   guid->u.Uuid.node[1] = chunk[6] & 0xff;
    400   guid->u.Uuid.node[2] = chunk[7] & 0xff;
    401   guid->u.Uuid.node[3] = chunk[8] & 0xff;
    402   guid->u.Uuid.node[4] = chunk[9] & 0xff;
    403   guid->u.Uuid.node[5] = chunk[10] & 0xff;
    404 
    405   return CGPT_OK;
    406 }
    407 void GuidToStr(const Guid *guid, char *str, unsigned int buflen) {
    408   require(buflen >= GUID_STRLEN);
    409   require(snprintf(str, buflen,
    410                   "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
    411                   le32toh(guid->u.Uuid.time_low),
    412                   le16toh(guid->u.Uuid.time_mid),
    413                   le16toh(guid->u.Uuid.time_high_and_version),
    414                   guid->u.Uuid.clock_seq_high_and_reserved,
    415                   guid->u.Uuid.clock_seq_low,
    416                   guid->u.Uuid.node[0], guid->u.Uuid.node[1],
    417                   guid->u.Uuid.node[2], guid->u.Uuid.node[3],
    418                   guid->u.Uuid.node[4], guid->u.Uuid.node[5]) == GUID_STRLEN-1);
    419 }
    420 
    421 /* Convert possibly unterminated UTF16 string to UTF8.
    422  * Caller must prepare enough space for UTF8, which could be up to
    423  * twice the byte length of UTF16 string plus the terminating '\0'.
    424  * See the following table for encoding lengths.
    425  *
    426  *     Code point       UTF16       UTF8
    427  *   0x0000-0x007F     2 bytes     1 byte
    428  *   0x0080-0x07FF     2 bytes     2 bytes
    429  *   0x0800-0xFFFF     2 bytes     3 bytes
    430  *  0x10000-0x10FFFF   4 bytes     4 bytes
    431  *
    432  * This function uses a simple state meachine to convert UTF-16 char(s) to
    433  * a code point. Once a code point is parsed out, the state machine throws
    434  * out sequencial UTF-8 chars in one time.
    435  *
    436  * Return: CGPT_OK --- all character are converted successfully.
    437  *         CGPT_FAILED --- convert error, i.e. output buffer is too short.
    438  */
    439 int UTF16ToUTF8(const uint16_t *utf16, unsigned int maxinput,
    440                 uint8_t *utf8, unsigned int maxoutput)
    441 {
    442   size_t s16idx, s8idx;
    443   uint32_t code_point = 0;
    444   int code_point_ready = 1;  // code point is ready to output.
    445   int retval = CGPT_OK;
    446 
    447   if (!utf16 || !maxinput || !utf8 || !maxoutput)
    448     return CGPT_FAILED;
    449 
    450   maxoutput--;                             /* plan for termination now */
    451 
    452   for (s16idx = s8idx = 0;
    453        s16idx < maxinput && utf16[s16idx] && maxoutput;
    454        s16idx++) {
    455     uint16_t codeunit = le16toh(utf16[s16idx]);
    456 
    457     if (code_point_ready) {
    458       if (codeunit >= 0xD800 && codeunit <= 0xDBFF) {
    459         /* high surrogate, need the low surrogate. */
    460         code_point_ready = 0;
    461         code_point = (codeunit & 0x03FF) + 0x0040;
    462       } else {
    463         /* BMP char, output it. */
    464         code_point = codeunit;
    465       }
    466     } else {
    467       /* expect the low surrogate */
    468       if (codeunit >= 0xDC00 && codeunit <= 0xDFFF) {
    469         code_point = (code_point << 10) | (codeunit & 0x03FF);
    470         code_point_ready = 1;
    471       } else {
    472         /* the second code unit is NOT the low surrogate. Unexpected. */
    473         code_point_ready = 0;
    474         retval = CGPT_FAILED;
    475         break;
    476       }
    477     }
    478 
    479     /* If UTF code point is ready, output it. */
    480     if (code_point_ready) {
    481       require(code_point <= 0x10FFFF);
    482       if (code_point <= 0x7F && maxoutput >= 1) {
    483         maxoutput -= 1;
    484         utf8[s8idx++] = code_point & 0x7F;
    485       } else if (code_point <= 0x7FF && maxoutput >= 2) {
    486         maxoutput -= 2;
    487         utf8[s8idx++] = 0xC0 | (code_point >> 6);
    488         utf8[s8idx++] = 0x80 | (code_point & 0x3F);
    489       } else if (code_point <= 0xFFFF && maxoutput >= 3) {
    490         maxoutput -= 3;
    491         utf8[s8idx++] = 0xE0 | (code_point >> 12);
    492         utf8[s8idx++] = 0x80 | ((code_point >> 6) & 0x3F);
    493         utf8[s8idx++] = 0x80 | (code_point & 0x3F);
    494       } else if (code_point <= 0x10FFFF && maxoutput >= 4) {
    495         maxoutput -= 4;
    496         utf8[s8idx++] = 0xF0 | (code_point >> 18);
    497         utf8[s8idx++] = 0x80 | ((code_point >> 12) & 0x3F);
    498         utf8[s8idx++] = 0x80 | ((code_point >> 6) & 0x3F);
    499         utf8[s8idx++] = 0x80 | (code_point & 0x3F);
    500       } else {
    501         /* buffer underrun */
    502         retval = CGPT_FAILED;
    503         break;
    504       }
    505     }
    506   }
    507   utf8[s8idx++] = 0;
    508   return retval;
    509 }
    510 
    511 /* Convert UTF8 string to UTF16. The UTF8 string must be null-terminated.
    512  * Caller must prepare enough space for UTF16, including a terminating 0x0000.
    513  * See the following table for encoding lengths. In any case, the caller
    514  * just needs to prepare the byte length of UTF8 plus the terminating 0x0000.
    515  *
    516  *     Code point       UTF16       UTF8
    517  *   0x0000-0x007F     2 bytes     1 byte
    518  *   0x0080-0x07FF     2 bytes     2 bytes
    519  *   0x0800-0xFFFF     2 bytes     3 bytes
    520  *  0x10000-0x10FFFF   4 bytes     4 bytes
    521  *
    522  * This function converts UTF8 chars to a code point first. Then, convrts it
    523  * to UTF16 code unit(s).
    524  *
    525  * Return: CGPT_OK --- all character are converted successfully.
    526  *         CGPT_FAILED --- convert error, i.e. output buffer is too short.
    527  */
    528 int UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16, unsigned int maxoutput)
    529 {
    530   size_t s16idx, s8idx;
    531   uint32_t code_point = 0;
    532   unsigned int expected_units = 1;
    533   unsigned int decoded_units = 1;
    534   int retval = CGPT_OK;
    535 
    536   if (!utf8 || !utf16 || !maxoutput)
    537     return CGPT_FAILED;
    538 
    539   maxoutput--;                             /* plan for termination */
    540 
    541   for (s8idx = s16idx = 0;
    542        utf8[s8idx] && maxoutput;
    543        s8idx++) {
    544     uint8_t code_unit;
    545     code_unit = utf8[s8idx];
    546 
    547     if (expected_units != decoded_units) {
    548       /* Trailing bytes of multi-byte character */
    549       if ((code_unit & 0xC0) == 0x80) {
    550         code_point = (code_point << 6) | (code_unit & 0x3F);
    551         ++decoded_units;
    552       } else {
    553         /* Unexpected code unit. */
    554         retval = CGPT_FAILED;
    555         break;
    556       }
    557     } else {
    558       /* parsing a new code point. */
    559       decoded_units = 1;
    560       if (code_unit <= 0x7F) {
    561         code_point = code_unit;
    562         expected_units = 1;
    563       } else if (code_unit <= 0xBF) {
    564         /* 0x80-0xBF must NOT be the heading byte unit of a new code point. */
    565         retval = CGPT_FAILED;
    566         break;
    567       } else if (code_unit >= 0xC2 && code_unit <= 0xDF) {
    568         code_point = code_unit & 0x1F;
    569         expected_units = 2;
    570       } else if (code_unit >= 0xE0 && code_unit <= 0xEF) {
    571         code_point = code_unit & 0x0F;
    572         expected_units = 3;
    573       } else if (code_unit >= 0xF0 && code_unit <= 0xF4) {
    574         code_point = code_unit & 0x07;
    575         expected_units = 4;
    576       } else {
    577         /* illegal code unit: 0xC0-0xC1, 0xF5-0xFF */
    578         retval = CGPT_FAILED;
    579         break;
    580       }
    581     }
    582 
    583     /* If no more unit is needed, output the UTF16 unit(s). */
    584     if ((retval == CGPT_OK) &&
    585         (expected_units == decoded_units)) {
    586       /* Check if the encoding is the shortest possible UTF-8 sequence. */
    587       switch (expected_units) {
    588         case 2:
    589           if (code_point <= 0x7F) retval = CGPT_FAILED;
    590           break;
    591         case 3:
    592           if (code_point <= 0x7FF) retval = CGPT_FAILED;
    593           break;
    594         case 4:
    595           if (code_point <= 0xFFFF) retval = CGPT_FAILED;
    596           break;
    597       }
    598       if (retval == CGPT_FAILED) break;  /* leave immediately */
    599 
    600       if ((code_point <= 0xD7FF) ||
    601           (code_point >= 0xE000 && code_point <= 0xFFFF)) {
    602         utf16[s16idx++] = code_point;
    603         maxoutput -= 1;
    604       } else if (code_point >= 0x10000 && code_point <= 0x10FFFF &&
    605                  maxoutput >= 2) {
    606         utf16[s16idx++] = 0xD800 | ((code_point >> 10) - 0x0040);
    607         utf16[s16idx++] = 0xDC00 | (code_point & 0x03FF);
    608         maxoutput -= 2;
    609       } else {
    610         /* Three possibilities fall into here. Both are failure cases.
    611          *   a. surrogate pair (non-BMP characters; 0xD800~0xDFFF)
    612          *   b. invalid code point > 0x10FFFF
    613          *   c. buffer underrun
    614          */
    615         retval = CGPT_FAILED;
    616         break;
    617       }
    618     }
    619   }
    620 
    621   /* A null-terminator shows up before the UTF8 sequence ends. */
    622   if (expected_units != decoded_units) {
    623     retval = CGPT_FAILED;
    624   }
    625 
    626   utf16[s16idx++] = 0;
    627   return retval;
    628 }
    629 
    630 /* global types to compare against */
    631 const Guid guid_chromeos_firmware = GPT_ENT_TYPE_CHROMEOS_FIRMWARE;
    632 const Guid guid_chromeos_kernel =   GPT_ENT_TYPE_CHROMEOS_KERNEL;
    633 const Guid guid_chromeos_rootfs =   GPT_ENT_TYPE_CHROMEOS_ROOTFS;
    634 const Guid guid_linux_data =        GPT_ENT_TYPE_LINUX_DATA;
    635 const Guid guid_chromeos_reserved = GPT_ENT_TYPE_CHROMEOS_RESERVED;
    636 const Guid guid_efi =               GPT_ENT_TYPE_EFI;
    637 const Guid guid_unused =            GPT_ENT_TYPE_UNUSED;
    638 
    639 const static struct {
    640   const Guid *type;
    641   char *name;
    642   char *description;
    643 } supported_types[] = {
    644   {&guid_chromeos_firmware, "firmware", "ChromeOS firmware"},
    645   {&guid_chromeos_kernel, "kernel", "ChromeOS kernel"},
    646   {&guid_chromeos_rootfs, "rootfs", "ChromeOS rootfs"},
    647   {&guid_linux_data, "data", "Linux data"},
    648   {&guid_chromeos_reserved, "reserved", "ChromeOS reserved"},
    649   {&guid_efi, "efi", "EFI System Partition"},
    650   {&guid_unused, "unused", "Unused (nonexistent) partition"},
    651 };
    652 
    653 /* Resolves human-readable GPT type.
    654  * Returns CGPT_OK if found.
    655  * Returns CGPT_FAILED if no known type found. */
    656 int ResolveType(const Guid *type, char *buf) {
    657   int i;
    658   for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
    659     if (!memcmp(type, supported_types[i].type, sizeof(Guid))) {
    660       strcpy(buf, supported_types[i].description);
    661       return CGPT_OK;
    662     }
    663   }
    664   return CGPT_FAILED;
    665 }
    666 
    667 int SupportedType(const char *name, Guid *type) {
    668   int i;
    669   for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
    670     if (!strcmp(name, supported_types[i].name)) {
    671       memcpy(type, supported_types[i].type, sizeof(Guid));
    672       return CGPT_OK;
    673     }
    674   }
    675   return CGPT_FAILED;
    676 }
    677 
    678 void PrintTypes(void) {
    679   int i;
    680   printf("The partition type may also be given as one of these aliases:\n\n");
    681   for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
    682     printf("    %-10s  %s\n", supported_types[i].name,
    683                           supported_types[i].description);
    684   }
    685   printf("\n");
    686 }
    687 
    688 static GptHeader* GetGptHeader(const GptData *gpt) {
    689   if (gpt->valid_headers & MASK_PRIMARY)
    690     return (GptHeader*)gpt->primary_header;
    691   else if (gpt->valid_headers & MASK_SECONDARY)
    692     return (GptHeader*)gpt->secondary_header;
    693   else
    694     return 0;
    695 }
    696 
    697 uint32_t GetNumberOfEntries(const struct drive *drive) {
    698   GptHeader *header = GetGptHeader(&drive->gpt);
    699   if (!header)
    700     return 0;
    701   return header->number_of_entries;
    702 }
    703 
    704 
    705 GptEntry *GetEntry(GptData *gpt, int secondary, uint32_t entry_index) {
    706   GptHeader *header = GetGptHeader(gpt);
    707   uint8_t *entries;
    708   uint32_t stride = header->size_of_entry;
    709   require(stride);
    710   require(entry_index < header->number_of_entries);
    711 
    712   if (secondary == PRIMARY) {
    713     entries = gpt->primary_entries;
    714   } else if (secondary == SECONDARY) {
    715     entries = gpt->secondary_entries;
    716   } else {  /* ANY_VALID */
    717     require(secondary == ANY_VALID);
    718     if (gpt->valid_entries & MASK_PRIMARY) {
    719       entries = gpt->primary_entries;
    720     } else {
    721       require(gpt->valid_entries & MASK_SECONDARY);
    722       entries = gpt->secondary_entries;
    723     }
    724   }
    725 
    726   return (GptEntry*)(&entries[stride * entry_index]);
    727 }
    728 
    729 void SetPriority(struct drive *drive, int secondary, uint32_t entry_index,
    730                  int priority) {
    731   require(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY);
    732   GptEntry *entry;
    733   entry = GetEntry(&drive->gpt, secondary, entry_index);
    734   SetEntryPriority(entry, priority);
    735 }
    736 
    737 int GetPriority(struct drive *drive, int secondary, uint32_t entry_index) {
    738   GptEntry *entry;
    739   entry = GetEntry(&drive->gpt, secondary, entry_index);
    740   return GetEntryPriority(entry);
    741 }
    742 
    743 void SetTries(struct drive *drive, int secondary, uint32_t entry_index,
    744               int tries) {
    745   require(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES);
    746   GptEntry *entry;
    747   entry = GetEntry(&drive->gpt, secondary, entry_index);
    748   SetEntryTries(entry, tries);
    749 }
    750 
    751 int GetTries(struct drive *drive, int secondary, uint32_t entry_index) {
    752   GptEntry *entry;
    753   entry = GetEntry(&drive->gpt, secondary, entry_index);
    754   return GetEntryTries(entry);
    755 }
    756 
    757 void SetSuccessful(struct drive *drive, int secondary, uint32_t entry_index,
    758                    int success) {
    759   require(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL);
    760   GptEntry *entry;
    761   entry = GetEntry(&drive->gpt, secondary, entry_index);
    762   SetEntrySuccessful(entry, success);
    763 }
    764 
    765 int GetSuccessful(struct drive *drive, int secondary, uint32_t entry_index) {
    766   GptEntry *entry;
    767   entry = GetEntry(&drive->gpt, secondary, entry_index);
    768   return GetEntrySuccessful(entry);
    769 }
    770 
    771 void SetRaw(struct drive *drive, int secondary, uint32_t entry_index,
    772             uint32_t raw) {
    773   GptEntry *entry;
    774   entry = GetEntry(&drive->gpt, secondary, entry_index);
    775   entry->attrs.fields.gpt_att = (uint16_t)raw;
    776 }
    777 
    778 void UpdateAllEntries(struct drive *drive) {
    779   RepairEntries(&drive->gpt, MASK_PRIMARY);
    780   RepairHeader(&drive->gpt, MASK_PRIMARY);
    781 
    782   drive->gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
    783                           GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
    784   UpdateCrc(&drive->gpt);
    785 }
    786 
    787 int IsUnused(struct drive *drive, int secondary, uint32_t index) {
    788   GptEntry *entry;
    789   entry = GetEntry(&drive->gpt, secondary, index);
    790   return GuidIsZero(&entry->type);
    791 }
    792 
    793 int IsKernel(struct drive *drive, int secondary, uint32_t index) {
    794   GptEntry *entry;
    795   entry = GetEntry(&drive->gpt, secondary, index);
    796   return GuidEqual(&entry->type, &guid_chromeos_kernel);
    797 }
    798 
    799 
    800 #define TOSTRING(A) #A
    801 const char *GptError(int errnum) {
    802   const char *error_string[] = {
    803     TOSTRING(GPT_SUCCESS),
    804     TOSTRING(GPT_ERROR_NO_VALID_KERNEL),
    805     TOSTRING(GPT_ERROR_INVALID_HEADERS),
    806     TOSTRING(GPT_ERROR_INVALID_ENTRIES),
    807     TOSTRING(GPT_ERROR_INVALID_SECTOR_SIZE),
    808     TOSTRING(GPT_ERROR_INVALID_SECTOR_NUMBER),
    809     TOSTRING(GPT_ERROR_INVALID_UPDATE_TYPE)
    810   };
    811   if (errnum < 0 || errnum >= ARRAY_COUNT(error_string))
    812     return "<illegal value>";
    813   return error_string[errnum];
    814 }
    815 
    816 /*  Update CRC value if necessary.  */
    817 void UpdateCrc(GptData *gpt) {
    818   GptHeader *primary_header, *secondary_header;
    819 
    820   primary_header = (GptHeader*)gpt->primary_header;
    821   secondary_header = (GptHeader*)gpt->secondary_header;
    822 
    823   if (gpt->modified & GPT_MODIFIED_ENTRIES1 &&
    824       memcmp(primary_header, GPT_HEADER_SIGNATURE2,
    825              GPT_HEADER_SIGNATURE_SIZE)) {
    826     size_t entries_size = primary_header->size_of_entry *
    827         primary_header->number_of_entries;
    828     primary_header->entries_crc32 =
    829         Crc32(gpt->primary_entries, entries_size);
    830   }
    831   if (gpt->modified & GPT_MODIFIED_ENTRIES2) {
    832     size_t entries_size = secondary_header->size_of_entry *
    833         secondary_header->number_of_entries;
    834     secondary_header->entries_crc32 =
    835         Crc32(gpt->secondary_entries, entries_size);
    836   }
    837   if (gpt->modified & GPT_MODIFIED_HEADER1) {
    838     primary_header->header_crc32 = 0;
    839     primary_header->header_crc32 = Crc32(
    840         (const uint8_t *)primary_header, sizeof(GptHeader));
    841   }
    842   if (gpt->modified & GPT_MODIFIED_HEADER2) {
    843     secondary_header->header_crc32 = 0;
    844     secondary_header->header_crc32 = Crc32(
    845         (const uint8_t *)secondary_header, sizeof(GptHeader));
    846   }
    847 }
    848 /* Two headers are NOT bitwise identical. For example, my_lba pointers to header
    849  * itself so that my_lba in primary and secondary is definitely different.
    850  * Only the following fields should be identical.
    851  *
    852  *   first_usable_lba
    853  *   last_usable_lba
    854  *   number_of_entries
    855  *   size_of_entry
    856  *   disk_uuid
    857  *
    858  * If any of above field are not matched, overwrite secondary with primary since
    859  * we always trust primary.
    860  * If any one of header is invalid, copy from another. */
    861 int IsSynonymous(const GptHeader* a, const GptHeader* b) {
    862   if ((a->first_usable_lba == b->first_usable_lba) &&
    863       (a->last_usable_lba == b->last_usable_lba) &&
    864       (a->number_of_entries == b->number_of_entries) &&
    865       (a->size_of_entry == b->size_of_entry) &&
    866       (!memcmp(&a->disk_uuid, &b->disk_uuid, sizeof(Guid))))
    867     return 1;
    868   return 0;
    869 }
    870 
    871 /* Primary entries and secondary entries should be bitwise identical.
    872  * If two entries tables are valid, compare them. If not the same,
    873  * overwrites secondary with primary (primary always has higher priority),
    874  * and marks secondary as modified.
    875  * If only one is valid, overwrites invalid one.
    876  * If all are invalid, does nothing.
    877  * This function returns bit masks for GptData.modified field.
    878  * Note that CRC is NOT re-computed in this function.
    879  */
    880 uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries) {
    881   /* If we have an alternate GPT header signature, don't overwrite
    882    * the secondary GPT with the primary one as that might wipe the
    883    * partition table. Also don't overwrite the primary one with the
    884    * secondary one as that will stop Windows from booting. */
    885   GptHeader* h = (GptHeader*)(gpt->primary_header);
    886   if (!memcmp(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE))
    887     return 0;
    888 
    889   if (gpt->valid_headers & MASK_PRIMARY) {
    890     h = (GptHeader*)gpt->primary_header;
    891   } else if (gpt->valid_headers & MASK_SECONDARY) {
    892     h = (GptHeader*)gpt->secondary_header;
    893   } else {
    894     /* We cannot trust any header, don't update entries. */
    895     return 0;
    896   }
    897 
    898   size_t entries_size = h->number_of_entries * h->size_of_entry;
    899   if (valid_entries == MASK_BOTH) {
    900     if (memcmp(gpt->primary_entries, gpt->secondary_entries, entries_size)) {
    901       memcpy(gpt->secondary_entries, gpt->primary_entries, entries_size);
    902       return GPT_MODIFIED_ENTRIES2;
    903     }
    904   } else if (valid_entries == MASK_PRIMARY) {
    905     memcpy(gpt->secondary_entries, gpt->primary_entries, entries_size);
    906     return GPT_MODIFIED_ENTRIES2;
    907   } else if (valid_entries == MASK_SECONDARY) {
    908     memcpy(gpt->primary_entries, gpt->secondary_entries, entries_size);
    909     return GPT_MODIFIED_ENTRIES1;
    910   }
    911 
    912   return 0;
    913 }
    914 
    915 /* The above five fields are shared between primary and secondary headers.
    916  * We can recover one header from another through copying those fields. */
    917 void CopySynonymousParts(GptHeader* target, const GptHeader* source) {
    918   target->first_usable_lba = source->first_usable_lba;
    919   target->last_usable_lba = source->last_usable_lba;
    920   target->number_of_entries = source->number_of_entries;
    921   target->size_of_entry = source->size_of_entry;
    922   memcpy(&target->disk_uuid, &source->disk_uuid, sizeof(Guid));
    923 }
    924 
    925 /* This function repairs primary and secondary headers if possible.
    926  * If both headers are valid (CRC32 is correct) but
    927  *   a) indicate inconsistent usable LBA ranges,
    928  *   b) inconsistent partition entry size and number,
    929  *   c) inconsistent disk_uuid,
    930  * we will use the primary header to overwrite secondary header.
    931  * If primary is invalid (CRC32 is wrong), then we repair it from secondary.
    932  * If secondary is invalid (CRC32 is wrong), then we repair it from primary.
    933  * This function returns the bitmasks for modified header.
    934  * Note that CRC value is NOT re-computed in this function. UpdateCrc() will
    935  * do it later.
    936  */
    937 uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers) {
    938   GptHeader *primary_header, *secondary_header;
    939 
    940   primary_header = (GptHeader*)gpt->primary_header;
    941   secondary_header = (GptHeader*)gpt->secondary_header;
    942 
    943   if (valid_headers == MASK_BOTH) {
    944     if (!IsSynonymous(primary_header, secondary_header)) {
    945       CopySynonymousParts(secondary_header, primary_header);
    946       return GPT_MODIFIED_HEADER2;
    947     }
    948   } else if (valid_headers == MASK_PRIMARY) {
    949     memcpy(secondary_header, primary_header, sizeof(GptHeader));
    950     secondary_header->my_lba = gpt->gpt_drive_sectors - 1;  /* the last sector */
    951     secondary_header->alternate_lba = primary_header->my_lba;
    952     secondary_header->entries_lba = secondary_header->my_lba -
    953         CalculateEntriesSectors(primary_header);
    954     return GPT_MODIFIED_HEADER2;
    955   } else if (valid_headers == MASK_SECONDARY) {
    956     memcpy(primary_header, secondary_header, sizeof(GptHeader));
    957     primary_header->my_lba = GPT_PMBR_SECTORS;  /* the second sector on drive */
    958     primary_header->alternate_lba = secondary_header->my_lba;
    959     /* TODO (namnguyen): Preserve (header, entries) padding space. */
    960     primary_header->entries_lba = primary_header->my_lba + GPT_HEADER_SECTORS;
    961     return GPT_MODIFIED_HEADER1;
    962   }
    963 
    964   return 0;
    965 }
    966 
    967 int CgptGetNumNonEmptyPartitions(CgptShowParams *params) {
    968   struct drive drive;
    969   int gpt_retval;
    970   int retval;
    971 
    972   if (params == NULL)
    973     return CGPT_FAILED;
    974 
    975   if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDONLY,
    976                            params->drive_size))
    977     return CGPT_FAILED;
    978 
    979   if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
    980     Error("GptSanityCheck() returned %d: %s\n",
    981           gpt_retval, GptError(gpt_retval));
    982     retval = CGPT_FAILED;
    983     goto done;
    984   }
    985 
    986   params->num_partitions = 0;
    987   int numEntries = GetNumberOfEntries(&drive);
    988   int i;
    989   for(i = 0; i < numEntries; i++) {
    990       GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, i);
    991       if (GuidIsZero(&entry->type))
    992         continue;
    993 
    994       params->num_partitions++;
    995   }
    996 
    997   retval = CGPT_OK;
    998 
    999 done:
   1000   DriveClose(&drive, 0);
   1001   return retval;
   1002 }
   1003 
   1004 int GuidEqual(const Guid *guid1, const Guid *guid2) {
   1005   return (0 == memcmp(guid1, guid2, sizeof(Guid)));
   1006 }
   1007 
   1008 int GuidIsZero(const Guid *gp) {
   1009   return GuidEqual(gp, &guid_unused);
   1010 }
   1011 
   1012 void PMBRToStr(struct pmbr *pmbr, char *str, unsigned int buflen) {
   1013   char buf[GUID_STRLEN];
   1014   if (GuidIsZero(&pmbr->boot_guid)) {
   1015     require(snprintf(str, buflen, "PMBR") < buflen);
   1016   } else {
   1017     GuidToStr(&pmbr->boot_guid, buf, sizeof(buf));
   1018     require(snprintf(str, buflen, "PMBR (Boot GUID: %s)", buf) < buflen);
   1019   }
   1020 }
   1021 
   1022 /* Optional */
   1023 int __GenerateGuid(Guid *newguid) { return CGPT_FAILED; };
   1024 #ifndef HAVE_MACOS
   1025 int GenerateGuid(Guid *newguid) __attribute__((weak, alias("__GenerateGuid")));
   1026 #endif
   1027