modules/libmar/src/mar_read.c

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include <sys/types.h>
michael@0 8 #include <fcntl.h>
michael@0 9 #include <stdlib.h>
michael@0 10 #include <string.h>
michael@0 11 #include "mar_private.h"
michael@0 12 #include "mar.h"
michael@0 13
michael@0 14 #ifdef XP_WIN
michael@0 15 #include <winsock2.h>
michael@0 16 #else
michael@0 17 #include <netinet/in.h>
michael@0 18 #endif
michael@0 19
michael@0 20
michael@0 21 /* this is the same hash algorithm used by nsZipArchive.cpp */
michael@0 22 static uint32_t mar_hash_name(const char *name) {
michael@0 23 uint32_t val = 0;
michael@0 24 unsigned char* c;
michael@0 25
michael@0 26 for (c = (unsigned char *) name; *c; ++c)
michael@0 27 val = val*37 + *c;
michael@0 28
michael@0 29 return val % TABLESIZE;
michael@0 30 }
michael@0 31
michael@0 32 static int mar_insert_item(MarFile *mar, const char *name, int namelen,
michael@0 33 uint32_t offset, uint32_t length, uint32_t flags) {
michael@0 34 MarItem *item, *root;
michael@0 35 uint32_t hash;
michael@0 36
michael@0 37 item = (MarItem *) malloc(sizeof(MarItem) + namelen);
michael@0 38 if (!item)
michael@0 39 return -1;
michael@0 40 item->next = NULL;
michael@0 41 item->offset = offset;
michael@0 42 item->length = length;
michael@0 43 item->flags = flags;
michael@0 44 memcpy(item->name, name, namelen + 1);
michael@0 45
michael@0 46 hash = mar_hash_name(name);
michael@0 47
michael@0 48 root = mar->item_table[hash];
michael@0 49 if (!root) {
michael@0 50 mar->item_table[hash] = item;
michael@0 51 } else {
michael@0 52 /* append item */
michael@0 53 while (root->next)
michael@0 54 root = root->next;
michael@0 55 root->next = item;
michael@0 56 }
michael@0 57 return 0;
michael@0 58 }
michael@0 59
michael@0 60 static int mar_consume_index(MarFile *mar, char **buf, const char *buf_end) {
michael@0 61 /*
michael@0 62 * Each item has the following structure:
michael@0 63 * uint32_t offset (network byte order)
michael@0 64 * uint32_t length (network byte order)
michael@0 65 * uint32_t flags (network byte order)
michael@0 66 * char name[N] (where N >= 1)
michael@0 67 * char null_byte;
michael@0 68 */
michael@0 69 uint32_t offset;
michael@0 70 uint32_t length;
michael@0 71 uint32_t flags;
michael@0 72 const char *name;
michael@0 73 int namelen;
michael@0 74
michael@0 75 if ((buf_end - *buf) < (int)(3*sizeof(uint32_t) + 2))
michael@0 76 return -1;
michael@0 77
michael@0 78 memcpy(&offset, *buf, sizeof(offset));
michael@0 79 *buf += sizeof(offset);
michael@0 80
michael@0 81 memcpy(&length, *buf, sizeof(length));
michael@0 82 *buf += sizeof(length);
michael@0 83
michael@0 84 memcpy(&flags, *buf, sizeof(flags));
michael@0 85 *buf += sizeof(flags);
michael@0 86
michael@0 87 offset = ntohl(offset);
michael@0 88 length = ntohl(length);
michael@0 89 flags = ntohl(flags);
michael@0 90
michael@0 91 name = *buf;
michael@0 92 /* find namelen; must take care not to read beyond buf_end */
michael@0 93 while (**buf) {
michael@0 94 if (*buf == buf_end)
michael@0 95 return -1;
michael@0 96 ++(*buf);
michael@0 97 }
michael@0 98 namelen = (*buf - name);
michael@0 99 /* consume null byte */
michael@0 100 if (*buf == buf_end)
michael@0 101 return -1;
michael@0 102 ++(*buf);
michael@0 103
michael@0 104 return mar_insert_item(mar, name, namelen, offset, length, flags);
michael@0 105 }
michael@0 106
michael@0 107 static int mar_read_index(MarFile *mar) {
michael@0 108 char id[MAR_ID_SIZE], *buf, *bufptr, *bufend;
michael@0 109 uint32_t offset_to_index, size_of_index;
michael@0 110
michael@0 111 /* verify MAR ID */
michael@0 112 if (fread(id, MAR_ID_SIZE, 1, mar->fp) != 1)
michael@0 113 return -1;
michael@0 114 if (memcmp(id, MAR_ID, MAR_ID_SIZE) != 0)
michael@0 115 return -1;
michael@0 116
michael@0 117 if (fread(&offset_to_index, sizeof(uint32_t), 1, mar->fp) != 1)
michael@0 118 return -1;
michael@0 119 offset_to_index = ntohl(offset_to_index);
michael@0 120
michael@0 121 if (fseek(mar->fp, offset_to_index, SEEK_SET))
michael@0 122 return -1;
michael@0 123 if (fread(&size_of_index, sizeof(uint32_t), 1, mar->fp) != 1)
michael@0 124 return -1;
michael@0 125 size_of_index = ntohl(size_of_index);
michael@0 126
michael@0 127 buf = (char *) malloc(size_of_index);
michael@0 128 if (!buf)
michael@0 129 return -1;
michael@0 130 if (fread(buf, size_of_index, 1, mar->fp) != 1) {
michael@0 131 free(buf);
michael@0 132 return -1;
michael@0 133 }
michael@0 134
michael@0 135 bufptr = buf;
michael@0 136 bufend = buf + size_of_index;
michael@0 137 while (bufptr < bufend && mar_consume_index(mar, &bufptr, bufend) == 0);
michael@0 138
michael@0 139 free(buf);
michael@0 140 return (bufptr == bufend) ? 0 : -1;
michael@0 141 }
michael@0 142
michael@0 143 /**
michael@0 144 * Internal shared code for mar_open and mar_wopen.
michael@0 145 * On failure, will fclose(fp).
michael@0 146 */
michael@0 147 static MarFile *mar_fpopen(FILE *fp)
michael@0 148 {
michael@0 149 MarFile *mar;
michael@0 150
michael@0 151 mar = (MarFile *) malloc(sizeof(*mar));
michael@0 152 if (!mar) {
michael@0 153 fclose(fp);
michael@0 154 return NULL;
michael@0 155 }
michael@0 156
michael@0 157 mar->fp = fp;
michael@0 158 memset(mar->item_table, 0, sizeof(mar->item_table));
michael@0 159 if (mar_read_index(mar)) {
michael@0 160 mar_close(mar);
michael@0 161 return NULL;
michael@0 162 }
michael@0 163
michael@0 164 return mar;
michael@0 165 }
michael@0 166
michael@0 167 MarFile *mar_open(const char *path) {
michael@0 168 FILE *fp;
michael@0 169
michael@0 170 fp = fopen(path, "rb");
michael@0 171 if (!fp) {
michael@0 172 fprintf(stderr, "ERROR: could not open file in mar_open()\n");
michael@0 173 perror(path);
michael@0 174 return NULL;
michael@0 175 }
michael@0 176
michael@0 177 return mar_fpopen(fp);
michael@0 178 }
michael@0 179
michael@0 180 #ifdef XP_WIN
michael@0 181 MarFile *mar_wopen(const wchar_t *path) {
michael@0 182 FILE *fp;
michael@0 183
michael@0 184 _wfopen_s(&fp, path, L"rb");
michael@0 185 if (!fp) {
michael@0 186 fprintf(stderr, "ERROR: could not open file in mar_wopen()\n");
michael@0 187 _wperror(path);
michael@0 188 return NULL;
michael@0 189 }
michael@0 190
michael@0 191 return mar_fpopen(fp);
michael@0 192 }
michael@0 193 #endif
michael@0 194
michael@0 195 void mar_close(MarFile *mar) {
michael@0 196 MarItem *item;
michael@0 197 int i;
michael@0 198
michael@0 199 fclose(mar->fp);
michael@0 200
michael@0 201 for (i = 0; i < TABLESIZE; ++i) {
michael@0 202 item = mar->item_table[i];
michael@0 203 while (item) {
michael@0 204 MarItem *temp = item;
michael@0 205 item = item->next;
michael@0 206 free(temp);
michael@0 207 }
michael@0 208 }
michael@0 209
michael@0 210 free(mar);
michael@0 211 }
michael@0 212
michael@0 213 /**
michael@0 214 * Determines the MAR file information.
michael@0 215 *
michael@0 216 * @param fp An opened MAR file in read mode.
michael@0 217 * @param hasSignatureBlock Optional out parameter specifying if the MAR
michael@0 218 * file has a signature block or not.
michael@0 219 * @param numSignatures Optional out parameter for storing the number
michael@0 220 * of signatures in the MAR file.
michael@0 221 * @param hasAdditionalBlocks Optional out parameter specifying if the MAR
michael@0 222 * file has additional blocks or not.
michael@0 223 * @param offsetAdditionalBlocks Optional out parameter for the offset to the
michael@0 224 * first additional block. Value is only valid if
michael@0 225 * hasAdditionalBlocks is not equal to 0.
michael@0 226 * @param numAdditionalBlocks Optional out parameter for the number of
michael@0 227 * additional blocks. Value is only valid if
michael@0 228 * hasAdditionalBlocks is not equal to 0.
michael@0 229 * @return 0 on success and non-zero on failure.
michael@0 230 */
michael@0 231 int get_mar_file_info_fp(FILE *fp,
michael@0 232 int *hasSignatureBlock,
michael@0 233 uint32_t *numSignatures,
michael@0 234 int *hasAdditionalBlocks,
michael@0 235 uint32_t *offsetAdditionalBlocks,
michael@0 236 uint32_t *numAdditionalBlocks)
michael@0 237 {
michael@0 238 uint32_t offsetToIndex, offsetToContent, signatureCount, signatureLen, i;
michael@0 239
michael@0 240 /* One of hasSignatureBlock or hasAdditionalBlocks must be non NULL */
michael@0 241 if (!hasSignatureBlock && !hasAdditionalBlocks) {
michael@0 242 return -1;
michael@0 243 }
michael@0 244
michael@0 245
michael@0 246 /* Skip to the start of the offset index */
michael@0 247 if (fseek(fp, MAR_ID_SIZE, SEEK_SET)) {
michael@0 248 return -1;
michael@0 249 }
michael@0 250
michael@0 251 /* Read the offset to the index. */
michael@0 252 if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fp) != 1) {
michael@0 253 return -1;
michael@0 254 }
michael@0 255 offsetToIndex = ntohl(offsetToIndex);
michael@0 256
michael@0 257 if (numSignatures) {
michael@0 258 /* Skip past the MAR file size field */
michael@0 259 if (fseek(fp, sizeof(uint64_t), SEEK_CUR)) {
michael@0 260 return -1;
michael@0 261 }
michael@0 262
michael@0 263 /* Read the number of signatures field */
michael@0 264 if (fread(numSignatures, sizeof(*numSignatures), 1, fp) != 1) {
michael@0 265 return -1;
michael@0 266 }
michael@0 267 *numSignatures = ntohl(*numSignatures);
michael@0 268 }
michael@0 269
michael@0 270 /* Skip to the first index entry past the index size field
michael@0 271 We do it in 2 calls because offsetToIndex + sizeof(uint32_t)
michael@0 272 could oerflow in theory. */
michael@0 273 if (fseek(fp, offsetToIndex, SEEK_SET)) {
michael@0 274 return -1;
michael@0 275 }
michael@0 276
michael@0 277 if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) {
michael@0 278 return -1;
michael@0 279 }
michael@0 280
michael@0 281 /* Read the first offset to content field. */
michael@0 282 if (fread(&offsetToContent, sizeof(offsetToContent), 1, fp) != 1) {
michael@0 283 return -1;
michael@0 284 }
michael@0 285 offsetToContent = ntohl(offsetToContent);
michael@0 286
michael@0 287 /* Check if we have a new or old MAR file */
michael@0 288 if (hasSignatureBlock) {
michael@0 289 if (offsetToContent == MAR_ID_SIZE + sizeof(uint32_t)) {
michael@0 290 *hasSignatureBlock = 0;
michael@0 291 } else {
michael@0 292 *hasSignatureBlock = 1;
michael@0 293 }
michael@0 294 }
michael@0 295
michael@0 296 /* If the caller doesn't care about the product info block
michael@0 297 value, then just return */
michael@0 298 if (!hasAdditionalBlocks) {
michael@0 299 return 0;
michael@0 300 }
michael@0 301
michael@0 302 /* Skip to the start of the signature block */
michael@0 303 if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
michael@0 304 return -1;
michael@0 305 }
michael@0 306
michael@0 307 /* Get the number of signatures */
michael@0 308 if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) {
michael@0 309 return -1;
michael@0 310 }
michael@0 311 signatureCount = ntohl(signatureCount);
michael@0 312
michael@0 313 /* Check that we have less than the max amount of signatures so we don't
michael@0 314 waste too much of either updater's or signmar's time. */
michael@0 315 if (signatureCount > MAX_SIGNATURES) {
michael@0 316 return -1;
michael@0 317 }
michael@0 318
michael@0 319 /* Skip past the whole signature block */
michael@0 320 for (i = 0; i < signatureCount; i++) {
michael@0 321 /* Skip past the signature algorithm ID */
michael@0 322 if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) {
michael@0 323 return -1;
michael@0 324 }
michael@0 325
michael@0 326 /* Read the signature length and skip past the signature */
michael@0 327 if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) {
michael@0 328 return -1;
michael@0 329 }
michael@0 330 signatureLen = ntohl(signatureLen);
michael@0 331 if (fseek(fp, signatureLen, SEEK_CUR)) {
michael@0 332 return -1;
michael@0 333 }
michael@0 334 }
michael@0 335
michael@0 336 if (ftell(fp) == offsetToContent) {
michael@0 337 *hasAdditionalBlocks = 0;
michael@0 338 } else {
michael@0 339 if (numAdditionalBlocks) {
michael@0 340 /* We have an additional block, so read in the number of additional blocks
michael@0 341 and set the offset. */
michael@0 342 *hasAdditionalBlocks = 1;
michael@0 343 if (fread(numAdditionalBlocks, sizeof(uint32_t), 1, fp) != 1) {
michael@0 344 return -1;
michael@0 345 }
michael@0 346 *numAdditionalBlocks = ntohl(*numAdditionalBlocks);
michael@0 347 if (offsetAdditionalBlocks) {
michael@0 348 *offsetAdditionalBlocks = ftell(fp);
michael@0 349 }
michael@0 350 } else if (offsetAdditionalBlocks) {
michael@0 351 /* numAdditionalBlocks is not specified but offsetAdditionalBlocks
michael@0 352 is, so fill it! */
michael@0 353 *offsetAdditionalBlocks = ftell(fp) + sizeof(uint32_t);
michael@0 354 }
michael@0 355 }
michael@0 356
michael@0 357 return 0;
michael@0 358 }
michael@0 359
michael@0 360 /**
michael@0 361 * Reads the product info block from the MAR file's additional block section.
michael@0 362 * The caller is responsible for freeing the fields in infoBlock
michael@0 363 * if the return is successful.
michael@0 364 *
michael@0 365 * @param infoBlock Out parameter for where to store the result to
michael@0 366 * @return 0 on success, -1 on failure
michael@0 367 */
michael@0 368 int
michael@0 369 read_product_info_block(char *path,
michael@0 370 struct ProductInformationBlock *infoBlock)
michael@0 371 {
michael@0 372 int rv;
michael@0 373 MarFile mar;
michael@0 374 mar.fp = fopen(path, "rb");
michael@0 375 if (!mar.fp) {
michael@0 376 fprintf(stderr, "ERROR: could not open file in read_product_info_block()\n");
michael@0 377 perror(path);
michael@0 378 return -1;
michael@0 379 }
michael@0 380 rv = mar_read_product_info_block(&mar, infoBlock);
michael@0 381 fclose(mar.fp);
michael@0 382 return rv;
michael@0 383 }
michael@0 384
michael@0 385 /**
michael@0 386 * Reads the product info block from the MAR file's additional block section.
michael@0 387 * The caller is responsible for freeing the fields in infoBlock
michael@0 388 * if the return is successful.
michael@0 389 *
michael@0 390 * @param infoBlock Out parameter for where to store the result to
michael@0 391 * @return 0 on success, -1 on failure
michael@0 392 */
michael@0 393 int
michael@0 394 mar_read_product_info_block(MarFile *mar,
michael@0 395 struct ProductInformationBlock *infoBlock)
michael@0 396 {
michael@0 397 uint32_t i, offsetAdditionalBlocks, numAdditionalBlocks,
michael@0 398 additionalBlockSize, additionalBlockID;
michael@0 399 int hasAdditionalBlocks;
michael@0 400
michael@0 401 /* The buffer size is 97 bytes because the MAR channel name < 64 bytes, and
michael@0 402 product version < 32 bytes + 3 NULL terminator bytes. */
michael@0 403 char buf[97] = { '\0' };
michael@0 404 int ret = get_mar_file_info_fp(mar->fp, NULL, NULL,
michael@0 405 &hasAdditionalBlocks,
michael@0 406 &offsetAdditionalBlocks,
michael@0 407 &numAdditionalBlocks);
michael@0 408 for (i = 0; i < numAdditionalBlocks; ++i) {
michael@0 409 /* Read the additional block size */
michael@0 410 if (fread(&additionalBlockSize,
michael@0 411 sizeof(additionalBlockSize),
michael@0 412 1, mar->fp) != 1) {
michael@0 413 return -1;
michael@0 414 }
michael@0 415 additionalBlockSize = ntohl(additionalBlockSize) -
michael@0 416 sizeof(additionalBlockSize) -
michael@0 417 sizeof(additionalBlockID);
michael@0 418
michael@0 419 /* Read the additional block ID */
michael@0 420 if (fread(&additionalBlockID,
michael@0 421 sizeof(additionalBlockID),
michael@0 422 1, mar->fp) != 1) {
michael@0 423 return -1;
michael@0 424 }
michael@0 425 additionalBlockID = ntohl(additionalBlockID);
michael@0 426
michael@0 427 if (PRODUCT_INFO_BLOCK_ID == additionalBlockID) {
michael@0 428 const char *location;
michael@0 429 int len;
michael@0 430
michael@0 431 /* This block must be at most 104 bytes.
michael@0 432 MAR channel name < 64 bytes, and product version < 32 bytes + 3 NULL
michael@0 433 terminator bytes. We only check for 96 though because we remove 8
michael@0 434 bytes above from the additionalBlockSize: We subtract
michael@0 435 sizeof(additionalBlockSize) and sizeof(additionalBlockID) */
michael@0 436 if (additionalBlockSize > 96) {
michael@0 437 return -1;
michael@0 438 }
michael@0 439
michael@0 440 if (fread(buf, additionalBlockSize, 1, mar->fp) != 1) {
michael@0 441 return -1;
michael@0 442 }
michael@0 443
michael@0 444 /* Extract the MAR channel name from the buffer. For now we
michael@0 445 point to the stack allocated buffer but we strdup this
michael@0 446 if we are within bounds of each field's max length. */
michael@0 447 location = buf;
michael@0 448 len = strlen(location);
michael@0 449 infoBlock->MARChannelID = location;
michael@0 450 location += len + 1;
michael@0 451 if (len >= 64) {
michael@0 452 infoBlock->MARChannelID = NULL;
michael@0 453 return -1;
michael@0 454 }
michael@0 455
michael@0 456 /* Extract the version from the buffer */
michael@0 457 len = strlen(location);
michael@0 458 infoBlock->productVersion = location;
michael@0 459 location += len + 1;
michael@0 460 if (len >= 32) {
michael@0 461 infoBlock->MARChannelID = NULL;
michael@0 462 infoBlock->productVersion = NULL;
michael@0 463 return -1;
michael@0 464 }
michael@0 465 infoBlock->MARChannelID =
michael@0 466 strdup(infoBlock->MARChannelID);
michael@0 467 infoBlock->productVersion =
michael@0 468 strdup(infoBlock->productVersion);
michael@0 469 return 0;
michael@0 470 } else {
michael@0 471 /* This is not the additional block you're looking for. Move along. */
michael@0 472 if (fseek(mar->fp, additionalBlockSize, SEEK_CUR)) {
michael@0 473 return -1;
michael@0 474 }
michael@0 475 }
michael@0 476 }
michael@0 477
michael@0 478 /* If we had a product info block we would have already returned */
michael@0 479 return -1;
michael@0 480 }
michael@0 481
michael@0 482 const MarItem *mar_find_item(MarFile *mar, const char *name) {
michael@0 483 uint32_t hash;
michael@0 484 const MarItem *item;
michael@0 485
michael@0 486 hash = mar_hash_name(name);
michael@0 487
michael@0 488 item = mar->item_table[hash];
michael@0 489 while (item && strcmp(item->name, name) != 0)
michael@0 490 item = item->next;
michael@0 491
michael@0 492 return item;
michael@0 493 }
michael@0 494
michael@0 495 int mar_enum_items(MarFile *mar, MarItemCallback callback, void *closure) {
michael@0 496 MarItem *item;
michael@0 497 int i;
michael@0 498
michael@0 499 for (i = 0; i < TABLESIZE; ++i) {
michael@0 500 item = mar->item_table[i];
michael@0 501 while (item) {
michael@0 502 int rv = callback(mar, item, closure);
michael@0 503 if (rv)
michael@0 504 return rv;
michael@0 505 item = item->next;
michael@0 506 }
michael@0 507 }
michael@0 508
michael@0 509 return 0;
michael@0 510 }
michael@0 511
michael@0 512 int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf,
michael@0 513 int bufsize) {
michael@0 514 int nr;
michael@0 515
michael@0 516 if (offset == (int) item->length)
michael@0 517 return 0;
michael@0 518 if (offset > (int) item->length)
michael@0 519 return -1;
michael@0 520
michael@0 521 nr = item->length - offset;
michael@0 522 if (nr > bufsize)
michael@0 523 nr = bufsize;
michael@0 524
michael@0 525 if (fseek(mar->fp, item->offset + offset, SEEK_SET))
michael@0 526 return -1;
michael@0 527
michael@0 528 return fread(buf, 1, nr, mar->fp);
michael@0 529 }
michael@0 530
michael@0 531 /**
michael@0 532 * Determines the MAR file information.
michael@0 533 *
michael@0 534 * @param path The path of the MAR file to check.
michael@0 535 * @param hasSignatureBlock Optional out parameter specifying if the MAR
michael@0 536 * file has a signature block or not.
michael@0 537 * @param numSignatures Optional out parameter for storing the number
michael@0 538 * of signatures in the MAR file.
michael@0 539 * @param hasAdditionalBlocks Optional out parameter specifying if the MAR
michael@0 540 * file has additional blocks or not.
michael@0 541 * @param offsetAdditionalBlocks Optional out parameter for the offset to the
michael@0 542 * first additional block. Value is only valid if
michael@0 543 * hasAdditionalBlocks is not equal to 0.
michael@0 544 * @param numAdditionalBlocks Optional out parameter for the number of
michael@0 545 * additional blocks. Value is only valid if
michael@0 546 * has_additional_blocks is not equal to 0.
michael@0 547 * @return 0 on success and non-zero on failure.
michael@0 548 */
michael@0 549 int get_mar_file_info(const char *path,
michael@0 550 int *hasSignatureBlock,
michael@0 551 uint32_t *numSignatures,
michael@0 552 int *hasAdditionalBlocks,
michael@0 553 uint32_t *offsetAdditionalBlocks,
michael@0 554 uint32_t *numAdditionalBlocks)
michael@0 555 {
michael@0 556 int rv;
michael@0 557 FILE *fp = fopen(path, "rb");
michael@0 558 if (!fp) {
michael@0 559 fprintf(stderr, "ERROR: could not open file in get_mar_file_info()\n");
michael@0 560 perror(path);
michael@0 561 return -1;
michael@0 562 }
michael@0 563
michael@0 564 rv = get_mar_file_info_fp(fp, hasSignatureBlock,
michael@0 565 numSignatures, hasAdditionalBlocks,
michael@0 566 offsetAdditionalBlocks, numAdditionalBlocks);
michael@0 567
michael@0 568 fclose(fp);
michael@0 569 return rv;
michael@0 570 }

mercurial