1228753Smm/*- 2228753Smm * Copyright (c) 2007 Kai Wang 3228753Smm * Copyright (c) 2007 Tim Kientzle 4228753Smm * All rights reserved. 5228753Smm * 6228753Smm * Redistribution and use in source and binary forms, with or without 7228753Smm * modification, are permitted provided that the following conditions 8228753Smm * are met: 9228753Smm * 1. Redistributions of source code must retain the above copyright 10228753Smm * notice, this list of conditions and the following disclaimer 11228753Smm * in this position and unchanged. 12228753Smm * 2. Redistributions in binary form must reproduce the above copyright 13228753Smm * notice, this list of conditions and the following disclaimer in the 14228753Smm * documentation and/or other materials provided with the distribution. 15228753Smm * 16228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26228753Smm */ 27228753Smm 28228753Smm#include "archive_platform.h" 29229592Smm__FBSDID("$FreeBSD$"); 30228753Smm 31228753Smm#ifdef HAVE_SYS_STAT_H 32228753Smm#include <sys/stat.h> 33228753Smm#endif 34228753Smm#ifdef HAVE_ERRNO_H 35228753Smm#include <errno.h> 36228753Smm#endif 37228753Smm#ifdef HAVE_STDLIB_H 38228753Smm#include <stdlib.h> 39228753Smm#endif 40228753Smm#ifdef HAVE_STRING_H 41228753Smm#include <string.h> 42228753Smm#endif 43228753Smm#ifdef HAVE_LIMITS_H 44228753Smm#include <limits.h> 45228753Smm#endif 46228753Smm 47228753Smm#include "archive.h" 48228753Smm#include "archive_entry.h" 49228753Smm#include "archive_private.h" 50228753Smm#include "archive_read_private.h" 51228753Smm 52228753Smmstruct ar { 53228753Smm off_t entry_bytes_remaining; 54228753Smm off_t entry_offset; 55228753Smm off_t entry_padding; 56228753Smm char *strtab; 57228753Smm size_t strtab_size; 58228753Smm}; 59228753Smm 60228753Smm/* 61228753Smm * Define structure of the "ar" header. 62228753Smm */ 63228753Smm#define AR_name_offset 0 64228753Smm#define AR_name_size 16 65228753Smm#define AR_date_offset 16 66228753Smm#define AR_date_size 12 67228753Smm#define AR_uid_offset 28 68228753Smm#define AR_uid_size 6 69228753Smm#define AR_gid_offset 34 70228753Smm#define AR_gid_size 6 71228753Smm#define AR_mode_offset 40 72228753Smm#define AR_mode_size 8 73228753Smm#define AR_size_offset 48 74228753Smm#define AR_size_size 10 75228753Smm#define AR_fmag_offset 58 76228753Smm#define AR_fmag_size 2 77228753Smm 78228753Smmstatic int archive_read_format_ar_bid(struct archive_read *a); 79228753Smmstatic int archive_read_format_ar_cleanup(struct archive_read *a); 80228753Smmstatic int archive_read_format_ar_read_data(struct archive_read *a, 81228753Smm const void **buff, size_t *size, off_t *offset); 82228753Smmstatic int archive_read_format_ar_skip(struct archive_read *a); 83228753Smmstatic int archive_read_format_ar_read_header(struct archive_read *a, 84228753Smm struct archive_entry *e); 85228753Smmstatic uint64_t ar_atol8(const char *p, unsigned char_cnt); 86228753Smmstatic uint64_t ar_atol10(const char *p, unsigned char_cnt); 87228753Smmstatic int ar_parse_gnu_filename_table(struct archive_read *a); 88228753Smmstatic int ar_parse_common_header(struct ar *ar, struct archive_entry *, 89228753Smm const char *h); 90228753Smm 91228753Smmint 92228753Smmarchive_read_support_format_ar(struct archive *_a) 93228753Smm{ 94228753Smm struct archive_read *a = (struct archive_read *)_a; 95228753Smm struct ar *ar; 96228753Smm int r; 97228753Smm 98228753Smm ar = (struct ar *)malloc(sizeof(*ar)); 99228753Smm if (ar == NULL) { 100228753Smm archive_set_error(&a->archive, ENOMEM, 101228753Smm "Can't allocate ar data"); 102228753Smm return (ARCHIVE_FATAL); 103228753Smm } 104228753Smm memset(ar, 0, sizeof(*ar)); 105228753Smm ar->strtab = NULL; 106228753Smm 107228753Smm r = __archive_read_register_format(a, 108228753Smm ar, 109228753Smm "ar", 110228753Smm archive_read_format_ar_bid, 111228753Smm NULL, 112228753Smm archive_read_format_ar_read_header, 113228753Smm archive_read_format_ar_read_data, 114228753Smm archive_read_format_ar_skip, 115228753Smm archive_read_format_ar_cleanup); 116228753Smm 117228753Smm if (r != ARCHIVE_OK) { 118228753Smm free(ar); 119228753Smm return (r); 120228753Smm } 121228753Smm return (ARCHIVE_OK); 122228753Smm} 123228753Smm 124228753Smmstatic int 125228753Smmarchive_read_format_ar_cleanup(struct archive_read *a) 126228753Smm{ 127228753Smm struct ar *ar; 128228753Smm 129228753Smm ar = (struct ar *)(a->format->data); 130228753Smm if (ar->strtab) 131228753Smm free(ar->strtab); 132228753Smm free(ar); 133228753Smm (a->format->data) = NULL; 134228753Smm return (ARCHIVE_OK); 135228753Smm} 136228753Smm 137228753Smmstatic int 138228753Smmarchive_read_format_ar_bid(struct archive_read *a) 139228753Smm{ 140228753Smm const void *h; 141228753Smm 142228753Smm if (a->archive.archive_format != 0 && 143228753Smm (a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) != 144228753Smm ARCHIVE_FORMAT_AR) 145228753Smm return(0); 146228753Smm 147228753Smm /* 148228753Smm * Verify the 8-byte file signature. 149228753Smm * TODO: Do we need to check more than this? 150228753Smm */ 151228753Smm if ((h = __archive_read_ahead(a, 8, NULL)) == NULL) 152228753Smm return (-1); 153228753Smm if (strncmp((const char*)h, "!<arch>\n", 8) == 0) { 154228753Smm return (64); 155228753Smm } 156228753Smm return (-1); 157228753Smm} 158228753Smm 159228753Smmstatic int 160228753Smmarchive_read_format_ar_read_header(struct archive_read *a, 161228753Smm struct archive_entry *entry) 162228753Smm{ 163228753Smm char filename[AR_name_size + 1]; 164228753Smm struct ar *ar; 165228753Smm uint64_t number; /* Used to hold parsed numbers before validation. */ 166228753Smm ssize_t bytes_read; 167228753Smm size_t bsd_name_length, entry_size; 168228753Smm char *p, *st; 169228753Smm const void *b; 170228753Smm const char *h; 171228753Smm int r; 172228753Smm 173228753Smm ar = (struct ar*)(a->format->data); 174228753Smm 175228753Smm if (a->archive.file_position == 0) { 176228753Smm /* 177228753Smm * We are now at the beginning of the archive, 178228753Smm * so we need first consume the ar global header. 179228753Smm */ 180228753Smm __archive_read_consume(a, 8); 181228753Smm /* Set a default format code for now. */ 182228753Smm a->archive.archive_format = ARCHIVE_FORMAT_AR; 183228753Smm } 184228753Smm 185228753Smm /* Read the header for the next file entry. */ 186228753Smm if ((b = __archive_read_ahead(a, 60, &bytes_read)) == NULL) 187228753Smm /* Broken header. */ 188228753Smm return (ARCHIVE_EOF); 189228753Smm __archive_read_consume(a, 60); 190228753Smm h = (const char *)b; 191228753Smm 192228753Smm /* Verify the magic signature on the file header. */ 193228753Smm if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) { 194228753Smm archive_set_error(&a->archive, EINVAL, 195228753Smm "Incorrect file header signature"); 196228753Smm return (ARCHIVE_WARN); 197228753Smm } 198228753Smm 199228753Smm /* Copy filename into work buffer. */ 200228753Smm strncpy(filename, h + AR_name_offset, AR_name_size); 201228753Smm filename[AR_name_size] = '\0'; 202228753Smm 203228753Smm /* 204228753Smm * Guess the format variant based on the filename. 205228753Smm */ 206228753Smm if (a->archive.archive_format == ARCHIVE_FORMAT_AR) { 207228753Smm /* We don't already know the variant, so let's guess. */ 208228753Smm /* 209228753Smm * Biggest clue is presence of '/': GNU starts special 210228753Smm * filenames with '/', appends '/' as terminator to 211228753Smm * non-special names, so anything with '/' should be 212228753Smm * GNU except for BSD long filenames. 213228753Smm */ 214228753Smm if (strncmp(filename, "#1/", 3) == 0) 215228753Smm a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD; 216228753Smm else if (strchr(filename, '/') != NULL) 217228753Smm a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU; 218228753Smm else if (strncmp(filename, "__.SYMDEF", 9) == 0) 219228753Smm a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD; 220228753Smm /* 221228753Smm * XXX Do GNU/SVR4 'ar' programs ever omit trailing '/' 222228753Smm * if name exactly fills 16-byte field? If so, we 223228753Smm * can't assume entries without '/' are BSD. XXX 224228753Smm */ 225228753Smm } 226228753Smm 227228753Smm /* Update format name from the code. */ 228228753Smm if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) 229228753Smm a->archive.archive_format_name = "ar (GNU/SVR4)"; 230228753Smm else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) 231228753Smm a->archive.archive_format_name = "ar (BSD)"; 232228753Smm else 233228753Smm a->archive.archive_format_name = "ar"; 234228753Smm 235228753Smm /* 236228753Smm * Remove trailing spaces from the filename. GNU and BSD 237228753Smm * variants both pad filename area out with spaces. 238228753Smm * This will only be wrong if GNU/SVR4 'ar' implementations 239228753Smm * omit trailing '/' for 16-char filenames and we have 240228753Smm * a 16-char filename that ends in ' '. 241228753Smm */ 242228753Smm p = filename + AR_name_size - 1; 243228753Smm while (p >= filename && *p == ' ') { 244228753Smm *p = '\0'; 245228753Smm p--; 246228753Smm } 247228753Smm 248228753Smm /* 249228753Smm * Remove trailing slash unless first character is '/'. 250228753Smm * (BSD entries never end in '/', so this will only trim 251228753Smm * GNU-format entries. GNU special entries start with '/' 252228753Smm * and are not terminated in '/', so we don't trim anything 253228753Smm * that starts with '/'.) 254228753Smm */ 255228753Smm if (filename[0] != '/' && *p == '/') 256228753Smm *p = '\0'; 257228753Smm 258228753Smm /* 259228753Smm * '//' is the GNU filename table. 260228753Smm * Later entries can refer to names in this table. 261228753Smm */ 262228753Smm if (strcmp(filename, "//") == 0) { 263228753Smm /* This must come before any call to _read_ahead. */ 264228753Smm ar_parse_common_header(ar, entry, h); 265228753Smm archive_entry_copy_pathname(entry, filename); 266228753Smm archive_entry_set_filetype(entry, AE_IFREG); 267228753Smm /* Get the size of the filename table. */ 268228753Smm number = ar_atol10(h + AR_size_offset, AR_size_size); 269228753Smm if (number > SIZE_MAX) { 270228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 271228753Smm "Filename table too large"); 272228753Smm return (ARCHIVE_FATAL); 273228753Smm } 274228753Smm entry_size = (size_t)number; 275228753Smm if (entry_size == 0) { 276228753Smm archive_set_error(&a->archive, EINVAL, 277228753Smm "Invalid string table"); 278228753Smm return (ARCHIVE_WARN); 279228753Smm } 280228753Smm if (ar->strtab != NULL) { 281228753Smm archive_set_error(&a->archive, EINVAL, 282228753Smm "More than one string tables exist"); 283228753Smm return (ARCHIVE_WARN); 284228753Smm } 285228753Smm 286228753Smm /* Read the filename table into memory. */ 287228753Smm st = malloc(entry_size); 288228753Smm if (st == NULL) { 289228753Smm archive_set_error(&a->archive, ENOMEM, 290228753Smm "Can't allocate filename table buffer"); 291228753Smm return (ARCHIVE_FATAL); 292228753Smm } 293228753Smm ar->strtab = st; 294228753Smm ar->strtab_size = entry_size; 295228753Smm if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL) 296228753Smm return (ARCHIVE_FATAL); 297228753Smm memcpy(st, b, entry_size); 298228753Smm __archive_read_consume(a, entry_size); 299228753Smm /* All contents are consumed. */ 300228753Smm ar->entry_bytes_remaining = 0; 301228753Smm archive_entry_set_size(entry, ar->entry_bytes_remaining); 302228753Smm 303228753Smm /* Parse the filename table. */ 304228753Smm return (ar_parse_gnu_filename_table(a)); 305228753Smm } 306228753Smm 307228753Smm /* 308228753Smm * GNU variant handles long filenames by storing /<number> 309228753Smm * to indicate a name stored in the filename table. 310228753Smm * XXX TODO: Verify that it's all digits... Don't be fooled 311228753Smm * by "/9xyz" XXX 312228753Smm */ 313228753Smm if (filename[0] == '/' && filename[1] >= '0' && filename[1] <= '9') { 314228753Smm number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1); 315228753Smm /* 316228753Smm * If we can't look up the real name, warn and return 317228753Smm * the entry with the wrong name. 318228753Smm */ 319228753Smm if (ar->strtab == NULL || number > ar->strtab_size) { 320228753Smm archive_set_error(&a->archive, EINVAL, 321228753Smm "Can't find long filename for entry"); 322228753Smm archive_entry_copy_pathname(entry, filename); 323228753Smm /* Parse the time, owner, mode, size fields. */ 324228753Smm ar_parse_common_header(ar, entry, h); 325228753Smm return (ARCHIVE_WARN); 326228753Smm } 327228753Smm 328228753Smm archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]); 329228753Smm /* Parse the time, owner, mode, size fields. */ 330228753Smm return (ar_parse_common_header(ar, entry, h)); 331228753Smm } 332228753Smm 333228753Smm /* 334228753Smm * BSD handles long filenames by storing "#1/" followed by the 335228753Smm * length of filename as a decimal number, then prepends the 336228753Smm * the filename to the file contents. 337228753Smm */ 338228753Smm if (strncmp(filename, "#1/", 3) == 0) { 339228753Smm /* Parse the time, owner, mode, size fields. */ 340228753Smm /* This must occur before _read_ahead is called again. */ 341228753Smm ar_parse_common_header(ar, entry, h); 342228753Smm 343228753Smm /* Parse the size of the name, adjust the file size. */ 344228753Smm number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3); 345228753Smm bsd_name_length = (size_t)number; 346228753Smm /* Guard against the filename + trailing NUL 347228753Smm * overflowing a size_t and against the filename size 348228753Smm * being larger than the entire entry. */ 349228753Smm if (number > (uint64_t)(bsd_name_length + 1) 350228753Smm || (off_t)bsd_name_length > ar->entry_bytes_remaining) { 351228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 352228753Smm "Bad input file size"); 353228753Smm return (ARCHIVE_FATAL); 354228753Smm } 355228753Smm ar->entry_bytes_remaining -= bsd_name_length; 356228753Smm /* Adjust file size reported to client. */ 357228753Smm archive_entry_set_size(entry, ar->entry_bytes_remaining); 358228753Smm 359228753Smm /* Read the long name into memory. */ 360228753Smm if ((b = __archive_read_ahead(a, bsd_name_length, NULL)) == NULL) { 361228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 362228753Smm "Truncated input file"); 363228753Smm return (ARCHIVE_FATAL); 364228753Smm } 365228753Smm __archive_read_consume(a, bsd_name_length); 366228753Smm 367228753Smm /* Store it in the entry. */ 368228753Smm p = (char *)malloc(bsd_name_length + 1); 369228753Smm if (p == NULL) { 370228753Smm archive_set_error(&a->archive, ENOMEM, 371228753Smm "Can't allocate fname buffer"); 372228753Smm return (ARCHIVE_FATAL); 373228753Smm } 374228753Smm strncpy(p, b, bsd_name_length); 375228753Smm p[bsd_name_length] = '\0'; 376228753Smm archive_entry_copy_pathname(entry, p); 377228753Smm free(p); 378228753Smm return (ARCHIVE_OK); 379228753Smm } 380228753Smm 381228753Smm /* 382228753Smm * "/" is the SVR4/GNU archive symbol table. 383228753Smm */ 384228753Smm if (strcmp(filename, "/") == 0) { 385228753Smm archive_entry_copy_pathname(entry, "/"); 386228753Smm /* Parse the time, owner, mode, size fields. */ 387228753Smm r = ar_parse_common_header(ar, entry, h); 388228753Smm /* Force the file type to a regular file. */ 389228753Smm archive_entry_set_filetype(entry, AE_IFREG); 390228753Smm return (r); 391228753Smm } 392228753Smm 393228753Smm /* 394228753Smm * "__.SYMDEF" is a BSD archive symbol table. 395228753Smm */ 396228753Smm if (strcmp(filename, "__.SYMDEF") == 0) { 397228753Smm archive_entry_copy_pathname(entry, filename); 398228753Smm /* Parse the time, owner, mode, size fields. */ 399228753Smm return (ar_parse_common_header(ar, entry, h)); 400228753Smm } 401228753Smm 402228753Smm /* 403228753Smm * Otherwise, this is a standard entry. The filename 404228753Smm * has already been trimmed as much as possible, based 405228753Smm * on our current knowledge of the format. 406228753Smm */ 407228753Smm archive_entry_copy_pathname(entry, filename); 408228753Smm return (ar_parse_common_header(ar, entry, h)); 409228753Smm} 410228753Smm 411228753Smmstatic int 412228753Smmar_parse_common_header(struct ar *ar, struct archive_entry *entry, 413228753Smm const char *h) 414228753Smm{ 415228753Smm uint64_t n; 416228753Smm 417228753Smm /* Copy remaining header */ 418228753Smm archive_entry_set_mtime(entry, 419228753Smm (time_t)ar_atol10(h + AR_date_offset, AR_date_size), 0L); 420228753Smm archive_entry_set_uid(entry, 421228753Smm (uid_t)ar_atol10(h + AR_uid_offset, AR_uid_size)); 422228753Smm archive_entry_set_gid(entry, 423228753Smm (gid_t)ar_atol10(h + AR_gid_offset, AR_gid_size)); 424228753Smm archive_entry_set_mode(entry, 425228753Smm (mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size)); 426228753Smm n = ar_atol10(h + AR_size_offset, AR_size_size); 427228753Smm 428228753Smm ar->entry_offset = 0; 429228753Smm ar->entry_padding = n % 2; 430228753Smm archive_entry_set_size(entry, n); 431228753Smm ar->entry_bytes_remaining = n; 432228753Smm return (ARCHIVE_OK); 433228753Smm} 434228753Smm 435228753Smmstatic int 436228753Smmarchive_read_format_ar_read_data(struct archive_read *a, 437228753Smm const void **buff, size_t *size, off_t *offset) 438228753Smm{ 439228753Smm ssize_t bytes_read; 440228753Smm struct ar *ar; 441228753Smm 442228753Smm ar = (struct ar *)(a->format->data); 443228753Smm 444228753Smm if (ar->entry_bytes_remaining > 0) { 445228753Smm *buff = __archive_read_ahead(a, 1, &bytes_read); 446228753Smm if (bytes_read == 0) { 447228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 448228753Smm "Truncated ar archive"); 449228753Smm return (ARCHIVE_FATAL); 450228753Smm } 451228753Smm if (bytes_read < 0) 452228753Smm return (ARCHIVE_FATAL); 453228753Smm if (bytes_read > ar->entry_bytes_remaining) 454228753Smm bytes_read = (ssize_t)ar->entry_bytes_remaining; 455228753Smm *size = bytes_read; 456228753Smm *offset = ar->entry_offset; 457228753Smm ar->entry_offset += bytes_read; 458228753Smm ar->entry_bytes_remaining -= bytes_read; 459228753Smm __archive_read_consume(a, (size_t)bytes_read); 460228753Smm return (ARCHIVE_OK); 461228753Smm } else { 462228753Smm while (ar->entry_padding > 0) { 463228753Smm *buff = __archive_read_ahead(a, 1, &bytes_read); 464228753Smm if (bytes_read <= 0) 465228753Smm return (ARCHIVE_FATAL); 466228753Smm if (bytes_read > ar->entry_padding) 467228753Smm bytes_read = (ssize_t)ar->entry_padding; 468228753Smm __archive_read_consume(a, (size_t)bytes_read); 469228753Smm ar->entry_padding -= bytes_read; 470228753Smm } 471228753Smm *buff = NULL; 472228753Smm *size = 0; 473228753Smm *offset = ar->entry_offset; 474228753Smm return (ARCHIVE_EOF); 475228753Smm } 476228753Smm} 477228753Smm 478228753Smmstatic int 479228753Smmarchive_read_format_ar_skip(struct archive_read *a) 480228753Smm{ 481228753Smm off_t bytes_skipped; 482228753Smm struct ar* ar; 483228753Smm 484228753Smm ar = (struct ar *)(a->format->data); 485228753Smm 486228753Smm bytes_skipped = __archive_read_skip(a, 487228753Smm ar->entry_bytes_remaining + ar->entry_padding); 488228753Smm if (bytes_skipped < 0) 489228753Smm return (ARCHIVE_FATAL); 490228753Smm 491228753Smm ar->entry_bytes_remaining = 0; 492228753Smm ar->entry_padding = 0; 493228753Smm 494228753Smm return (ARCHIVE_OK); 495228753Smm} 496228753Smm 497228753Smmstatic int 498228753Smmar_parse_gnu_filename_table(struct archive_read *a) 499228753Smm{ 500228753Smm struct ar *ar; 501228753Smm char *p; 502228753Smm size_t size; 503228753Smm 504228753Smm ar = (struct ar*)(a->format->data); 505228753Smm size = ar->strtab_size; 506228753Smm 507228753Smm for (p = ar->strtab; p < ar->strtab + size - 1; ++p) { 508228753Smm if (*p == '/') { 509228753Smm *p++ = '\0'; 510228753Smm if (*p != '\n') 511228753Smm goto bad_string_table; 512228753Smm *p = '\0'; 513228753Smm } 514228753Smm } 515228753Smm /* 516228753Smm * GNU ar always pads the table to an even size. 517228753Smm * The pad character is either '\n' or '`'. 518228753Smm */ 519228753Smm if (p != ar->strtab + size && *p != '\n' && *p != '`') 520228753Smm goto bad_string_table; 521228753Smm 522228753Smm /* Enforce zero termination. */ 523228753Smm ar->strtab[size - 1] = '\0'; 524228753Smm 525228753Smm return (ARCHIVE_OK); 526228753Smm 527228753Smmbad_string_table: 528228753Smm archive_set_error(&a->archive, EINVAL, 529228753Smm "Invalid string table"); 530228753Smm free(ar->strtab); 531228753Smm ar->strtab = NULL; 532228753Smm return (ARCHIVE_WARN); 533228753Smm} 534228753Smm 535228753Smmstatic uint64_t 536228753Smmar_atol8(const char *p, unsigned char_cnt) 537228753Smm{ 538228753Smm uint64_t l, limit, last_digit_limit; 539228753Smm unsigned int digit, base; 540228753Smm 541228753Smm base = 8; 542228753Smm limit = UINT64_MAX / base; 543228753Smm last_digit_limit = UINT64_MAX % base; 544228753Smm 545228753Smm while ((*p == ' ' || *p == '\t') && char_cnt-- > 0) 546228753Smm p++; 547228753Smm 548228753Smm l = 0; 549228753Smm digit = *p - '0'; 550228753Smm while (*p >= '0' && digit < base && char_cnt-- > 0) { 551228753Smm if (l>limit || (l == limit && digit > last_digit_limit)) { 552228753Smm l = UINT64_MAX; /* Truncate on overflow. */ 553228753Smm break; 554228753Smm } 555228753Smm l = (l * base) + digit; 556228753Smm digit = *++p - '0'; 557228753Smm } 558228753Smm return (l); 559228753Smm} 560228753Smm 561228753Smmstatic uint64_t 562228753Smmar_atol10(const char *p, unsigned char_cnt) 563228753Smm{ 564228753Smm uint64_t l, limit, last_digit_limit; 565228753Smm unsigned int base, digit; 566228753Smm 567228753Smm base = 10; 568228753Smm limit = UINT64_MAX / base; 569228753Smm last_digit_limit = UINT64_MAX % base; 570228753Smm 571228753Smm while ((*p == ' ' || *p == '\t') && char_cnt-- > 0) 572228753Smm p++; 573228753Smm l = 0; 574228753Smm digit = *p - '0'; 575228753Smm while (*p >= '0' && digit < base && char_cnt-- > 0) { 576228753Smm if (l > limit || (l == limit && digit > last_digit_limit)) { 577228753Smm l = UINT64_MAX; /* Truncate on overflow. */ 578228753Smm break; 579228753Smm } 580228753Smm l = (l * base) + digit; 581228753Smm digit = *++p - '0'; 582228753Smm } 583228753Smm return (l); 584228753Smm} 585