archive_read_support_format_ar.c revision 229592
11590Srgrimes/*- 218905Swosch * Copyright (c) 2007 Kai Wang 31590Srgrimes * Copyright (c) 2007 Tim Kientzle 41590Srgrimes * All rights reserved. 51590Srgrimes * 61590Srgrimes * Redistribution and use in source and binary forms, with or without 71590Srgrimes * modification, are permitted provided that the following conditions 81590Srgrimes * are met: 91590Srgrimes * 1. Redistributions of source code must retain the above copyright 101590Srgrimes * notice, this list of conditions and the following disclaimer 111590Srgrimes * in this position and unchanged. 121590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 131590Srgrimes * notice, this list of conditions and the following disclaimer in the 141590Srgrimes * documentation and/or other materials provided with the distribution. 151590Srgrimes * 161590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 171590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191590Srgrimes * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 201590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 211590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 221590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 231590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 241590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 251590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 261590Srgrimes */ 271590Srgrimes 281590Srgrimes#include "archive_platform.h" 291590Srgrimes__FBSDID("$FreeBSD: stable/9/contrib/libarchive/libarchive/archive_read_support_format_ar.c 229592 2012-01-05 12:06:54Z mm $"); 301590Srgrimes 311590Srgrimes#ifdef HAVE_SYS_STAT_H 321590Srgrimes#include <sys/stat.h> 331590Srgrimes#endif 341590Srgrimes#ifdef HAVE_ERRNO_H 351590Srgrimes#include <errno.h> 3617776Swosch#endif 3750477Speter#ifdef HAVE_STDLIB_H 381590Srgrimes#include <stdlib.h> 391590Srgrimes#endif 40209571Sgavin#ifdef HAVE_STRING_H 411590Srgrimes#include <string.h> 421590Srgrimes#endif 431590Srgrimes#ifdef HAVE_LIMITS_H 441590Srgrimes#include <limits.h> 451590Srgrimes#endif 461590Srgrimes 471590Srgrimes#include "archive.h" 481590Srgrimes#include "archive_entry.h" 491590Srgrimes#include "archive_private.h" 50209571Sgavin#include "archive_read_private.h" 511590Srgrimes 521590Srgrimesstruct ar { 531590Srgrimes off_t entry_bytes_remaining; 541590Srgrimes off_t entry_offset; 551590Srgrimes off_t entry_padding; 561590Srgrimes char *strtab; 571590Srgrimes size_t strtab_size; 581590Srgrimes}; 591590Srgrimes 601590Srgrimes/* 611590Srgrimes * Define structure of the "ar" header. 621590Srgrimes */ 631590Srgrimes#define AR_name_offset 0 641590Srgrimes#define AR_name_size 16 651590Srgrimes#define AR_date_offset 16 661590Srgrimes#define AR_date_size 12 671590Srgrimes#define AR_uid_offset 28 681590Srgrimes#define AR_uid_size 6 691590Srgrimes#define AR_gid_offset 34 701590Srgrimes#define AR_gid_size 6 711590Srgrimes#define AR_mode_offset 40 721590Srgrimes#define AR_mode_size 8 731590Srgrimes#define AR_size_offset 48 741590Srgrimes#define AR_size_size 10 751590Srgrimes#define AR_fmag_offset 58 761590Srgrimes#define AR_fmag_size 2 771590Srgrimes 7818905Swoschstatic int archive_read_format_ar_bid(struct archive_read *a); 791590Srgrimesstatic int archive_read_format_ar_cleanup(struct archive_read *a); 801590Srgrimesstatic int archive_read_format_ar_read_data(struct archive_read *a, 811590Srgrimes const void **buff, size_t *size, off_t *offset); 8218905Swoschstatic int archive_read_format_ar_skip(struct archive_read *a); 8318905Swoschstatic int archive_read_format_ar_read_header(struct archive_read *a, 8418905Swosch struct archive_entry *e); 8518905Swoschstatic uint64_t ar_atol8(const char *p, unsigned char_cnt); 8618905Swoschstatic uint64_t ar_atol10(const char *p, unsigned char_cnt); 871590Srgrimesstatic int ar_parse_gnu_filename_table(struct archive_read *a); 8818905Swoschstatic int ar_parse_common_header(struct ar *ar, struct archive_entry *, 8918905Swosch const char *h); 901590Srgrimes 911590Srgrimesint 9218905Swoscharchive_read_support_format_ar(struct archive *_a) 9318905Swosch{ 941590Srgrimes struct archive_read *a = (struct archive_read *)_a; 951590Srgrimes struct ar *ar; 961590Srgrimes int r; 971590Srgrimes 981590Srgrimes ar = (struct ar *)malloc(sizeof(*ar)); 991590Srgrimes if (ar == NULL) { 1001590Srgrimes archive_set_error(&a->archive, ENOMEM, 1011590Srgrimes "Can't allocate ar data"); 10265428Simp return (ARCHIVE_FATAL); 1031590Srgrimes } 1041590Srgrimes memset(ar, 0, sizeof(*ar)); 1051590Srgrimes ar->strtab = NULL; 1061590Srgrimes 10717592Swosch r = __archive_read_register_format(a, 10817592Swosch ar, 10918905Swosch "ar", 1101590Srgrimes archive_read_format_ar_bid, 11117776Swosch NULL, 11217776Swosch archive_read_format_ar_read_header, 11317592Swosch archive_read_format_ar_read_data, 11418905Swosch archive_read_format_ar_skip, 11518905Swosch archive_read_format_ar_cleanup); 11618905Swosch 11717592Swosch if (r != ARCHIVE_OK) { 11817592Swosch free(ar); 11917592Swosch return (r); 12092920Simp } 12117776Swosch return (ARCHIVE_OK); 12217592Swosch} 12317776Swosch 12492920Simpstatic int 1251590Srgrimesarchive_read_format_ar_cleanup(struct archive_read *a) 1261590Srgrimes{ 127209571Sgavin struct ar *ar; 1281590Srgrimes 129209571Sgavin ar = (struct ar *)(a->format->data); 1301590Srgrimes if (ar->strtab) 131209571Sgavin free(ar->strtab); 1321590Srgrimes free(ar); 1331590Srgrimes (a->format->data) = NULL; 13424360Simp return (ARCHIVE_OK); 1351590Srgrimes} 1361590Srgrimes 1371590Srgrimesstatic int 1381590Srgrimesarchive_read_format_ar_bid(struct archive_read *a) 1391590Srgrimes{ 1401590Srgrimes const void *h; 1411590Srgrimes 1421590Srgrimes if (a->archive.archive_format != 0 && 1431590Srgrimes (a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) != 1441590Srgrimes ARCHIVE_FORMAT_AR) 1451590Srgrimes return(0); 1461590Srgrimes 1471590Srgrimes /* 1481590Srgrimes * Verify the 8-byte file signature. 1491590Srgrimes * TODO: Do we need to check more than this? 15017776Swosch */ 1511590Srgrimes if ((h = __archive_read_ahead(a, 8, NULL)) == NULL) 1521590Srgrimes return (-1); 1531590Srgrimes if (strncmp((const char*)h, "!<arch>\n", 8) == 0) { 1541590Srgrimes return (64); 15517592Swosch } 15617592Swosch return (-1); 15718905Swosch} 15818905Swosch 15917592Swoschstatic int 16017592Swoscharchive_read_format_ar_read_header(struct archive_read *a, 16117972Swosch struct archive_entry *entry) 16218905Swosch{ 16318905Swosch char filename[AR_name_size + 1]; 16417776Swosch struct ar *ar; 16517592Swosch uint64_t number; /* Used to hold parsed numbers before validation. */ 1661590Srgrimes ssize_t bytes_read; 1671590Srgrimes size_t bsd_name_length, entry_size; 1681590Srgrimes char *p, *st; 16917776Swosch const void *b; 17017592Swosch const char *h; 1711590Srgrimes int r; 17218905Swosch 17317592Swosch ar = (struct ar*)(a->format->data); 17417592Swosch 17517592Swosch if (a->archive.file_position == 0) { 17618905Swosch /* 17717972Swosch * We are now at the beginning of the archive, 17819213Swosch * so we need first consume the ar global header. 17919213Swosch */ 18019213Swosch __archive_read_consume(a, 8); 18119213Swosch /* Set a default format code for now. */ 18219213Swosch a->archive.archive_format = ARCHIVE_FORMAT_AR; 18319213Swosch } 18419213Swosch 18517592Swosch /* Read the header for the next file entry. */ 18617592Swosch if ((b = __archive_read_ahead(a, 60, &bytes_read)) == NULL) 18717972Swosch /* Broken header. */ 1881590Srgrimes return (ARCHIVE_EOF); 1891590Srgrimes __archive_read_consume(a, 60); 1901590Srgrimes h = (const char *)b; 19118905Swosch 19218905Swosch /* Verify the magic signature on the file header. */ 19318905Swosch if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) { 19417592Swosch archive_set_error(&a->archive, EINVAL, 1951590Srgrimes "Incorrect file header signature"); 1961590Srgrimes return (ARCHIVE_WARN); 1971590Srgrimes } 1981590Srgrimes 1991590Srgrimes /* Copy filename into work buffer. */ 2001590Srgrimes strncpy(filename, h + AR_name_offset, AR_name_size); 2011590Srgrimes filename[AR_name_size] = '\0'; 2021590Srgrimes 2031590Srgrimes /* 2041590Srgrimes * Guess the format variant based on the filename. 2051590Srgrimes */ 20617972Swosch if (a->archive.archive_format == ARCHIVE_FORMAT_AR) { 20718905Swosch /* We don't already know the variant, so let's guess. */ 20818905Swosch /* 20918905Swosch * Biggest clue is presence of '/': GNU starts special 21018905Swosch * filenames with '/', appends '/' as terminator to 21118905Swosch * non-special names, so anything with '/' should be 21218905Swosch * GNU except for BSD long filenames. 21318905Swosch */ 21418905Swosch if (strncmp(filename, "#1/", 3) == 0) 2151590Srgrimes a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD; 2161590Srgrimes else if (strchr(filename, '/') != NULL) 2171590Srgrimes a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU; 2181590Srgrimes else if (strncmp(filename, "__.SYMDEF", 9) == 0) 21918905Swosch a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD; 22018905Swosch /* 22118905Swosch * XXX Do GNU/SVR4 'ar' programs ever omit trailing '/' 22218905Swosch * if name exactly fills 16-byte field? If so, we 22318905Swosch * can't assume entries without '/' are BSD. XXX 22418905Swosch */ 22518905Swosch } 22618905Swosch 22718905Swosch /* Update format name from the code. */ 22818905Swosch if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) 22918905Swosch a->archive.archive_format_name = "ar (GNU/SVR4)"; 23018905Swosch else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) 23118905Swosch a->archive.archive_format_name = "ar (BSD)"; 23218905Swosch else 23318905Swosch a->archive.archive_format_name = "ar"; 23418905Swosch 23518905Swosch /* 23618905Swosch * Remove trailing spaces from the filename. GNU and BSD 23718905Swosch * variants both pad filename area out with spaces. 23818905Swosch * This will only be wrong if GNU/SVR4 'ar' implementations 23918905Swosch * omit trailing '/' for 16-char filenames and we have 24018905Swosch * a 16-char filename that ends in ' '. 2411590Srgrimes */ 24218905Swosch p = filename + AR_name_size - 1; 2431590Srgrimes while (p >= filename && *p == ' ') { 2441590Srgrimes *p = '\0'; 2451590Srgrimes p--; 2461590Srgrimes } 2471590Srgrimes 2481590Srgrimes /* 2491590Srgrimes * Remove trailing slash unless first character is '/'. 2501590Srgrimes * (BSD entries never end in '/', so this will only trim 2511590Srgrimes * GNU-format entries. GNU special entries start with '/' 2521590Srgrimes * and are not terminated in '/', so we don't trim anything 2531590Srgrimes * that starts with '/'.) 2541590Srgrimes */ 2551590Srgrimes if (filename[0] != '/' && *p == '/') 2561590Srgrimes *p = '\0'; 25717592Swosch 2581590Srgrimes /* 259209571Sgavin * '//' is the GNU filename table. 2601590Srgrimes * Later entries can refer to names in this table. 261209571Sgavin */ 2621590Srgrimes if (strcmp(filename, "//") == 0) { 2631590Srgrimes /* This must come before any call to _read_ahead. */ 2641590Srgrimes ar_parse_common_header(ar, entry, h); 2651590Srgrimes archive_entry_copy_pathname(entry, filename); 2661590Srgrimes archive_entry_set_filetype(entry, AE_IFREG); 2671590Srgrimes /* Get the size of the filename table. */ 26817776Swosch number = ar_atol10(h + AR_size_offset, AR_size_size); 2691590Srgrimes if (number > SIZE_MAX) { 27017592Swosch archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 2711590Srgrimes "Filename table too large"); 2721590Srgrimes return (ARCHIVE_FATAL); 273209571Sgavin } 2741590Srgrimes entry_size = (size_t)number; 2751590Srgrimes if (entry_size == 0) { 2761590Srgrimes archive_set_error(&a->archive, EINVAL, 2771590Srgrimes "Invalid string table"); 2781590Srgrimes return (ARCHIVE_WARN); 279 } 280 if (ar->strtab != NULL) { 281 archive_set_error(&a->archive, EINVAL, 282 "More than one string tables exist"); 283 return (ARCHIVE_WARN); 284 } 285 286 /* Read the filename table into memory. */ 287 st = malloc(entry_size); 288 if (st == NULL) { 289 archive_set_error(&a->archive, ENOMEM, 290 "Can't allocate filename table buffer"); 291 return (ARCHIVE_FATAL); 292 } 293 ar->strtab = st; 294 ar->strtab_size = entry_size; 295 if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL) 296 return (ARCHIVE_FATAL); 297 memcpy(st, b, entry_size); 298 __archive_read_consume(a, entry_size); 299 /* All contents are consumed. */ 300 ar->entry_bytes_remaining = 0; 301 archive_entry_set_size(entry, ar->entry_bytes_remaining); 302 303 /* Parse the filename table. */ 304 return (ar_parse_gnu_filename_table(a)); 305 } 306 307 /* 308 * GNU variant handles long filenames by storing /<number> 309 * to indicate a name stored in the filename table. 310 * XXX TODO: Verify that it's all digits... Don't be fooled 311 * by "/9xyz" XXX 312 */ 313 if (filename[0] == '/' && filename[1] >= '0' && filename[1] <= '9') { 314 number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1); 315 /* 316 * If we can't look up the real name, warn and return 317 * the entry with the wrong name. 318 */ 319 if (ar->strtab == NULL || number > ar->strtab_size) { 320 archive_set_error(&a->archive, EINVAL, 321 "Can't find long filename for entry"); 322 archive_entry_copy_pathname(entry, filename); 323 /* Parse the time, owner, mode, size fields. */ 324 ar_parse_common_header(ar, entry, h); 325 return (ARCHIVE_WARN); 326 } 327 328 archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]); 329 /* Parse the time, owner, mode, size fields. */ 330 return (ar_parse_common_header(ar, entry, h)); 331 } 332 333 /* 334 * BSD handles long filenames by storing "#1/" followed by the 335 * length of filename as a decimal number, then prepends the 336 * the filename to the file contents. 337 */ 338 if (strncmp(filename, "#1/", 3) == 0) { 339 /* Parse the time, owner, mode, size fields. */ 340 /* This must occur before _read_ahead is called again. */ 341 ar_parse_common_header(ar, entry, h); 342 343 /* Parse the size of the name, adjust the file size. */ 344 number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3); 345 bsd_name_length = (size_t)number; 346 /* Guard against the filename + trailing NUL 347 * overflowing a size_t and against the filename size 348 * being larger than the entire entry. */ 349 if (number > (uint64_t)(bsd_name_length + 1) 350 || (off_t)bsd_name_length > ar->entry_bytes_remaining) { 351 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 352 "Bad input file size"); 353 return (ARCHIVE_FATAL); 354 } 355 ar->entry_bytes_remaining -= bsd_name_length; 356 /* Adjust file size reported to client. */ 357 archive_entry_set_size(entry, ar->entry_bytes_remaining); 358 359 /* Read the long name into memory. */ 360 if ((b = __archive_read_ahead(a, bsd_name_length, NULL)) == NULL) { 361 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 362 "Truncated input file"); 363 return (ARCHIVE_FATAL); 364 } 365 __archive_read_consume(a, bsd_name_length); 366 367 /* Store it in the entry. */ 368 p = (char *)malloc(bsd_name_length + 1); 369 if (p == NULL) { 370 archive_set_error(&a->archive, ENOMEM, 371 "Can't allocate fname buffer"); 372 return (ARCHIVE_FATAL); 373 } 374 strncpy(p, b, bsd_name_length); 375 p[bsd_name_length] = '\0'; 376 archive_entry_copy_pathname(entry, p); 377 free(p); 378 return (ARCHIVE_OK); 379 } 380 381 /* 382 * "/" is the SVR4/GNU archive symbol table. 383 */ 384 if (strcmp(filename, "/") == 0) { 385 archive_entry_copy_pathname(entry, "/"); 386 /* Parse the time, owner, mode, size fields. */ 387 r = ar_parse_common_header(ar, entry, h); 388 /* Force the file type to a regular file. */ 389 archive_entry_set_filetype(entry, AE_IFREG); 390 return (r); 391 } 392 393 /* 394 * "__.SYMDEF" is a BSD archive symbol table. 395 */ 396 if (strcmp(filename, "__.SYMDEF") == 0) { 397 archive_entry_copy_pathname(entry, filename); 398 /* Parse the time, owner, mode, size fields. */ 399 return (ar_parse_common_header(ar, entry, h)); 400 } 401 402 /* 403 * Otherwise, this is a standard entry. The filename 404 * has already been trimmed as much as possible, based 405 * on our current knowledge of the format. 406 */ 407 archive_entry_copy_pathname(entry, filename); 408 return (ar_parse_common_header(ar, entry, h)); 409} 410 411static int 412ar_parse_common_header(struct ar *ar, struct archive_entry *entry, 413 const char *h) 414{ 415 uint64_t n; 416 417 /* Copy remaining header */ 418 archive_entry_set_mtime(entry, 419 (time_t)ar_atol10(h + AR_date_offset, AR_date_size), 0L); 420 archive_entry_set_uid(entry, 421 (uid_t)ar_atol10(h + AR_uid_offset, AR_uid_size)); 422 archive_entry_set_gid(entry, 423 (gid_t)ar_atol10(h + AR_gid_offset, AR_gid_size)); 424 archive_entry_set_mode(entry, 425 (mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size)); 426 n = ar_atol10(h + AR_size_offset, AR_size_size); 427 428 ar->entry_offset = 0; 429 ar->entry_padding = n % 2; 430 archive_entry_set_size(entry, n); 431 ar->entry_bytes_remaining = n; 432 return (ARCHIVE_OK); 433} 434 435static int 436archive_read_format_ar_read_data(struct archive_read *a, 437 const void **buff, size_t *size, off_t *offset) 438{ 439 ssize_t bytes_read; 440 struct ar *ar; 441 442 ar = (struct ar *)(a->format->data); 443 444 if (ar->entry_bytes_remaining > 0) { 445 *buff = __archive_read_ahead(a, 1, &bytes_read); 446 if (bytes_read == 0) { 447 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 448 "Truncated ar archive"); 449 return (ARCHIVE_FATAL); 450 } 451 if (bytes_read < 0) 452 return (ARCHIVE_FATAL); 453 if (bytes_read > ar->entry_bytes_remaining) 454 bytes_read = (ssize_t)ar->entry_bytes_remaining; 455 *size = bytes_read; 456 *offset = ar->entry_offset; 457 ar->entry_offset += bytes_read; 458 ar->entry_bytes_remaining -= bytes_read; 459 __archive_read_consume(a, (size_t)bytes_read); 460 return (ARCHIVE_OK); 461 } else { 462 while (ar->entry_padding > 0) { 463 *buff = __archive_read_ahead(a, 1, &bytes_read); 464 if (bytes_read <= 0) 465 return (ARCHIVE_FATAL); 466 if (bytes_read > ar->entry_padding) 467 bytes_read = (ssize_t)ar->entry_padding; 468 __archive_read_consume(a, (size_t)bytes_read); 469 ar->entry_padding -= bytes_read; 470 } 471 *buff = NULL; 472 *size = 0; 473 *offset = ar->entry_offset; 474 return (ARCHIVE_EOF); 475 } 476} 477 478static int 479archive_read_format_ar_skip(struct archive_read *a) 480{ 481 off_t bytes_skipped; 482 struct ar* ar; 483 484 ar = (struct ar *)(a->format->data); 485 486 bytes_skipped = __archive_read_skip(a, 487 ar->entry_bytes_remaining + ar->entry_padding); 488 if (bytes_skipped < 0) 489 return (ARCHIVE_FATAL); 490 491 ar->entry_bytes_remaining = 0; 492 ar->entry_padding = 0; 493 494 return (ARCHIVE_OK); 495} 496 497static int 498ar_parse_gnu_filename_table(struct archive_read *a) 499{ 500 struct ar *ar; 501 char *p; 502 size_t size; 503 504 ar = (struct ar*)(a->format->data); 505 size = ar->strtab_size; 506 507 for (p = ar->strtab; p < ar->strtab + size - 1; ++p) { 508 if (*p == '/') { 509 *p++ = '\0'; 510 if (*p != '\n') 511 goto bad_string_table; 512 *p = '\0'; 513 } 514 } 515 /* 516 * GNU ar always pads the table to an even size. 517 * The pad character is either '\n' or '`'. 518 */ 519 if (p != ar->strtab + size && *p != '\n' && *p != '`') 520 goto bad_string_table; 521 522 /* Enforce zero termination. */ 523 ar->strtab[size - 1] = '\0'; 524 525 return (ARCHIVE_OK); 526 527bad_string_table: 528 archive_set_error(&a->archive, EINVAL, 529 "Invalid string table"); 530 free(ar->strtab); 531 ar->strtab = NULL; 532 return (ARCHIVE_WARN); 533} 534 535static uint64_t 536ar_atol8(const char *p, unsigned char_cnt) 537{ 538 uint64_t l, limit, last_digit_limit; 539 unsigned int digit, base; 540 541 base = 8; 542 limit = UINT64_MAX / base; 543 last_digit_limit = UINT64_MAX % base; 544 545 while ((*p == ' ' || *p == '\t') && char_cnt-- > 0) 546 p++; 547 548 l = 0; 549 digit = *p - '0'; 550 while (*p >= '0' && digit < base && char_cnt-- > 0) { 551 if (l>limit || (l == limit && digit > last_digit_limit)) { 552 l = UINT64_MAX; /* Truncate on overflow. */ 553 break; 554 } 555 l = (l * base) + digit; 556 digit = *++p - '0'; 557 } 558 return (l); 559} 560 561static uint64_t 562ar_atol10(const char *p, unsigned char_cnt) 563{ 564 uint64_t l, limit, last_digit_limit; 565 unsigned int base, digit; 566 567 base = 10; 568 limit = UINT64_MAX / base; 569 last_digit_limit = UINT64_MAX % base; 570 571 while ((*p == ' ' || *p == '\t') && char_cnt-- > 0) 572 p++; 573 l = 0; 574 digit = *p - '0'; 575 while (*p >= '0' && digit < base && char_cnt-- > 0) { 576 if (l > limit || (l == limit && digit > last_digit_limit)) { 577 l = UINT64_MAX; /* Truncate on overflow. */ 578 break; 579 } 580 l = (l * base) + digit; 581 digit = *++p - '0'; 582 } 583 return (l); 584} 585