archive_read_support_format_ar.c revision 228759
1251875Speter/*- 2251875Speter * Copyright (c) 2007 Kai Wang 3251875Speter * Copyright (c) 2007 Tim Kientzle 4251875Speter * All rights reserved. 5251875Speter * 6251875Speter * Redistribution and use in source and binary forms, with or without 7251875Speter * modification, are permitted provided that the following conditions 8251875Speter * are met: 9251875Speter * 1. Redistributions of source code must retain the above copyright 10251875Speter * notice, this list of conditions and the following disclaimer 11251875Speter * in this position and unchanged. 12251875Speter * 2. Redistributions in binary form must reproduce the above copyright 13251875Speter * notice, this list of conditions and the following disclaimer in the 14251875Speter * documentation and/or other materials provided with the distribution. 15251875Speter * 16251875Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17251875Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18251875Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19251875Speter * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20251875Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21251875Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22251875Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23251875Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24251875Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25251875Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26251875Speter */ 27251875Speter 28251875Speter#include "archive_platform.h" 29362181Sdim__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_ar.c 201101 2009-12-28 03:06:27Z kientzle $"); 30251875Speter 31251875Speter#ifdef HAVE_SYS_STAT_H 32251875Speter#include <sys/stat.h> 33251875Speter#endif 34362181Sdim#ifdef HAVE_ERRNO_H 35362181Sdim#include <errno.h> 36362181Sdim#endif 37251875Speter#ifdef HAVE_STDLIB_H 38251875Speter#include <stdlib.h> 39251875Speter#endif 40251875Speter#ifdef HAVE_STRING_H 41251875Speter#include <string.h> 42251875Speter#endif 43251875Speter#ifdef HAVE_LIMITS_H 44251875Speter#include <limits.h> 45251875Speter#endif 46251875Speter 47251875Speter#include "archive.h" 48251875Speter#include "archive_entry.h" 49251875Speter#include "archive_private.h" 50251875Speter#include "archive_read_private.h" 51251875Speter 52251875Speterstruct ar { 53251875Speter off_t entry_bytes_remaining; 54251875Speter off_t entry_offset; 55251875Speter off_t entry_padding; 56251875Speter char *strtab; 57251875Speter size_t strtab_size; 58251875Speter}; 59251875Speter 60251875Speter/* 61251875Speter * Define structure of the "ar" header. 62251875Speter */ 63251875Speter#define AR_name_offset 0 64251875Speter#define AR_name_size 16 65251875Speter#define AR_date_offset 16 66251875Speter#define AR_date_size 12 67251875Speter#define AR_uid_offset 28 68251875Speter#define AR_uid_size 6 69251875Speter#define AR_gid_offset 34 70251875Speter#define AR_gid_size 6 71251875Speter#define AR_mode_offset 40 72251875Speter#define AR_mode_size 8 73251875Speter#define AR_size_offset 48 74251875Speter#define AR_size_size 10 75251875Speter#define AR_fmag_offset 58 76251875Speter#define AR_fmag_size 2 77251875Speter 78251875Speterstatic int archive_read_format_ar_bid(struct archive_read *a); 79251875Speterstatic int archive_read_format_ar_cleanup(struct archive_read *a); 80251875Speterstatic int archive_read_format_ar_read_data(struct archive_read *a, 81251875Speter const void **buff, size_t *size, off_t *offset); 82251875Speterstatic int archive_read_format_ar_skip(struct archive_read *a); 83251875Speterstatic int archive_read_format_ar_read_header(struct archive_read *a, 84251875Speter struct archive_entry *e); 85251875Speterstatic uint64_t ar_atol8(const char *p, unsigned char_cnt); 86251875Speterstatic uint64_t ar_atol10(const char *p, unsigned char_cnt); 87251875Speterstatic int ar_parse_gnu_filename_table(struct archive_read *a); 88251875Speterstatic int ar_parse_common_header(struct ar *ar, struct archive_entry *, 89251875Speter const char *h); 90251875Speter 91251875Speterint 92251875Speterarchive_read_support_format_ar(struct archive *_a) 93251875Speter{ 94251875Speter struct archive_read *a = (struct archive_read *)_a; 95251875Speter struct ar *ar; 96251875Speter int r; 97251875Speter 98251875Speter ar = (struct ar *)malloc(sizeof(*ar)); 99251875Speter if (ar == NULL) { 100251875Speter archive_set_error(&a->archive, ENOMEM, 101251875Speter "Can't allocate ar data"); 102251875Speter return (ARCHIVE_FATAL); 103251875Speter } 104251875Speter memset(ar, 0, sizeof(*ar)); 105251875Speter ar->strtab = NULL; 106266735Speter 107266735Speter r = __archive_read_register_format(a, 108362181Sdim ar, 109362181Sdim "ar", 110362181Sdim archive_read_format_ar_bid, 111251875Speter NULL, 112251875Speter archive_read_format_ar_read_header, 113251875Speter archive_read_format_ar_read_data, 114251875Speter archive_read_format_ar_skip, 115251875Speter archive_read_format_ar_cleanup); 116251875Speter 117251875Speter if (r != ARCHIVE_OK) { 118251875Speter free(ar); 119251875Speter return (r); 120251875Speter } 121251875Speter return (ARCHIVE_OK); 122251875Speter} 123251875Speter 124251875Speterstatic int 125251875Speterarchive_read_format_ar_cleanup(struct archive_read *a) 126251875Speter{ 127251875Speter struct ar *ar; 128251875Speter 129251875Speter ar = (struct ar *)(a->format->data); 130251875Speter if (ar->strtab) 131251875Speter free(ar->strtab); 132251875Speter free(ar); 133251875Speter (a->format->data) = NULL; 134251875Speter return (ARCHIVE_OK); 135251875Speter} 136251875Speter 137251875Speterstatic int 138251875Speterarchive_read_format_ar_bid(struct archive_read *a) 139251875Speter{ 140251875Speter const void *h; 141251875Speter 142251875Speter if (a->archive.archive_format != 0 && 143251875Speter (a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) != 144251875Speter ARCHIVE_FORMAT_AR) 145251875Speter return(0); 146251875Speter 147251875Speter /* 148251875Speter * Verify the 8-byte file signature. 149251875Speter * TODO: Do we need to check more than this? 150251875Speter */ 151251875Speter if ((h = __archive_read_ahead(a, 8, NULL)) == NULL) 152251875Speter return (-1); 153251875Speter if (strncmp((const char*)h, "!<arch>\n", 8) == 0) { 154251875Speter return (64); 155251875Speter } 156251875Speter return (-1); 157251875Speter} 158251875Speter 159251875Speterstatic int 160251875Speterarchive_read_format_ar_read_header(struct archive_read *a, 161251875Speter struct archive_entry *entry) 162251875Speter{ 163251875Speter char filename[AR_name_size + 1]; 164251875Speter struct ar *ar; 165251875Speter uint64_t number; /* Used to hold parsed numbers before validation. */ 166362181Sdim ssize_t bytes_read; 167362181Sdim size_t bsd_name_length, entry_size; 168362181Sdim char *p, *st; 169362181Sdim const void *b; 170362181Sdim const char *h; 171362181Sdim int r; 172362181Sdim 173362181Sdim ar = (struct ar*)(a->format->data); 174362181Sdim 175362181Sdim if (a->archive.file_position == 0) { 176362181Sdim /* 177362181Sdim * We are now at the beginning of the archive, 178362181Sdim * so we need first consume the ar global header. 179362181Sdim */ 180362181Sdim __archive_read_consume(a, 8); 181362181Sdim /* Set a default format code for now. */ 182362181Sdim a->archive.archive_format = ARCHIVE_FORMAT_AR; 183362181Sdim } 184362181Sdim 185251875Speter /* Read the header for the next file entry. */ 186251875Speter if ((b = __archive_read_ahead(a, 60, &bytes_read)) == NULL) 187251875Speter /* Broken header. */ 188251875Speter return (ARCHIVE_EOF); 189251875Speter __archive_read_consume(a, 60); 190251875Speter h = (const char *)b; 191251875Speter 192251875Speter /* Verify the magic signature on the file header. */ 193251875Speter if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) { 194251875Speter archive_set_error(&a->archive, EINVAL, 195251875Speter "Incorrect file header signature"); 196251875Speter return (ARCHIVE_WARN); 197251875Speter } 198251875Speter 199251875Speter /* Copy filename into work buffer. */ 200251875Speter strncpy(filename, h + AR_name_offset, AR_name_size); 201251875Speter filename[AR_name_size] = '\0'; 202251875Speter 203251875Speter /* 204251875Speter * Guess the format variant based on the filename. 205251875Speter */ 206251875Speter if (a->archive.archive_format == ARCHIVE_FORMAT_AR) { 207251875Speter /* We don't already know the variant, so let's guess. */ 208251875Speter /* 209251875Speter * Biggest clue is presence of '/': GNU starts special 210251875Speter * filenames with '/', appends '/' as terminator to 211251875Speter * non-special names, so anything with '/' should be 212251875Speter * GNU except for BSD long filenames. 213251875Speter */ 214251875Speter if (strncmp(filename, "#1/", 3) == 0) 215251875Speter a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD; 216251875Speter else if (strchr(filename, '/') != NULL) 217251875Speter a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU; 218251875Speter else if (strncmp(filename, "__.SYMDEF", 9) == 0) 219251875Speter a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD; 220251875Speter /* 221251875Speter * XXX Do GNU/SVR4 'ar' programs ever omit trailing '/' 222251875Speter * if name exactly fills 16-byte field? If so, we 223251875Speter * can't assume entries without '/' are BSD. XXX 224251875Speter */ 225251875Speter } 226251875Speter 227251875Speter /* Update format name from the code. */ 228251875Speter if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) 229251875Speter a->archive.archive_format_name = "ar (GNU/SVR4)"; 230251875Speter else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) 231251875Speter a->archive.archive_format_name = "ar (BSD)"; 232251875Speter else 233251875Speter a->archive.archive_format_name = "ar"; 234251875Speter 235251875Speter /* 236251875Speter * Remove trailing spaces from the filename. GNU and BSD 237251875Speter * variants both pad filename area out with spaces. 238251875Speter * This will only be wrong if GNU/SVR4 'ar' implementations 239251875Speter * omit trailing '/' for 16-char filenames and we have 240251875Speter * a 16-char filename that ends in ' '. 241251875Speter */ 242251875Speter p = filename + AR_name_size - 1; 243251875Speter while (p >= filename && *p == ' ') { 244251875Speter *p = '\0'; 245251875Speter p--; 246251875Speter } 247251875Speter 248251875Speter /* 249251875Speter * Remove trailing slash unless first character is '/'. 250251875Speter * (BSD entries never end in '/', so this will only trim 251251875Speter * GNU-format entries. GNU special entries start with '/' 252251875Speter * and are not terminated in '/', so we don't trim anything 253251875Speter * that starts with '/'.) 254251875Speter */ 255251875Speter if (filename[0] != '/' && *p == '/') 256251875Speter *p = '\0'; 257251875Speter 258251875Speter /* 259251875Speter * '//' is the GNU filename table. 260251875Speter * Later entries can refer to names in this table. 261251875Speter */ 262251875Speter if (strcmp(filename, "//") == 0) { 263251875Speter /* This must come before any call to _read_ahead. */ 264251875Speter ar_parse_common_header(ar, entry, h); 265251875Speter archive_entry_copy_pathname(entry, filename); 266251875Speter archive_entry_set_filetype(entry, AE_IFREG); 267251875Speter /* Get the size of the filename table. */ 268251875Speter number = ar_atol10(h + AR_size_offset, AR_size_size); 269251875Speter if (number > SIZE_MAX) { 270251875Speter archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 271251875Speter "Filename table too large"); 272251875Speter return (ARCHIVE_FATAL); 273251875Speter } 274251875Speter entry_size = (size_t)number; 275251875Speter if (entry_size == 0) { 276362181Sdim archive_set_error(&a->archive, EINVAL, 277362181Sdim "Invalid string table"); 278362181Sdim return (ARCHIVE_WARN); 279362181Sdim } 280251875Speter if (ar->strtab != NULL) { 281251875Speter archive_set_error(&a->archive, EINVAL, 282251875Speter "More than one string tables exist"); 283251875Speter return (ARCHIVE_WARN); 284251875Speter } 285251875Speter 286251875Speter /* Read the filename table into memory. */ 287251875Speter st = malloc(entry_size); 288251875Speter if (st == NULL) { 289251875Speter archive_set_error(&a->archive, ENOMEM, 290251875Speter "Can't allocate filename table buffer"); 291251875Speter return (ARCHIVE_FATAL); 292251875Speter } 293251875Speter ar->strtab = st; 294251875Speter ar->strtab_size = entry_size; 295251875Speter if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL) 296251875Speter return (ARCHIVE_FATAL); 297251875Speter memcpy(st, b, entry_size); 298251875Speter __archive_read_consume(a, entry_size); 299251875Speter /* All contents are consumed. */ 300251875Speter ar->entry_bytes_remaining = 0; 301251875Speter archive_entry_set_size(entry, ar->entry_bytes_remaining); 302251875Speter 303251875Speter /* Parse the filename table. */ 304251875Speter return (ar_parse_gnu_filename_table(a)); 305251875Speter } 306251875Speter 307251875Speter /* 308251875Speter * GNU variant handles long filenames by storing /<number> 309251875Speter * to indicate a name stored in the filename table. 310251875Speter * XXX TODO: Verify that it's all digits... Don't be fooled 311251875Speter * by "/9xyz" XXX 312251875Speter */ 313266735Speter if (filename[0] == '/' && filename[1] >= '0' && filename[1] <= '9') { 314266735Speter number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1); 315266735Speter /* 316251875Speter * If we can't look up the real name, warn and return 317251875Speter * the entry with the wrong name. 318251875Speter */ 319251875Speter if (ar->strtab == NULL || number > ar->strtab_size) { 320251875Speter archive_set_error(&a->archive, EINVAL, 321251875Speter "Can't find long filename for entry"); 322251875Speter archive_entry_copy_pathname(entry, filename); 323251875Speter /* Parse the time, owner, mode, size fields. */ 324251875Speter ar_parse_common_header(ar, entry, h); 325251875Speter return (ARCHIVE_WARN); 326251875Speter } 327251875Speter 328251875Speter archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]); 329251875Speter /* Parse the time, owner, mode, size fields. */ 330251875Speter return (ar_parse_common_header(ar, entry, h)); 331251875Speter } 332251875Speter 333251875Speter /* 334251875Speter * BSD handles long filenames by storing "#1/" followed by the 335251875Speter * length of filename as a decimal number, then prepends the 336251875Speter * the filename to the file contents. 337251875Speter */ 338251875Speter if (strncmp(filename, "#1/", 3) == 0) { 339251875Speter /* Parse the time, owner, mode, size fields. */ 340251875Speter /* This must occur before _read_ahead is called again. */ 341251875Speter ar_parse_common_header(ar, entry, h); 342251875Speter 343251875Speter /* Parse the size of the name, adjust the file size. */ 344251875Speter number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3); 345251875Speter bsd_name_length = (size_t)number; 346251875Speter /* Guard against the filename + trailing NUL 347251875Speter * overflowing a size_t and against the filename size 348251875Speter * being larger than the entire entry. */ 349251875Speter if (number > (uint64_t)(bsd_name_length + 1) 350251875Speter || (off_t)bsd_name_length > ar->entry_bytes_remaining) { 351251875Speter archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 352251875Speter "Bad input file size"); 353251875Speter return (ARCHIVE_FATAL); 354251875Speter } 355251875Speter ar->entry_bytes_remaining -= bsd_name_length; 356251875Speter /* Adjust file size reported to client. */ 357251875Speter archive_entry_set_size(entry, ar->entry_bytes_remaining); 358251875Speter 359251875Speter /* Read the long name into memory. */ 360251875Speter if ((b = __archive_read_ahead(a, bsd_name_length, NULL)) == NULL) { 361251875Speter archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 362251875Speter "Truncated input file"); 363251875Speter return (ARCHIVE_FATAL); 364251875Speter } 365251875Speter __archive_read_consume(a, bsd_name_length); 366251875Speter 367251875Speter /* Store it in the entry. */ 368251875Speter p = (char *)malloc(bsd_name_length + 1); 369251875Speter if (p == NULL) { 370251875Speter archive_set_error(&a->archive, ENOMEM, 371266735Speter "Can't allocate fname buffer"); 372266735Speter return (ARCHIVE_FATAL); 373266735Speter } 374251875Speter strncpy(p, b, bsd_name_length); 375251875Speter p[bsd_name_length] = '\0'; 376251875Speter archive_entry_copy_pathname(entry, p); 377251875Speter free(p); 378251875Speter return (ARCHIVE_OK); 379251875Speter } 380251875Speter 381251875Speter /* 382251875Speter * "/" is the SVR4/GNU archive symbol table. 383251875Speter */ 384251875Speter if (strcmp(filename, "/") == 0) { 385251875Speter archive_entry_copy_pathname(entry, "/"); 386251875Speter /* Parse the time, owner, mode, size fields. */ 387251875Speter r = ar_parse_common_header(ar, entry, h); 388251875Speter /* Force the file type to a regular file. */ 389251875Speter archive_entry_set_filetype(entry, AE_IFREG); 390251875Speter return (r); 391251875Speter } 392251875Speter 393251875Speter /* 394251875Speter * "__.SYMDEF" is a BSD archive symbol table. 395251875Speter */ 396251875Speter if (strcmp(filename, "__.SYMDEF") == 0) { 397251875Speter archive_entry_copy_pathname(entry, filename); 398251875Speter /* Parse the time, owner, mode, size fields. */ 399251875Speter return (ar_parse_common_header(ar, entry, h)); 400251875Speter } 401251875Speter 402251875Speter /* 403251875Speter * Otherwise, this is a standard entry. The filename 404251875Speter * has already been trimmed as much as possible, based 405251875Speter * on our current knowledge of the format. 406251875Speter */ 407251875Speter archive_entry_copy_pathname(entry, filename); 408362181Sdim return (ar_parse_common_header(ar, entry, h)); 409251875Speter} 410251875Speter 411251875Speterstatic int 412251875Speterar_parse_common_header(struct ar *ar, struct archive_entry *entry, 413251875Speter const char *h) 414251875Speter{ 415251875Speter uint64_t n; 416251875Speter 417251875Speter /* Copy remaining header */ 418251875Speter archive_entry_set_mtime(entry, 419251875Speter (time_t)ar_atol10(h + AR_date_offset, AR_date_size), 0L); 420251875Speter archive_entry_set_uid(entry, 421251875Speter (uid_t)ar_atol10(h + AR_uid_offset, AR_uid_size)); 422251875Speter archive_entry_set_gid(entry, 423251875Speter (gid_t)ar_atol10(h + AR_gid_offset, AR_gid_size)); 424251875Speter archive_entry_set_mode(entry, 425251875Speter (mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size)); 426251875Speter n = ar_atol10(h + AR_size_offset, AR_size_size); 427251875Speter 428251875Speter ar->entry_offset = 0; 429251875Speter ar->entry_padding = n % 2; 430251875Speter archive_entry_set_size(entry, n); 431251875Speter ar->entry_bytes_remaining = n; 432251875Speter return (ARCHIVE_OK); 433251875Speter} 434251875Speter 435362181Sdimstatic int 436362181Sdimarchive_read_format_ar_read_data(struct archive_read *a, 437362181Sdim const void **buff, size_t *size, off_t *offset) 438362181Sdim{ 439362181Sdim ssize_t bytes_read; 440362181Sdim struct ar *ar; 441362181Sdim 442362181Sdim ar = (struct ar *)(a->format->data); 443362181Sdim 444362181Sdim if (ar->entry_bytes_remaining > 0) { 445362181Sdim *buff = __archive_read_ahead(a, 1, &bytes_read); 446362181Sdim if (bytes_read == 0) { 447362181Sdim archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 448362181Sdim "Truncated ar archive"); 449362181Sdim return (ARCHIVE_FATAL); 450362181Sdim } 451362181Sdim if (bytes_read < 0) 452362181Sdim return (ARCHIVE_FATAL); 453362181Sdim if (bytes_read > ar->entry_bytes_remaining) 454362181Sdim bytes_read = (ssize_t)ar->entry_bytes_remaining; 455362181Sdim *size = bytes_read; 456362181Sdim *offset = ar->entry_offset; 457362181Sdim ar->entry_offset += bytes_read; 458362181Sdim ar->entry_bytes_remaining -= bytes_read; 459362181Sdim __archive_read_consume(a, (size_t)bytes_read); 460362181Sdim return (ARCHIVE_OK); 461362181Sdim } else { 462362181Sdim while (ar->entry_padding > 0) { 463362181Sdim *buff = __archive_read_ahead(a, 1, &bytes_read); 464362181Sdim if (bytes_read <= 0) 465362181Sdim return (ARCHIVE_FATAL); 466362181Sdim if (bytes_read > ar->entry_padding) 467362181Sdim bytes_read = (ssize_t)ar->entry_padding; 468362181Sdim __archive_read_consume(a, (size_t)bytes_read); 469362181Sdim ar->entry_padding -= bytes_read; 470251875Speter } 471251875Speter *buff = NULL; 472251875Speter *size = 0; 473251875Speter *offset = ar->entry_offset; 474266735Speter return (ARCHIVE_EOF); 475266735Speter } 476251875Speter} 477251875Speter 478251875Speterstatic int 479251875Speterarchive_read_format_ar_skip(struct archive_read *a) 480251875Speter{ 481251875Speter off_t bytes_skipped; 482251875Speter struct ar* ar; 483251875Speter 484251875Speter ar = (struct ar *)(a->format->data); 485251875Speter 486251875Speter bytes_skipped = __archive_read_skip(a, 487251875Speter ar->entry_bytes_remaining + ar->entry_padding); 488251875Speter if (bytes_skipped < 0) 489251875Speter return (ARCHIVE_FATAL); 490251875Speter 491251875Speter ar->entry_bytes_remaining = 0; 492251875Speter ar->entry_padding = 0; 493251875Speter 494251875Speter return (ARCHIVE_OK); 495251875Speter} 496251875Speter 497251875Speterstatic int 498251875Speterar_parse_gnu_filename_table(struct archive_read *a) 499251875Speter{ 500251875Speter struct ar *ar; 501251875Speter char *p; 502251875Speter size_t size; 503251875Speter 504251875Speter ar = (struct ar*)(a->format->data); 505251875Speter size = ar->strtab_size; 506251875Speter 507251875Speter for (p = ar->strtab; p < ar->strtab + size - 1; ++p) { 508251875Speter if (*p == '/') { 509251875Speter *p++ = '\0'; 510251875Speter if (*p != '\n') 511251875Speter goto bad_string_table; 512251875Speter *p = '\0'; 513251875Speter } 514251875Speter } 515251875Speter /* 516251875Speter * GNU ar always pads the table to an even size. 517251875Speter * The pad character is either '\n' or '`'. 518251875Speter */ 519251875Speter if (p != ar->strtab + size && *p != '\n' && *p != '`') 520251875Speter goto bad_string_table; 521251875Speter 522251875Speter /* Enforce zero termination. */ 523251875Speter ar->strtab[size - 1] = '\0'; 524251875Speter 525251875Speter return (ARCHIVE_OK); 526251875Speter 527251875Speterbad_string_table: 528251875Speter archive_set_error(&a->archive, EINVAL, 529251875Speter "Invalid string table"); 530251875Speter free(ar->strtab); 531251875Speter ar->strtab = NULL; 532251875Speter return (ARCHIVE_WARN); 533251875Speter} 534251875Speter 535251875Speterstatic uint64_t 536251875Speterar_atol8(const char *p, unsigned char_cnt) 537251875Speter{ 538251875Speter uint64_t l, limit, last_digit_limit; 539251875Speter unsigned int digit, base; 540251875Speter 541251875Speter base = 8; 542251875Speter limit = UINT64_MAX / base; 543251875Speter last_digit_limit = UINT64_MAX % base; 544251875Speter 545251875Speter while ((*p == ' ' || *p == '\t') && char_cnt-- > 0) 546251875Speter p++; 547251875Speter 548251875Speter l = 0; 549251875Speter digit = *p - '0'; 550251875Speter while (*p >= '0' && digit < base && char_cnt-- > 0) { 551251875Speter if (l>limit || (l == limit && digit > last_digit_limit)) { 552251875Speter l = UINT64_MAX; /* Truncate on overflow. */ 553251875Speter break; 554251875Speter } 555251875Speter l = (l * base) + digit; 556251875Speter digit = *++p - '0'; 557251875Speter } 558251875Speter return (l); 559251875Speter} 560251875Speter 561251875Speterstatic uint64_t 562251875Speterar_atol10(const char *p, unsigned char_cnt) 563251875Speter{ 564251875Speter uint64_t l, limit, last_digit_limit; 565251875Speter unsigned int base, digit; 566251875Speter 567251875Speter base = 10; 568266735Speter limit = UINT64_MAX / base; 569251875Speter last_digit_limit = UINT64_MAX % base; 570251875Speter 571251875Speter while ((*p == ' ' || *p == '\t') && char_cnt-- > 0) 572251875Speter p++; 573251875Speter l = 0; 574251875Speter digit = *p - '0'; 575251875Speter while (*p >= '0' && digit < base && char_cnt-- > 0) { 576251875Speter if (l > limit || (l == limit && digit > last_digit_limit)) { 577251875Speter l = UINT64_MAX; /* Truncate on overflow. */ 578266735Speter break; 579251875Speter } 580251875Speter l = (l * base) + digit; 581251875Speter digit = *++p - '0'; 582251875Speter } 583251875Speter return (l); 584251875Speter} 585251875Speter