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"
29228763Smm__FBSDID("$FreeBSD: stable/10/contrib/libarchive/libarchive/archive_read_support_format_ar.c 344674 2019-02-28 22:57:09Z mm $");
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 {
53232153Smm	int64_t	 entry_bytes_remaining;
54232153Smm	/* unconsumed is purely to track data we've gotten from readahead,
55232153Smm	 * but haven't yet marked as consumed.  Must be paired with
56232153Smm	 * entry_bytes_remaining usage/modification.
57232153Smm	 */
58232153Smm	size_t   entry_bytes_unconsumed;
59232153Smm	int64_t	 entry_offset;
60232153Smm	int64_t	 entry_padding;
61228753Smm	char	*strtab;
62228753Smm	size_t	 strtab_size;
63232153Smm	char	 read_global_header;
64228753Smm};
65228753Smm
66228753Smm/*
67228753Smm * Define structure of the "ar" header.
68228753Smm */
69228753Smm#define AR_name_offset 0
70228753Smm#define AR_name_size 16
71228753Smm#define AR_date_offset 16
72228753Smm#define AR_date_size 12
73228753Smm#define AR_uid_offset 28
74228753Smm#define AR_uid_size 6
75228753Smm#define AR_gid_offset 34
76228753Smm#define AR_gid_size 6
77228753Smm#define AR_mode_offset 40
78228753Smm#define AR_mode_size 8
79228753Smm#define AR_size_offset 48
80228753Smm#define AR_size_size 10
81228753Smm#define AR_fmag_offset 58
82228753Smm#define AR_fmag_size 2
83228753Smm
84232153Smmstatic int	archive_read_format_ar_bid(struct archive_read *a, int);
85228753Smmstatic int	archive_read_format_ar_cleanup(struct archive_read *a);
86228753Smmstatic int	archive_read_format_ar_read_data(struct archive_read *a,
87232153Smm		    const void **buff, size_t *size, int64_t *offset);
88228753Smmstatic int	archive_read_format_ar_skip(struct archive_read *a);
89228753Smmstatic int	archive_read_format_ar_read_header(struct archive_read *a,
90228753Smm		    struct archive_entry *e);
91228753Smmstatic uint64_t	ar_atol8(const char *p, unsigned char_cnt);
92228753Smmstatic uint64_t	ar_atol10(const char *p, unsigned char_cnt);
93228753Smmstatic int	ar_parse_gnu_filename_table(struct archive_read *a);
94228753Smmstatic int	ar_parse_common_header(struct ar *ar, struct archive_entry *,
95228753Smm		    const char *h);
96228753Smm
97228753Smmint
98228753Smmarchive_read_support_format_ar(struct archive *_a)
99228753Smm{
100228753Smm	struct archive_read *a = (struct archive_read *)_a;
101228753Smm	struct ar *ar;
102228753Smm	int r;
103228753Smm
104232153Smm	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
105232153Smm	    ARCHIVE_STATE_NEW, "archive_read_support_format_ar");
106232153Smm
107311042Smm	ar = (struct ar *)calloc(1, sizeof(*ar));
108228753Smm	if (ar == NULL) {
109228753Smm		archive_set_error(&a->archive, ENOMEM,
110228753Smm		    "Can't allocate ar data");
111228753Smm		return (ARCHIVE_FATAL);
112228753Smm	}
113228753Smm	ar->strtab = NULL;
114228753Smm
115228753Smm	r = __archive_read_register_format(a,
116228753Smm	    ar,
117228753Smm	    "ar",
118228753Smm	    archive_read_format_ar_bid,
119228753Smm	    NULL,
120228753Smm	    archive_read_format_ar_read_header,
121228753Smm	    archive_read_format_ar_read_data,
122228753Smm	    archive_read_format_ar_skip,
123248616Smm	    NULL,
124302001Smm	    archive_read_format_ar_cleanup,
125302001Smm	    NULL,
126302001Smm	    NULL);
127228753Smm
128228753Smm	if (r != ARCHIVE_OK) {
129228753Smm		free(ar);
130228753Smm		return (r);
131228753Smm	}
132228753Smm	return (ARCHIVE_OK);
133228753Smm}
134228753Smm
135228753Smmstatic int
136228753Smmarchive_read_format_ar_cleanup(struct archive_read *a)
137228753Smm{
138228753Smm	struct ar *ar;
139228753Smm
140228753Smm	ar = (struct ar *)(a->format->data);
141344674Smm	free(ar->strtab);
142228753Smm	free(ar);
143228753Smm	(a->format->data) = NULL;
144228753Smm	return (ARCHIVE_OK);
145228753Smm}
146228753Smm
147228753Smmstatic int
148232153Smmarchive_read_format_ar_bid(struct archive_read *a, int best_bid)
149228753Smm{
150228753Smm	const void *h;
151228753Smm
152232153Smm	(void)best_bid; /* UNUSED */
153228753Smm
154228753Smm	/*
155228753Smm	 * Verify the 8-byte file signature.
156228753Smm	 * TODO: Do we need to check more than this?
157228753Smm	 */
158228753Smm	if ((h = __archive_read_ahead(a, 8, NULL)) == NULL)
159228753Smm		return (-1);
160232153Smm	if (memcmp(h, "!<arch>\n", 8) == 0) {
161228753Smm		return (64);
162228753Smm	}
163228753Smm	return (-1);
164228753Smm}
165228753Smm
166228753Smmstatic int
167232153Smm_ar_read_header(struct archive_read *a, struct archive_entry *entry,
168232153Smm	struct ar *ar, const char *h, size_t *unconsumed)
169228753Smm{
170228753Smm	char filename[AR_name_size + 1];
171228753Smm	uint64_t number; /* Used to hold parsed numbers before validation. */
172228753Smm	size_t bsd_name_length, entry_size;
173228753Smm	char *p, *st;
174228753Smm	const void *b;
175228753Smm	int r;
176228753Smm
177228753Smm	/* Verify the magic signature on the file header. */
178228753Smm	if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) {
179228753Smm		archive_set_error(&a->archive, EINVAL,
180228753Smm		    "Incorrect file header signature");
181302001Smm		return (ARCHIVE_FATAL);
182228753Smm	}
183228753Smm
184228753Smm	/* Copy filename into work buffer. */
185228753Smm	strncpy(filename, h + AR_name_offset, AR_name_size);
186228753Smm	filename[AR_name_size] = '\0';
187228753Smm
188228753Smm	/*
189228753Smm	 * Guess the format variant based on the filename.
190228753Smm	 */
191228753Smm	if (a->archive.archive_format == ARCHIVE_FORMAT_AR) {
192228753Smm		/* We don't already know the variant, so let's guess. */
193228753Smm		/*
194228753Smm		 * Biggest clue is presence of '/': GNU starts special
195228753Smm		 * filenames with '/', appends '/' as terminator to
196228753Smm		 * non-special names, so anything with '/' should be
197228753Smm		 * GNU except for BSD long filenames.
198228753Smm		 */
199228753Smm		if (strncmp(filename, "#1/", 3) == 0)
200228753Smm			a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD;
201228753Smm		else if (strchr(filename, '/') != NULL)
202228753Smm			a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU;
203228753Smm		else if (strncmp(filename, "__.SYMDEF", 9) == 0)
204228753Smm			a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD;
205228753Smm		/*
206228753Smm		 * XXX Do GNU/SVR4 'ar' programs ever omit trailing '/'
207228753Smm		 * if name exactly fills 16-byte field?  If so, we
208228753Smm		 * can't assume entries without '/' are BSD. XXX
209228753Smm		 */
210228753Smm	}
211228753Smm
212228753Smm	/* Update format name from the code. */
213228753Smm	if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU)
214228753Smm		a->archive.archive_format_name = "ar (GNU/SVR4)";
215228753Smm	else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD)
216228753Smm		a->archive.archive_format_name = "ar (BSD)";
217228753Smm	else
218228753Smm		a->archive.archive_format_name = "ar";
219228753Smm
220228753Smm	/*
221228753Smm	 * Remove trailing spaces from the filename.  GNU and BSD
222228753Smm	 * variants both pad filename area out with spaces.
223228753Smm	 * This will only be wrong if GNU/SVR4 'ar' implementations
224228753Smm	 * omit trailing '/' for 16-char filenames and we have
225228753Smm	 * a 16-char filename that ends in ' '.
226228753Smm	 */
227228753Smm	p = filename + AR_name_size - 1;
228228753Smm	while (p >= filename && *p == ' ') {
229228753Smm		*p = '\0';
230228753Smm		p--;
231228753Smm	}
232228753Smm
233228753Smm	/*
234228753Smm	 * Remove trailing slash unless first character is '/'.
235228753Smm	 * (BSD entries never end in '/', so this will only trim
236228753Smm	 * GNU-format entries.  GNU special entries start with '/'
237228753Smm	 * and are not terminated in '/', so we don't trim anything
238228753Smm	 * that starts with '/'.)
239228753Smm	 */
240302001Smm	if (filename[0] != '/' && p > filename && *p == '/') {
241228753Smm		*p = '\0';
242302001Smm	}
243228753Smm
244302001Smm	if (p < filename) {
245302001Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
246302001Smm		    "Found entry with empty filename");
247302001Smm		return (ARCHIVE_FATAL);
248302001Smm	}
249302001Smm
250228753Smm	/*
251228753Smm	 * '//' is the GNU filename table.
252228753Smm	 * Later entries can refer to names in this table.
253228753Smm	 */
254228753Smm	if (strcmp(filename, "//") == 0) {
255228753Smm		/* This must come before any call to _read_ahead. */
256228753Smm		ar_parse_common_header(ar, entry, h);
257228753Smm		archive_entry_copy_pathname(entry, filename);
258228753Smm		archive_entry_set_filetype(entry, AE_IFREG);
259228753Smm		/* Get the size of the filename table. */
260228753Smm		number = ar_atol10(h + AR_size_offset, AR_size_size);
261311042Smm		if (number > SIZE_MAX || number > 1024 * 1024 * 1024) {
262228753Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
263228753Smm			    "Filename table too large");
264228753Smm			return (ARCHIVE_FATAL);
265228753Smm		}
266228753Smm		entry_size = (size_t)number;
267228753Smm		if (entry_size == 0) {
268228753Smm			archive_set_error(&a->archive, EINVAL,
269228753Smm			    "Invalid string table");
270302001Smm			return (ARCHIVE_FATAL);
271228753Smm		}
272228753Smm		if (ar->strtab != NULL) {
273228753Smm			archive_set_error(&a->archive, EINVAL,
274228753Smm			    "More than one string tables exist");
275302001Smm			return (ARCHIVE_FATAL);
276228753Smm		}
277228753Smm
278228753Smm		/* Read the filename table into memory. */
279228753Smm		st = malloc(entry_size);
280228753Smm		if (st == NULL) {
281228753Smm			archive_set_error(&a->archive, ENOMEM,
282228753Smm			    "Can't allocate filename table buffer");
283228753Smm			return (ARCHIVE_FATAL);
284228753Smm		}
285228753Smm		ar->strtab = st;
286228753Smm		ar->strtab_size = entry_size;
287232153Smm
288232153Smm		if (*unconsumed) {
289232153Smm			__archive_read_consume(a, *unconsumed);
290232153Smm			*unconsumed = 0;
291232153Smm		}
292232153Smm
293228753Smm		if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL)
294228753Smm			return (ARCHIVE_FATAL);
295228753Smm		memcpy(st, b, entry_size);
296228753Smm		__archive_read_consume(a, entry_size);
297228753Smm		/* All contents are consumed. */
298228753Smm		ar->entry_bytes_remaining = 0;
299228753Smm		archive_entry_set_size(entry, ar->entry_bytes_remaining);
300228753Smm
301228753Smm		/* Parse the filename table. */
302228753Smm		return (ar_parse_gnu_filename_table(a));
303228753Smm	}
304228753Smm
305228753Smm	/*
306228753Smm	 * GNU variant handles long filenames by storing /<number>
307228753Smm	 * to indicate a name stored in the filename table.
308228753Smm	 * XXX TODO: Verify that it's all digits... Don't be fooled
309228753Smm	 * by "/9xyz" XXX
310228753Smm	 */
311228753Smm	if (filename[0] == '/' && filename[1] >= '0' && filename[1] <= '9') {
312228753Smm		number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1);
313228753Smm		/*
314228753Smm		 * If we can't look up the real name, warn and return
315228753Smm		 * the entry with the wrong name.
316228753Smm		 */
317311042Smm		if (ar->strtab == NULL || number >= ar->strtab_size) {
318228753Smm			archive_set_error(&a->archive, EINVAL,
319302001Smm			    "Can't find long filename for GNU/SVR4 archive entry");
320228753Smm			archive_entry_copy_pathname(entry, filename);
321228753Smm			/* Parse the time, owner, mode, size fields. */
322228753Smm			ar_parse_common_header(ar, entry, h);
323302001Smm			return (ARCHIVE_FATAL);
324228753Smm		}
325228753Smm
326228753Smm		archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]);
327228753Smm		/* Parse the time, owner, mode, size fields. */
328228753Smm		return (ar_parse_common_header(ar, entry, h));
329228753Smm	}
330228753Smm
331228753Smm	/*
332228753Smm	 * BSD handles long filenames by storing "#1/" followed by the
333228753Smm	 * length of filename as a decimal number, then prepends the
334228753Smm	 * the filename to the file contents.
335228753Smm	 */
336228753Smm	if (strncmp(filename, "#1/", 3) == 0) {
337228753Smm		/* Parse the time, owner, mode, size fields. */
338228753Smm		/* This must occur before _read_ahead is called again. */
339228753Smm		ar_parse_common_header(ar, entry, h);
340228753Smm
341228753Smm		/* Parse the size of the name, adjust the file size. */
342228753Smm		number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3);
343311042Smm		/* Sanity check the filename length:
344311042Smm		 *   = Must be <= SIZE_MAX - 1
345311042Smm		 *   = Must be <= 1MB
346311042Smm		 *   = Cannot be bigger than the entire entry
347311042Smm		 */
348311042Smm		if (number > SIZE_MAX - 1
349311042Smm		    || number > 1024 * 1024
350311042Smm		    || (int64_t)number > ar->entry_bytes_remaining) {
351228753Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
352228753Smm			    "Bad input file size");
353228753Smm			return (ARCHIVE_FATAL);
354228753Smm		}
355311042Smm		bsd_name_length = (size_t)number;
356228753Smm		ar->entry_bytes_remaining -= bsd_name_length;
357228753Smm		/* Adjust file size reported to client. */
358228753Smm		archive_entry_set_size(entry, ar->entry_bytes_remaining);
359228753Smm
360232153Smm		if (*unconsumed) {
361232153Smm			__archive_read_consume(a, *unconsumed);
362232153Smm			*unconsumed = 0;
363232153Smm		}
364232153Smm
365228753Smm		/* Read the long name into memory. */
366228753Smm		if ((b = __archive_read_ahead(a, bsd_name_length, NULL)) == NULL) {
367228753Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
368228753Smm			    "Truncated input file");
369228753Smm			return (ARCHIVE_FATAL);
370228753Smm		}
371228753Smm		/* Store it in the entry. */
372228753Smm		p = (char *)malloc(bsd_name_length + 1);
373228753Smm		if (p == NULL) {
374228753Smm			archive_set_error(&a->archive, ENOMEM,
375228753Smm			    "Can't allocate fname buffer");
376228753Smm			return (ARCHIVE_FATAL);
377228753Smm		}
378228753Smm		strncpy(p, b, bsd_name_length);
379228753Smm		p[bsd_name_length] = '\0';
380232153Smm
381232153Smm		__archive_read_consume(a, bsd_name_length);
382232153Smm
383228753Smm		archive_entry_copy_pathname(entry, p);
384228753Smm		free(p);
385228753Smm		return (ARCHIVE_OK);
386228753Smm	}
387228753Smm
388228753Smm	/*
389228753Smm	 * "/" is the SVR4/GNU archive symbol table.
390344674Smm	 * "/SYM64/" is the SVR4/GNU 64-bit variant archive symbol table.
391228753Smm	 */
392344674Smm	if (strcmp(filename, "/") == 0 || strcmp(filename, "/SYM64/") == 0) {
393344674Smm		archive_entry_copy_pathname(entry, filename);
394228753Smm		/* Parse the time, owner, mode, size fields. */
395228753Smm		r = ar_parse_common_header(ar, entry, h);
396228753Smm		/* Force the file type to a regular file. */
397228753Smm		archive_entry_set_filetype(entry, AE_IFREG);
398228753Smm		return (r);
399228753Smm	}
400228753Smm
401228753Smm	/*
402228753Smm	 * "__.SYMDEF" is a BSD archive symbol table.
403228753Smm	 */
404228753Smm	if (strcmp(filename, "__.SYMDEF") == 0) {
405228753Smm		archive_entry_copy_pathname(entry, filename);
406228753Smm		/* Parse the time, owner, mode, size fields. */
407228753Smm		return (ar_parse_common_header(ar, entry, h));
408228753Smm	}
409228753Smm
410228753Smm	/*
411228753Smm	 * Otherwise, this is a standard entry.  The filename
412228753Smm	 * has already been trimmed as much as possible, based
413228753Smm	 * on our current knowledge of the format.
414228753Smm	 */
415228753Smm	archive_entry_copy_pathname(entry, filename);
416228753Smm	return (ar_parse_common_header(ar, entry, h));
417228753Smm}
418228753Smm
419228753Smmstatic int
420232153Smmarchive_read_format_ar_read_header(struct archive_read *a,
421232153Smm    struct archive_entry *entry)
422232153Smm{
423232153Smm	struct ar *ar = (struct ar*)(a->format->data);
424232153Smm	size_t unconsumed;
425232153Smm	const void *header_data;
426232153Smm	int ret;
427232153Smm
428232153Smm	if (!ar->read_global_header) {
429232153Smm		/*
430232153Smm		 * We are now at the beginning of the archive,
431232153Smm		 * so we need first consume the ar global header.
432232153Smm		 */
433232153Smm		__archive_read_consume(a, 8);
434232153Smm		ar->read_global_header = 1;
435232153Smm		/* Set a default format code for now. */
436232153Smm		a->archive.archive_format = ARCHIVE_FORMAT_AR;
437232153Smm	}
438232153Smm
439232153Smm	/* Read the header for the next file entry. */
440232153Smm	if ((header_data = __archive_read_ahead(a, 60, NULL)) == NULL)
441232153Smm		/* Broken header. */
442232153Smm		return (ARCHIVE_EOF);
443232153Smm
444232153Smm	unconsumed = 60;
445232153Smm
446232153Smm	ret = _ar_read_header(a, entry, ar, (const char *)header_data, &unconsumed);
447232153Smm
448232153Smm	if (unconsumed)
449232153Smm		__archive_read_consume(a, unconsumed);
450232153Smm
451232153Smm	return ret;
452232153Smm}
453232153Smm
454232153Smm
455232153Smmstatic int
456228753Smmar_parse_common_header(struct ar *ar, struct archive_entry *entry,
457228753Smm    const char *h)
458228753Smm{
459228753Smm	uint64_t n;
460228753Smm
461228753Smm	/* Copy remaining header */
462339006Smm	archive_entry_set_filetype(entry, AE_IFREG);
463228753Smm	archive_entry_set_mtime(entry,
464228753Smm	    (time_t)ar_atol10(h + AR_date_offset, AR_date_size), 0L);
465228753Smm	archive_entry_set_uid(entry,
466228753Smm	    (uid_t)ar_atol10(h + AR_uid_offset, AR_uid_size));
467228753Smm	archive_entry_set_gid(entry,
468228753Smm	    (gid_t)ar_atol10(h + AR_gid_offset, AR_gid_size));
469228753Smm	archive_entry_set_mode(entry,
470228753Smm	    (mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size));
471228753Smm	n = ar_atol10(h + AR_size_offset, AR_size_size);
472228753Smm
473228753Smm	ar->entry_offset = 0;
474228753Smm	ar->entry_padding = n % 2;
475228753Smm	archive_entry_set_size(entry, n);
476228753Smm	ar->entry_bytes_remaining = n;
477228753Smm	return (ARCHIVE_OK);
478228753Smm}
479228753Smm
480228753Smmstatic int
481228753Smmarchive_read_format_ar_read_data(struct archive_read *a,
482232153Smm    const void **buff, size_t *size, int64_t *offset)
483228753Smm{
484228753Smm	ssize_t bytes_read;
485228753Smm	struct ar *ar;
486228753Smm
487228753Smm	ar = (struct ar *)(a->format->data);
488228753Smm
489232153Smm	if (ar->entry_bytes_unconsumed) {
490232153Smm		__archive_read_consume(a, ar->entry_bytes_unconsumed);
491232153Smm		ar->entry_bytes_unconsumed = 0;
492232153Smm	}
493232153Smm
494228753Smm	if (ar->entry_bytes_remaining > 0) {
495228753Smm		*buff = __archive_read_ahead(a, 1, &bytes_read);
496228753Smm		if (bytes_read == 0) {
497228753Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
498228753Smm			    "Truncated ar archive");
499228753Smm			return (ARCHIVE_FATAL);
500228753Smm		}
501228753Smm		if (bytes_read < 0)
502228753Smm			return (ARCHIVE_FATAL);
503228753Smm		if (bytes_read > ar->entry_bytes_remaining)
504228753Smm			bytes_read = (ssize_t)ar->entry_bytes_remaining;
505228753Smm		*size = bytes_read;
506232153Smm		ar->entry_bytes_unconsumed = bytes_read;
507228753Smm		*offset = ar->entry_offset;
508228753Smm		ar->entry_offset += bytes_read;
509228753Smm		ar->entry_bytes_remaining -= bytes_read;
510228753Smm		return (ARCHIVE_OK);
511228753Smm	} else {
512232153Smm		int64_t skipped = __archive_read_consume(a, ar->entry_padding);
513232153Smm		if (skipped >= 0) {
514232153Smm			ar->entry_padding -= skipped;
515228753Smm		}
516232153Smm		if (ar->entry_padding) {
517232153Smm			if (skipped >= 0) {
518232153Smm				archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
519232153Smm					"Truncated ar archive- failed consuming padding");
520232153Smm			}
521232153Smm			return (ARCHIVE_FATAL);
522232153Smm		}
523228753Smm		*buff = NULL;
524228753Smm		*size = 0;
525228753Smm		*offset = ar->entry_offset;
526228753Smm		return (ARCHIVE_EOF);
527228753Smm	}
528228753Smm}
529228753Smm
530228753Smmstatic int
531228753Smmarchive_read_format_ar_skip(struct archive_read *a)
532228753Smm{
533232153Smm	int64_t bytes_skipped;
534228753Smm	struct ar* ar;
535228753Smm
536228753Smm	ar = (struct ar *)(a->format->data);
537228753Smm
538232153Smm	bytes_skipped = __archive_read_consume(a,
539232153Smm	    ar->entry_bytes_remaining + ar->entry_padding
540232153Smm	    + ar->entry_bytes_unconsumed);
541228753Smm	if (bytes_skipped < 0)
542228753Smm		return (ARCHIVE_FATAL);
543228753Smm
544228753Smm	ar->entry_bytes_remaining = 0;
545232153Smm	ar->entry_bytes_unconsumed = 0;
546228753Smm	ar->entry_padding = 0;
547228753Smm
548228753Smm	return (ARCHIVE_OK);
549228753Smm}
550228753Smm
551228753Smmstatic int
552228753Smmar_parse_gnu_filename_table(struct archive_read *a)
553228753Smm{
554228753Smm	struct ar *ar;
555228753Smm	char *p;
556228753Smm	size_t size;
557228753Smm
558228753Smm	ar = (struct ar*)(a->format->data);
559228753Smm	size = ar->strtab_size;
560228753Smm
561228753Smm	for (p = ar->strtab; p < ar->strtab + size - 1; ++p) {
562228753Smm		if (*p == '/') {
563228753Smm			*p++ = '\0';
564228753Smm			if (*p != '\n')
565228753Smm				goto bad_string_table;
566228753Smm			*p = '\0';
567228753Smm		}
568228753Smm	}
569228753Smm	/*
570228753Smm	 * GNU ar always pads the table to an even size.
571228753Smm	 * The pad character is either '\n' or '`'.
572228753Smm	 */
573228753Smm	if (p != ar->strtab + size && *p != '\n' && *p != '`')
574228753Smm		goto bad_string_table;
575228753Smm
576228753Smm	/* Enforce zero termination. */
577228753Smm	ar->strtab[size - 1] = '\0';
578228753Smm
579228753Smm	return (ARCHIVE_OK);
580228753Smm
581228753Smmbad_string_table:
582228753Smm	archive_set_error(&a->archive, EINVAL,
583228753Smm	    "Invalid string table");
584228753Smm	free(ar->strtab);
585228753Smm	ar->strtab = NULL;
586302001Smm	return (ARCHIVE_FATAL);
587228753Smm}
588228753Smm
589228753Smmstatic uint64_t
590228753Smmar_atol8(const char *p, unsigned char_cnt)
591228753Smm{
592228753Smm	uint64_t l, limit, last_digit_limit;
593228753Smm	unsigned int digit, base;
594228753Smm
595228753Smm	base = 8;
596228753Smm	limit = UINT64_MAX / base;
597228753Smm	last_digit_limit = UINT64_MAX % base;
598228753Smm
599228753Smm	while ((*p == ' ' || *p == '\t') && char_cnt-- > 0)
600228753Smm		p++;
601228753Smm
602228753Smm	l = 0;
603228753Smm	digit = *p - '0';
604228753Smm	while (*p >= '0' && digit < base  && char_cnt-- > 0) {
605228753Smm		if (l>limit || (l == limit && digit > last_digit_limit)) {
606228753Smm			l = UINT64_MAX; /* Truncate on overflow. */
607228753Smm			break;
608228753Smm		}
609228753Smm		l = (l * base) + digit;
610228753Smm		digit = *++p - '0';
611228753Smm	}
612228753Smm	return (l);
613228753Smm}
614228753Smm
615228753Smmstatic uint64_t
616228753Smmar_atol10(const char *p, unsigned char_cnt)
617228753Smm{
618228753Smm	uint64_t l, limit, last_digit_limit;
619228753Smm	unsigned int base, digit;
620228753Smm
621228753Smm	base = 10;
622228753Smm	limit = UINT64_MAX / base;
623228753Smm	last_digit_limit = UINT64_MAX % base;
624228753Smm
625228753Smm	while ((*p == ' ' || *p == '\t') && char_cnt-- > 0)
626228753Smm		p++;
627228753Smm	l = 0;
628228753Smm	digit = *p - '0';
629228753Smm	while (*p >= '0' && digit < base  && char_cnt-- > 0) {
630228753Smm		if (l > limit || (l == limit && digit > last_digit_limit)) {
631228753Smm			l = UINT64_MAX; /* Truncate on overflow. */
632228753Smm			break;
633228753Smm		}
634228753Smm		l = (l * base) + digit;
635228753Smm		digit = *++p - '0';
636228753Smm	}
637228753Smm	return (l);
638228753Smm}
639