partitions.c revision 4f115c7127037e3729bb64c149df298e269a17a7
1/* 2 * Copyright (c) 2009-2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google, Inc. nor the names of its contributors 15 * may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 25 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/types.h> 33#include <sys/stat.h> 34#include <fcntl.h> 35#include <sys/mman.h> 36#include <sys/stat.h> 37#include <sys/types.h> 38#include <unistd.h> 39#include <endian.h> 40#include <zlib.h> 41#include <linux/hdreg.h> 42#include <sys/ioctl.h> 43#include <stdlib.h> 44#include <cutils/config_utils.h> 45 46#include "partitions.h" 47#include "debug.h" 48#include "utils.h" 49#include "protocol.h" 50 51#define BLKRRPART _IO(0x12,95) /* re-read partition table */ 52#define BLKSSZGET _IO(0x12,104) 53 54#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y)) 55#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y))) 56#define ALIGN_DOWN(x, y) ((y) * ((x) / (y))) 57 58 59const uint8_t partition_type_uuid[16] = { 60 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, 61 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7, 62}; 63 64//TODO: If both blocks are invalid should I leave everything to vendor (through libvendor) 65 66static void GPT_entry_clear(struct GPT_entry_raw *entry) 67{ 68 memset(entry, 0, sizeof(*entry)); 69} 70 71/* 72 * returns mapped location to choosen area 73 * mapped_ptr is pointer to whole area mapped (it can be bigger then requested) 74 */ 75int gpt_mmap(struct GPT_mapping *mapping, uint64_t location, int size, int fd) 76{ 77 unsigned int location_diff = location & ~PAGE_MASK; 78 79 mapping->size = ALIGN(size + location_diff, PAGE_SIZE); 80 81 uint64_t sz = get_file_size64(fd); 82 if (sz < size + location) { 83 D(ERR, "the location of mapping area is outside of the device size %lld", sz); 84 return 1; 85 } 86 87 mapping->map_ptr = mmap64(NULL, mapping->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, location); 88 89 if (mapping->map_ptr == MAP_FAILED) { 90 mapping->ptr = MAP_FAILED; 91 D(ERR, "map failed %d", (int) mapping->map_ptr); 92 return 1; 93 } 94 95 mapping->ptr = (void *)((char *) mapping->map_ptr + location_diff); 96 return 0; 97} 98 99void gpt_unmap(struct GPT_mapping *mapping) { 100 munmap(mapping->map_ptr, mapping->size); 101} 102 103 104#define LBA_ADDR(table, value) ((uint64_t) (table)->sector_size * (value)) 105 106int GPT_map_from_content(struct GPT_entry_table *table, const struct GPT_content *content) 107{ 108 109 // Mapping header 110 if (gpt_mmap(&table->header_map, LBA_ADDR(table, content->header.current_lba), 111 table->sector_size, table->fd)) { 112 D(ERR, "unable to map header:%s\n", strerror(errno)); 113 goto error_header; 114 } 115 116 table->header = (struct GPT_header *) table->header_map.ptr; 117 118 table->partition_table_size = ROUND_UP(content->header.entries_count * sizeof(*table->entries), 119 table->sector_size); 120 121 // Mapping entry table 122 if (gpt_mmap(&table->entries_map, LBA_ADDR(table, content->header.entries_lba), 123 table->partition_table_size, table->fd)) { 124 D(ERR, "unable to map entries"); 125 goto error_signature; 126 } 127 128 table->entries = (struct GPT_entry_raw *) table->entries_map.ptr; 129 130 // Mapping secondary header 131 if (gpt_mmap(&table->sec_header_map, LBA_ADDR(table, content->header.backup_lba), 132 table->sector_size, table->fd)) { 133 D(ERR, "unable to map backup gpt header"); 134 goto error_sec_header; 135 } 136 137 // Mapping secondary entries table 138 if (gpt_mmap(&table->sec_entries_map, 139 LBA_ADDR(table, content->header.backup_lba) - table->partition_table_size, 140 table->partition_table_size, table->fd)) { 141 D(ERR, "unable to map secondary gpt table"); 142 goto error_sec_entries; 143 } 144 145 table->second_header = (struct GPT_header *) table->sec_header_map.ptr; 146 table->second_entries = (struct GPT_entry_raw *) table->sec_entries_map.ptr; 147 table->second_valid = strcmp("EFI PART", (char *) table->second_header->signature) == 0; 148 149 return 0; 150 151error_sec_entries: 152 gpt_unmap(&table->sec_header_map); 153error_sec_header: 154 gpt_unmap(&table->entries_map); 155error_signature: 156 gpt_unmap(&table->header_map); 157error_header: 158 return 1; 159} 160 161int GPT_map(struct GPT_entry_table *table, unsigned header_lba) 162{ 163 struct GPT_content content; 164 struct GPT_mapping mapping; 165 struct GPT_header *header; 166 167 if (gpt_mmap(&mapping, LBA_ADDR(table, header_lba), table->sector_size, table->fd)) { 168 D(ERR, "unable to map header: %s", strerror(errno)); 169 goto error_header; 170 } 171 172 header = (struct GPT_header *) mapping.ptr; 173 174 if (strcmp("EFI PART", (char *) header->signature)) { 175 D(ERR, "GPT entry not valid"); 176 goto error_signature; 177 } 178 179 content.header = *header; 180 181 gpt_unmap(&mapping); 182 183 return GPT_map_from_content(table, &content); 184 185error_signature: 186 gpt_unmap(&table->header_map); 187error_header: 188 return 1; 189} 190 191struct GPT_entry_table* GPT_get_device(const char *path, unsigned header_lba) 192{ 193 struct GPT_entry_table *table; 194 size_t sector_bytes; 195 196 table = (struct GPT_entry_table *) malloc(sizeof(*table)); 197 table->fd = open(path, O_RDWR); 198 199 if (table->fd < 0) { 200 D(ERR, "unable to open file %s:%s\n", path, strerror(errno)); 201 return NULL; 202 } 203 204 if (!ioctl(table->fd, BLKSSZGET, §or_bytes)) { 205 table->sector_size = (unsigned) sector_bytes; 206 D(INFO, "Got sector size %d", table->sector_size); 207 } else { 208 D(WARN, "unable to get sector size, assuming 512"); 209 table->sector_size = 512; 210 } 211 212 if (GPT_map(table, header_lba)) { 213 D(ERR, "Could not map gpt"); 214 return NULL; 215 } 216 217 return table; 218} 219 220static struct GPT_entry_table* GPT_get_from_content(const char *path, const struct GPT_content *content) 221{ 222 struct GPT_entry_table *table; 223 size_t sector_bytes; 224 225 table = (struct GPT_entry_table *) malloc(sizeof(*table)); 226 table->fd = open(path, O_RDWR); 227 228 if (table->fd < 0) { 229 D(ERR, "unable to open file %s:%s\n", path, strerror(errno)); 230 return NULL; 231 } 232 233 if (!ioctl(table->fd, BLKSSZGET, §or_bytes)) { 234 table->sector_size = (unsigned) sector_bytes; 235 D(INFO, "Got sector size %d", table->sector_size); 236 } else { 237 D(WARN, "unable to get sector size %s, assuming 512", strerror(errno)); 238 table->sector_size = 512; 239 } 240 241 if (GPT_map_from_content(table, content)) { 242 D(ERR, "Could not map gpt"); 243 return NULL; 244 } 245 246 return table; 247} 248 249 250void GPT_release_device(struct GPT_entry_table *table) 251{ 252 gpt_unmap(&table->header_map); 253 gpt_unmap(&table->entries_map); 254 gpt_unmap(&table->sec_header_map); 255 gpt_unmap(&table->sec_entries_map); 256 close(table->fd); 257 free(table); 258} 259 260static int GPT_check_overlap(struct GPT_entry_table *table, struct GPT_entry_raw *entry); 261static int GPT_check_overlap_except(struct GPT_entry_table *table, 262 struct GPT_entry_raw *entry, 263 struct GPT_entry_raw *exclude); 264 265void GPT_edit_entry(struct GPT_entry_table *table, 266 struct GPT_entry_raw *old_entry, 267 struct GPT_entry_raw *new_entry) 268{ 269 struct GPT_entry_raw *current_entry = GPT_get_pointer(table, old_entry); 270 271 if (GPT_check_overlap_except(table, new_entry, current_entry)) { 272 D(ERR, "Couldn't add overlaping partition"); 273 return; 274 } 275 276 if (current_entry == NULL) { 277 D(ERR, "Couldn't find entry"); 278 return; 279 } 280 281 *current_entry = *new_entry; 282} 283 284int GPT_delete_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry) 285{ 286 struct GPT_entry_raw *raw = GPT_get_pointer(table, entry); 287 288 if (raw == NULL) { 289 D(ERR, "could not find entry"); 290 return 1; 291 } 292 D(DEBUG, "Deleting gpt entry '%s'\n", raw->partition_guid); 293 294 // This entry can be empty in the middle 295 GPT_entry_clear(raw); 296 297 return 0; 298} 299 300void GPT_add_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry) 301{ 302 unsigned i; 303 int inserted = 0; 304 if (GPT_check_overlap(table, entry)) { 305 D(ERR, "Couldn't add overlaping partition"); 306 return; 307 } 308 309 if (GPT_get_pointer(table, entry) != NULL) { 310 D(WARN, "Add entry fault, this entry already exists"); 311 return; 312 } 313 314 struct GPT_entry_raw *entries = table->entries; 315 316 for (i = 0; i < table->header->entries_count; ++i) { 317 if (!entries[i].type_guid[0]) { 318 inserted = 1; 319 D(DEBUG, "inserting"); 320 memcpy(&entries[i], entry, sizeof(entries[i])); 321 break; 322 } 323 } 324 325 if (!inserted) { 326 D(ERR, "Unable to find empty partion entry"); 327 } 328} 329 330struct GPT_entry_raw *GPT_get_pointer_by_UTFname(struct GPT_entry_table *table, const uint16_t *name); 331 332struct GPT_entry_raw *GPT_get_pointer(struct GPT_entry_table *table, struct GPT_entry_raw *entry) 333{ 334 if (entry->partition_guid[0] != 0) 335 return GPT_get_pointer_by_guid(table, (const char *) entry->partition_guid); 336 else if (entry->name[0] != 0) 337 return GPT_get_pointer_by_UTFname(table, entry->name); 338 339 D(WARN, "Name or guid needed to find entry"); 340 return NULL; 341} 342 343struct GPT_entry_raw *GPT_get_pointer_by_guid(struct GPT_entry_table *table, const char *name) 344{ 345 int current = (int) table->header->entries_count; 346 347 for (current = current - 1; current >= 0; --current) { 348 if (strncmp((char *) name, 349 (char *) table->entries[current].partition_guid, 16) == 0) { 350 return &table->entries[current]; 351 } 352 } 353 354 return NULL; 355} 356 357int strncmp_UTF16_char(const uint16_t *s1, const char *s2, size_t n) 358{ 359 if (n == 0) 360 return (0); 361 do { 362 if (((*s1) & 127) != *s2++) 363 return (((unsigned char) ((*s1) & 127)) - *(unsigned char *)--s2); 364 if (*s1++ == 0) 365 break; 366 } while (--n != 0); 367 return (0); 368} 369 370int strncmp_UTF16(const uint16_t *s1, const uint16_t *s2, size_t n) 371{ 372 if (n == 0) 373 return (0); 374 do { 375 if ((*s1) != *s2++) 376 return (*s1 - *--s2); 377 if (*s1++ == 0) 378 break; 379 } while (--n != 0); 380 return (0); 381} 382 383struct GPT_entry_raw *GPT_get_pointer_by_name(struct GPT_entry_table *table, const char *name) 384{ 385 //TODO: reverse direction 386 int count = (int) table->header->entries_count; 387 int current; 388 389 for (current = 0; current < count; ++current) { 390 if (strncmp_UTF16_char(table->entries[current].name, 391 (char *) name, 16) == 0) { 392 return &table->entries[current]; 393 } 394 } 395 396 return NULL; 397} 398 399struct GPT_entry_raw *GPT_get_pointer_by_UTFname(struct GPT_entry_table *table, const uint16_t *name) 400{ 401 int count = (int) table->header->entries_count; 402 int current; 403 404 for (current = 0; current < count; ++current) { 405 if (strncmp_UTF16(table->entries[current].name, 406 name, GPT_NAMELEN) == 0) { 407 return &table->entries[current]; 408 } 409 } 410 411 return NULL; 412} 413 414void GPT_sync(struct GPT_entry_table *table) 415{ 416 uint32_t crc; 417 418 //calculate crc32 419 crc = crc32(0, Z_NULL, 0); 420 crc = crc32(crc, (void*) table->entries, table->header->entries_count * sizeof(*table->entries)); 421 table->header->partition_array_checksum = crc; 422 423 table->header->header_checksum = 0; 424 crc = crc32(0, Z_NULL, 0); 425 crc = crc32(crc, (void*) table->header, table->header->header_size); 426 table->header->header_checksum = crc; 427 428 //sync secondary partion 429 if (table->second_valid) { 430 memcpy((void *)table->second_entries, (void *) table->entries, table->partition_table_size); 431 memcpy((void *)table->second_header, (void *)table->header, sizeof(*table->header)); 432 } 433 434 if(!ioctl(table->fd, BLKRRPART, NULL)) { 435 D(WARN, "Unable to force kernel to refresh partition table"); 436 } 437} 438 439void GPT_to_UTF16(uint16_t *to, const char *from, int n) 440{ 441 int i; 442 for (i = 0; i < (n - 1) && (to[i] = from[i]) != '\0'; ++i); 443 to[i] = '\0'; 444} 445 446void GPT_from_UTF16(char *to, const uint16_t *from, int n) 447{ 448 int i; 449 for (i = 0; i < (n - 1) && (to[i] = from[i] & 127) != '\0'; ++i); 450 to[i] = '\0'; 451} 452 453static int GPT_check_overlap_except(struct GPT_entry_table *table, 454 struct GPT_entry_raw *entry, 455 struct GPT_entry_raw *exclude) { 456 int current = (int) table->header->entries_count; 457 int dontcheck; 458 struct GPT_entry_raw *current_entry; 459 if (entry->last_lba < entry->first_lba) { 460 D(WARN, "Start address have to be less than end address"); 461 return 1; 462 } 463 464 for (current = current - 1; current >= 0; --current) { 465 current_entry = &table->entries[current]; 466 dontcheck = strncmp((char *) entry->partition_guid, 467 (char *) current_entry->partition_guid , 16) == 0; 468 dontcheck |= current_entry->type_guid[0] == 0; 469 dontcheck |= current_entry == exclude; 470 471 if (!dontcheck && ((entry->last_lba >= current_entry->first_lba && 472 entry->first_lba < current_entry->last_lba ))) { 473 return 1; 474 } 475 } 476 477 return 0; 478} 479 480static int GPT_check_overlap(struct GPT_entry_table *table, struct GPT_entry_raw *entry) 481{ 482 return GPT_check_overlap_except(table, entry, NULL); 483} 484 485static char *get_key_value(char *ptr, char **key, char **value) 486{ 487 *key = ptr; 488 ptr = strchr(ptr, '='); 489 490 if (ptr == NULL) 491 return NULL; 492 493 *ptr++ = '\0'; 494 *value = ptr; 495 ptr = strchr(ptr, ';'); 496 497 if (ptr == NULL) 498 ptr = *value + strlen(*value); 499 else 500 *ptr = '\0'; 501 502 *key = strip(*key); 503 *value = strip(*value); 504 505 return ptr; 506} 507 508//TODO: little endian? 509static int add_key_value(const char *key, const char *value, struct GPT_entry_raw *entry) 510{ 511 char *endptr; 512 if (!strcmp(key, "type")) { 513 strncpy((char *) entry->type_guid, value, 16); 514 entry->type_guid[15] = 0; 515 } 516 else if (!strcmp(key, "guid")) { 517 strncpy((char *) entry->partition_guid, value, 16); 518 entry->type_guid[15] = 0; 519 } 520 else if (!strcmp(key, "firstlba")) { 521 entry->first_lba = strtoul(value, &endptr, 10); 522 if (*endptr != '\0') goto error; 523 } 524 else if (!strcmp(key, "lastlba")) { 525 entry->last_lba = strtoul(value, &endptr, 10); 526 if (*endptr != '\0') goto error; 527 } 528 else if (!strcmp(key, "flags")) { 529 entry->flags = strtoul(value, &endptr, 16); 530 if (*endptr != '\0') goto error; 531 } 532 else if (!strcmp(key, "name")) { 533 GPT_to_UTF16(entry->name, value, GPT_NAMELEN); 534 } 535 else { 536 goto error; 537 } 538 539 return 0; 540 541error: 542 D(ERR, "Could not find key or parse value: %s,%s", key, value); 543 return 1; 544} 545 546int GPT_parse_entry(char *string, struct GPT_entry_raw *entry) 547{ 548 char *ptr = string; 549 char *key, *value; 550 551 while ((ptr = get_key_value(ptr, &key, &value)) != NULL) { 552 if (add_key_value(key, value, entry)) { 553 D(WARN, "key or value not valid: %s %s", key, value); 554 return 1; 555 } 556 } 557 558 return 0; 559} 560 561void entry_set_guid(int n, uint8_t *guid) 562{ 563 guid[0] = (uint8_t) (n + 1); 564 int fd; 565 fd = open("/dev/urandom", O_RDONLY); 566 read(fd, &guid[1], 15); 567 close(fd); 568 569 //rfc4122 570 guid[8] = (guid[8] & 0x3F) | 0x80; 571 guid[7] = (guid[7] & 0x0F) | 0x40; 572} 573 574void GPT_default_content(struct GPT_content *content, struct GPT_entry_table *table) 575{ 576 if (table != NULL) { 577 memcpy(&content->header, table->header, sizeof(content->header)); 578 content->header.header_size = sizeof(content->header); 579 content->header.entry_size = sizeof(struct GPT_entry_raw); 580 } 581 else { 582 D(WARN, "Could not locate old gpt table, using default values"); 583 memset(&content->header, 0, sizeof(content->header) / sizeof(int)); 584 content->header = (struct GPT_header) { 585 .revision = 0x10000, 586 .header_size = sizeof(content->header), 587 .header_checksum = 0, 588 .reserved_zeros = 0, 589 .current_lba = 1, 590 .backup_lba = 1, 591 .entry_size = sizeof(struct GPT_entry_raw), 592 .partition_array_checksum = 0 593 }; 594 strncpy((char *)content->header.signature, "EFI PART", 8); 595 strncpy((char *)content->header.disk_guid, "ANDROID MMC DISK", 16); 596 } 597} 598 599static int get_config_uint64(cnode *node, uint64_t *ptr, const char *name) 600{ 601 const char *tmp; 602 uint64_t val; 603 char *endptr; 604 if ((tmp = config_str(node, name, NULL))) { 605 val = strtoull(tmp, &endptr, 10); 606 if (*endptr != '\0') { 607 D(WARN, "Value for %s is not a number: %s", name, tmp); 608 return 1; 609 } 610 *ptr = val; 611 return 0; 612 } 613 return 1; 614} 615 616static int get_config_string(cnode *node, char *ptr, int max_len, const char *name) 617{ 618 size_t begin, end; 619 const char *value = config_str(node, name, NULL); 620 if (!value) 621 return -1; 622 623 begin = strcspn(value, "\"") + 1; 624 end = strcspn(&value[begin], "\""); 625 626 if ((int) end > max_len) { 627 D(WARN, "Identifier \"%s\" too long", value); 628 return -1; 629 } 630 631 strncpy(ptr, &value[begin], end); 632 if((int) end < max_len) 633 ptr[end] = 0; 634 return 0; 635} 636 637static void GPT_parse_header(cnode *node, struct GPT_content *content) 638{ 639 get_config_uint64(node, &content->header.current_lba, "header_lba"); 640 get_config_uint64(node, &content->header.backup_lba, "backup_lba"); 641 get_config_uint64(node, &content->header.first_usable_lba, "first_lba"); 642 get_config_uint64(node, &content->header.last_usable_lba, "last_lba"); 643 get_config_uint64(node, &content->header.entries_lba, "entries_lba"); 644 get_config_string(node, (char *) content->header.disk_guid, 16, "guid"); 645} 646 647static int GPT_parse_partitions(cnode *node, struct GPT_content *content) 648{ 649 cnode *current; 650 int i; 651 uint64_t partition_size; 652 struct GPT_entry_raw *entry; 653 for (i = 0, current = node->first_child; current; current = current->next, ++i) { 654 entry = &content->entries[i]; 655 entry_set_guid(i, content->entries[i].partition_guid); 656 memcpy(&content->entries[i].type_guid, partition_type_uuid, 16); 657 if (get_config_uint64(current, &entry->first_lba, "first_lba")) { 658 D(ERR, "first_lba not specified"); 659 return 1; 660 } 661 if (get_config_uint64(current, &partition_size, "partition_size")) { 662 D(ERR, "partition_size not specified"); 663 return 1; 664 } 665 if (config_str(current, "system", NULL)) { 666 entry->flags |= GPT_FLAG_SYSTEM; 667 } 668 if (config_str(current, "bootable", NULL)) { 669 entry->flags |= GPT_FLAG_BOOTABLE; 670 } 671 if (config_str(current, "readonly", NULL)) { 672 entry->flags |= GPT_FLAG_READONLY; 673 } 674 if (config_str(current, "automount", NULL)) { 675 entry->flags |= GPT_FLAG_DOAUTOMOUNT; 676 } 677 678 get_config_uint64(current, &content->entries[i].flags, "flags"); 679 content->entries[i].last_lba = content->entries[i].first_lba + partition_size - 1; 680 GPT_to_UTF16(content->entries[i].name, current->name, 16); 681 } 682 return 0; 683} 684 685static inline int cnode_count(cnode *node) 686{ 687 int i; 688 cnode *current; 689 for (i = 0, current = node->first_child; current; current = current->next, ++i) 690 ; 691 return i; 692} 693 694 695static int GPT_parse_cnode(cnode *root, struct GPT_content *content) 696{ 697 cnode *partnode; 698 699 if (!(partnode = config_find(root, "partitions"))) { 700 D(ERR, "Could not find partition table"); 701 return 0; 702 } 703 704 GPT_parse_header(root, content); 705 706 content->header.entries_count = cnode_count(partnode); 707 content->entries = malloc(content->header.entries_count * sizeof(struct GPT_entry_raw)); 708 709 if (GPT_parse_partitions(partnode, content)) { 710 D(ERR, "Could not parse partitions"); 711 return 0; 712 } 713 714 return 1; 715} 716 717int GPT_parse_file(int fd, struct GPT_content *content) 718{ 719 char *data; 720 int size; 721 int ret; 722 cnode *root = config_node("", ""); 723 724 size = get_file_size(fd); 725 data = (char *) mmap(NULL, size + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 726 727 if (data == NULL) { 728 if (size == 0) 729 D(ERR, "config file empty"); 730 else 731 D(ERR, "Out of memory"); 732 return 0; 733 } 734 735 data[size - 1] = 0; 736 config_load(root, data); 737 738 if (root->first_child == NULL) { 739 D(ERR, "Could not read config file"); 740 return 0; 741 } 742 743 ret = GPT_parse_cnode(root, content); 744 munmap(data, size); 745 return ret; 746} 747 748void GPT_release_content(struct GPT_content *content) 749{ 750 free(content->entries); 751} 752 753int GPT_write_content(const char *device, struct GPT_content *content) 754{ 755 struct GPT_entry_table *maptable; 756 757 maptable = GPT_get_from_content(device, content); 758 if (maptable == NULL) { 759 D(ERR, "could not map device"); 760 return 0; 761 } 762 763 memcpy(maptable->header, &content->header, sizeof(*maptable->header)); 764 memcpy(maptable->entries, content->entries, 765 content->header.entries_count * sizeof(*maptable->entries)); 766 767 GPT_sync(maptable); 768 GPT_release_device(maptable); 769 770 return 1; 771} 772 773