mar_read.c (23440B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <sys/types.h> 8 #include <fcntl.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include "city.h" 12 #include "mar_private.h" 13 #include "mar.h" 14 #ifdef XP_WIN 15 # define strdup _strdup 16 #endif 17 18 /* This block must be at most 104 bytes. 19 MAR channel name < 64 bytes, and product version < 32 bytes + 3 NULL 20 terminator bytes. We only check for 96 though because we remove 8 21 bytes above from the additionalBlockSize: We subtract 22 sizeof(additionalBlockSize) and sizeof(additionalBlockID) */ 23 #define MAXADDITIONALBLOCKSIZE 96 24 25 static uint32_t mar_hash_name(const char* name) { 26 return CityHash64(name, strlen(name)) % TABLESIZE; 27 } 28 29 static int mar_insert_item(MarFile* mar, const char* name, uint32_t namelen, 30 uint32_t offset, uint32_t length, uint32_t flags) { 31 MarItem *item, *root; 32 uint32_t hash; 33 34 item = (MarItem*)malloc(sizeof(MarItem) + namelen); 35 if (!item) { 36 return -1; 37 } 38 item->next = NULL; 39 item->offset = offset; 40 item->length = length; 41 item->flags = flags; 42 memcpy(item->name, name, namelen + 1); 43 44 hash = mar_hash_name(name); 45 46 root = mar->item_table[hash]; 47 if (!root) { 48 mar->item_table[hash] = item; 49 } else { 50 /* append item */ 51 while (root->next) root = root->next; 52 root->next = item; 53 } 54 return 0; 55 } 56 57 static int mar_consume_index(MarFile* mar, char** buf, const char* buf_end) { 58 /* 59 * Each item has the following structure: 60 * uint32_t offset (network byte order) 61 * uint32_t length (network byte order) 62 * uint32_t flags (network byte order) 63 * char name[N] (where N >= 1) 64 * char null_byte; 65 */ 66 uint32_t offset; 67 uint32_t length; 68 uint32_t flags; 69 const char* name; 70 int namelen; 71 72 if ((buf_end - *buf) < (int)(3 * sizeof(uint32_t) + 2)) { 73 return -1; 74 } 75 76 memcpy(&offset, *buf, sizeof(offset)); 77 *buf += sizeof(offset); 78 79 memcpy(&length, *buf, sizeof(length)); 80 *buf += sizeof(length); 81 82 memcpy(&flags, *buf, sizeof(flags)); 83 *buf += sizeof(flags); 84 85 offset = ntohl(offset); 86 length = ntohl(length); 87 flags = ntohl(flags); 88 89 name = *buf; 90 /* find namelen; must take care not to read beyond buf_end */ 91 while (**buf) { 92 /* buf_end points one byte past the end of buf's allocation */ 93 if (*buf == (buf_end - 1)) { 94 return -1; 95 } 96 ++(*buf); 97 } 98 namelen = (*buf - name); 99 /* must ensure that namelen is valid */ 100 if (namelen < 0) { 101 return -1; 102 } 103 /* consume null byte */ 104 if (*buf == buf_end) { 105 return -1; 106 } 107 ++(*buf); 108 109 return mar_insert_item(mar, name, namelen, offset, length, flags); 110 } 111 112 static int mar_read_index(MarFile* mar) { 113 char id[MAR_ID_SIZE], *buf, *bufptr, *bufend; 114 uint32_t offset_to_index, size_of_index; 115 size_t mar_position = 0; 116 117 /* verify MAR ID */ 118 if (mar_read_buffer(mar, id, &mar_position, MAR_ID_SIZE) != 0) { 119 return -1; 120 } 121 if (memcmp(id, MAR_ID, MAR_ID_SIZE) != 0) { 122 return -1; 123 } 124 125 if (mar_read_buffer(mar, &offset_to_index, &mar_position, sizeof(uint32_t)) != 126 0) { 127 return -1; 128 } 129 offset_to_index = ntohl(offset_to_index); 130 131 mar_position = 0; 132 if (mar_buffer_seek(mar, &mar_position, offset_to_index) != 0) { 133 return -1; 134 } 135 if (mar_read_buffer(mar, &size_of_index, &mar_position, sizeof(uint32_t)) != 136 0) { 137 return -1; 138 } 139 size_of_index = ntohl(size_of_index); 140 141 buf = (char*)malloc(size_of_index); 142 if (!buf) { 143 return -1; 144 } 145 if (mar_read_buffer(mar, buf, &mar_position, size_of_index) != 0) { 146 free(buf); 147 return -1; 148 } 149 150 bufptr = buf; 151 bufend = buf + size_of_index; 152 while (bufptr < bufend && mar_consume_index(mar, &bufptr, bufend) == 0); 153 154 free(buf); 155 return (bufptr == bufend) ? 0 : -1; 156 } 157 158 /** 159 * Adds an offset and length to the MarFile's index_list 160 * @param mar The MarFile that owns this offset length pair 161 * @param offset The byte offset in the archive to be marked as processed 162 * @param length The length corresponding to this byte offset 163 * @return int 1 on success, 0 if offset has been previously processed 164 * -1 if unable to allocate space for the SeenIndexes 165 */ 166 static int mar_insert_offset(MarFile* mar, uint32_t offset, uint32_t length) { 167 /* Ignore files with no length */ 168 if (length == 0) { 169 return 1; 170 } 171 172 SeenIndex* index = (SeenIndex*)malloc(sizeof(SeenIndex)); 173 if (!index) { 174 return -1; 175 } 176 index->next = NULL; 177 index->offset = offset; 178 index->length = length; 179 uint32_t index_end = index->offset + index->length - 1; 180 181 /* If this is our first index store it at the front */ 182 if (mar->index_list == NULL) { 183 mar->index_list = index; 184 return 1; 185 } 186 187 /* Search for matching indexes in the list of those previously visited */ 188 SeenIndex* previous; 189 SeenIndex* current = mar->index_list; 190 while (current != NULL) { 191 uint32_t current_end = current->offset + current->length - 1; 192 193 /* If index has collided with the front or end of current or if current has 194 collided with the front or end of index return false */ 195 if ((index->offset >= current->offset && index->offset <= current_end) || 196 (index_end >= current->offset && index_end <= current_end) || 197 (current->offset >= index->offset && current->offset <= index_end) || 198 (current_end >= index->offset && current_end <= index_end)) { 199 free(index); 200 return 0; 201 } 202 203 /* else move to the next in the list */ 204 previous = current; 205 current = current->next; 206 } 207 208 /* These indexes are valid, track them */ 209 previous->next = index; 210 return 1; 211 } 212 213 /** 214 * Internal shared code for mar_open and mar_wopen. 215 * Reads the entire MAR into memory. Fails if it is bigger than 216 * MAX_SIZE_OF_MAR_FILE bytes. 217 */ 218 static MarReadResult mar_fpopen(FILE* fp, MarFile** out_mar) { 219 *out_mar = NULL; 220 MarFile* mar; 221 222 mar = (MarFile*)malloc(sizeof(*mar)); 223 if (!mar) { 224 return MAR_MEM_ERROR; 225 } 226 227 off_t buffer_size = -1; 228 if (fseeko(fp, 0, SEEK_END) == 0) { 229 buffer_size = ftello(fp); 230 } 231 rewind(fp); 232 if (buffer_size < 0) { 233 fprintf(stderr, "Warning: MAR size could not be determined\n"); 234 buffer_size = MAX_SIZE_OF_MAR_FILE; 235 } 236 if (buffer_size > MAX_SIZE_OF_MAR_FILE) { 237 fprintf(stderr, "ERROR: MAR exceeds maximum size (%lli)\n", 238 (long long int)buffer_size); 239 free(mar); 240 return MAR_FILE_TOO_BIG_ERROR; 241 } 242 243 mar->buffer = malloc(buffer_size); 244 if (!mar->buffer) { 245 fprintf(stderr, "ERROR: MAR buffer could not be allocated\n"); 246 free(mar); 247 return MAR_MEM_ERROR; 248 } 249 mar->data_len = fread(mar->buffer, 1, buffer_size, fp); 250 if (fgetc(fp) != EOF) { 251 fprintf(stderr, "ERROR: File is larger than buffer (%lli)\n", 252 (long long int)buffer_size); 253 free(mar->buffer); 254 free(mar); 255 return MAR_IO_ERROR; 256 } 257 if (ferror(fp)) { 258 fprintf(stderr, "ERROR: Failed to read MAR\n"); 259 free(mar->buffer); 260 free(mar); 261 return MAR_IO_ERROR; 262 } 263 264 mar->item_table_is_valid = 0; 265 memset(mar->item_table, 0, sizeof(mar->item_table)); 266 mar->index_list = NULL; 267 268 *out_mar = mar; 269 return MAR_READ_SUCCESS; 270 } 271 272 MarReadResult mar_open(const char* path, MarFile** out_mar) { 273 *out_mar = NULL; 274 275 FILE* fp; 276 277 fp = fopen(path, "rb"); 278 if (!fp) { 279 fprintf(stderr, "ERROR: could not open file in mar_open()\n"); 280 perror(path); 281 return MAR_IO_ERROR; 282 } 283 284 MarReadResult result = mar_fpopen(fp, out_mar); 285 fclose(fp); 286 return result; 287 } 288 289 #ifdef XP_WIN 290 MarReadResult mar_wopen(const wchar_t* path, MarFile** out_mar) { 291 *out_mar = NULL; 292 293 FILE* fp; 294 295 _wfopen_s(&fp, path, L"rb"); 296 if (!fp) { 297 fprintf(stderr, "ERROR: could not open file in mar_wopen()\n"); 298 _wperror(path); 299 return MAR_IO_ERROR; 300 } 301 302 MarReadResult result = mar_fpopen(fp, out_mar); 303 fclose(fp); 304 return result; 305 } 306 #endif 307 308 void mar_close(MarFile* mar) { 309 MarItem* item; 310 SeenIndex* index; 311 int i; 312 313 free(mar->buffer); 314 315 for (i = 0; i < TABLESIZE; ++i) { 316 item = mar->item_table[i]; 317 while (item) { 318 MarItem* temp = item; 319 item = item->next; 320 free(temp); 321 } 322 } 323 324 while (mar->index_list != NULL) { 325 index = mar->index_list; 326 mar->index_list = index->next; 327 free(index); 328 } 329 330 free(mar); 331 } 332 333 int mar_read_buffer(MarFile* mar, void* dest, size_t* position, size_t size) { 334 // size may be provided by the MAR, which we may not have finished validating 335 // the signature on yet. Make sure not to trust it in a way that could 336 // cause an overflow. 337 if (size > mar->data_len) { 338 return -1; 339 } 340 if (*position > mar->data_len - size) { 341 return -1; 342 } 343 memcpy(dest, mar->buffer + *position, size); 344 *position += size; 345 return 0; 346 } 347 348 int mar_read_buffer_max(MarFile* mar, void* dest, size_t* position, 349 size_t size) { 350 // size may be provided by the MAR, which we may not have finished validating 351 // the signature on yet. Make sure not to trust it in a way that could 352 // cause an overflow. 353 if (mar->data_len <= *position) { 354 return 0; 355 } 356 size_t read_count = mar->data_len - *position; 357 if (read_count > size) { 358 read_count = size; 359 } 360 memcpy(dest, mar->buffer + *position, read_count); 361 *position += read_count; 362 return read_count; 363 } 364 365 int mar_buffer_seek(MarFile* mar, size_t* position, size_t distance) { 366 // distance may be provided by the MAR, which we may not have finished 367 // validating the signature on yet. Make sure not to trust it in a way that 368 // could cause an overflow. 369 if (distance > mar->data_len) { 370 return -1; 371 } 372 if (*position > mar->data_len - distance) { 373 return -1; 374 } 375 *position += distance; 376 return 0; 377 } 378 379 /** 380 * Determines the MAR file information. 381 * 382 * @param mar An open MAR file. 383 * @param mar_position The current position in the MAR. 384 * Its value will be updated to the current 385 * position in the MAR after the function exits. 386 * Since its initial value will never actually be 387 * used, this is effectively an outparam. 388 * @param hasSignatureBlock Optional out parameter specifying if the MAR 389 * file has a signature block or not. 390 * @param numSignatures Optional out parameter for storing the number 391 * of signatures in the MAR file. 392 * @param hasAdditionalBlocks Optional out parameter specifying if the MAR 393 * file has additional blocks or not. 394 * @param offsetAdditionalBlocks Optional out parameter for the offset to the 395 * first additional block. Value is only valid if 396 * hasAdditionalBlocks is not equal to 0. 397 * @param numAdditionalBlocks Optional out parameter for the number of 398 * additional blocks. Value is only valid if 399 * hasAdditionalBlocks is not equal to 0. 400 * @return 0 on success and non-zero on failure. 401 */ 402 int get_open_mar_file_info(MarFile* mar, size_t* mar_position, 403 int* hasSignatureBlock, uint32_t* numSignatures, 404 int* hasAdditionalBlocks, 405 uint32_t* offsetAdditionalBlocks, 406 uint32_t* numAdditionalBlocks) { 407 uint32_t offsetToIndex, offsetToContent, signatureCount, signatureLen, i; 408 409 /* One of hasSignatureBlock or hasAdditionalBlocks must be non NULL */ 410 if (!hasSignatureBlock && !hasAdditionalBlocks) { 411 return -1; 412 } 413 414 /* Skip to the start of the offset index */ 415 *mar_position = 0; 416 if (mar_buffer_seek(mar, mar_position, MAR_ID_SIZE) != 0) { 417 return -1; 418 } 419 420 /* Read the offset to the index. */ 421 if (mar_read_buffer(mar, &offsetToIndex, mar_position, 422 sizeof(offsetToIndex)) != 0) { 423 return -1; 424 } 425 offsetToIndex = ntohl(offsetToIndex); 426 427 if (numSignatures) { 428 /* Skip past the MAR file size field */ 429 if (mar_buffer_seek(mar, mar_position, sizeof(uint64_t)) != 0) { 430 return -1; 431 } 432 433 /* Read the number of signatures field */ 434 if (mar_read_buffer(mar, numSignatures, mar_position, 435 sizeof(*numSignatures)) != 0) { 436 return -1; 437 } 438 *numSignatures = ntohl(*numSignatures); 439 } 440 441 /* Skip to the first index entry past the index size field 442 We do it in 2 calls because offsetToIndex + sizeof(uint32_t) 443 could overflow in theory. */ 444 *mar_position = 0; 445 if (mar_buffer_seek(mar, mar_position, offsetToIndex) != 0) { 446 return -1; 447 } 448 449 if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) { 450 return -1; 451 } 452 453 /* Read the first offset to content field. */ 454 if (mar_read_buffer(mar, &offsetToContent, mar_position, 455 sizeof(offsetToContent)) != 0) { 456 return -1; 457 } 458 offsetToContent = ntohl(offsetToContent); 459 460 /* Check if we have a new or old MAR file */ 461 if (hasSignatureBlock) { 462 if (offsetToContent == MAR_ID_SIZE + sizeof(uint32_t)) { 463 *hasSignatureBlock = 0; 464 } else { 465 *hasSignatureBlock = 1; 466 } 467 } 468 469 /* If the caller doesn't care about the product info block 470 value, then just return */ 471 if (!hasAdditionalBlocks) { 472 return 0; 473 } 474 475 /* Skip to the start of the signature block */ 476 *mar_position = 0; 477 if (mar_buffer_seek(mar, mar_position, SIGNATURE_BLOCK_OFFSET) != 0) { 478 return -1; 479 } 480 481 /* Get the number of signatures */ 482 if (mar_read_buffer(mar, &signatureCount, mar_position, 483 sizeof(signatureCount)) != 0) { 484 return -1; 485 } 486 signatureCount = ntohl(signatureCount); 487 488 /* Check that we have less than the max amount of signatures so we don't 489 waste too much of either updater's or signmar's time. */ 490 if (signatureCount > MAX_SIGNATURES) { 491 return -1; 492 } 493 494 /* Skip past the whole signature block */ 495 for (i = 0; i < signatureCount; i++) { 496 /* Skip past the signature algorithm ID */ 497 if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) { 498 return -1; 499 } 500 501 /* Read the signature length and skip past the signature */ 502 if (mar_read_buffer(mar, &signatureLen, mar_position, sizeof(uint32_t)) != 503 0) { 504 return -1; 505 } 506 signatureLen = ntohl(signatureLen); 507 if (mar_buffer_seek(mar, mar_position, signatureLen) != 0) { 508 return -1; 509 } 510 } 511 512 if (*mar_position <= (size_t)INT64_MAX && 513 (int64_t)mar_position == (int64_t)offsetToContent) { 514 *hasAdditionalBlocks = 0; 515 } else { 516 if (numAdditionalBlocks) { 517 /* We have an additional block, so read in the number of additional blocks 518 and set the offset. */ 519 *hasAdditionalBlocks = 1; 520 if (mar_read_buffer(mar, numAdditionalBlocks, mar_position, 521 sizeof(uint32_t)) != 0) { 522 return -1; 523 } 524 *numAdditionalBlocks = ntohl(*numAdditionalBlocks); 525 if (offsetAdditionalBlocks) { 526 if (*mar_position > (size_t)UINT32_MAX) { 527 return -1; 528 } 529 *offsetAdditionalBlocks = (uint32_t)*mar_position; 530 } 531 } else if (offsetAdditionalBlocks) { 532 /* numAdditionalBlocks is not specified but offsetAdditionalBlocks 533 is, so fill it! */ 534 if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) { 535 return -1; 536 } 537 if (*mar_position > (size_t)UINT32_MAX) { 538 return -1; 539 } 540 *offsetAdditionalBlocks = (uint32_t)*mar_position; 541 } 542 } 543 544 return 0; 545 } 546 547 /** 548 * Reads the product info block from the MAR file's additional block section. 549 * The caller is responsible for freeing the fields in infoBlock 550 * if the return is successful. 551 * 552 * @param infoBlock Out parameter for where to store the result to 553 * @return 0 on success, -1 on failure 554 */ 555 int read_product_info_block(char* path, 556 struct ProductInformationBlock* infoBlock) { 557 int rv; 558 MarFile* mar; 559 MarReadResult result = mar_open(path, &mar); 560 if (result != MAR_READ_SUCCESS) { 561 fprintf(stderr, 562 "ERROR: could not open file in read_product_info_block()\n"); 563 return -1; 564 } 565 rv = mar_read_product_info_block(mar, infoBlock); 566 mar_close(mar); 567 return rv; 568 } 569 570 /** 571 * Reads the product info block from the MAR file's additional block section. 572 * The caller is responsible for freeing the fields in infoBlock 573 * if the return is successful. 574 * 575 * @param infoBlock Out parameter for where to store the result to 576 * @return 0 on success, -1 on failure 577 */ 578 int mar_read_product_info_block(MarFile* mar, 579 struct ProductInformationBlock* infoBlock) { 580 uint32_t offsetAdditionalBlocks, numAdditionalBlocks, additionalBlockSize, 581 additionalBlockID; 582 int hasAdditionalBlocks; 583 size_t mar_position = 0; 584 585 /* The buffer size is 97 bytes because the MAR channel name < 64 bytes, and 586 product version < 32 bytes + 3 NULL terminator bytes. */ 587 char buf[MAXADDITIONALBLOCKSIZE + 1] = {'\0'}; 588 if (get_open_mar_file_info(mar, &mar_position, NULL, NULL, 589 &hasAdditionalBlocks, &offsetAdditionalBlocks, 590 &numAdditionalBlocks) != 0) { 591 return -1; 592 } 593 594 /* We only have the one additional block type and only one is expected to be 595 in a MAR file so check if any exist and process the first found */ 596 if (numAdditionalBlocks > 0) { 597 /* Read the additional block size */ 598 if (mar_read_buffer(mar, &additionalBlockSize, &mar_position, 599 sizeof(additionalBlockSize)) != 0) { 600 return -1; 601 } 602 additionalBlockSize = ntohl(additionalBlockSize) - 603 sizeof(additionalBlockSize) - 604 sizeof(additionalBlockID); 605 606 /* Additional Block sizes should only be 96 bytes long */ 607 if (additionalBlockSize > MAXADDITIONALBLOCKSIZE) { 608 return -1; 609 } 610 611 /* Read the additional block ID */ 612 if (mar_read_buffer(mar, &additionalBlockID, &mar_position, 613 sizeof(additionalBlockID)) != 0) { 614 return -1; 615 } 616 additionalBlockID = ntohl(additionalBlockID); 617 618 if (PRODUCT_INFO_BLOCK_ID == additionalBlockID) { 619 const char* location; 620 int len; 621 622 if (mar_read_buffer(mar, buf, &mar_position, additionalBlockSize) != 0) { 623 return -1; 624 } 625 626 /* Extract the MAR channel name from the buffer. For now we 627 point to the stack allocated buffer but we strdup this 628 if we are within bounds of each field's max length. */ 629 location = buf; 630 len = strlen(location); 631 infoBlock->MARChannelID = location; 632 location += len + 1; 633 if (len >= 64) { 634 infoBlock->MARChannelID = NULL; 635 return -1; 636 } 637 638 /* Extract the version from the buffer */ 639 len = strlen(location); 640 infoBlock->productVersion = location; 641 if (len >= 32) { 642 infoBlock->MARChannelID = NULL; 643 infoBlock->productVersion = NULL; 644 return -1; 645 } 646 infoBlock->MARChannelID = strdup(infoBlock->MARChannelID); 647 infoBlock->productVersion = strdup(infoBlock->productVersion); 648 return 0; 649 } else { 650 /* This is not the additional block you're looking for. Move along. */ 651 if (mar_buffer_seek(mar, &mar_position, additionalBlockSize) != 0) { 652 return -1; 653 } 654 } 655 } 656 657 /* If we had a product info block we would have already returned */ 658 return -1; 659 } 660 661 const MarItem* mar_find_item(MarFile* mar, const char* name) { 662 uint32_t hash; 663 const MarItem* item; 664 665 if (!mar->item_table_is_valid) { 666 if (mar_read_index(mar)) { 667 return NULL; 668 } else { 669 mar->item_table_is_valid = 1; 670 } 671 } 672 673 hash = mar_hash_name(name); 674 675 item = mar->item_table[hash]; 676 while (item && strcmp(item->name, name) != 0) { 677 item = item->next; 678 } 679 680 /* If this is the first time seeing this item's indexes, return it */ 681 if (mar_insert_offset(mar, item->offset, item->length) == 1) { 682 return item; 683 } else { 684 fprintf(stderr, "ERROR: file content collision in mar_find_item()\n"); 685 return NULL; 686 } 687 } 688 689 int mar_enum_items(MarFile* mar, MarItemCallback callback, void* closure) { 690 MarItem* item; 691 int i, rv; 692 693 if (!mar->item_table_is_valid) { 694 if (mar_read_index(mar)) { 695 return -1; 696 } else { 697 mar->item_table_is_valid = 1; 698 } 699 } 700 701 for (i = 0; i < TABLESIZE; ++i) { 702 item = mar->item_table[i]; 703 while (item) { 704 /* if this is the first time seeing this item's indexes, process it */ 705 if (mar_insert_offset(mar, item->offset, item->length) == 1) { 706 rv = callback(mar, item, closure); 707 if (rv) { 708 return rv; 709 } 710 } else { 711 fprintf(stderr, "ERROR: file content collision in mar_enum_items()\n"); 712 return 1; 713 } 714 item = item->next; 715 } 716 } 717 718 return 0; 719 } 720 721 int mar_read(MarFile* mar, const MarItem* item, int offset, uint8_t* buf, 722 int bufsize) { 723 int nr; 724 size_t mar_position = 0; 725 726 if (offset == (int)item->length) { 727 return 0; 728 } 729 if (offset > (int)item->length) { 730 return -1; 731 } 732 733 nr = item->length - offset; 734 if (nr > bufsize) { 735 nr = bufsize; 736 } 737 738 // Avoid adding item->offset and offset directly, just in case of overflow. 739 if (mar_buffer_seek(mar, &mar_position, item->offset)) { 740 return -1; 741 } 742 if (mar_buffer_seek(mar, &mar_position, offset)) { 743 return -1; 744 } 745 746 return mar_read_buffer_max(mar, buf, &mar_position, nr); 747 } 748 749 /** 750 * Determines the MAR file information. 751 * 752 * @param path The path of the MAR file to check. 753 * @param hasSignatureBlock Optional out parameter specifying if the MAR 754 * file has a signature block or not. 755 * @param numSignatures Optional out parameter for storing the number 756 * of signatures in the MAR file. 757 * @param hasAdditionalBlocks Optional out parameter specifying if the MAR 758 * file has additional blocks or not. 759 * @param offsetAdditionalBlocks Optional out parameter for the offset to the 760 * first additional block. Value is only valid if 761 * hasAdditionalBlocks is not equal to 0. 762 * @param numAdditionalBlocks Optional out parameter for the number of 763 * additional blocks. Value is only valid if 764 * has_additional_blocks is not equal to 0. 765 * @return 0 on success and non-zero on failure. 766 */ 767 int get_mar_file_info(const char* path, int* hasSignatureBlock, 768 uint32_t* numSignatures, int* hasAdditionalBlocks, 769 uint32_t* offsetAdditionalBlocks, 770 uint32_t* numAdditionalBlocks) { 771 int rv; 772 MarFile* mar; 773 size_t mar_position = 0; 774 MarReadResult result = mar_open(path, &mar); 775 if (result != MAR_READ_SUCCESS) { 776 fprintf(stderr, "ERROR: could not read file in get_mar_file_info()\n"); 777 return -1; 778 } 779 780 rv = get_open_mar_file_info(mar, &mar_position, hasSignatureBlock, 781 numSignatures, hasAdditionalBlocks, 782 offsetAdditionalBlocks, numAdditionalBlocks); 783 784 mar_close(mar); 785 return rv; 786 }