| 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 |