OLD | NEW |
1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 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 | 2 * Use of this source code is governed by a BSD-style license that can be |
3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
4 * | 4 * |
5 * Utility for ChromeOS-specific GPT partitions, Please see corresponding .c | 5 * Utility for ChromeOS-specific GPT partitions, Please see corresponding .c |
6 * files for more details. | 6 * files for more details. |
7 */ | 7 */ |
8 | 8 |
9 #include "cgpt.h" | 9 #include "cgpt.h" |
10 | 10 |
11 #include <errno.h> | 11 #include <errno.h> |
12 #include <fcntl.h> | 12 #include <fcntl.h> |
13 #include <getopt.h> | 13 #include <getopt.h> |
| 14 #include <stdarg.h> |
14 #include <stdint.h> | 15 #include <stdint.h> |
15 #include <stdio.h> | 16 #include <stdio.h> |
16 #include <stdlib.h> | 17 #include <stdlib.h> |
17 #include <string.h> | 18 #include <string.h> |
18 #include <sys/ioctl.h> | 19 #include <sys/ioctl.h> |
19 #include <sys/mount.h> | 20 #include <sys/mount.h> |
20 #include <sys/stat.h> | 21 #include <sys/stat.h> |
21 #include <sys/types.h> | 22 #include <sys/types.h> |
22 #include <unistd.h> | 23 #include <unistd.h> |
23 #include <assert.h> | |
24 #include <stdarg.h> | |
25 | 24 |
26 #include "cgptlib_internal.h" | 25 #include "cgptlib_internal.h" |
27 #include "crc32.h" | 26 #include "crc32.h" |
28 | 27 |
29 | |
30 void Error(const char *format, ...) { | 28 void Error(const char *format, ...) { |
31 va_list ap; | 29 va_list ap; |
32 va_start(ap, format); | 30 va_start(ap, format); |
33 fprintf(stderr, "ERROR: %s %s: ", progname, command); | 31 fprintf(stderr, "ERROR: %s %s: ", progname, command); |
34 vfprintf(stderr, format, ap); | 32 vfprintf(stderr, format, ap); |
35 va_end(ap); | 33 va_end(ap); |
36 } | 34 } |
37 | 35 |
38 | 36 |
39 int CheckValid(const struct drive *drive) { | 37 int CheckValid(const struct drive *drive) { |
(...skipping 18 matching lines...) Expand all Loading... |
58 * | 56 * |
59 * Returns CGPT_OK for successful. Aborts if any error occurs. | 57 * Returns CGPT_OK for successful. Aborts if any error occurs. |
60 */ | 58 */ |
61 static int Load(const int fd, uint8_t **buf, | 59 static int Load(const int fd, uint8_t **buf, |
62 const uint64_t sector, | 60 const uint64_t sector, |
63 const uint64_t sector_bytes, | 61 const uint64_t sector_bytes, |
64 const uint64_t sector_count) { | 62 const uint64_t sector_count) { |
65 int count; /* byte count to read */ | 63 int count; /* byte count to read */ |
66 int nread; | 64 int nread; |
67 | 65 |
68 assert(buf); | 66 require(buf); |
| 67 if (!sector_count || !sector_bytes) { |
| 68 Error("%s() failed at line %d: sector_count=%d, sector_bytes=%d\n", |
| 69 __FUNCTION__, __LINE__, sector_count, sector_bytes); |
| 70 return CGPT_FAILED; |
| 71 } |
| 72 /* Make sure that sector_bytes * sector_count doesn't roll over. */ |
| 73 if (sector_bytes > (UINT64_MAX / sector_count)) { |
| 74 Error("%s() failed at line %d: sector_count=%d, sector_bytes=%d\n", |
| 75 __FUNCTION__, __LINE__, sector_count, sector_bytes); |
| 76 return CGPT_FAILED; |
| 77 } |
69 count = sector_bytes * sector_count; | 78 count = sector_bytes * sector_count; |
70 *buf = malloc(count); | 79 *buf = malloc(count); |
71 assert(*buf); | 80 require(*buf); |
72 | 81 |
73 if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET)) | 82 if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET)) { |
| 83 Error("Can't lseek: %s\n", strerror(errno)); |
74 goto error_free; | 84 goto error_free; |
| 85 } |
75 | 86 |
76 nread = read(fd, *buf, count); | 87 nread = read(fd, *buf, count); |
77 if (nread < count) | 88 if (nread < count) { |
| 89 Error("Can't read enough: %d, not %d\n", nread, count); |
78 goto error_free; | 90 goto error_free; |
| 91 } |
79 | 92 |
80 return CGPT_OK; | 93 return CGPT_OK; |
81 | 94 |
82 error_free: | 95 error_free: |
83 free(*buf); | 96 free(*buf); |
84 *buf = 0; | 97 *buf = 0; |
85 return CGPT_FAILED; | 98 return CGPT_FAILED; |
86 } | 99 } |
87 | 100 |
88 | 101 |
(...skipping 29 matching lines...) Expand all Loading... |
118 * | 131 * |
119 * Returns CGPT_OK for successful, CGPT_FAILED for failed. | 132 * Returns CGPT_OK for successful, CGPT_FAILED for failed. |
120 */ | 133 */ |
121 static int Save(const int fd, const uint8_t *buf, | 134 static int Save(const int fd, const uint8_t *buf, |
122 const uint64_t sector, | 135 const uint64_t sector, |
123 const uint64_t sector_bytes, | 136 const uint64_t sector_bytes, |
124 const uint64_t sector_count) { | 137 const uint64_t sector_count) { |
125 int count; /* byte count to write */ | 138 int count; /* byte count to write */ |
126 int nwrote; | 139 int nwrote; |
127 | 140 |
128 assert(buf); | 141 require(buf); |
129 count = sector_bytes * sector_count; | 142 count = sector_bytes * sector_count; |
130 | 143 |
131 if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET)) | 144 if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET)) |
132 return CGPT_FAILED; | 145 return CGPT_FAILED; |
133 | 146 |
134 nwrote = write(fd, buf, count); | 147 nwrote = write(fd, buf, count); |
135 if (nwrote < count) | 148 if (nwrote < count) |
136 return CGPT_FAILED; | 149 return CGPT_FAILED; |
137 | 150 |
138 return CGPT_OK; | 151 return CGPT_OK; |
139 } | 152 } |
140 | 153 |
141 | 154 |
142 // Opens a block device or file, loads raw GPT data from it. | 155 // Opens a block device or file, loads raw GPT data from it. |
143 // | 156 // |
144 // Returns CGPT_FAILED if any error happens. | 157 // Returns CGPT_FAILED if any error happens. |
145 // Returns CGPT_OK if success and information are stored in 'drive'. */ | 158 // Returns CGPT_OK if success and information are stored in 'drive'. */ |
146 int DriveOpen(const char *drive_path, struct drive *drive) { | 159 int DriveOpen(const char *drive_path, struct drive *drive) { |
147 struct stat stat; | 160 struct stat stat; |
148 | 161 |
149 assert(drive_path); | 162 require(drive_path); |
150 assert(drive); | 163 require(drive); |
151 | 164 |
152 // Clear struct for proper error handling. | 165 // Clear struct for proper error handling. |
153 memset(drive, 0, sizeof(struct drive)); | 166 memset(drive, 0, sizeof(struct drive)); |
154 | 167 |
155 drive->fd = open(drive_path, O_RDWR | O_LARGEFILE); | 168 drive->fd = open(drive_path, O_RDWR | O_LARGEFILE | O_NOFOLLOW); |
156 if (drive->fd == -1) { | 169 if (drive->fd == -1) { |
157 Error("Can't open %s: %s\n", drive_path, strerror(errno)); | 170 Error("Can't open %s: %s\n", drive_path, strerror(errno)); |
158 return CGPT_FAILED; | 171 return CGPT_FAILED; |
159 } | 172 } |
160 | 173 |
161 if (fstat(drive->fd, &stat) == -1) { | 174 if (fstat(drive->fd, &stat) == -1) { |
| 175 Error("Can't fstat %s: %s\n", drive_path, strerror(errno)); |
162 goto error_close; | 176 goto error_close; |
163 } | 177 } |
164 if ((stat.st_mode & S_IFMT) != S_IFREG) { | 178 if ((stat.st_mode & S_IFMT) != S_IFREG) { |
165 if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) { | 179 if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) { |
166 Error("Can't read drive size from %s: %s\n", drive_path, strerror(errno)); | 180 Error("Can't read drive size from %s: %s\n", drive_path, strerror(errno)); |
167 goto error_close; | 181 goto error_close; |
168 } | 182 } |
169 if (ioctl(drive->fd, BLKSSZGET, &drive->gpt.sector_bytes) < 0) { | 183 if (ioctl(drive->fd, BLKSSZGET, &drive->gpt.sector_bytes) < 0) { |
170 Error("Can't read sector size from %s: %s\n", | 184 Error("Can't read sector size from %s: %s\n", |
171 drive_path, strerror(errno)); | 185 drive_path, strerror(errno)); |
(...skipping 25 matching lines...) Expand all Loading... |
197 GPT_PMBR_SECTOR + GPT_HEADER_SECTOR, | 211 GPT_PMBR_SECTOR + GPT_HEADER_SECTOR, |
198 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { | 212 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { |
199 goto error_close; | 213 goto error_close; |
200 } | 214 } |
201 if (CGPT_OK != Load(drive->fd, &drive->gpt.secondary_entries, | 215 if (CGPT_OK != Load(drive->fd, &drive->gpt.secondary_entries, |
202 drive->gpt.drive_sectors - GPT_HEADER_SECTOR | 216 drive->gpt.drive_sectors - GPT_HEADER_SECTOR |
203 - GPT_ENTRIES_SECTORS, | 217 - GPT_ENTRIES_SECTORS, |
204 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { | 218 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { |
205 goto error_close; | 219 goto error_close; |
206 } | 220 } |
207 | 221 |
208 // We just load the data. Caller must validate it. | 222 // We just load the data. Caller must validate it. |
209 return CGPT_OK; | 223 return CGPT_OK; |
210 | 224 |
211 error_close: | 225 error_close: |
212 (void) DriveClose(drive, 0); | 226 (void) DriveClose(drive, 0); |
213 return CGPT_FAILED; | 227 return CGPT_FAILED; |
214 } | 228 } |
215 | 229 |
216 | 230 |
217 int DriveClose(struct drive *drive, int update_as_needed) { | 231 int DriveClose(struct drive *drive, int update_as_needed) { |
218 int errors = 0; | 232 int errors = 0; |
219 | 233 |
220 if (update_as_needed) { | 234 if (update_as_needed) { |
221 if (drive->gpt.modified & GPT_MODIFIED_HEADER1) { | 235 if (drive->gpt.modified & GPT_MODIFIED_HEADER1) { |
222 if (CGPT_OK != Save(drive->fd, drive->gpt.primary_header, | 236 if (CGPT_OK != Save(drive->fd, drive->gpt.primary_header, |
223 GPT_PMBR_SECTOR, | 237 GPT_PMBR_SECTOR, |
224 drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { | 238 drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { |
225 errors++; | 239 errors++; |
226 Error("Cannot write primary header: %s\n", strerror(errno)); | 240 Error("Cannot write primary header: %s\n", strerror(errno)); |
227 } | 241 } |
228 } | 242 } |
229 | 243 |
230 if (drive->gpt.modified & GPT_MODIFIED_HEADER2) { | 244 if (drive->gpt.modified & GPT_MODIFIED_HEADER2) { |
231 if(CGPT_OK != Save(drive->fd, drive->gpt.secondary_header, | 245 if(CGPT_OK != Save(drive->fd, drive->gpt.secondary_header, |
232 drive->gpt.drive_sectors - GPT_PMBR_SECTOR, | 246 drive->gpt.drive_sectors - GPT_PMBR_SECTOR, |
233 drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { | 247 drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { |
234 errors++; | 248 errors++; |
235 Error("Cannot write secondary header: %s\n", strerror(errno)); | 249 Error("Cannot write secondary header: %s\n", strerror(errno)); |
236 } | 250 } |
237 } | 251 } |
238 if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) { | 252 if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) { |
239 if (CGPT_OK != Save(drive->fd, drive->gpt.primary_entries, | 253 if (CGPT_OK != Save(drive->fd, drive->gpt.primary_entries, |
(...skipping 26 matching lines...) Expand all Loading... |
266 free(drive->gpt.secondary_header); | 280 free(drive->gpt.secondary_header); |
267 drive->gpt.secondary_header = 0; | 281 drive->gpt.secondary_header = 0; |
268 if (drive->gpt.secondary_entries) | 282 if (drive->gpt.secondary_entries) |
269 free(drive->gpt.secondary_entries); | 283 free(drive->gpt.secondary_entries); |
270 drive->gpt.secondary_entries = 0; | 284 drive->gpt.secondary_entries = 0; |
271 | 285 |
272 return errors ? CGPT_FAILED : CGPT_OK; | 286 return errors ? CGPT_FAILED : CGPT_OK; |
273 } | 287 } |
274 | 288 |
275 | 289 |
276 | |
277 /* GUID conversion functions. Accepted format: | 290 /* GUID conversion functions. Accepted format: |
278 * | 291 * |
279 * "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" | 292 * "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" |
280 * | 293 * |
281 * Returns CGPT_OK if parsing is successful; otherwise CGPT_FAILED. | 294 * Returns CGPT_OK if parsing is successful; otherwise CGPT_FAILED. |
282 */ | 295 */ |
283 int StrToGuid(const char *str, Guid *guid) { | 296 int StrToGuid(const char *str, Guid *guid) { |
284 uint32_t time_low; | 297 uint32_t time_low; |
285 uint16_t time_mid; | 298 uint16_t time_mid; |
286 uint16_t time_high_and_version; | 299 uint16_t time_high_and_version; |
287 unsigned int chunk[11]; | 300 unsigned int chunk[11]; |
288 | 301 |
289 if (11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", | 302 if (11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", |
290 chunk+0, | 303 chunk+0, |
291 chunk+1, | 304 chunk+1, |
292 chunk+2, | 305 chunk+2, |
293 chunk+3, | 306 chunk+3, |
294 chunk+4, | 307 chunk+4, |
295 chunk+5, | 308 chunk+5, |
296 chunk+6, | 309 chunk+6, |
297 chunk+7, | 310 chunk+7, |
298 chunk+8, | 311 chunk+8, |
299 chunk+9, | 312 chunk+9, |
300 chunk+10)) { | 313 chunk+10)) { |
301 printf("FAILED\n"); | 314 printf("FAILED\n"); |
302 return CGPT_FAILED; | 315 return CGPT_FAILED; |
303 } | 316 } |
304 | 317 |
305 time_low = chunk[0] & 0xffffffff; | 318 time_low = chunk[0] & 0xffffffff; |
306 time_mid = chunk[1] & 0xffff; | 319 time_mid = chunk[1] & 0xffff; |
307 time_high_and_version = chunk[2] & 0xffff; | 320 time_high_and_version = chunk[2] & 0xffff; |
308 | 321 |
309 guid->u.Uuid.time_low = htole32(time_low); | 322 guid->u.Uuid.time_low = htole32(time_low); |
310 guid->u.Uuid.time_mid = htole16(time_mid); | 323 guid->u.Uuid.time_mid = htole16(time_mid); |
311 guid->u.Uuid.time_high_and_version = htole16(time_high_and_version); | 324 guid->u.Uuid.time_high_and_version = htole16(time_high_and_version); |
312 | 325 |
313 guid->u.Uuid.clock_seq_high_and_reserved = chunk[3] & 0xff; | 326 guid->u.Uuid.clock_seq_high_and_reserved = chunk[3] & 0xff; |
314 guid->u.Uuid.clock_seq_low = chunk[4] & 0xff; | 327 guid->u.Uuid.clock_seq_low = chunk[4] & 0xff; |
315 guid->u.Uuid.node[0] = chunk[5] & 0xff; | 328 guid->u.Uuid.node[0] = chunk[5] & 0xff; |
316 guid->u.Uuid.node[1] = chunk[6] & 0xff; | 329 guid->u.Uuid.node[1] = chunk[6] & 0xff; |
317 guid->u.Uuid.node[2] = chunk[7] & 0xff; | 330 guid->u.Uuid.node[2] = chunk[7] & 0xff; |
318 guid->u.Uuid.node[3] = chunk[8] & 0xff; | 331 guid->u.Uuid.node[3] = chunk[8] & 0xff; |
319 guid->u.Uuid.node[4] = chunk[9] & 0xff; | 332 guid->u.Uuid.node[4] = chunk[9] & 0xff; |
320 guid->u.Uuid.node[5] = chunk[10] & 0xff; | 333 guid->u.Uuid.node[5] = chunk[10] & 0xff; |
321 | 334 |
322 return CGPT_OK; | 335 return CGPT_OK; |
323 } | 336 } |
324 void GuidToStr(const Guid *guid, char *str) { | 337 void GuidToStr(const Guid *guid, char *str, unsigned int buflen) { |
325 sprintf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", | 338 require(buflen >= GUID_STRLEN); |
326 le32toh(guid->u.Uuid.time_low), le16toh(guid->u.Uuid.time_mid), | 339 require(snprintf(str, buflen, |
327 le16toh(guid->u.Uuid.time_high_and_version), | 340 "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", |
328 guid->u.Uuid.clock_seq_high_and_reserved, guid->u.Uuid.clock_seq_low, | 341 le32toh(guid->u.Uuid.time_low), |
329 guid->u.Uuid.node[0], guid->u.Uuid.node[1], guid->u.Uuid.node[2], | 342 le16toh(guid->u.Uuid.time_mid), |
330 guid->u.Uuid.node[3], guid->u.Uuid.node[4], guid->u.Uuid.node[5]); | 343 le16toh(guid->u.Uuid.time_high_and_version), |
| 344 guid->u.Uuid.clock_seq_high_and_reserved, |
| 345 guid->u.Uuid.clock_seq_low, |
| 346 guid->u.Uuid.node[0], guid->u.Uuid.node[1], |
| 347 guid->u.Uuid.node[2], guid->u.Uuid.node[3], |
| 348 guid->u.Uuid.node[4], guid->u.Uuid.node[5]) == GUID_STRLEN-1); |
331 } | 349 } |
332 | 350 |
333 /* Convert UTF16 string to UTF8. Rewritten from gpt utility. | 351 /* Convert possibly unterminated UTF16 string to UTF8. |
334 * Caller must prepare enough space for UTF8. The rough estimation is: | 352 * Caller must prepare enough space for UTF8, which could be up to |
335 * | 353 * twice the number of UTF16 chars plus the terminating '\0'. |
336 * utf8 length = bytecount(utf16) * 1.5 | 354 * FIXME(wfrichar): The original implementation had security issues. As a |
| 355 * temporary fix, I'm making this ONLY support ASCII codepoints. Bug 7542 |
| 356 * (http://code.google.com/p/chromium-os/issues/detail?id=7542) is filed to fix |
| 357 * this. |
337 */ | 358 */ |
338 #define SIZEOF_GPTENTRY_NAME 36 /* sizeof(GptEntry.name[]) */ | 359 void UTF16ToUTF8(const uint16_t *utf16, unsigned int maxinput, |
339 void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8) | 360 uint8_t *utf8, unsigned int maxoutput) |
340 { | 361 { |
341 size_t s8idx, s16idx, s16len; | 362 size_t s16idx, s8idx; |
342 uint32_t utfchar; | 363 uint32_t utfchar; |
343 unsigned int next_utf16; | |
344 | 364 |
345 for (s16len = 0; s16len < SIZEOF_GPTENTRY_NAME && utf16[s16len]; ++s16len); | 365 if (!utf16 || !maxinput || !utf8 || !maxoutput) |
| 366 return; |
346 | 367 |
347 *utf8 = s8idx = s16idx = 0; | 368 maxoutput--; /* plan for termination now */ |
348 while (s16idx < s16len) { | 369 |
349 utfchar = le16toh(utf16[s16idx++]); | 370 for (s16idx = s8idx = 0; |
350 if ((utfchar & 0xf800) == 0xd800) { | 371 s16idx < maxinput && utf16[s16idx] && maxoutput; |
351 next_utf16 = le16toh(utf16[s16idx]); | 372 s16idx++, maxoutput--) { |
352 if ((utfchar & 0x400) != 0 || (next_utf16 & 0xfc00) != 0xdc00) | 373 utfchar = le16toh(utf16[s16idx]); |
353 utfchar = 0xfffd; | 374 utf8[s8idx++] = utfchar & 0x7F; |
354 else | |
355 s16idx++; | |
356 } | |
357 if (utfchar < 0x80) { | |
358 utf8[s8idx++] = utfchar; | |
359 } else if (utfchar < 0x800) { | |
360 utf8[s8idx++] = 0xc0 | (utfchar >> 6); | |
361 utf8[s8idx++] = 0x80 | (utfchar & 0x3f); | |
362 } else if (utfchar < 0x10000) { | |
363 utf8[s8idx++] = 0xe0 | (utfchar >> 12); | |
364 utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f); | |
365 utf8[s8idx++] = 0x80 | (utfchar & 0x3f); | |
366 } else if (utfchar < 0x200000) { | |
367 utf8[s8idx++] = 0xf0 | (utfchar >> 18); | |
368 utf8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f); | |
369 utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f); | |
370 utf8[s8idx++] = 0x80 | (utfchar & 0x3f); | |
371 } | |
372 } | 375 } |
373 utf8[s8idx++] = 0; | 376 utf8[s8idx++] = 0; |
374 } | 377 } |
375 | 378 |
376 /* Convert UTF8 string to UTF16. Rewritten from gpt utility. | 379 /* Convert UTF8 string to UTF16. The UTF8 string must be null-terminated. |
377 * Caller must prepare enough space for UTF16. The conservative estimation is: | 380 * Caller must prepare enough space for UTF16, including a terminating 0x0000. |
378 * | 381 * FIXME(wfrichar): The original implementation had security issues. As a |
379 * utf16 bytecount = bytecount(utf8) / 3 * 4 | 382 * temporary fix, I'm making this ONLY support ASCII codepoints. Bug 7542 |
| 383 * (http://code.google.com/p/chromium-os/issues/detail?id=7542) is filed to fix |
| 384 * this. |
380 */ | 385 */ |
381 void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16) | 386 void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16, unsigned int maxoutput) |
382 { | 387 { |
383 size_t s16idx, s8idx, s8len; | 388 size_t s16idx, s8idx; |
384 uint32_t utfchar; | 389 uint32_t utfchar; |
385 unsigned int c, utfbytes; | |
386 | 390 |
387 for (s8len = 0; utf8[s8len]; ++s8len); | 391 if (!utf8 || !utf16 || !maxoutput) |
| 392 return; |
388 | 393 |
389 s8idx = s16idx = 0; | 394 maxoutput--; /* plan for termination */ |
390 utfbytes = 0; | 395 |
391 do { | 396 for (s8idx = s16idx = 0; |
392 c = utf8[s8idx++]; | 397 utf8[s8idx] && maxoutput; |
393 if ((c & 0xc0) != 0x80) { | 398 s8idx++, maxoutput--) { |
394 /* Initial characters. */ | 399 utfchar = utf8[s8idx]; |
395 if (utfbytes != 0) { | 400 utf16[s16idx++] = utfchar & 0x7F; |
396 /* Incomplete encoding. */ | 401 } |
397 utf16[s16idx++] = 0xfffd; | 402 utf16[s16idx++] = 0; |
398 } | |
399 if ((c & 0xf8) == 0xf0) { | |
400 utfchar = c & 0x07; | |
401 utfbytes = 3; | |
402 } else if ((c & 0xf0) == 0xe0) { | |
403 utfchar = c & 0x0f; | |
404 utfbytes = 2; | |
405 } else if ((c & 0xe0) == 0xc0) { | |
406 utfchar = c & 0x1f; | |
407 utfbytes = 1; | |
408 } else { | |
409 utfchar = c & 0x7f; | |
410 utfbytes = 0; | |
411 } | |
412 } else { | |
413 /* Followup characters. */ | |
414 if (utfbytes > 0) { | |
415 utfchar = (utfchar << 6) + (c & 0x3f); | |
416 utfbytes--; | |
417 } else if (utfbytes == 0) | |
418 utfbytes = -1; | |
419 utfchar = 0xfffd; | |
420 } | |
421 if (utfbytes == 0) { | |
422 if (utfchar >= 0x10000) { | |
423 utf16[s16idx++] = htole16(0xd800 | ((utfchar>>10)-0x40)); | |
424 if (s16idx >= SIZEOF_GPTENTRY_NAME) break; | |
425 utf16[s16idx++] = htole16(0xdc00 | (utfchar & 0x3ff)); | |
426 } else { | |
427 utf16[s16idx++] = htole16(utfchar); | |
428 } | |
429 } | |
430 } while (c != 0 && s16idx < SIZEOF_GPTENTRY_NAME); | |
431 if (s16idx < SIZEOF_GPTENTRY_NAME) | |
432 utf16[s16idx++] = 0; | |
433 } | 403 } |
434 | 404 |
435 struct { | 405 struct { |
436 Guid type; | 406 Guid type; |
437 char *name; | 407 char *name; |
438 char *description; | 408 char *description; |
439 } supported_types[] = { | 409 } supported_types[] = { |
440 {GPT_ENT_TYPE_CHROMEOS_KERNEL, "kernel", "ChromeOS kernel"}, | 410 {GPT_ENT_TYPE_CHROMEOS_KERNEL, "kernel", "ChromeOS kernel"}, |
441 {GPT_ENT_TYPE_CHROMEOS_ROOTFS, "rootfs", "ChromeOS rootfs"}, | 411 {GPT_ENT_TYPE_CHROMEOS_ROOTFS, "rootfs", "ChromeOS rootfs"}, |
442 {GPT_ENT_TYPE_LINUX_DATA, "data", "Linux data"}, | 412 {GPT_ENT_TYPE_LINUX_DATA, "data", "Linux data"}, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
492 } | 462 } |
493 | 463 |
494 static uint32_t GetSizeOfEntries(const GptData *gpt) { | 464 static uint32_t GetSizeOfEntries(const GptData *gpt) { |
495 GptHeader *header = 0; | 465 GptHeader *header = 0; |
496 if (gpt->valid_headers & MASK_PRIMARY) | 466 if (gpt->valid_headers & MASK_PRIMARY) |
497 header = (GptHeader*)gpt->primary_header; | 467 header = (GptHeader*)gpt->primary_header; |
498 else if (gpt->valid_headers & MASK_SECONDARY) | 468 else if (gpt->valid_headers & MASK_SECONDARY) |
499 header = (GptHeader*)gpt->secondary_header; | 469 header = (GptHeader*)gpt->secondary_header; |
500 else | 470 else |
501 return 0; | 471 return 0; |
502 return header->number_of_entries; | 472 return header->size_of_entry; |
503 } | 473 } |
504 | 474 |
505 GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index) { | 475 GptEntry *GetEntry(GptData *gpt, int secondary, uint32_t entry_index) { |
506 uint8_t *entries; | 476 uint8_t *entries; |
507 int stride = GetSizeOfEntries(gpt); | 477 uint32_t stride = GetSizeOfEntries(gpt); |
508 if (!stride) | 478 require(stride); |
509 return 0; | 479 require(entry_index < GetNumberOfEntries(gpt)); |
510 | 480 |
511 if (secondary == PRIMARY) { | 481 if (secondary == PRIMARY) { |
512 entries = gpt->primary_entries; | 482 entries = gpt->primary_entries; |
513 } else { | 483 } else { |
514 entries = gpt->secondary_entries; | 484 entries = gpt->secondary_entries; |
515 } | 485 } |
516 | 486 |
517 return (GptEntry*)(&entries[stride * entry_index]); | 487 return (GptEntry*)(&entries[stride * entry_index]); |
518 } | 488 } |
519 | 489 |
520 void SetPriority(GptData *gpt, int secondary, int entry_index, int priority) { | 490 void SetPriority(GptData *gpt, int secondary, uint32_t entry_index, |
| 491 int priority) { |
521 GptEntry *entry; | 492 GptEntry *entry; |
522 entry = GetEntry(gpt, secondary, entry_index); | 493 entry = GetEntry(gpt, secondary, entry_index); |
523 | 494 require(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY); |
524 assert(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY); | |
525 entry->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_PRIORITY_MASK; | 495 entry->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_PRIORITY_MASK; |
526 entry->attrs.fields.gpt_att |= priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET; | 496 entry->attrs.fields.gpt_att |= priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET; |
527 } | 497 } |
528 | 498 |
529 int GetPriority(GptData *gpt, int secondary, int entry_index) { | 499 int GetPriority(GptData *gpt, int secondary, uint32_t entry_index) { |
530 GptEntry *entry; | 500 GptEntry *entry; |
531 entry = GetEntry(gpt, secondary, entry_index); | 501 entry = GetEntry(gpt, secondary, entry_index); |
532 return (entry->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK) >> | 502 return (entry->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK) >> |
533 CGPT_ATTRIBUTE_PRIORITY_OFFSET; | 503 CGPT_ATTRIBUTE_PRIORITY_OFFSET; |
534 } | 504 } |
535 | 505 |
536 void SetTries(GptData *gpt, int secondary, int entry_index, int tries) { | 506 void SetTries(GptData *gpt, int secondary, uint32_t entry_index, int tries) { |
537 GptEntry *entry; | 507 GptEntry *entry; |
538 entry = GetEntry(gpt, secondary, entry_index); | 508 entry = GetEntry(gpt, secondary, entry_index); |
539 | 509 require(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES); |
540 assert(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES); | |
541 entry->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_TRIES_MASK; | 510 entry->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_TRIES_MASK; |
542 entry->attrs.fields.gpt_att |= tries << CGPT_ATTRIBUTE_TRIES_OFFSET; | 511 entry->attrs.fields.gpt_att |= tries << CGPT_ATTRIBUTE_TRIES_OFFSET; |
543 } | 512 } |
544 | 513 |
545 int GetTries(GptData *gpt, int secondary, int entry_index) { | 514 int GetTries(GptData *gpt, int secondary, uint32_t entry_index) { |
546 GptEntry *entry; | 515 GptEntry *entry; |
547 entry = GetEntry(gpt, secondary, entry_index); | 516 entry = GetEntry(gpt, secondary, entry_index); |
548 return (entry->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >> | 517 return (entry->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >> |
549 CGPT_ATTRIBUTE_TRIES_OFFSET; | 518 CGPT_ATTRIBUTE_TRIES_OFFSET; |
550 } | 519 } |
551 | 520 |
552 void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success) { | 521 void SetSuccessful(GptData *gpt, int secondary, uint32_t entry_index, |
| 522 int success) { |
553 GptEntry *entry; | 523 GptEntry *entry; |
554 entry = GetEntry(gpt, secondary, entry_index); | 524 entry = GetEntry(gpt, secondary, entry_index); |
555 | 525 |
556 assert(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL); | 526 require(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL); |
557 entry->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK; | 527 entry->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK; |
558 entry->attrs.fields.gpt_att |= success << CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; | 528 entry->attrs.fields.gpt_att |= success << CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; |
559 } | 529 } |
560 | 530 |
561 int GetSuccessful(GptData *gpt, int secondary, int entry_index) { | 531 int GetSuccessful(GptData *gpt, int secondary, uint32_t entry_index) { |
562 GptEntry *entry; | 532 GptEntry *entry; |
563 entry = GetEntry(gpt, secondary, entry_index); | 533 entry = GetEntry(gpt, secondary, entry_index); |
564 return (entry->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >> | 534 return (entry->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >> |
565 CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; | 535 CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; |
566 } | 536 } |
567 | 537 |
568 | 538 |
569 #define TOSTRING(A) #A | 539 #define TOSTRING(A) #A |
570 const char *GptError(int errnum) { | 540 const char *GptError(int errnum) { |
571 const char *error_string[] = { | 541 const char *error_string[] = { |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
707 } | 677 } |
708 | 678 |
709 return 0; | 679 return 0; |
710 } | 680 } |
711 | 681 |
712 | 682 |
713 int IsZero(const Guid *gp) { | 683 int IsZero(const Guid *gp) { |
714 return (0 == memcmp(gp, &guid_unused, sizeof(Guid))); | 684 return (0 == memcmp(gp, &guid_unused, sizeof(Guid))); |
715 } | 685 } |
716 | 686 |
717 void PMBRToStr(struct pmbr *pmbr, char *str) { | 687 void PMBRToStr(struct pmbr *pmbr, char *str, unsigned int buflen) { |
718 char buf[256]; | 688 char buf[GUID_STRLEN]; |
719 if (IsZero(&pmbr->boot_guid)) { | 689 if (IsZero(&pmbr->boot_guid)) { |
720 sprintf(str, "PMBR"); | 690 require(snprintf(str, buflen, "PMBR") < buflen); |
721 } else { | 691 } else { |
722 GuidToStr(&pmbr->boot_guid, buf); | 692 GuidToStr(&pmbr->boot_guid, buf, sizeof(buf)); |
723 sprintf(str, "PMBR (Boot GUID: %s)", buf); | 693 require(snprintf(str, buflen, "PMBR (Boot GUID: %s)", buf) < buflen); |
724 } | 694 } |
725 } | 695 } |
726 | 696 |
OLD | NEW |