1 /* $OpenBSD: gpt.c,v 1.47 2021/07/21 12:22:54 krw Exp $ */ 2 /* 3 * Copyright (c) 2015 Markus Muller <mmu@grummel.net> 4 * Copyright (c) 2015 Kenneth R Westerback <krw@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> /* DEV_BSIZE */ 20 #include <sys/disklabel.h> 21 #include <sys/dkio.h> 22 #include <sys/ioctl.h> 23 24 #include <errno.h> 25 #include <stdio.h> 26 #include <stdint.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 #include <uuid.h> 31 32 #include "part.h" 33 #include "disk.h" 34 #include "mbr.h" 35 #include "misc.h" 36 #include "gpt.h" 37 38 #ifdef DEBUG 39 #define DPRINTF(x...) printf(x) 40 #else 41 #define DPRINTF(x...) 42 #endif 43 44 struct mbr gmbr; 45 struct gpt_header gh; 46 struct gpt_partition gp[NGPTPARTITIONS]; 47 48 struct gpt_partition **sort_gpt(void); 49 int lba_start_cmp(const void *e1, const void *e2); 50 int lba_free(uint64_t *, uint64_t *); 51 int add_partition(const uint8_t *, const char *, uint64_t); 52 int get_header(const uint64_t); 53 int get_partition_table(void); 54 int init_gh(void); 55 int init_gp(const int); 56 uint32_t crc32(const u_char *, const uint32_t); 57 int protective_mbr(const struct mbr *); 58 int gpt_chk_mbr(struct dos_partition *, uint64_t); 59 60 /* 61 * Return the index into dp[] of the EFI GPT (0xEE) partition, or -1 if no such 62 * partition exists. 63 * 64 * Taken from kern/subr_disk.c. 65 * 66 */ 67 int 68 gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) 69 { 70 struct dos_partition *dp2; 71 int efi, eficnt, found, i; 72 uint32_t psize; 73 74 found = efi = eficnt = 0; 75 for (dp2 = dp, i = 0; i < NDOSPART; i++, dp2++) { 76 if (dp2->dp_typ == DOSPTYP_UNUSED) 77 continue; 78 found++; 79 if (dp2->dp_typ != DOSPTYP_EFI) 80 continue; 81 if (letoh32(dp2->dp_start) != GPTSECTOR) 82 continue; 83 psize = letoh32(dp2->dp_size); 84 if (psize <= (dsize - GPTSECTOR) || psize == UINT32_MAX) { 85 efi = i; 86 eficnt++; 87 } 88 } 89 if (found == 1 && eficnt == 1) 90 return efi; 91 92 return -1; 93 } 94 95 int 96 protective_mbr(const struct mbr *mbr) 97 { 98 struct dos_partition dp[NDOSPART], dos_partition; 99 int i; 100 101 if (mbr->mbr_lba_self != 0) 102 return -1; 103 104 for (i = 0; i < NDOSPART; i++) { 105 PRT_make(&mbr->mbr_prt[i], mbr->mbr_lba_self, mbr->mbr_lba_firstembr, 106 &dos_partition); 107 memcpy(&dp[i], &dos_partition, sizeof(dp[i])); 108 } 109 110 return gpt_chk_mbr(dp, DL_GETDSIZE(&dl)); 111 } 112 113 int 114 get_header(const uint64_t sector) 115 { 116 char *secbuf; 117 uint64_t partlastlba, partslen, lba_end; 118 int partspersec; 119 uint32_t orig_gh_csum, new_gh_csum; 120 121 secbuf = DISK_readsector(sector); 122 if (secbuf == NULL) 123 return -1; 124 125 memcpy(&gh, secbuf, sizeof(struct gpt_header)); 126 free(secbuf); 127 128 if (letoh64(gh.gh_sig) != GPTSIGNATURE) { 129 DPRINTF("gpt signature: expected 0x%llx, got 0x%llx\n", 130 GPTSIGNATURE, letoh64(gh.gh_sig)); 131 return -1; 132 } 133 134 if (letoh32(gh.gh_rev) != GPTREVISION) { 135 DPRINTF("gpt revision: expected 0x%x, got 0x%x\n", 136 GPTREVISION, letoh32(gh.gh_rev)); 137 return -1; 138 } 139 140 if (letoh64(gh.gh_lba_self) != sector) { 141 DPRINTF("gpt self lba: expected %llu, got %llu\n", 142 sector, letoh64(gh.gh_lba_self)); 143 return -1; 144 } 145 146 if (letoh32(gh.gh_size) != GPTMINHDRSIZE) { 147 DPRINTF("gpt header size: expected %u, got %u\n", 148 GPTMINHDRSIZE, letoh32(gh.gh_size)); 149 return -1; 150 } 151 152 if (letoh32(gh.gh_part_size) != GPTMINPARTSIZE) { 153 DPRINTF("gpt partition size: expected %u, got %u\n", 154 GPTMINPARTSIZE, letoh32(gh.gh_part_size)); 155 return -1; 156 } 157 158 if (letoh32(gh.gh_part_num) > NGPTPARTITIONS) { 159 DPRINTF("gpt partition count: expected <= %u, got %u\n", 160 NGPTPARTITIONS, letoh32(gh.gh_part_num)); 161 return -1; 162 } 163 164 orig_gh_csum = gh.gh_csum; 165 gh.gh_csum = 0; 166 new_gh_csum = crc32((unsigned char *)&gh, letoh32(gh.gh_size)); 167 gh.gh_csum = orig_gh_csum; 168 if (letoh32(orig_gh_csum) != new_gh_csum) { 169 DPRINTF("gpt header checksum: expected 0x%x, got 0x%x\n", 170 orig_gh_csum, new_gh_csum); 171 return -1; 172 } 173 174 /* XXX Assume part_num * part_size is multiple of secsize. */ 175 partslen = letoh32(gh.gh_part_num) * letoh32(gh.gh_part_size) / 176 dl.d_secsize; 177 lba_end = DL_GETDSIZE(&dl) - partslen - 2; 178 if (letoh64(gh.gh_lba_end) > lba_end) { 179 DPRINTF("gpt last usable LBA: reduced from %llu to %llu\n", 180 letoh64(gh.gh_lba_end), lba_end); 181 gh.gh_lba_end = htole64(lba_end); 182 } 183 184 if (letoh64(gh.gh_lba_start) >= letoh64(gh.gh_lba_end)) { 185 DPRINTF("gpt first usable LBA: expected < %llu, got %llu\n", 186 letoh64(gh.gh_lba_end), letoh64(gh.gh_lba_start)); 187 return -1; 188 } 189 190 if (letoh64(gh.gh_part_lba) <= letoh64(gh.gh_lba_end) && 191 letoh64(gh.gh_part_lba) >= letoh64(gh.gh_lba_start)) { 192 DPRINTF("gpt partition table start lba: expected < %llu or " 193 "> %llu, got %llu\n", letoh64(gh.gh_lba_start), 194 letoh64(gh.gh_lba_end), letoh64(gh.gh_part_lba)); 195 return -1; 196 } 197 198 partspersec = dl.d_secsize / letoh32(gh.gh_part_size); 199 partlastlba = letoh64(gh.gh_part_lba) + 200 ((letoh32(gh.gh_part_num) + partspersec - 1) / partspersec) - 1; 201 if (partlastlba <= letoh64(gh.gh_lba_end) && 202 partlastlba >= letoh64(gh.gh_lba_start)) { 203 DPRINTF("gpt partition table last LBA: expected < %llu or " 204 "> %llu, got %llu\n", letoh64(gh.gh_lba_start), 205 letoh64(gh.gh_lba_end), partlastlba); 206 return -1; 207 } 208 209 /* 210 * Other possible paranoia checks: 211 * 1) partition table starts before primary gpt lba. 212 * 2) partition table extends into lowest partition. 213 * 3) alt partition table starts before gh_lba_end. 214 */ 215 return 0; 216 } 217 218 int 219 get_partition_table(void) 220 { 221 ssize_t len; 222 off_t off, where; 223 int secs; 224 uint32_t checksum, partspersec; 225 226 DPRINTF("gpt partition table being read from LBA %llu\n", 227 letoh64(gh.gh_part_lba)); 228 229 partspersec = dl.d_secsize / letoh32(gh.gh_part_size); 230 if (partspersec * letoh32(gh.gh_part_size) != dl.d_secsize) { 231 DPRINTF("gpt partition table entry invalid size. %u\n", 232 letoh32(gh.gh_part_size)); 233 return -1; 234 } 235 secs = (letoh32(gh.gh_part_num) + partspersec - 1) / partspersec; 236 237 memset(&gp, 0, sizeof(gp)); 238 239 where = letoh64(gh.gh_part_lba) * dl.d_secsize; 240 off = lseek(disk.dk_fd, where, SEEK_SET); 241 if (off == -1) { 242 DPRINTF("seek to gpt partition table @ sector %llu failed\n", 243 (unsigned long long)where / dl.d_secsize); 244 return -1; 245 } 246 len = read(disk.dk_fd, &gp, secs * dl.d_secsize); 247 if (len == -1 || len != secs * dl.d_secsize) { 248 DPRINTF("gpt partition table read failed.\n"); 249 return -1; 250 } 251 252 checksum = crc32((unsigned char *)&gp, letoh32(gh.gh_part_num) * 253 letoh32(gh.gh_part_size)); 254 if (checksum != letoh32(gh.gh_part_csum)) { 255 DPRINTF("gpt partition table checksum: expected %x, got %x\n", 256 checksum, letoh32(gh.gh_part_csum)); 257 return -1; 258 } 259 260 return 0; 261 } 262 263 int 264 GPT_read(const int which) 265 { 266 int error; 267 268 error = MBR_read(0, 0, &gmbr); 269 if (error == 0) 270 error = protective_mbr(&gmbr); 271 if (error) 272 goto done; 273 274 switch (which) { 275 case PRIMARYGPT: 276 error = get_header(GPTSECTOR); 277 break; 278 case SECONDARYGPT: 279 error = get_header(DL_GETDSIZE(&dl) - 1); 280 break; 281 case ANYGPT: 282 error = get_header(GPTSECTOR); 283 if (error != 0 || get_partition_table() != 0) 284 error = get_header(DL_GETDSIZE(&dl) - 1); 285 break; 286 default: 287 return -1; 288 } 289 290 if (error == 0) 291 error = get_partition_table(); 292 293 done: 294 if (error != 0) { 295 /* No valid GPT found. Zap any artifacts. */ 296 memset(&gmbr, 0, sizeof(gmbr)); 297 memset(&gh, 0, sizeof(gh)); 298 memset(&gp, 0, sizeof(gp)); 299 } 300 301 return error; 302 } 303 304 void 305 GPT_print(const char *units, const int verbosity) 306 { 307 const int secsize = unit_types[SECTORS].ut_conversion; 308 struct uuid guid; 309 char *guidstr = NULL; 310 double size; 311 int i, u, status; 312 313 u = unit_lookup(units); 314 size = ((double)DL_GETDSIZE(&dl) * secsize) / unit_types[u].ut_conversion; 315 printf("Disk: %s Usable LBA: %llu to %llu [%.0f ", 316 disk.dk_name, letoh64(gh.gh_lba_start), letoh64(gh.gh_lba_end), size); 317 318 if (u == SECTORS && secsize != DEV_BSIZE) 319 printf("%d-byte ", secsize); 320 printf("%s]\n", unit_types[u].ut_lname); 321 322 if (verbosity == VERBOSE) { 323 printf("GUID: "); 324 uuid_dec_le(&gh.gh_guid, &guid); 325 uuid_to_string(&guid, &guidstr, &status); 326 if (status == uuid_s_ok) 327 printf("%s\n", guidstr); 328 else 329 printf("<invalid header GUID>\n"); 330 free(guidstr); 331 } 332 333 GPT_print_parthdr(verbosity); 334 for (i = 0; i < letoh32(gh.gh_part_num); i++) { 335 if (uuid_is_nil(&gp[i].gp_type, NULL)) 336 continue; 337 GPT_print_part(i, units, verbosity); 338 } 339 } 340 341 void 342 GPT_print_parthdr(const int verbosity) 343 { 344 printf(" #: type " 345 " [ start: size ]\n"); 346 if (verbosity == VERBOSE) 347 printf(" guid name\n"); 348 printf("--------------------------------------------------------" 349 "----------------\n"); 350 } 351 352 void 353 GPT_print_part(const int n, const char *units, const int verbosity) 354 { 355 struct uuid guid; 356 struct gpt_partition *partn = &gp[n]; 357 char *guidstr = NULL; 358 const int secsize = unit_types[SECTORS].ut_conversion; 359 double size; 360 int u, status; 361 362 uuid_dec_le(&partn->gp_type, &guid); 363 u = unit_lookup(units); 364 size = letoh64(partn->gp_lba_end) - letoh64(partn->gp_lba_start) + 1; 365 size = (size * secsize) / unit_types[u].ut_conversion; 366 printf("%c%3d: %-36s [%12lld: %12.0f%s]\n", 367 (letoh64(partn->gp_attrs) & GPTDOSACTIVE)?'*':' ', n, 368 PRT_uuid_to_typename(&guid), letoh64(partn->gp_lba_start), 369 size, unit_types[u].ut_abbr); 370 371 if (verbosity == VERBOSE) { 372 uuid_dec_le(&partn->gp_guid, &guid); 373 uuid_to_string(&guid, &guidstr, &status); 374 if (status != uuid_s_ok) 375 printf(" <invalid partition guid> "); 376 else 377 printf(" %-36s ", guidstr); 378 printf("%-36s\n", utf16le_to_string(partn->gp_name)); 379 free(guidstr); 380 } 381 } 382 383 int 384 add_partition(const uint8_t *beuuid, const char *name, uint64_t sectors) 385 { 386 struct uuid uuid, gp_type; 387 int rslt; 388 uint64_t end, freesectors, start; 389 uint32_t status, pn, pncnt; 390 391 uuid_dec_be(beuuid, &uuid); 392 uuid_enc_le(&gp_type, &uuid); 393 394 pncnt = letoh32(gh.gh_part_num); 395 for (pn = 0; pn < pncnt; pn++) { 396 if (uuid_is_nil(&gp[pn].gp_type, NULL)) 397 break; 398 } 399 if (pn == pncnt) 400 goto done; 401 402 rslt = lba_free(&start, &end); 403 if (rslt == -1) 404 goto done; 405 406 if (start % BLOCKALIGNMENT) 407 start += (BLOCKALIGNMENT - start % BLOCKALIGNMENT); 408 if (start >= end) 409 goto done; 410 411 freesectors = end - start + 1; 412 413 if (sectors == 0) 414 sectors = freesectors; 415 416 if (freesectors < sectors) 417 goto done; 418 else if (freesectors > sectors) 419 end = start + sectors - 1; 420 421 gp[pn].gp_type = gp_type; 422 gp[pn].gp_lba_start = htole64(start); 423 gp[pn].gp_lba_end = htole64(end); 424 memcpy(gp[pn].gp_name, string_to_utf16le(name), 425 sizeof(gp[pn].gp_name)); 426 427 uuid_create(&uuid, &status); 428 if (status != uuid_s_ok) 429 goto done; 430 431 uuid_enc_le(&gp[pn].gp_guid, &uuid); 432 gh.gh_part_csum = crc32((unsigned char *)&gp, sizeof(gp)); 433 gh.gh_csum = crc32((unsigned char *)&gh, sizeof(gh)); 434 435 return 0; 436 437 done: 438 if (pn != pncnt) 439 memset(&gp[pn], 0, sizeof(gp[pn])); 440 printf("unable to add %s\n", name); 441 return -1; 442 } 443 444 int 445 init_gh(void) 446 { 447 struct gpt_header oldgh; 448 struct uuid guid; 449 const int secsize = unit_types[SECTORS].ut_conversion; 450 int needed; 451 uint32_t status; 452 453 memcpy(&oldgh, &gh, sizeof(oldgh)); 454 memset(&gh, 0, sizeof(gh)); 455 memset(&gmbr, 0, sizeof(gmbr)); 456 457 /* XXX Do we need the boot code? UEFI spec & Apple says no. */ 458 memcpy(gmbr.mbr_code, initial_mbr.mbr_code, sizeof(gmbr.mbr_code)); 459 gmbr.mbr_prt[0].prt_id = DOSPTYP_EFI; 460 gmbr.mbr_prt[0].prt_bs = 1; 461 gmbr.mbr_prt[0].prt_ns = UINT32_MAX; 462 PRT_fix_CHS(&gmbr.mbr_prt[0]); 463 gmbr.mbr_signature = DOSMBR_SIGNATURE; 464 465 needed = sizeof(gp) / secsize + 2; 466 467 if (needed % BLOCKALIGNMENT) 468 needed += (needed - (needed % BLOCKALIGNMENT)); 469 470 gh.gh_sig = htole64(GPTSIGNATURE); 471 gh.gh_rev = htole32(GPTREVISION); 472 gh.gh_size = htole32(GPTMINHDRSIZE); 473 gh.gh_csum = 0; 474 gh.gh_rsvd = 0; 475 gh.gh_lba_self = htole64(1); 476 gh.gh_lba_alt = htole64(DL_GETDSIZE(&dl) - 1); 477 gh.gh_lba_start = htole64(needed); 478 gh.gh_lba_end = htole64(DL_GETDSIZE(&dl) - needed); 479 gh.gh_part_lba = htole64(2); 480 gh.gh_part_num = htole32(NGPTPARTITIONS); 481 gh.gh_part_size = htole32(GPTMINPARTSIZE); 482 483 uuid_create(&guid, &status); 484 if (status != uuid_s_ok) { 485 memcpy(&gh, &oldgh, sizeof(gh)); 486 return -1; 487 } 488 489 uuid_enc_le(&gh.gh_guid, &guid); 490 return 0; 491 } 492 493 int 494 init_gp(const int how) 495 { 496 struct gpt_partition oldgp[NGPTPARTITIONS]; 497 const uint8_t gpt_uuid_efi_system[] = GPT_UUID_EFI_SYSTEM; 498 const uint8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD; 499 int pn, rslt; 500 501 memcpy(&oldgp, &gp, sizeof(oldgp)); 502 if (how == GHANDGP) 503 memset(&gp, 0, sizeof(gp)); 504 else { 505 for (pn = 0; pn < NGPTPARTITIONS; pn++) { 506 if (PRT_protected_guid(&gp[pn].gp_type)) 507 continue; 508 memset(&gp[pn], 0, sizeof(gp[pn])); 509 } 510 } 511 512 rslt = 0; 513 if (disk.dk_bootprt.prt_ns > 0) { 514 rslt = add_partition(gpt_uuid_efi_system, "EFI System Area", 515 disk.dk_bootprt.prt_ns); 516 } 517 if (rslt == 0) 518 rslt = add_partition(gpt_uuid_openbsd, "OpenBSD Area", 0); 519 520 if (rslt != 0) 521 memcpy(&gp, &oldgp, sizeof(gp)); 522 523 return rslt; 524 } 525 526 int 527 GPT_init(const int how) 528 { 529 int rslt = 0; 530 531 if (how == GHANDGP) 532 rslt = init_gh(); 533 if (rslt == 0) 534 rslt = init_gp(how); 535 536 return rslt; 537 } 538 539 void 540 GPT_zap_headers(void) 541 { 542 char *secbuf; 543 uint64_t sig; 544 545 secbuf = DISK_readsector(GPTSECTOR); 546 if (secbuf == NULL) 547 return; 548 549 memcpy(&sig, secbuf, sizeof(sig)); 550 if (letoh64(sig) == GPTSIGNATURE) { 551 memset(secbuf, 0, dl.d_secsize); 552 DISK_writesector(secbuf, GPTSECTOR); 553 } 554 free(secbuf); 555 556 secbuf = DISK_readsector(DL_GETDSIZE(&dl) - 1); 557 if (secbuf == NULL) 558 return; 559 560 memcpy(&sig, secbuf, sizeof(sig)); 561 if (letoh64(sig) == GPTSIGNATURE) { 562 memset(secbuf, 0, dl.d_secsize); 563 DISK_writesector(secbuf, DL_GETDSIZE(&dl) - 1); 564 } 565 free(secbuf); 566 } 567 568 int 569 GPT_write(void) 570 { 571 char *secbuf; 572 ssize_t len; 573 off_t off; 574 const int secsize = unit_types[SECTORS].ut_conversion; 575 uint64_t altgh, altgp, prigh, prigp, gpbytes; 576 577 MBR_write(&gmbr); 578 579 /* 580 * XXX Assume size of gp is multiple of sector size. 581 */ 582 gpbytes = letoh32(gh.gh_part_num) * letoh32(gh.gh_part_size); 583 584 prigh = GPTSECTOR; 585 prigp = prigh + 1; 586 altgh = DL_GETDSIZE(&dl) - 1; 587 altgp = DL_GETDSIZE(&dl) - 1 - (gpbytes / secsize); 588 589 gh.gh_lba_self = htole64(prigh); 590 gh.gh_lba_alt = htole64(altgh); 591 gh.gh_part_lba = htole64(prigp); 592 gh.gh_part_csum = crc32((unsigned char *)&gp, gpbytes); 593 gh.gh_csum = 0; 594 gh.gh_csum = crc32((unsigned char *)&gh, letoh32(gh.gh_size)); 595 596 secbuf = DISK_readsector(prigh); 597 if (secbuf == NULL) 598 return -1; 599 600 memcpy(secbuf, &gh, sizeof(gh)); 601 DISK_writesector(secbuf, prigh); 602 free(secbuf); 603 604 gh.gh_lba_self = htole64(altgh); 605 gh.gh_lba_alt = htole64(prigh); 606 gh.gh_part_lba = htole64(altgp); 607 gh.gh_csum = 0; 608 gh.gh_csum = crc32((unsigned char *)&gh, letoh32(gh.gh_size)); 609 610 secbuf = DISK_readsector(altgh); 611 if (secbuf == NULL) 612 return -1; 613 614 memcpy(secbuf, &gh, sizeof(gh)); 615 DISK_writesector(secbuf, altgh); 616 free(secbuf); 617 618 off = lseek(disk.dk_fd, secsize * prigp, SEEK_SET); 619 if (off == secsize * prigp) 620 len = write(disk.dk_fd, &gp, gpbytes); 621 else 622 len = -1; 623 if (len == -1 || len != gpbytes) { 624 errno = EIO; 625 return -1; 626 } 627 628 off = lseek(disk.dk_fd, secsize * altgp, SEEK_SET); 629 if (off == secsize * altgp) 630 len = write(disk.dk_fd, &gp, gpbytes); 631 else 632 len = -1; 633 634 if (len == -1 || len != gpbytes) { 635 errno = EIO; 636 return -1; 637 } 638 639 /* Refresh in-kernel disklabel from the updated disk information. */ 640 ioctl(disk.dk_fd, DIOCRLDINFO, 0); 641 642 return 0; 643 } 644 645 int 646 gp_lba_start_cmp(const void *e1, const void *e2) 647 { 648 struct gpt_partition *p1 = *(struct gpt_partition **)e1; 649 struct gpt_partition *p2 = *(struct gpt_partition **)e2; 650 uint64_t o1; 651 uint64_t o2; 652 653 o1 = letoh64(p1->gp_lba_start); 654 o2 = letoh64(p2->gp_lba_start); 655 656 if (o1 < o2) 657 return -1; 658 else if (o1 > o2) 659 return 1; 660 else 661 return 0; 662 } 663 664 struct gpt_partition ** 665 sort_gpt(void) 666 { 667 static struct gpt_partition *sgp[NGPTPARTITIONS+2]; 668 unsigned int i, j; 669 670 memset(sgp, 0, sizeof(sgp)); 671 672 j = 0; 673 for (i = 0; i < letoh32(gh.gh_part_num); i++) { 674 if (letoh64(gp[i].gp_lba_start) >= letoh64(gh.gh_lba_start)) 675 sgp[j++] = &gp[i]; 676 } 677 678 if (j > 1) { 679 if (mergesort(sgp, j, sizeof(sgp[0]), gp_lba_start_cmp) == -1) { 680 printf("unable to sort gpt by lba start\n"); 681 return NULL; 682 } 683 } 684 685 return sgp; 686 } 687 688 int 689 lba_free(uint64_t *start, uint64_t *end) 690 { 691 struct gpt_partition **sgp; 692 uint64_t bs, bigbs, nextbs, ns; 693 unsigned int i; 694 695 sgp = sort_gpt(); 696 if (sgp == NULL) 697 return -1; 698 699 bs = letoh64(gh.gh_lba_start); 700 ns = letoh64(gh.gh_lba_end) - bs + 1; 701 702 if (sgp[0] != NULL) { 703 bigbs = bs; 704 ns = 0; 705 for (i = 0; sgp[i] != NULL; i++) { 706 nextbs = letoh64(sgp[i]->gp_lba_start); 707 if (bs < nextbs && ns < nextbs - bs) { 708 ns = nextbs - bs; 709 bigbs = bs; 710 } 711 bs = letoh64(sgp[i]->gp_lba_end) + 1; 712 } 713 nextbs = letoh64(gh.gh_lba_end) + 1; 714 if (bs < nextbs && ns < nextbs - bs) { 715 ns = nextbs - bs; 716 bigbs = bs; 717 } 718 bs = bigbs; 719 } 720 721 if (ns == 0) 722 return -1; 723 724 if (start != NULL) 725 *start = bs; 726 if (end != NULL) 727 *end = bs + ns - 1; 728 729 return 0; 730 } 731 732 int 733 GPT_get_lba_start(const unsigned int pn) 734 { 735 uint64_t bs; 736 unsigned int i; 737 int rslt; 738 739 bs = letoh64(gh.gh_lba_start); 740 741 if (letoh64(gp[pn].gp_lba_start) >= bs) { 742 bs = letoh64(gp[pn].gp_lba_start); 743 } else { 744 rslt = lba_free(&bs, NULL); 745 if (rslt == -1) { 746 printf("no space for partition %u\n", pn); 747 return -1; 748 } 749 } 750 751 bs = getuint64("Partition offset", bs, letoh64(gh.gh_lba_start), 752 letoh64(gh.gh_lba_end)); 753 754 for (i = 0; i < letoh32(gh.gh_part_num); i++) { 755 if (i == pn) 756 continue; 757 if (bs >= letoh64(gp[i].gp_lba_start) && 758 bs <= letoh64(gp[i].gp_lba_end)) { 759 printf("partition %u can't start inside partition %u\n", 760 pn, i); 761 return -1; 762 } 763 } 764 765 gp[pn].gp_lba_start = htole64(bs); 766 767 return 0; 768 } 769 770 int 771 GPT_get_lba_end(const unsigned int pn) 772 { 773 struct gpt_partition **sgp; 774 uint64_t bs, nextbs, ns; 775 unsigned int i; 776 777 sgp = sort_gpt(); 778 if (sgp == NULL) 779 return -1; 780 781 bs = letoh64(gp[pn].gp_lba_start); 782 ns = letoh64(gh.gh_lba_end) - bs + 1; 783 for (i = 0; sgp[i] != NULL; i++) { 784 nextbs = letoh64(sgp[i]->gp_lba_start); 785 if (nextbs > bs) { 786 ns = nextbs - bs; 787 break; 788 } 789 } 790 ns = getuint64("Partition size", ns, 1, ns); 791 792 gp[pn].gp_lba_end = htole64(bs + ns - 1); 793 794 return 0; 795 } 796 797 /* 798 * Adapted from Hacker's Delight crc32b(). 799 * 800 * To quote http://www.hackersdelight.org/permissions.htm : 801 * 802 * "You are free to use, copy, and distribute any of the code on 803 * this web site, whether modified by you or not. You need not give 804 * attribution. This includes the algorithms (some of which appear 805 * in Hacker's Delight), the Hacker's Assistant, and any code submitted 806 * by readers. Submitters implicitly agree to this." 807 */ 808 uint32_t 809 crc32(const u_char *buf, const uint32_t size) 810 { 811 int j; 812 uint32_t i, byte, crc, mask; 813 814 crc = 0xFFFFFFFF; 815 816 for (i = 0; i < size; i++) { 817 byte = buf[i]; /* Get next byte. */ 818 crc = crc ^ byte; 819 for (j = 7; j >= 0; j--) { /* Do eight times. */ 820 mask = -(crc & 1); 821 crc = (crc >> 1) ^ (0xEDB88320 & mask); 822 } 823 } 824 825 return ~crc; 826 } 827