| 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 /* To compile on host without compatility to BSD, we include |
| 9 * endian.h under chroot. */ |
| 10 #define _BSD_SOURCE |
| 11 #include "endian.h" |
| 12 |
| 13 #define __USE_LARGEFILE64 |
| 14 #define __USE_FILE_OFFSET64 |
| 15 #define _LARGEFILE64_SOURCE |
| 8 #include "cgpt.h" | 16 #include "cgpt.h" |
| 9 #include <errno.h> | 17 #include <errno.h> |
| 10 #include <fcntl.h> | 18 #include <fcntl.h> |
| 11 #include <getopt.h> | 19 #include <getopt.h> |
| 12 #include <stdint.h> | 20 #include <stdint.h> |
| 13 #include <stdio.h> | 21 #include <stdio.h> |
| 14 #include <stdlib.h> | 22 #include <stdlib.h> |
| 15 #include <string.h> | 23 #include <string.h> |
| 16 #include <sys/ioctl.h> | 24 #include <sys/ioctl.h> |
| 17 #include <sys/mount.h> | 25 #include <sys/mount.h> |
| 18 #include <sys/stat.h> | 26 #include <sys/stat.h> |
| 19 #include <sys/types.h> | 27 #include <sys/types.h> |
| 20 #include <unistd.h> | 28 #include <unistd.h> |
| 29 #include "cgptlib_internal.h" |
| 21 #include "utility.h" | 30 #include "utility.h" |
| 22 | 31 |
| 23 /* For usage print */ | 32 /* For usage print */ |
| 24 const char* progname; | 33 const char* progname; |
| 25 | 34 |
| 26 /* Lists all command here. */ | 35 /* Lists all command here. */ |
| 27 struct { | 36 struct { |
| 28 const char *name; | 37 const char *name; |
| 29 int (*fp)(int argc, char *argv[]); | 38 int (*fp)(int argc, char *argv[]); |
| 30 const char *comment; | 39 const char *comment; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 43 if (message) printf("%s\n", message); | 52 if (message) printf("%s\n", message); |
| 44 printf("Usage: %s COMMAND [OPTIONS]\n\n" | 53 printf("Usage: %s COMMAND [OPTIONS]\n\n" |
| 45 "Supported commands:\n\n", | 54 "Supported commands:\n\n", |
| 46 progname); | 55 progname); |
| 47 for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) { | 56 for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) { |
| 48 printf(" %-10s %s\n", cmds[i].name, cmds[i].comment); | 57 printf(" %-10s %s\n", cmds[i].name, cmds[i].comment); |
| 49 } | 58 } |
| 50 printf("\nFor more detailed usage, use %s COMMAND --help.\n\n", progname); | 59 printf("\nFor more detailed usage, use %s COMMAND --help.\n\n", progname); |
| 51 } | 60 } |
| 52 | 61 |
| 62 /* GUID conversion functions. Accepted format: |
| 63 * |
| 64 * "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" |
| 65 */ |
| 66 void StrToGuid(const char *str, Guid *guid) { |
| 67 uint32_t time_low, time_mid, time_high_and_version; |
| 68 |
| 69 sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", |
| 70 &time_low, |
| 71 (unsigned int *)&time_mid, |
| 72 (unsigned int *)&time_high_and_version, |
| 73 (unsigned int *)&guid->u.Uuid.clock_seq_high_and_reserved, |
| 74 (unsigned int *)&guid->u.Uuid.clock_seq_low, |
| 75 (unsigned int *)&guid->u.Uuid.node[0], |
| 76 (unsigned int *)&guid->u.Uuid.node[1], |
| 77 (unsigned int *)&guid->u.Uuid.node[2], |
| 78 (unsigned int *)&guid->u.Uuid.node[3], |
| 79 (unsigned int *)&guid->u.Uuid.node[4], |
| 80 (unsigned int *)&guid->u.Uuid.node[5]); |
| 81 |
| 82 guid->u.Uuid.time_low = htole32(time_low); |
| 83 guid->u.Uuid.time_mid = htole16(time_mid); |
| 84 guid->u.Uuid.time_high_and_version = htole16(time_high_and_version); |
| 85 } |
| 86 |
| 87 void GuidToStr(const Guid *guid, char *str) { |
| 88 sprintf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", |
| 89 le32toh(guid->u.Uuid.time_low), le16toh(guid->u.Uuid.time_mid), |
| 90 le16toh(guid->u.Uuid.time_high_and_version), |
| 91 guid->u.Uuid.clock_seq_high_and_reserved, guid->u.Uuid.clock_seq_low, |
| 92 guid->u.Uuid.node[0], guid->u.Uuid.node[1], guid->u.Uuid.node[2], |
| 93 guid->u.Uuid.node[3], guid->u.Uuid.node[4], guid->u.Uuid.node[5]); |
| 94 } |
| 95 |
| 96 /* Convert UTF16 string to UTF8. Rewritten from gpt utility. |
| 97 * Caller must prepare enough space for UTF8. The rough estimation is: |
| 98 * |
| 99 * utf8 length = bytecount(utf16) * 1.5 |
| 100 */ |
| 101 #define SIZEOF_GPTENTRY_NAME 36 /* sizeof(GptEntry.name[]) */ |
| 102 void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8) |
| 103 { |
| 104 size_t s8idx, s16idx, s16len; |
| 105 uint32_t utfchar; |
| 106 unsigned int next_utf16; |
| 107 |
| 108 for (s16len = 0; s16len < SIZEOF_GPTENTRY_NAME && utf16[s16len]; ++s16len); |
| 109 |
| 110 *utf8 = s8idx = s16idx = 0; |
| 111 while (s16idx < s16len) { |
| 112 utfchar = le16toh(utf16[s16idx++]); |
| 113 if ((utfchar & 0xf800) == 0xd800) { |
| 114 next_utf16 = le16toh(utf16[s16idx]); |
| 115 if ((utfchar & 0x400) != 0 || (next_utf16 & 0xfc00) != 0xdc00) |
| 116 utfchar = 0xfffd; |
| 117 else |
| 118 s16idx++; |
| 119 } |
| 120 if (utfchar < 0x80) { |
| 121 utf8[s8idx++] = utfchar; |
| 122 } else if (utfchar < 0x800) { |
| 123 utf8[s8idx++] = 0xc0 | (utfchar >> 6); |
| 124 utf8[s8idx++] = 0x80 | (utfchar & 0x3f); |
| 125 } else if (utfchar < 0x10000) { |
| 126 utf8[s8idx++] = 0xe0 | (utfchar >> 12); |
| 127 utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f); |
| 128 utf8[s8idx++] = 0x80 | (utfchar & 0x3f); |
| 129 } else if (utfchar < 0x200000) { |
| 130 utf8[s8idx++] = 0xf0 | (utfchar >> 18); |
| 131 utf8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f); |
| 132 utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f); |
| 133 utf8[s8idx++] = 0x80 | (utfchar & 0x3f); |
| 134 } |
| 135 } |
| 136 } |
| 137 |
| 138 /* Convert UTF8 string to UTF16. Rewritten from gpt utility. |
| 139 * Caller must prepare enough space for UTF16. The conservative estimation is: |
| 140 * |
| 141 * utf16 bytecount = bytecount(utf8) / 3 * 4 |
| 142 */ |
| 143 void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16) |
| 144 { |
| 145 size_t s16idx, s8idx, s8len; |
| 146 uint32_t utfchar; |
| 147 unsigned int c, utfbytes; |
| 148 |
| 149 for (s8len = 0; utf8[s8len]; ++s8len); |
| 150 |
| 151 s8idx = s16idx = 0; |
| 152 utfbytes = 0; |
| 153 do { |
| 154 c = utf8[s8idx++]; |
| 155 if ((c & 0xc0) != 0x80) { |
| 156 /* Initial characters. */ |
| 157 if (utfbytes != 0) { |
| 158 /* Incomplete encoding. */ |
| 159 utf16[s16idx++] = 0xfffd; |
| 160 } |
| 161 if ((c & 0xf8) == 0xf0) { |
| 162 utfchar = c & 0x07; |
| 163 utfbytes = 3; |
| 164 } else if ((c & 0xf0) == 0xe0) { |
| 165 utfchar = c & 0x0f; |
| 166 utfbytes = 2; |
| 167 } else if ((c & 0xe0) == 0xc0) { |
| 168 utfchar = c & 0x1f; |
| 169 utfbytes = 1; |
| 170 } else { |
| 171 utfchar = c & 0x7f; |
| 172 utfbytes = 0; |
| 173 } |
| 174 } else { |
| 175 /* Followup characters. */ |
| 176 if (utfbytes > 0) { |
| 177 utfchar = (utfchar << 6) + (c & 0x3f); |
| 178 utfbytes--; |
| 179 } else if (utfbytes == 0) |
| 180 utfbytes = -1; |
| 181 utfchar = 0xfffd; |
| 182 } |
| 183 if (utfbytes == 0) { |
| 184 if (utfchar >= 0x10000) { |
| 185 utf16[s16idx++] = htole16(0xd800 | ((utfchar>>10)-0x40)); |
| 186 if (s16idx >= SIZEOF_GPTENTRY_NAME) break; |
| 187 utf16[s16idx++] = htole16(0xdc00 | (utfchar & 0x3ff)); |
| 188 } else { |
| 189 utf16[s16idx++] = htole16(utfchar); |
| 190 } |
| 191 } |
| 192 } while (c != 0 && s16idx < SIZEOF_GPTENTRY_NAME); |
| 193 if (s16idx < SIZEOF_GPTENTRY_NAME) |
| 194 utf16[s16idx++] = 0; |
| 195 } |
| 196 |
| 53 /* Loads sectors from 'fd'. | 197 /* Loads sectors from 'fd'. |
| 54 * *buf is pointed to an allocated memory when returned, and should be | 198 * *buf is pointed to an allocated memory when returned, and should be |
| 55 * freed by cgpt_close(). | 199 * freed by cgpt_close(). |
| 56 * | 200 * |
| 57 * fd -- file descriptot. | 201 * fd -- file descriptot. |
| 58 * buf -- pointer to buffer pointer | 202 * buf -- pointer to buffer pointer |
| 59 * sector -- offset of starting sector (in sectors) | 203 * sector -- offset of starting sector (in sectors) |
| 60 * sector_bytes -- bytes per sector | 204 * sector_bytes -- bytes per sector |
| 61 * sector_count -- number of sectors to load | 205 * sector_count -- number of sectors to load |
| 62 * | 206 * |
| 63 * Returns CGPT_OK for successful. Aborts if any error occurs. | 207 * Returns CGPT_OK for successful. Aborts if any error occurs. |
| 64 */ | 208 */ |
| 65 int Load(const int fd, uint8_t **buf, | 209 int Load(const int fd, uint8_t **buf, |
| 66 const uint64_t sector, | 210 const uint64_t sector, |
| 67 const uint64_t sector_bytes, | 211 const uint64_t sector_bytes, |
| 68 const uint64_t sector_count) { | 212 const uint64_t sector_count) { |
| 69 int count; /* byte count to read */ | 213 int count; /* byte count to read */ |
| 70 int nread; | 214 int nread; |
| 71 | 215 |
| 72 assert(buf); | 216 assert(buf); |
| 73 count = sector_bytes * sector_count; | 217 count = sector_bytes * sector_count; |
| 74 *buf = Malloc(count); | 218 *buf = Malloc(count); |
| 75 assert(*buf); | 219 assert(*buf); |
| 76 | 220 |
| 77 if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET)) | 221 if (-1 == lseek64(fd, sector * sector_bytes, SEEK_SET)) |
| 78 goto error_free; | 222 goto error_free; |
| 79 | 223 |
| 80 nread = read(fd, *buf, count); | 224 nread = read(fd, *buf, count); |
| 81 if (nread < count) | 225 if (nread < count) |
| 82 goto error_free; | 226 goto error_free; |
| 83 | 227 |
| 84 return CGPT_OK; | 228 return CGPT_OK; |
| 85 | 229 |
| 86 error_free: | 230 error_free: |
| 87 Free(*buf); | 231 Free(*buf); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 102 int Save(const int fd, const uint8_t *buf, | 246 int Save(const int fd, const uint8_t *buf, |
| 103 const uint64_t sector, | 247 const uint64_t sector, |
| 104 const uint64_t sector_bytes, | 248 const uint64_t sector_bytes, |
| 105 const uint64_t sector_count) { | 249 const uint64_t sector_count) { |
| 106 int count; /* byte count to write */ | 250 int count; /* byte count to write */ |
| 107 int nwrote; | 251 int nwrote; |
| 108 | 252 |
| 109 assert(buf); | 253 assert(buf); |
| 110 count = sector_bytes * sector_count; | 254 count = sector_bytes * sector_count; |
| 111 | 255 |
| 112 if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET)) | 256 if (-1 == lseek64(fd, sector * sector_bytes, SEEK_SET)) |
| 113 return CGPT_FAILED; | 257 return CGPT_FAILED; |
| 114 | 258 |
| 115 nwrote = write(fd, buf, count); | 259 nwrote = write(fd, buf, count); |
| 116 if (nwrote < count) | 260 if (nwrote < count) |
| 117 return CGPT_FAILED; | 261 return CGPT_FAILED; |
| 118 | 262 |
| 119 return CGPT_OK; | 263 return CGPT_OK; |
| 120 } | 264 } |
| 121 | 265 |
| 266 int CheckValid(const struct drive *drive) { |
| 267 if ((drive->gpt.valid_headers != MASK_BOTH) || |
| 268 (drive->gpt.valid_entries != MASK_BOTH)) { |
| 269 printf("\n[ERROR] any of GPT header/entries is invalid, " |
| 270 "please run --repair first\n"); |
| 271 return CGPT_FAILED; |
| 272 } |
| 273 return CGPT_OK; |
| 274 } |
| 275 |
| 122 /* Opens a block device (a regular file works well too). | 276 /* Opens a block device (a regular file works well too). |
| 123 * | 277 * |
| 124 * Returns CGPT_FAILED if any error happens. | 278 * Returns CGPT_FAILED if any error happens. |
| 125 * Returns CGPT_OK if success and information are stored in 'drive'. */ | 279 * Returns CGPT_OK if success and information are stored in 'drive'. */ |
| 126 int DriveOpen(const char *drive_path, struct drive *drive) { | 280 int DriveOpen(const char *drive_path, struct drive *drive) { |
| 127 struct stat stat; | 281 struct stat stat; |
| 128 int gpt_retval; | 282 int gpt_retval; |
| 129 | 283 |
| 130 assert(drive_path); | 284 assert(drive_path); |
| 131 assert(drive); | 285 assert(drive); |
| 132 | 286 |
| 133 Memset(drive, 0, sizeof(struct drive)); | 287 Memset(drive, 0, sizeof(struct drive)); |
| 134 drive->fd = open(drive_path, O_RDWR); | 288 drive->fd = open(drive_path, O_RDWR | O_LARGEFILE); |
| 135 if (drive->fd == -1) { | 289 if (drive->fd == -1) { |
| 136 printf("[ERROR] Cannot open drive file [%s]: %s\n", | 290 printf("[ERROR] Cannot open drive file [%s]: %s\n", |
| 137 drive_path, strerror(errno)); | 291 drive_path, strerror(errno)); |
| 138 return CGPT_FAILED; | 292 return CGPT_FAILED; |
| 139 } | 293 } |
| 140 | 294 |
| 141 if (fstat(drive->fd, &stat) == -1) { | 295 if (fstat(drive->fd, &stat) == -1) { |
| 142 goto error_close; | 296 goto error_close; |
| 143 } | 297 } |
| 144 if ((stat.st_mode & S_IFMT) != S_IFREG) { | 298 if ((stat.st_mode & S_IFMT) != S_IFREG) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 171 Load(drive->fd, &drive->gpt.secondary_header, | 325 Load(drive->fd, &drive->gpt.secondary_header, |
| 172 drive->gpt.drive_sectors - GPT_PMBR_SECTOR, | 326 drive->gpt.drive_sectors - GPT_PMBR_SECTOR, |
| 173 drive->gpt.sector_bytes, GPT_HEADER_SECTOR); | 327 drive->gpt.sector_bytes, GPT_HEADER_SECTOR); |
| 174 Load(drive->fd, &drive->gpt.primary_entries, | 328 Load(drive->fd, &drive->gpt.primary_entries, |
| 175 GPT_PMBR_SECTOR + GPT_HEADER_SECTOR, | 329 GPT_PMBR_SECTOR + GPT_HEADER_SECTOR, |
| 176 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS); | 330 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS); |
| 177 Load(drive->fd, &drive->gpt.secondary_entries, | 331 Load(drive->fd, &drive->gpt.secondary_entries, |
| 178 drive->gpt.drive_sectors - GPT_HEADER_SECTOR - GPT_ENTRIES_SECTORS, | 332 drive->gpt.drive_sectors - GPT_HEADER_SECTOR - GPT_ENTRIES_SECTORS, |
| 179 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS); | 333 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS); |
| 180 | 334 |
| 181 if (GPT_SUCCESS != (gpt_retval = GptInit(&drive->gpt))) { | 335 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive->gpt))) { |
| 182 printf("[ERROR] GptInit(): %s\n", GptError(gpt_retval)); | 336 printf("[ERROR] GptSanityCheck(): %s\n", GptError(gpt_retval)); |
| 183 goto error_close; | 337 goto error_close; |
| 184 } | 338 } |
| 185 | 339 |
| 186 drive->inited = 1; | 340 drive->inited = 1; |
| 187 | 341 |
| 188 return CGPT_OK; | 342 return CGPT_OK; |
| 189 | 343 |
| 190 error_close: | 344 error_close: |
| 191 close(drive->fd); | 345 close(drive->fd); |
| 192 return CGPT_FAILED; | 346 return CGPT_FAILED; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 progname = argv[0]; | 392 progname = argv[0]; |
| 239 cmd = argv[optind++]; | 393 cmd = argv[optind++]; |
| 240 for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) { | 394 for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) { |
| 241 if (cmd && !strcmp(cmds[i].name, cmd)) | 395 if (cmd && !strcmp(cmds[i].name, cmd)) |
| 242 return cmds[i].fp(argc, argv); | 396 return cmds[i].fp(argc, argv); |
| 243 } | 397 } |
| 244 | 398 |
| 245 Usage(0); | 399 Usage(0); |
| 246 return CGPT_FAILED; | 400 return CGPT_FAILED; |
| 247 } | 401 } |
| OLD | NEW |