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