xref: /dflybsd-src/contrib/libarchive/libarchive/archive_read_support_format_cpio.c (revision afd311f52496a4b5c3df02ea6d4bdab591886c60)
160b4ad09SPeter Avalos /*-
260b4ad09SPeter Avalos  * Copyright (c) 2003-2007 Tim Kientzle
359bf7050SPeter Avalos  * Copyright (c) 2010-2012 Michihiro NAKAJIMA
460b4ad09SPeter Avalos  * All rights reserved.
560b4ad09SPeter Avalos  *
660b4ad09SPeter Avalos  * Redistribution and use in source and binary forms, with or without
760b4ad09SPeter Avalos  * modification, are permitted provided that the following conditions
860b4ad09SPeter Avalos  * are met:
960b4ad09SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
1060b4ad09SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1160b4ad09SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1260b4ad09SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1360b4ad09SPeter Avalos  *    documentation and/or other materials provided with the distribution.
1460b4ad09SPeter Avalos  *
1560b4ad09SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
1660b4ad09SPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1760b4ad09SPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1860b4ad09SPeter Avalos  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
1960b4ad09SPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2060b4ad09SPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2160b4ad09SPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2260b4ad09SPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2360b4ad09SPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2460b4ad09SPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2560b4ad09SPeter Avalos  */
2660b4ad09SPeter Avalos 
2760b4ad09SPeter Avalos #include "archive_platform.h"
289c82a63eSPeter Avalos __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_cpio.c 201163 2009-12-29 05:50:34Z kientzle $");
2960b4ad09SPeter Avalos 
3060b4ad09SPeter Avalos #ifdef HAVE_ERRNO_H
3160b4ad09SPeter Avalos #include <errno.h>
3260b4ad09SPeter Avalos #endif
3360b4ad09SPeter Avalos /* #include <stdint.h> */ /* See archive_platform.h */
3460b4ad09SPeter Avalos #ifdef HAVE_STDLIB_H
3560b4ad09SPeter Avalos #include <stdlib.h>
3660b4ad09SPeter Avalos #endif
3760b4ad09SPeter Avalos #ifdef HAVE_STRING_H
3860b4ad09SPeter Avalos #include <string.h>
3960b4ad09SPeter Avalos #endif
4060b4ad09SPeter Avalos 
4160b4ad09SPeter Avalos #include "archive.h"
4260b4ad09SPeter Avalos #include "archive_entry.h"
43c09f92d2SPeter Avalos #include "archive_entry_locale.h"
4460b4ad09SPeter Avalos #include "archive_private.h"
4560b4ad09SPeter Avalos #include "archive_read_private.h"
4660b4ad09SPeter Avalos 
47c09f92d2SPeter Avalos #define	bin_magic_offset 0
48c09f92d2SPeter Avalos #define	bin_magic_size 2
49c09f92d2SPeter Avalos #define	bin_dev_offset 2
50c09f92d2SPeter Avalos #define	bin_dev_size 2
51c09f92d2SPeter Avalos #define	bin_ino_offset 4
52c09f92d2SPeter Avalos #define	bin_ino_size 2
53c09f92d2SPeter Avalos #define	bin_mode_offset 6
54c09f92d2SPeter Avalos #define	bin_mode_size 2
55c09f92d2SPeter Avalos #define	bin_uid_offset 8
56c09f92d2SPeter Avalos #define	bin_uid_size 2
57c09f92d2SPeter Avalos #define	bin_gid_offset 10
58c09f92d2SPeter Avalos #define	bin_gid_size 2
59c09f92d2SPeter Avalos #define	bin_nlink_offset 12
60c09f92d2SPeter Avalos #define	bin_nlink_size 2
61c09f92d2SPeter Avalos #define	bin_rdev_offset 14
62c09f92d2SPeter Avalos #define	bin_rdev_size 2
63c09f92d2SPeter Avalos #define	bin_mtime_offset 16
64c09f92d2SPeter Avalos #define	bin_mtime_size 4
65c09f92d2SPeter Avalos #define	bin_namesize_offset 20
66c09f92d2SPeter Avalos #define	bin_namesize_size 2
67c09f92d2SPeter Avalos #define	bin_filesize_offset 22
68c09f92d2SPeter Avalos #define	bin_filesize_size 4
69c09f92d2SPeter Avalos #define	bin_header_size 26
7060b4ad09SPeter Avalos 
71c09f92d2SPeter Avalos #define	odc_magic_offset 0
72c09f92d2SPeter Avalos #define	odc_magic_size 6
73c09f92d2SPeter Avalos #define	odc_dev_offset 6
74c09f92d2SPeter Avalos #define	odc_dev_size 6
75c09f92d2SPeter Avalos #define	odc_ino_offset 12
76c09f92d2SPeter Avalos #define	odc_ino_size 6
77c09f92d2SPeter Avalos #define	odc_mode_offset 18
78c09f92d2SPeter Avalos #define	odc_mode_size 6
79c09f92d2SPeter Avalos #define	odc_uid_offset 24
80c09f92d2SPeter Avalos #define	odc_uid_size 6
81c09f92d2SPeter Avalos #define	odc_gid_offset 30
82c09f92d2SPeter Avalos #define	odc_gid_size 6
83c09f92d2SPeter Avalos #define	odc_nlink_offset 36
84c09f92d2SPeter Avalos #define	odc_nlink_size 6
85c09f92d2SPeter Avalos #define	odc_rdev_offset 42
86c09f92d2SPeter Avalos #define	odc_rdev_size 6
87c09f92d2SPeter Avalos #define	odc_mtime_offset 48
88c09f92d2SPeter Avalos #define	odc_mtime_size 11
89c09f92d2SPeter Avalos #define	odc_namesize_offset 59
90c09f92d2SPeter Avalos #define	odc_namesize_size 6
91c09f92d2SPeter Avalos #define	odc_filesize_offset 65
92c09f92d2SPeter Avalos #define	odc_filesize_size 11
93c09f92d2SPeter Avalos #define	odc_header_size 76
9460b4ad09SPeter Avalos 
95c09f92d2SPeter Avalos #define	newc_magic_offset 0
96c09f92d2SPeter Avalos #define	newc_magic_size 6
97c09f92d2SPeter Avalos #define	newc_ino_offset 6
98c09f92d2SPeter Avalos #define	newc_ino_size 8
99c09f92d2SPeter Avalos #define	newc_mode_offset 14
100c09f92d2SPeter Avalos #define	newc_mode_size 8
101c09f92d2SPeter Avalos #define	newc_uid_offset 22
102c09f92d2SPeter Avalos #define	newc_uid_size 8
103c09f92d2SPeter Avalos #define	newc_gid_offset 30
104c09f92d2SPeter Avalos #define	newc_gid_size 8
105c09f92d2SPeter Avalos #define	newc_nlink_offset 38
106c09f92d2SPeter Avalos #define	newc_nlink_size 8
107c09f92d2SPeter Avalos #define	newc_mtime_offset 46
108c09f92d2SPeter Avalos #define	newc_mtime_size 8
109c09f92d2SPeter Avalos #define	newc_filesize_offset 54
110c09f92d2SPeter Avalos #define	newc_filesize_size 8
111c09f92d2SPeter Avalos #define	newc_devmajor_offset 62
112c09f92d2SPeter Avalos #define	newc_devmajor_size 8
113c09f92d2SPeter Avalos #define	newc_devminor_offset 70
114c09f92d2SPeter Avalos #define	newc_devminor_size 8
115c09f92d2SPeter Avalos #define	newc_rdevmajor_offset 78
116c09f92d2SPeter Avalos #define	newc_rdevmajor_size 8
117c09f92d2SPeter Avalos #define	newc_rdevminor_offset 86
118c09f92d2SPeter Avalos #define	newc_rdevminor_size 8
119c09f92d2SPeter Avalos #define	newc_namesize_offset 94
120c09f92d2SPeter Avalos #define	newc_namesize_size 8
121c09f92d2SPeter Avalos #define	newc_checksum_offset 102
122c09f92d2SPeter Avalos #define	newc_checksum_size 8
123c09f92d2SPeter Avalos #define	newc_header_size 110
124c09f92d2SPeter Avalos 
125c09f92d2SPeter Avalos /*
126c09f92d2SPeter Avalos  * An afio large ASCII header, which they named itself.
127c09f92d2SPeter Avalos  * afio utility uses this header, if a file size is larger than 2G bytes
128c09f92d2SPeter Avalos  * or inode/uid/gid is bigger than 65535(0xFFFF) or mtime is bigger than
129c09f92d2SPeter Avalos  * 0x7fffffff, which we cannot record to odc header because of its limit.
130c09f92d2SPeter Avalos  * If not, uses odc header.
131c09f92d2SPeter Avalos  */
132c09f92d2SPeter Avalos #define	afiol_magic_offset 0
133c09f92d2SPeter Avalos #define	afiol_magic_size 6
134c09f92d2SPeter Avalos #define	afiol_dev_offset 6
135c09f92d2SPeter Avalos #define	afiol_dev_size 8	/* hex */
136c09f92d2SPeter Avalos #define	afiol_ino_offset 14
137c09f92d2SPeter Avalos #define	afiol_ino_size 16	/* hex */
138c09f92d2SPeter Avalos #define	afiol_ino_m_offset 30	/* 'm' */
139c09f92d2SPeter Avalos #define	afiol_mode_offset 31
140c09f92d2SPeter Avalos #define	afiol_mode_size 6	/* oct */
141c09f92d2SPeter Avalos #define	afiol_uid_offset 37
142c09f92d2SPeter Avalos #define	afiol_uid_size 8	/* hex */
143c09f92d2SPeter Avalos #define	afiol_gid_offset 45
144c09f92d2SPeter Avalos #define	afiol_gid_size 8	/* hex */
145c09f92d2SPeter Avalos #define	afiol_nlink_offset 53
146c09f92d2SPeter Avalos #define	afiol_nlink_size 8	/* hex */
147c09f92d2SPeter Avalos #define	afiol_rdev_offset 61
148c09f92d2SPeter Avalos #define	afiol_rdev_size 8	/* hex */
149c09f92d2SPeter Avalos #define	afiol_mtime_offset 69
150c09f92d2SPeter Avalos #define	afiol_mtime_size 16	/* hex */
151c09f92d2SPeter Avalos #define	afiol_mtime_n_offset 85	/* 'n' */
152c09f92d2SPeter Avalos #define	afiol_namesize_offset 86
153c09f92d2SPeter Avalos #define	afiol_namesize_size 4	/* hex */
154c09f92d2SPeter Avalos #define	afiol_flag_offset 90
155c09f92d2SPeter Avalos #define	afiol_flag_size 4	/* hex */
156c09f92d2SPeter Avalos #define	afiol_xsize_offset 94
157c09f92d2SPeter Avalos #define	afiol_xsize_size 4	/* hex */
158c09f92d2SPeter Avalos #define	afiol_xsize_s_offset 98	/* 's' */
159c09f92d2SPeter Avalos #define	afiol_filesize_offset 99
160c09f92d2SPeter Avalos #define	afiol_filesize_size 16	/* hex */
161c09f92d2SPeter Avalos #define	afiol_filesize_c_offset 115	/* ':' */
162c09f92d2SPeter Avalos #define afiol_header_size 116
163c09f92d2SPeter Avalos 
16460b4ad09SPeter Avalos 
16560b4ad09SPeter Avalos struct links_entry {
16660b4ad09SPeter Avalos         struct links_entry      *next;
16760b4ad09SPeter Avalos         struct links_entry      *previous;
168e95abc47Szrj         unsigned int             links;
16960b4ad09SPeter Avalos         dev_t                    dev;
1709c82a63eSPeter Avalos         int64_t                  ino;
17160b4ad09SPeter Avalos         char                    *name;
17260b4ad09SPeter Avalos };
17360b4ad09SPeter Avalos 
17460b4ad09SPeter Avalos #define	CPIO_MAGIC   0x13141516
17560b4ad09SPeter Avalos struct cpio {
17660b4ad09SPeter Avalos 	int			  magic;
17760b4ad09SPeter Avalos 	int			(*read_header)(struct archive_read *, struct cpio *,
17860b4ad09SPeter Avalos 				     struct archive_entry *, size_t *, size_t *);
17960b4ad09SPeter Avalos 	struct links_entry	 *links_head;
180c09f92d2SPeter Avalos 	int64_t			  entry_bytes_remaining;
181c09f92d2SPeter Avalos 	int64_t			  entry_bytes_unconsumed;
182c09f92d2SPeter Avalos 	int64_t			  entry_offset;
183c09f92d2SPeter Avalos 	int64_t			  entry_padding;
184c09f92d2SPeter Avalos 
185c09f92d2SPeter Avalos 	struct archive_string_conv *opt_sconv;
186c09f92d2SPeter Avalos 	struct archive_string_conv *sconv_default;
187c09f92d2SPeter Avalos 	int			  init_default_conversion;
188*50f8aa9cSAntonio Huete Jimenez 
189*50f8aa9cSAntonio Huete Jimenez 	int			  option_pwb;
19060b4ad09SPeter Avalos };
19160b4ad09SPeter Avalos 
19260b4ad09SPeter Avalos static int64_t	atol16(const char *, unsigned);
19360b4ad09SPeter Avalos static int64_t	atol8(const char *, unsigned);
194c09f92d2SPeter Avalos static int	archive_read_format_cpio_bid(struct archive_read *, int);
195c09f92d2SPeter Avalos static int	archive_read_format_cpio_options(struct archive_read *,
196c09f92d2SPeter Avalos 		    const char *, const char *);
19760b4ad09SPeter Avalos static int	archive_read_format_cpio_cleanup(struct archive_read *);
19860b4ad09SPeter Avalos static int	archive_read_format_cpio_read_data(struct archive_read *,
199c09f92d2SPeter Avalos 		    const void **, size_t *, int64_t *);
20060b4ad09SPeter Avalos static int	archive_read_format_cpio_read_header(struct archive_read *,
20160b4ad09SPeter Avalos 		    struct archive_entry *);
202c09f92d2SPeter Avalos static int	archive_read_format_cpio_skip(struct archive_read *);
2036b384f39SPeter Avalos static int64_t	be4(const unsigned char *);
20460b4ad09SPeter Avalos static int	find_odc_header(struct archive_read *);
20560b4ad09SPeter Avalos static int	find_newc_header(struct archive_read *);
20660b4ad09SPeter Avalos static int	header_bin_be(struct archive_read *, struct cpio *,
20760b4ad09SPeter Avalos 		    struct archive_entry *, size_t *, size_t *);
20860b4ad09SPeter Avalos static int	header_bin_le(struct archive_read *, struct cpio *,
20960b4ad09SPeter Avalos 		    struct archive_entry *, size_t *, size_t *);
21060b4ad09SPeter Avalos static int	header_newc(struct archive_read *, struct cpio *,
21160b4ad09SPeter Avalos 		    struct archive_entry *, size_t *, size_t *);
21260b4ad09SPeter Avalos static int	header_odc(struct archive_read *, struct cpio *,
21360b4ad09SPeter Avalos 		    struct archive_entry *, size_t *, size_t *);
214c09f92d2SPeter Avalos static int	header_afiol(struct archive_read *, struct cpio *,
215c09f92d2SPeter Avalos 		    struct archive_entry *, size_t *, size_t *);
21660b4ad09SPeter Avalos static int	is_octal(const char *, size_t);
21760b4ad09SPeter Avalos static int	is_hex(const char *, size_t);
2186b384f39SPeter Avalos static int64_t	le4(const unsigned char *);
219c09f92d2SPeter Avalos static int	record_hardlink(struct archive_read *a,
220c09f92d2SPeter Avalos 		    struct cpio *cpio, struct archive_entry *entry);
22160b4ad09SPeter Avalos 
22260b4ad09SPeter Avalos int
archive_read_support_format_cpio(struct archive * _a)22360b4ad09SPeter Avalos archive_read_support_format_cpio(struct archive *_a)
22460b4ad09SPeter Avalos {
22560b4ad09SPeter Avalos 	struct archive_read *a = (struct archive_read *)_a;
22660b4ad09SPeter Avalos 	struct cpio *cpio;
22760b4ad09SPeter Avalos 	int r;
22860b4ad09SPeter Avalos 
229c09f92d2SPeter Avalos 	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
230c09f92d2SPeter Avalos 	    ARCHIVE_STATE_NEW, "archive_read_support_format_cpio");
231c09f92d2SPeter Avalos 
232c09f92d2SPeter Avalos 	cpio = (struct cpio *)calloc(1, sizeof(*cpio));
23360b4ad09SPeter Avalos 	if (cpio == NULL) {
23460b4ad09SPeter Avalos 		archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
23560b4ad09SPeter Avalos 		return (ARCHIVE_FATAL);
23660b4ad09SPeter Avalos 	}
23760b4ad09SPeter Avalos 	cpio->magic = CPIO_MAGIC;
23860b4ad09SPeter Avalos 
23960b4ad09SPeter Avalos 	r = __archive_read_register_format(a,
24060b4ad09SPeter Avalos 	    cpio,
2418029ab02SPeter Avalos 	    "cpio",
24260b4ad09SPeter Avalos 	    archive_read_format_cpio_bid,
243c09f92d2SPeter Avalos 	    archive_read_format_cpio_options,
24460b4ad09SPeter Avalos 	    archive_read_format_cpio_read_header,
24560b4ad09SPeter Avalos 	    archive_read_format_cpio_read_data,
246c09f92d2SPeter Avalos 	    archive_read_format_cpio_skip,
247d4d8193eSPeter Avalos 	    NULL,
2486b384f39SPeter Avalos 	    archive_read_format_cpio_cleanup,
2496b384f39SPeter Avalos 	    NULL,
2506b384f39SPeter Avalos 	    NULL);
25160b4ad09SPeter Avalos 
25260b4ad09SPeter Avalos 	if (r != ARCHIVE_OK)
25360b4ad09SPeter Avalos 		free(cpio);
25460b4ad09SPeter Avalos 	return (ARCHIVE_OK);
25560b4ad09SPeter Avalos }
25660b4ad09SPeter Avalos 
25760b4ad09SPeter Avalos 
25860b4ad09SPeter Avalos static int
archive_read_format_cpio_bid(struct archive_read * a,int best_bid)259c09f92d2SPeter Avalos archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
26060b4ad09SPeter Avalos {
26160b4ad09SPeter Avalos 	const unsigned char *p;
26260b4ad09SPeter Avalos 	struct cpio *cpio;
26360b4ad09SPeter Avalos 	int bid;
26460b4ad09SPeter Avalos 
265c09f92d2SPeter Avalos 	(void)best_bid; /* UNUSED */
266c09f92d2SPeter Avalos 
26760b4ad09SPeter Avalos 	cpio = (struct cpio *)(a->format->data);
26860b4ad09SPeter Avalos 
269c09f92d2SPeter Avalos 	if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
27060b4ad09SPeter Avalos 		return (-1);
27160b4ad09SPeter Avalos 
27260b4ad09SPeter Avalos 	bid = 0;
27360b4ad09SPeter Avalos 	if (memcmp(p, "070707", 6) == 0) {
27460b4ad09SPeter Avalos 		/* ASCII cpio archive (odc, POSIX.1) */
27560b4ad09SPeter Avalos 		cpio->read_header = header_odc;
27660b4ad09SPeter Avalos 		bid += 48;
27760b4ad09SPeter Avalos 		/*
27860b4ad09SPeter Avalos 		 * XXX TODO:  More verification; Could check that only octal
27960b4ad09SPeter Avalos 		 * digits appear in appropriate header locations. XXX
28060b4ad09SPeter Avalos 		 */
281c09f92d2SPeter Avalos 	} else if (memcmp(p, "070727", 6) == 0) {
282c09f92d2SPeter Avalos 		/* afio large ASCII cpio archive */
283c09f92d2SPeter Avalos 		cpio->read_header = header_odc;
284c09f92d2SPeter Avalos 		bid += 48;
285c09f92d2SPeter Avalos 		/*
286c09f92d2SPeter Avalos 		 * XXX TODO:  More verification; Could check that almost hex
287c09f92d2SPeter Avalos 		 * digits appear in appropriate header locations. XXX
288c09f92d2SPeter Avalos 		 */
28960b4ad09SPeter Avalos 	} else if (memcmp(p, "070701", 6) == 0) {
29060b4ad09SPeter Avalos 		/* ASCII cpio archive (SVR4 without CRC) */
29160b4ad09SPeter Avalos 		cpio->read_header = header_newc;
29260b4ad09SPeter Avalos 		bid += 48;
29360b4ad09SPeter Avalos 		/*
29460b4ad09SPeter Avalos 		 * XXX TODO:  More verification; Could check that only hex
29560b4ad09SPeter Avalos 		 * digits appear in appropriate header locations. XXX
29660b4ad09SPeter Avalos 		 */
29760b4ad09SPeter Avalos 	} else if (memcmp(p, "070702", 6) == 0) {
29860b4ad09SPeter Avalos 		/* ASCII cpio archive (SVR4 with CRC) */
29960b4ad09SPeter Avalos 		/* XXX TODO: Flag that we should check the CRC. XXX */
30060b4ad09SPeter Avalos 		cpio->read_header = header_newc;
30160b4ad09SPeter Avalos 		bid += 48;
30260b4ad09SPeter Avalos 		/*
30360b4ad09SPeter Avalos 		 * XXX TODO:  More verification; Could check that only hex
30460b4ad09SPeter Avalos 		 * digits appear in appropriate header locations. XXX
30560b4ad09SPeter Avalos 		 */
30660b4ad09SPeter Avalos 	} else if (p[0] * 256 + p[1] == 070707) {
30760b4ad09SPeter Avalos 		/* big-endian binary cpio archives */
30860b4ad09SPeter Avalos 		cpio->read_header = header_bin_be;
30960b4ad09SPeter Avalos 		bid += 16;
31060b4ad09SPeter Avalos 		/* Is more verification possible here? */
31160b4ad09SPeter Avalos 	} else if (p[0] + p[1] * 256 == 070707) {
31260b4ad09SPeter Avalos 		/* little-endian binary cpio archives */
31360b4ad09SPeter Avalos 		cpio->read_header = header_bin_le;
31460b4ad09SPeter Avalos 		bid += 16;
31560b4ad09SPeter Avalos 		/* Is more verification possible here? */
31660b4ad09SPeter Avalos 	} else
31760b4ad09SPeter Avalos 		return (ARCHIVE_WARN);
31860b4ad09SPeter Avalos 
31960b4ad09SPeter Avalos 	return (bid);
32060b4ad09SPeter Avalos }
32160b4ad09SPeter Avalos 
32260b4ad09SPeter Avalos static int
archive_read_format_cpio_options(struct archive_read * a,const char * key,const char * val)323c09f92d2SPeter Avalos archive_read_format_cpio_options(struct archive_read *a,
324c09f92d2SPeter Avalos     const char *key, const char *val)
325c09f92d2SPeter Avalos {
326c09f92d2SPeter Avalos 	struct cpio *cpio;
327c09f92d2SPeter Avalos 	int ret = ARCHIVE_FAILED;
328c09f92d2SPeter Avalos 
329c09f92d2SPeter Avalos 	cpio = (struct cpio *)(a->format->data);
330c09f92d2SPeter Avalos 	if (strcmp(key, "compat-2x")  == 0) {
331e95abc47Szrj 		/* Handle filenames as libarchive 2.x */
332c09f92d2SPeter Avalos 		cpio->init_default_conversion = (val != NULL)?1:0;
33359bf7050SPeter Avalos 		return (ARCHIVE_OK);
334c09f92d2SPeter Avalos 	} else if (strcmp(key, "hdrcharset")  == 0) {
335c09f92d2SPeter Avalos 		if (val == NULL || val[0] == 0)
336c09f92d2SPeter Avalos 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
337c09f92d2SPeter Avalos 			    "cpio: hdrcharset option needs a character-set name");
338c09f92d2SPeter Avalos 		else {
339c09f92d2SPeter Avalos 			cpio->opt_sconv =
340c09f92d2SPeter Avalos 			    archive_string_conversion_from_charset(
341c09f92d2SPeter Avalos 				&a->archive, val, 0);
342c09f92d2SPeter Avalos 			if (cpio->opt_sconv != NULL)
343c09f92d2SPeter Avalos 				ret = ARCHIVE_OK;
344c09f92d2SPeter Avalos 			else
345c09f92d2SPeter Avalos 				ret = ARCHIVE_FATAL;
346c09f92d2SPeter Avalos 		}
347c09f92d2SPeter Avalos 		return (ret);
348*50f8aa9cSAntonio Huete Jimenez 	} else if (strcmp(key, "pwb")  == 0) {
349*50f8aa9cSAntonio Huete Jimenez 		if (val != NULL && val[0] != 0)
350*50f8aa9cSAntonio Huete Jimenez 			cpio->option_pwb = 1;
351*50f8aa9cSAntonio Huete Jimenez 		return (ARCHIVE_OK);
352c09f92d2SPeter Avalos 	}
353c09f92d2SPeter Avalos 
35459bf7050SPeter Avalos 	/* Note: The "warn" return is just to inform the options
35559bf7050SPeter Avalos 	 * supervisor that we didn't handle it.  It will generate
35659bf7050SPeter Avalos 	 * a suitable error if no one used this option. */
35759bf7050SPeter Avalos 	return (ARCHIVE_WARN);
35859bf7050SPeter Avalos }
35959bf7050SPeter Avalos 
360c09f92d2SPeter Avalos static int
archive_read_format_cpio_read_header(struct archive_read * a,struct archive_entry * entry)36160b4ad09SPeter Avalos archive_read_format_cpio_read_header(struct archive_read *a,
36260b4ad09SPeter Avalos     struct archive_entry *entry)
36360b4ad09SPeter Avalos {
36460b4ad09SPeter Avalos 	struct cpio *cpio;
365e95abc47Szrj 	const void *h, *hl;
366c09f92d2SPeter Avalos 	struct archive_string_conv *sconv;
36760b4ad09SPeter Avalos 	size_t namelength;
36860b4ad09SPeter Avalos 	size_t name_pad;
36960b4ad09SPeter Avalos 	int r;
37060b4ad09SPeter Avalos 
37160b4ad09SPeter Avalos 	cpio = (struct cpio *)(a->format->data);
372c09f92d2SPeter Avalos 	sconv = cpio->opt_sconv;
373c09f92d2SPeter Avalos 	if (sconv == NULL) {
374c09f92d2SPeter Avalos 		if (!cpio->init_default_conversion) {
375c09f92d2SPeter Avalos 			cpio->sconv_default =
376c09f92d2SPeter Avalos 			    archive_string_default_conversion_for_read(
377c09f92d2SPeter Avalos 			      &(a->archive));
378c09f92d2SPeter Avalos 			cpio->init_default_conversion = 1;
379c09f92d2SPeter Avalos 		}
380c09f92d2SPeter Avalos 		sconv = cpio->sconv_default;
381c09f92d2SPeter Avalos 	}
382c09f92d2SPeter Avalos 
38360b4ad09SPeter Avalos 	r = (cpio->read_header(a, cpio, entry, &namelength, &name_pad));
38460b4ad09SPeter Avalos 
38560b4ad09SPeter Avalos 	if (r < ARCHIVE_WARN)
38660b4ad09SPeter Avalos 		return (r);
38760b4ad09SPeter Avalos 
38860b4ad09SPeter Avalos 	/* Read name from buffer. */
3898029ab02SPeter Avalos 	h = __archive_read_ahead(a, namelength + name_pad, NULL);
3908029ab02SPeter Avalos 	if (h == NULL)
39160b4ad09SPeter Avalos 	    return (ARCHIVE_FATAL);
392c09f92d2SPeter Avalos 	if (archive_entry_copy_pathname_l(entry,
393c09f92d2SPeter Avalos 	    (const char *)h, namelength, sconv) != 0) {
394c09f92d2SPeter Avalos 		if (errno == ENOMEM) {
395c09f92d2SPeter Avalos 			archive_set_error(&a->archive, ENOMEM,
396c09f92d2SPeter Avalos 			    "Can't allocate memory for Pathname");
397c09f92d2SPeter Avalos 			return (ARCHIVE_FATAL);
398c09f92d2SPeter Avalos 		}
399c09f92d2SPeter Avalos 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
400c09f92d2SPeter Avalos 		    "Pathname can't be converted from %s to current locale.",
401c09f92d2SPeter Avalos 		    archive_string_conversion_charset_name(sconv));
402c09f92d2SPeter Avalos 		r = ARCHIVE_WARN;
403c09f92d2SPeter Avalos 	}
40460b4ad09SPeter Avalos 	cpio->entry_offset = 0;
40560b4ad09SPeter Avalos 
406c09f92d2SPeter Avalos 	__archive_read_consume(a, namelength + name_pad);
407c09f92d2SPeter Avalos 
40860b4ad09SPeter Avalos 	/* If this is a symlink, read the link contents. */
40960b4ad09SPeter Avalos 	if (archive_entry_filetype(entry) == AE_IFLNK) {
4109a9a081fSPeter Avalos 		if (cpio->entry_bytes_remaining > 1024 * 1024) {
4119a9a081fSPeter Avalos 			archive_set_error(&a->archive, ENOMEM,
4129a9a081fSPeter Avalos 			    "Rejecting malformed cpio archive: symlink contents exceed 1 megabyte");
4139a9a081fSPeter Avalos 			return (ARCHIVE_FATAL);
4149a9a081fSPeter Avalos 		}
415e95abc47Szrj 		hl = __archive_read_ahead(a,
41659bf7050SPeter Avalos 			(size_t)cpio->entry_bytes_remaining, NULL);
417e95abc47Szrj 		if (hl == NULL)
41860b4ad09SPeter Avalos 			return (ARCHIVE_FATAL);
419e95abc47Szrj 		if (archive_entry_copy_symlink_l(entry, (const char *)hl,
42059bf7050SPeter Avalos 		    (size_t)cpio->entry_bytes_remaining, sconv) != 0) {
421c09f92d2SPeter Avalos 			if (errno == ENOMEM) {
422c09f92d2SPeter Avalos 				archive_set_error(&a->archive, ENOMEM,
423c09f92d2SPeter Avalos 				    "Can't allocate memory for Linkname");
424c09f92d2SPeter Avalos 				return (ARCHIVE_FATAL);
425c09f92d2SPeter Avalos 			}
426c09f92d2SPeter Avalos 			archive_set_error(&a->archive,
427c09f92d2SPeter Avalos 			    ARCHIVE_ERRNO_FILE_FORMAT,
428c09f92d2SPeter Avalos 			    "Linkname can't be converted from %s to "
429c09f92d2SPeter Avalos 			    "current locale.",
430c09f92d2SPeter Avalos 			    archive_string_conversion_charset_name(sconv));
431c09f92d2SPeter Avalos 			r = ARCHIVE_WARN;
432c09f92d2SPeter Avalos 		}
4338029ab02SPeter Avalos 		__archive_read_consume(a, cpio->entry_bytes_remaining);
43460b4ad09SPeter Avalos 		cpio->entry_bytes_remaining = 0;
43560b4ad09SPeter Avalos 	}
43660b4ad09SPeter Avalos 
4379c82a63eSPeter Avalos 	/* XXX TODO: If the full mode is 0160200, then this is a Solaris
4389c82a63eSPeter Avalos 	 * ACL description for the following entry.  Read this body
4399c82a63eSPeter Avalos 	 * and parse it as a Solaris-style ACL, then read the next
4409c82a63eSPeter Avalos 	 * header.  XXX */
4419c82a63eSPeter Avalos 
44260b4ad09SPeter Avalos 	/* Compare name to "TRAILER!!!" to test for end-of-archive. */
443e95abc47Szrj 	if (namelength == 11 && strncmp((const char *)h, "TRAILER!!!",
444e95abc47Szrj 	    11) == 0) {
44560b4ad09SPeter Avalos 		/* TODO: Store file location of start of block. */
446c09f92d2SPeter Avalos 		archive_clear_error(&a->archive);
44760b4ad09SPeter Avalos 		return (ARCHIVE_EOF);
44860b4ad09SPeter Avalos 	}
44960b4ad09SPeter Avalos 
45060b4ad09SPeter Avalos 	/* Detect and record hardlinks to previously-extracted entries. */
451c09f92d2SPeter Avalos 	if (record_hardlink(a, cpio, entry) != ARCHIVE_OK) {
452c09f92d2SPeter Avalos 		return (ARCHIVE_FATAL);
453c09f92d2SPeter Avalos 	}
45460b4ad09SPeter Avalos 
45560b4ad09SPeter Avalos 	return (r);
45660b4ad09SPeter Avalos }
45760b4ad09SPeter Avalos 
45860b4ad09SPeter Avalos static int
archive_read_format_cpio_read_data(struct archive_read * a,const void ** buff,size_t * size,int64_t * offset)45960b4ad09SPeter Avalos archive_read_format_cpio_read_data(struct archive_read *a,
460c09f92d2SPeter Avalos     const void **buff, size_t *size, int64_t *offset)
46160b4ad09SPeter Avalos {
46260b4ad09SPeter Avalos 	ssize_t bytes_read;
46360b4ad09SPeter Avalos 	struct cpio *cpio;
46460b4ad09SPeter Avalos 
46560b4ad09SPeter Avalos 	cpio = (struct cpio *)(a->format->data);
466c09f92d2SPeter Avalos 
467c09f92d2SPeter Avalos 	if (cpio->entry_bytes_unconsumed) {
468c09f92d2SPeter Avalos 		__archive_read_consume(a, cpio->entry_bytes_unconsumed);
469c09f92d2SPeter Avalos 		cpio->entry_bytes_unconsumed = 0;
470c09f92d2SPeter Avalos 	}
471c09f92d2SPeter Avalos 
47260b4ad09SPeter Avalos 	if (cpio->entry_bytes_remaining > 0) {
4738029ab02SPeter Avalos 		*buff = __archive_read_ahead(a, 1, &bytes_read);
47460b4ad09SPeter Avalos 		if (bytes_read <= 0)
47560b4ad09SPeter Avalos 			return (ARCHIVE_FATAL);
47660b4ad09SPeter Avalos 		if (bytes_read > cpio->entry_bytes_remaining)
47759bf7050SPeter Avalos 			bytes_read = (ssize_t)cpio->entry_bytes_remaining;
47860b4ad09SPeter Avalos 		*size = bytes_read;
479c09f92d2SPeter Avalos 		cpio->entry_bytes_unconsumed = bytes_read;
48060b4ad09SPeter Avalos 		*offset = cpio->entry_offset;
48160b4ad09SPeter Avalos 		cpio->entry_offset += bytes_read;
48260b4ad09SPeter Avalos 		cpio->entry_bytes_remaining -= bytes_read;
48360b4ad09SPeter Avalos 		return (ARCHIVE_OK);
48460b4ad09SPeter Avalos 	} else {
485c09f92d2SPeter Avalos 		if (cpio->entry_padding !=
486c09f92d2SPeter Avalos 			__archive_read_consume(a, cpio->entry_padding)) {
48760b4ad09SPeter Avalos 			return (ARCHIVE_FATAL);
48860b4ad09SPeter Avalos 		}
489c09f92d2SPeter Avalos 		cpio->entry_padding = 0;
49060b4ad09SPeter Avalos 		*buff = NULL;
49160b4ad09SPeter Avalos 		*size = 0;
49260b4ad09SPeter Avalos 		*offset = cpio->entry_offset;
49360b4ad09SPeter Avalos 		return (ARCHIVE_EOF);
49460b4ad09SPeter Avalos 	}
49560b4ad09SPeter Avalos }
49660b4ad09SPeter Avalos 
497c09f92d2SPeter Avalos static int
archive_read_format_cpio_skip(struct archive_read * a)498c09f92d2SPeter Avalos archive_read_format_cpio_skip(struct archive_read *a)
499c09f92d2SPeter Avalos {
500c09f92d2SPeter Avalos 	struct cpio *cpio = (struct cpio *)(a->format->data);
501c09f92d2SPeter Avalos 	int64_t to_skip = cpio->entry_bytes_remaining + cpio->entry_padding +
502c09f92d2SPeter Avalos 		cpio->entry_bytes_unconsumed;
503c09f92d2SPeter Avalos 
504c09f92d2SPeter Avalos 	if (to_skip != __archive_read_consume(a, to_skip)) {
505c09f92d2SPeter Avalos 		return (ARCHIVE_FATAL);
506c09f92d2SPeter Avalos 	}
507c09f92d2SPeter Avalos 	cpio->entry_bytes_remaining = 0;
508c09f92d2SPeter Avalos 	cpio->entry_padding = 0;
509c09f92d2SPeter Avalos 	cpio->entry_bytes_unconsumed = 0;
510c09f92d2SPeter Avalos 	return (ARCHIVE_OK);
511c09f92d2SPeter Avalos }
512c09f92d2SPeter Avalos 
51360b4ad09SPeter Avalos /*
51460b4ad09SPeter Avalos  * Skip forward to the next cpio newc header by searching for the
51560b4ad09SPeter Avalos  * 07070[12] string.  This should be generalized and merged with
51660b4ad09SPeter Avalos  * find_odc_header below.
51760b4ad09SPeter Avalos  */
51860b4ad09SPeter Avalos static int
is_hex(const char * p,size_t len)51960b4ad09SPeter Avalos is_hex(const char *p, size_t len)
52060b4ad09SPeter Avalos {
52160b4ad09SPeter Avalos 	while (len-- > 0) {
52260b4ad09SPeter Avalos 		if ((*p >= '0' && *p <= '9')
52360b4ad09SPeter Avalos 		    || (*p >= 'a' && *p <= 'f')
52460b4ad09SPeter Avalos 		    || (*p >= 'A' && *p <= 'F'))
52560b4ad09SPeter Avalos 			++p;
52660b4ad09SPeter Avalos 		else
52760b4ad09SPeter Avalos 			return (0);
52860b4ad09SPeter Avalos 	}
52960b4ad09SPeter Avalos 	return (1);
53060b4ad09SPeter Avalos }
53160b4ad09SPeter Avalos 
53260b4ad09SPeter Avalos static int
find_newc_header(struct archive_read * a)53360b4ad09SPeter Avalos find_newc_header(struct archive_read *a)
53460b4ad09SPeter Avalos {
53560b4ad09SPeter Avalos 	const void *h;
53660b4ad09SPeter Avalos 	const char *p, *q;
5378029ab02SPeter Avalos 	size_t skip, skipped = 0;
5388029ab02SPeter Avalos 	ssize_t bytes;
53960b4ad09SPeter Avalos 
54060b4ad09SPeter Avalos 	for (;;) {
541c09f92d2SPeter Avalos 		h = __archive_read_ahead(a, newc_header_size, &bytes);
5428029ab02SPeter Avalos 		if (h == NULL)
54360b4ad09SPeter Avalos 			return (ARCHIVE_FATAL);
54460b4ad09SPeter Avalos 		p = h;
54560b4ad09SPeter Avalos 		q = p + bytes;
54660b4ad09SPeter Avalos 
54760b4ad09SPeter Avalos 		/* Try the typical case first, then go into the slow search.*/
54860b4ad09SPeter Avalos 		if (memcmp("07070", p, 5) == 0
54960b4ad09SPeter Avalos 		    && (p[5] == '1' || p[5] == '2')
550c09f92d2SPeter Avalos 		    && is_hex(p, newc_header_size))
55160b4ad09SPeter Avalos 			return (ARCHIVE_OK);
55260b4ad09SPeter Avalos 
55360b4ad09SPeter Avalos 		/*
55460b4ad09SPeter Avalos 		 * Scan ahead until we find something that looks
555c09f92d2SPeter Avalos 		 * like a newc header.
55660b4ad09SPeter Avalos 		 */
557c09f92d2SPeter Avalos 		while (p + newc_header_size <= q) {
55860b4ad09SPeter Avalos 			switch (p[5]) {
55960b4ad09SPeter Avalos 			case '1':
56060b4ad09SPeter Avalos 			case '2':
56160b4ad09SPeter Avalos 				if (memcmp("07070", p, 5) == 0
562c09f92d2SPeter Avalos 				    && is_hex(p, newc_header_size)) {
56360b4ad09SPeter Avalos 					skip = p - (const char *)h;
5648029ab02SPeter Avalos 					__archive_read_consume(a, skip);
56560b4ad09SPeter Avalos 					skipped += skip;
56660b4ad09SPeter Avalos 					if (skipped > 0) {
56760b4ad09SPeter Avalos 						archive_set_error(&a->archive,
56860b4ad09SPeter Avalos 						    0,
56960b4ad09SPeter Avalos 						    "Skipped %d bytes before "
57060b4ad09SPeter Avalos 						    "finding valid header",
57160b4ad09SPeter Avalos 						    (int)skipped);
57260b4ad09SPeter Avalos 						return (ARCHIVE_WARN);
57360b4ad09SPeter Avalos 					}
57460b4ad09SPeter Avalos 					return (ARCHIVE_OK);
57560b4ad09SPeter Avalos 				}
57660b4ad09SPeter Avalos 				p += 2;
57760b4ad09SPeter Avalos 				break;
57860b4ad09SPeter Avalos 			case '0':
57960b4ad09SPeter Avalos 				p++;
58060b4ad09SPeter Avalos 				break;
58160b4ad09SPeter Avalos 			default:
58260b4ad09SPeter Avalos 				p += 6;
58360b4ad09SPeter Avalos 				break;
58460b4ad09SPeter Avalos 			}
58560b4ad09SPeter Avalos 		}
58660b4ad09SPeter Avalos 		skip = p - (const char *)h;
5878029ab02SPeter Avalos 		__archive_read_consume(a, skip);
58860b4ad09SPeter Avalos 		skipped += skip;
58960b4ad09SPeter Avalos 	}
59060b4ad09SPeter Avalos }
59160b4ad09SPeter Avalos 
59260b4ad09SPeter Avalos static int
header_newc(struct archive_read * a,struct cpio * cpio,struct archive_entry * entry,size_t * namelength,size_t * name_pad)59360b4ad09SPeter Avalos header_newc(struct archive_read *a, struct cpio *cpio,
59460b4ad09SPeter Avalos     struct archive_entry *entry, size_t *namelength, size_t *name_pad)
59560b4ad09SPeter Avalos {
59660b4ad09SPeter Avalos 	const void *h;
597c09f92d2SPeter Avalos 	const char *header;
59860b4ad09SPeter Avalos 	int r;
59960b4ad09SPeter Avalos 
60060b4ad09SPeter Avalos 	r = find_newc_header(a);
60160b4ad09SPeter Avalos 	if (r < ARCHIVE_WARN)
60260b4ad09SPeter Avalos 		return (r);
60360b4ad09SPeter Avalos 
60460b4ad09SPeter Avalos 	/* Read fixed-size portion of header. */
605c09f92d2SPeter Avalos 	h = __archive_read_ahead(a, newc_header_size, NULL);
6068029ab02SPeter Avalos 	if (h == NULL)
60760b4ad09SPeter Avalos 	    return (ARCHIVE_FATAL);
60860b4ad09SPeter Avalos 
60960b4ad09SPeter Avalos 	/* Parse out hex fields. */
610c09f92d2SPeter Avalos 	header = (const char *)h;
61160b4ad09SPeter Avalos 
612c09f92d2SPeter Avalos 	if (memcmp(header + newc_magic_offset, "070701", 6) == 0) {
61360b4ad09SPeter Avalos 		a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
61460b4ad09SPeter Avalos 		a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)";
615c09f92d2SPeter Avalos 	} else if (memcmp(header + newc_magic_offset, "070702", 6) == 0) {
61660b4ad09SPeter Avalos 		a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC;
61760b4ad09SPeter Avalos 		a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)";
61860b4ad09SPeter Avalos 	} else {
61960b4ad09SPeter Avalos 		/* TODO: Abort here? */
62060b4ad09SPeter Avalos 	}
62160b4ad09SPeter Avalos 
62259bf7050SPeter Avalos 	archive_entry_set_devmajor(entry,
62359bf7050SPeter Avalos 		(dev_t)atol16(header + newc_devmajor_offset, newc_devmajor_size));
62459bf7050SPeter Avalos 	archive_entry_set_devminor(entry,
62559bf7050SPeter Avalos 		(dev_t)atol16(header + newc_devminor_offset, newc_devminor_size));
626c09f92d2SPeter Avalos 	archive_entry_set_ino(entry, atol16(header + newc_ino_offset, newc_ino_size));
62759bf7050SPeter Avalos 	archive_entry_set_mode(entry,
62859bf7050SPeter Avalos 		(mode_t)atol16(header + newc_mode_offset, newc_mode_size));
629c09f92d2SPeter Avalos 	archive_entry_set_uid(entry, atol16(header + newc_uid_offset, newc_uid_size));
630c09f92d2SPeter Avalos 	archive_entry_set_gid(entry, atol16(header + newc_gid_offset, newc_gid_size));
63159bf7050SPeter Avalos 	archive_entry_set_nlink(entry,
63259bf7050SPeter Avalos 		(unsigned int)atol16(header + newc_nlink_offset, newc_nlink_size));
63359bf7050SPeter Avalos 	archive_entry_set_rdevmajor(entry,
63459bf7050SPeter Avalos 		(dev_t)atol16(header + newc_rdevmajor_offset, newc_rdevmajor_size));
63559bf7050SPeter Avalos 	archive_entry_set_rdevminor(entry,
63659bf7050SPeter Avalos 		(dev_t)atol16(header + newc_rdevminor_offset, newc_rdevminor_size));
637c09f92d2SPeter Avalos 	archive_entry_set_mtime(entry, atol16(header + newc_mtime_offset, newc_mtime_size), 0);
63859bf7050SPeter Avalos 	*namelength = (size_t)atol16(header + newc_namesize_offset, newc_namesize_size);
63960b4ad09SPeter Avalos 	/* Pad name to 2 more than a multiple of 4. */
64060b4ad09SPeter Avalos 	*name_pad = (2 - *namelength) & 3;
64160b4ad09SPeter Avalos 
642e95abc47Szrj 	/* Make sure that the padded name length fits into size_t. */
643e95abc47Szrj 	if (*name_pad > SIZE_MAX - *namelength) {
644e95abc47Szrj 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
645e95abc47Szrj 		    "cpio archive has invalid namelength");
646e95abc47Szrj 		return (ARCHIVE_FATAL);
647e95abc47Szrj 	}
648e95abc47Szrj 
64960b4ad09SPeter Avalos 	/*
65060b4ad09SPeter Avalos 	 * Note: entry_bytes_remaining is at least 64 bits and
65160b4ad09SPeter Avalos 	 * therefore guaranteed to be big enough for a 33-bit file
65260b4ad09SPeter Avalos 	 * size.
65360b4ad09SPeter Avalos 	 */
65460b4ad09SPeter Avalos 	cpio->entry_bytes_remaining =
655c09f92d2SPeter Avalos 	    atol16(header + newc_filesize_offset, newc_filesize_size);
65660b4ad09SPeter Avalos 	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
65760b4ad09SPeter Avalos 	/* Pad file contents to a multiple of 4. */
65860b4ad09SPeter Avalos 	cpio->entry_padding = 3 & -cpio->entry_bytes_remaining;
659c09f92d2SPeter Avalos 	__archive_read_consume(a, newc_header_size);
66060b4ad09SPeter Avalos 	return (r);
66160b4ad09SPeter Avalos }
66260b4ad09SPeter Avalos 
66360b4ad09SPeter Avalos /*
66460b4ad09SPeter Avalos  * Skip forward to the next cpio odc header by searching for the
66560b4ad09SPeter Avalos  * 070707 string.  This is a hand-optimized search that could
66660b4ad09SPeter Avalos  * probably be easily generalized to handle all character-based
66760b4ad09SPeter Avalos  * cpio variants.
66860b4ad09SPeter Avalos  */
66960b4ad09SPeter Avalos static int
is_octal(const char * p,size_t len)67060b4ad09SPeter Avalos is_octal(const char *p, size_t len)
67160b4ad09SPeter Avalos {
67260b4ad09SPeter Avalos 	while (len-- > 0) {
67360b4ad09SPeter Avalos 		if (*p < '0' || *p > '7')
67460b4ad09SPeter Avalos 			return (0);
67560b4ad09SPeter Avalos 	        ++p;
67660b4ad09SPeter Avalos 	}
67760b4ad09SPeter Avalos 	return (1);
67860b4ad09SPeter Avalos }
67960b4ad09SPeter Avalos 
68060b4ad09SPeter Avalos static int
is_afio_large(const char * h,size_t len)681c09f92d2SPeter Avalos is_afio_large(const char *h, size_t len)
682c09f92d2SPeter Avalos {
683c09f92d2SPeter Avalos 	if (len < afiol_header_size)
684c09f92d2SPeter Avalos 		return (0);
685c09f92d2SPeter Avalos 	if (h[afiol_ino_m_offset] != 'm'
686c09f92d2SPeter Avalos 	    || h[afiol_mtime_n_offset] != 'n'
687c09f92d2SPeter Avalos 	    || h[afiol_xsize_s_offset] != 's'
688c09f92d2SPeter Avalos 	    || h[afiol_filesize_c_offset] != ':')
689c09f92d2SPeter Avalos 		return (0);
690c09f92d2SPeter Avalos 	if (!is_hex(h + afiol_dev_offset, afiol_ino_m_offset - afiol_dev_offset))
691c09f92d2SPeter Avalos 		return (0);
692c09f92d2SPeter Avalos 	if (!is_hex(h + afiol_mode_offset, afiol_mtime_n_offset - afiol_mode_offset))
693c09f92d2SPeter Avalos 		return (0);
694c09f92d2SPeter Avalos 	if (!is_hex(h + afiol_namesize_offset, afiol_xsize_s_offset - afiol_namesize_offset))
695c09f92d2SPeter Avalos 		return (0);
696c09f92d2SPeter Avalos 	if (!is_hex(h + afiol_filesize_offset, afiol_filesize_size))
697c09f92d2SPeter Avalos 		return (0);
698c09f92d2SPeter Avalos 	return (1);
699c09f92d2SPeter Avalos }
700c09f92d2SPeter Avalos 
701c09f92d2SPeter Avalos static int
find_odc_header(struct archive_read * a)70260b4ad09SPeter Avalos find_odc_header(struct archive_read *a)
70360b4ad09SPeter Avalos {
70460b4ad09SPeter Avalos 	const void *h;
70560b4ad09SPeter Avalos 	const char *p, *q;
7068029ab02SPeter Avalos 	size_t skip, skipped = 0;
7078029ab02SPeter Avalos 	ssize_t bytes;
70860b4ad09SPeter Avalos 
70960b4ad09SPeter Avalos 	for (;;) {
710c09f92d2SPeter Avalos 		h = __archive_read_ahead(a, odc_header_size, &bytes);
7118029ab02SPeter Avalos 		if (h == NULL)
71260b4ad09SPeter Avalos 			return (ARCHIVE_FATAL);
71360b4ad09SPeter Avalos 		p = h;
71460b4ad09SPeter Avalos 		q = p + bytes;
71560b4ad09SPeter Avalos 
71660b4ad09SPeter Avalos 		/* Try the typical case first, then go into the slow search.*/
717c09f92d2SPeter Avalos 		if (memcmp("070707", p, 6) == 0 && is_octal(p, odc_header_size))
71860b4ad09SPeter Avalos 			return (ARCHIVE_OK);
719c09f92d2SPeter Avalos 		if (memcmp("070727", p, 6) == 0 && is_afio_large(p, bytes)) {
720c09f92d2SPeter Avalos 			a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE;
721c09f92d2SPeter Avalos 			return (ARCHIVE_OK);
722c09f92d2SPeter Avalos 		}
72360b4ad09SPeter Avalos 
72460b4ad09SPeter Avalos 		/*
72560b4ad09SPeter Avalos 		 * Scan ahead until we find something that looks
72660b4ad09SPeter Avalos 		 * like an odc header.
72760b4ad09SPeter Avalos 		 */
728c09f92d2SPeter Avalos 		while (p + odc_header_size <= q) {
72960b4ad09SPeter Avalos 			switch (p[5]) {
73060b4ad09SPeter Avalos 			case '7':
731c09f92d2SPeter Avalos 				if ((memcmp("070707", p, 6) == 0
732c09f92d2SPeter Avalos 				    && is_octal(p, odc_header_size))
733c09f92d2SPeter Avalos 				    || (memcmp("070727", p, 6) == 0
734c09f92d2SPeter Avalos 				        && is_afio_large(p, q - p))) {
73560b4ad09SPeter Avalos 					skip = p - (const char *)h;
7368029ab02SPeter Avalos 					__archive_read_consume(a, skip);
73760b4ad09SPeter Avalos 					skipped += skip;
738c09f92d2SPeter Avalos 					if (p[4] == '2')
739c09f92d2SPeter Avalos 						a->archive.archive_format =
740c09f92d2SPeter Avalos 						    ARCHIVE_FORMAT_CPIO_AFIO_LARGE;
74160b4ad09SPeter Avalos 					if (skipped > 0) {
74260b4ad09SPeter Avalos 						archive_set_error(&a->archive,
74360b4ad09SPeter Avalos 						    0,
74460b4ad09SPeter Avalos 						    "Skipped %d bytes before "
74560b4ad09SPeter Avalos 						    "finding valid header",
74660b4ad09SPeter Avalos 						    (int)skipped);
74760b4ad09SPeter Avalos 						return (ARCHIVE_WARN);
74860b4ad09SPeter Avalos 					}
74960b4ad09SPeter Avalos 					return (ARCHIVE_OK);
75060b4ad09SPeter Avalos 				}
75160b4ad09SPeter Avalos 				p += 2;
75260b4ad09SPeter Avalos 				break;
75360b4ad09SPeter Avalos 			case '0':
75460b4ad09SPeter Avalos 				p++;
75560b4ad09SPeter Avalos 				break;
75660b4ad09SPeter Avalos 			default:
75760b4ad09SPeter Avalos 				p += 6;
75860b4ad09SPeter Avalos 				break;
75960b4ad09SPeter Avalos 			}
76060b4ad09SPeter Avalos 		}
76160b4ad09SPeter Avalos 		skip = p - (const char *)h;
7628029ab02SPeter Avalos 		__archive_read_consume(a, skip);
76360b4ad09SPeter Avalos 		skipped += skip;
76460b4ad09SPeter Avalos 	}
76560b4ad09SPeter Avalos }
76660b4ad09SPeter Avalos 
76760b4ad09SPeter Avalos static int
header_odc(struct archive_read * a,struct cpio * cpio,struct archive_entry * entry,size_t * namelength,size_t * name_pad)76860b4ad09SPeter Avalos header_odc(struct archive_read *a, struct cpio *cpio,
76960b4ad09SPeter Avalos     struct archive_entry *entry, size_t *namelength, size_t *name_pad)
77060b4ad09SPeter Avalos {
77160b4ad09SPeter Avalos 	const void *h;
77260b4ad09SPeter Avalos 	int r;
773c09f92d2SPeter Avalos 	const char *header;
77460b4ad09SPeter Avalos 
77560b4ad09SPeter Avalos 	a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
77660b4ad09SPeter Avalos 	a->archive.archive_format_name = "POSIX octet-oriented cpio";
77760b4ad09SPeter Avalos 
77860b4ad09SPeter Avalos 	/* Find the start of the next header. */
77960b4ad09SPeter Avalos 	r = find_odc_header(a);
78060b4ad09SPeter Avalos 	if (r < ARCHIVE_WARN)
78160b4ad09SPeter Avalos 		return (r);
78260b4ad09SPeter Avalos 
783c09f92d2SPeter Avalos 	if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_AFIO_LARGE) {
784c09f92d2SPeter Avalos 		int r2 = (header_afiol(a, cpio, entry, namelength, name_pad));
785c09f92d2SPeter Avalos 		if (r2 == ARCHIVE_OK)
786c09f92d2SPeter Avalos 			return (r);
787c09f92d2SPeter Avalos 		else
788c09f92d2SPeter Avalos 			return (r2);
789c09f92d2SPeter Avalos 	}
790c09f92d2SPeter Avalos 
79160b4ad09SPeter Avalos 	/* Read fixed-size portion of header. */
792c09f92d2SPeter Avalos 	h = __archive_read_ahead(a, odc_header_size, NULL);
7938029ab02SPeter Avalos 	if (h == NULL)
79460b4ad09SPeter Avalos 	    return (ARCHIVE_FATAL);
79560b4ad09SPeter Avalos 
79660b4ad09SPeter Avalos 	/* Parse out octal fields. */
797c09f92d2SPeter Avalos 	header = (const char *)h;
79860b4ad09SPeter Avalos 
79959bf7050SPeter Avalos 	archive_entry_set_dev(entry,
80059bf7050SPeter Avalos 		(dev_t)atol8(header + odc_dev_offset, odc_dev_size));
801c09f92d2SPeter Avalos 	archive_entry_set_ino(entry, atol8(header + odc_ino_offset, odc_ino_size));
80259bf7050SPeter Avalos 	archive_entry_set_mode(entry,
80359bf7050SPeter Avalos 		(mode_t)atol8(header + odc_mode_offset, odc_mode_size));
804c09f92d2SPeter Avalos 	archive_entry_set_uid(entry, atol8(header + odc_uid_offset, odc_uid_size));
805c09f92d2SPeter Avalos 	archive_entry_set_gid(entry, atol8(header + odc_gid_offset, odc_gid_size));
80659bf7050SPeter Avalos 	archive_entry_set_nlink(entry,
80759bf7050SPeter Avalos 		(unsigned int)atol8(header + odc_nlink_offset, odc_nlink_size));
80859bf7050SPeter Avalos 	archive_entry_set_rdev(entry,
80959bf7050SPeter Avalos 		(dev_t)atol8(header + odc_rdev_offset, odc_rdev_size));
810c09f92d2SPeter Avalos 	archive_entry_set_mtime(entry, atol8(header + odc_mtime_offset, odc_mtime_size), 0);
81159bf7050SPeter Avalos 	*namelength = (size_t)atol8(header + odc_namesize_offset, odc_namesize_size);
81260b4ad09SPeter Avalos 	*name_pad = 0; /* No padding of filename. */
81360b4ad09SPeter Avalos 
81460b4ad09SPeter Avalos 	/*
81560b4ad09SPeter Avalos 	 * Note: entry_bytes_remaining is at least 64 bits and
81660b4ad09SPeter Avalos 	 * therefore guaranteed to be big enough for a 33-bit file
81760b4ad09SPeter Avalos 	 * size.
81860b4ad09SPeter Avalos 	 */
81960b4ad09SPeter Avalos 	cpio->entry_bytes_remaining =
820c09f92d2SPeter Avalos 	    atol8(header + odc_filesize_offset, odc_filesize_size);
82160b4ad09SPeter Avalos 	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
82260b4ad09SPeter Avalos 	cpio->entry_padding = 0;
823c09f92d2SPeter Avalos 	__archive_read_consume(a, odc_header_size);
82460b4ad09SPeter Avalos 	return (r);
82560b4ad09SPeter Avalos }
82660b4ad09SPeter Avalos 
827c09f92d2SPeter Avalos /*
828c09f92d2SPeter Avalos  * NOTE: if a filename suffix is ".z", it is the file gziped by afio.
829c09f92d2SPeter Avalos  * it would be nice that we can show uncompressed file size and we can
830c09f92d2SPeter Avalos  * uncompressed file contents automatically, unfortunately we have nothing
831e95abc47Szrj  * to get a uncompressed file size while reading each header. It means
832e95abc47Szrj  * we also cannot uncompress file contents under our framework.
833c09f92d2SPeter Avalos  */
834c09f92d2SPeter Avalos static int
header_afiol(struct archive_read * a,struct cpio * cpio,struct archive_entry * entry,size_t * namelength,size_t * name_pad)835c09f92d2SPeter Avalos header_afiol(struct archive_read *a, struct cpio *cpio,
836c09f92d2SPeter Avalos     struct archive_entry *entry, size_t *namelength, size_t *name_pad)
837c09f92d2SPeter Avalos {
838c09f92d2SPeter Avalos 	const void *h;
839c09f92d2SPeter Avalos 	const char *header;
840c09f92d2SPeter Avalos 
841c09f92d2SPeter Avalos 	a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE;
842c09f92d2SPeter Avalos 	a->archive.archive_format_name = "afio large ASCII";
843c09f92d2SPeter Avalos 
844c09f92d2SPeter Avalos 	/* Read fixed-size portion of header. */
845c09f92d2SPeter Avalos 	h = __archive_read_ahead(a, afiol_header_size, NULL);
846c09f92d2SPeter Avalos 	if (h == NULL)
847c09f92d2SPeter Avalos 	    return (ARCHIVE_FATAL);
848c09f92d2SPeter Avalos 
849c09f92d2SPeter Avalos 	/* Parse out octal fields. */
850c09f92d2SPeter Avalos 	header = (const char *)h;
851c09f92d2SPeter Avalos 
85259bf7050SPeter Avalos 	archive_entry_set_dev(entry,
85359bf7050SPeter Avalos 		(dev_t)atol16(header + afiol_dev_offset, afiol_dev_size));
854c09f92d2SPeter Avalos 	archive_entry_set_ino(entry, atol16(header + afiol_ino_offset, afiol_ino_size));
85559bf7050SPeter Avalos 	archive_entry_set_mode(entry,
85659bf7050SPeter Avalos 		(mode_t)atol8(header + afiol_mode_offset, afiol_mode_size));
857c09f92d2SPeter Avalos 	archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size));
858c09f92d2SPeter Avalos 	archive_entry_set_gid(entry, atol16(header + afiol_gid_offset, afiol_gid_size));
85959bf7050SPeter Avalos 	archive_entry_set_nlink(entry,
86059bf7050SPeter Avalos 		(unsigned int)atol16(header + afiol_nlink_offset, afiol_nlink_size));
86159bf7050SPeter Avalos 	archive_entry_set_rdev(entry,
86259bf7050SPeter Avalos 		(dev_t)atol16(header + afiol_rdev_offset, afiol_rdev_size));
863c09f92d2SPeter Avalos 	archive_entry_set_mtime(entry, atol16(header + afiol_mtime_offset, afiol_mtime_size), 0);
86459bf7050SPeter Avalos 	*namelength = (size_t)atol16(header + afiol_namesize_offset, afiol_namesize_size);
865c09f92d2SPeter Avalos 	*name_pad = 0; /* No padding of filename. */
866c09f92d2SPeter Avalos 
867c09f92d2SPeter Avalos 	cpio->entry_bytes_remaining =
868c09f92d2SPeter Avalos 	    atol16(header + afiol_filesize_offset, afiol_filesize_size);
869c09f92d2SPeter Avalos 	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
870c09f92d2SPeter Avalos 	cpio->entry_padding = 0;
871c09f92d2SPeter Avalos 	__archive_read_consume(a, afiol_header_size);
872c09f92d2SPeter Avalos 	return (ARCHIVE_OK);
873c09f92d2SPeter Avalos }
874c09f92d2SPeter Avalos 
875c09f92d2SPeter Avalos 
87660b4ad09SPeter Avalos static int
header_bin_le(struct archive_read * a,struct cpio * cpio,struct archive_entry * entry,size_t * namelength,size_t * name_pad)87760b4ad09SPeter Avalos header_bin_le(struct archive_read *a, struct cpio *cpio,
87860b4ad09SPeter Avalos     struct archive_entry *entry, size_t *namelength, size_t *name_pad)
87960b4ad09SPeter Avalos {
88060b4ad09SPeter Avalos 	const void *h;
881c09f92d2SPeter Avalos 	const unsigned char *header;
88260b4ad09SPeter Avalos 
88360b4ad09SPeter Avalos 	a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;
88460b4ad09SPeter Avalos 	a->archive.archive_format_name = "cpio (little-endian binary)";
88560b4ad09SPeter Avalos 
88660b4ad09SPeter Avalos 	/* Read fixed-size portion of header. */
887c09f92d2SPeter Avalos 	h = __archive_read_ahead(a, bin_header_size, NULL);
8886b384f39SPeter Avalos 	if (h == NULL) {
8896b384f39SPeter Avalos 	    archive_set_error(&a->archive, 0,
8906b384f39SPeter Avalos 		"End of file trying to read next cpio header");
89160b4ad09SPeter Avalos 	    return (ARCHIVE_FATAL);
8926b384f39SPeter Avalos 	}
89360b4ad09SPeter Avalos 
89460b4ad09SPeter Avalos 	/* Parse out binary fields. */
895c09f92d2SPeter Avalos 	header = (const unsigned char *)h;
89660b4ad09SPeter Avalos 
897c09f92d2SPeter Avalos 	archive_entry_set_dev(entry, header[bin_dev_offset] + header[bin_dev_offset + 1] * 256);
898c09f92d2SPeter Avalos 	archive_entry_set_ino(entry, header[bin_ino_offset] + header[bin_ino_offset + 1] * 256);
899c09f92d2SPeter Avalos 	archive_entry_set_mode(entry, header[bin_mode_offset] + header[bin_mode_offset + 1] * 256);
900*50f8aa9cSAntonio Huete Jimenez 	if (cpio->option_pwb) {
901*50f8aa9cSAntonio Huete Jimenez 		/* turn off random bits left over from V6 inode */
902*50f8aa9cSAntonio Huete Jimenez 		archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);
903*50f8aa9cSAntonio Huete Jimenez 		if ((archive_entry_mode(entry) & AE_IFMT) == 0)
904*50f8aa9cSAntonio Huete Jimenez 			archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);
905*50f8aa9cSAntonio Huete Jimenez 	}
906c09f92d2SPeter Avalos 	archive_entry_set_uid(entry, header[bin_uid_offset] + header[bin_uid_offset + 1] * 256);
907c09f92d2SPeter Avalos 	archive_entry_set_gid(entry, header[bin_gid_offset] + header[bin_gid_offset + 1] * 256);
908c09f92d2SPeter Avalos 	archive_entry_set_nlink(entry, header[bin_nlink_offset] + header[bin_nlink_offset + 1] * 256);
909c09f92d2SPeter Avalos 	archive_entry_set_rdev(entry, header[bin_rdev_offset] + header[bin_rdev_offset + 1] * 256);
910c09f92d2SPeter Avalos 	archive_entry_set_mtime(entry, le4(header + bin_mtime_offset), 0);
911c09f92d2SPeter Avalos 	*namelength = header[bin_namesize_offset] + header[bin_namesize_offset + 1] * 256;
91260b4ad09SPeter Avalos 	*name_pad = *namelength & 1; /* Pad to even. */
91360b4ad09SPeter Avalos 
914c09f92d2SPeter Avalos 	cpio->entry_bytes_remaining = le4(header + bin_filesize_offset);
91560b4ad09SPeter Avalos 	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
91660b4ad09SPeter Avalos 	cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
917c09f92d2SPeter Avalos 	__archive_read_consume(a, bin_header_size);
91860b4ad09SPeter Avalos 	return (ARCHIVE_OK);
91960b4ad09SPeter Avalos }
92060b4ad09SPeter Avalos 
92160b4ad09SPeter Avalos static int
header_bin_be(struct archive_read * a,struct cpio * cpio,struct archive_entry * entry,size_t * namelength,size_t * name_pad)92260b4ad09SPeter Avalos header_bin_be(struct archive_read *a, struct cpio *cpio,
92360b4ad09SPeter Avalos     struct archive_entry *entry, size_t *namelength, size_t *name_pad)
92460b4ad09SPeter Avalos {
92560b4ad09SPeter Avalos 	const void *h;
926c09f92d2SPeter Avalos 	const unsigned char *header;
92760b4ad09SPeter Avalos 
92860b4ad09SPeter Avalos 	a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
92960b4ad09SPeter Avalos 	a->archive.archive_format_name = "cpio (big-endian binary)";
93060b4ad09SPeter Avalos 
93160b4ad09SPeter Avalos 	/* Read fixed-size portion of header. */
932c09f92d2SPeter Avalos 	h = __archive_read_ahead(a, bin_header_size, NULL);
9336b384f39SPeter Avalos 	if (h == NULL) {
9346b384f39SPeter Avalos 	    archive_set_error(&a->archive, 0,
9356b384f39SPeter Avalos 		"End of file trying to read next cpio header");
93660b4ad09SPeter Avalos 	    return (ARCHIVE_FATAL);
9376b384f39SPeter Avalos 	}
93860b4ad09SPeter Avalos 
93960b4ad09SPeter Avalos 	/* Parse out binary fields. */
940c09f92d2SPeter Avalos 	header = (const unsigned char *)h;
941c09f92d2SPeter Avalos 
942c09f92d2SPeter Avalos 	archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]);
943c09f92d2SPeter Avalos 	archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]);
944c09f92d2SPeter Avalos 	archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]);
945*50f8aa9cSAntonio Huete Jimenez 	if (cpio->option_pwb) {
946*50f8aa9cSAntonio Huete Jimenez 		/* turn off random bits left over from V6 inode */
947*50f8aa9cSAntonio Huete Jimenez 		archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);
948*50f8aa9cSAntonio Huete Jimenez 		if ((archive_entry_mode(entry) & AE_IFMT) == 0)
949*50f8aa9cSAntonio Huete Jimenez 			archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);
950*50f8aa9cSAntonio Huete Jimenez 	}
951c09f92d2SPeter Avalos 	archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]);
952c09f92d2SPeter Avalos 	archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]);
953c09f92d2SPeter Avalos 	archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]);
954c09f92d2SPeter Avalos 	archive_entry_set_rdev(entry, header[bin_rdev_offset] * 256 + header[bin_rdev_offset + 1]);
955c09f92d2SPeter Avalos 	archive_entry_set_mtime(entry, be4(header + bin_mtime_offset), 0);
956c09f92d2SPeter Avalos 	*namelength = header[bin_namesize_offset] * 256 + header[bin_namesize_offset + 1];
95760b4ad09SPeter Avalos 	*name_pad = *namelength & 1; /* Pad to even. */
95860b4ad09SPeter Avalos 
959c09f92d2SPeter Avalos 	cpio->entry_bytes_remaining = be4(header + bin_filesize_offset);
96060b4ad09SPeter Avalos 	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
96160b4ad09SPeter Avalos 	cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
962c09f92d2SPeter Avalos 	    __archive_read_consume(a, bin_header_size);
96360b4ad09SPeter Avalos 	return (ARCHIVE_OK);
96460b4ad09SPeter Avalos }
96560b4ad09SPeter Avalos 
96660b4ad09SPeter Avalos static int
archive_read_format_cpio_cleanup(struct archive_read * a)96760b4ad09SPeter Avalos archive_read_format_cpio_cleanup(struct archive_read *a)
96860b4ad09SPeter Avalos {
96960b4ad09SPeter Avalos 	struct cpio *cpio;
97060b4ad09SPeter Avalos 
97160b4ad09SPeter Avalos 	cpio = (struct cpio *)(a->format->data);
97260b4ad09SPeter Avalos         /* Free inode->name map */
97360b4ad09SPeter Avalos         while (cpio->links_head != NULL) {
97460b4ad09SPeter Avalos                 struct links_entry *lp = cpio->links_head->next;
97560b4ad09SPeter Avalos 
97660b4ad09SPeter Avalos                 free(cpio->links_head->name);
97760b4ad09SPeter Avalos                 free(cpio->links_head);
97860b4ad09SPeter Avalos                 cpio->links_head = lp;
97960b4ad09SPeter Avalos         }
98060b4ad09SPeter Avalos 	free(cpio);
98160b4ad09SPeter Avalos 	(a->format->data) = NULL;
98260b4ad09SPeter Avalos 	return (ARCHIVE_OK);
98360b4ad09SPeter Avalos }
98460b4ad09SPeter Avalos 
9856b384f39SPeter Avalos static int64_t
le4(const unsigned char * p)98660b4ad09SPeter Avalos le4(const unsigned char *p)
98760b4ad09SPeter Avalos {
9886b384f39SPeter Avalos 	return ((p[0] << 16) + (((int64_t)p[1]) << 24) + (p[2] << 0) + (p[3] << 8));
98960b4ad09SPeter Avalos }
99060b4ad09SPeter Avalos 
99160b4ad09SPeter Avalos 
9926b384f39SPeter Avalos static int64_t
be4(const unsigned char * p)99360b4ad09SPeter Avalos be4(const unsigned char *p)
99460b4ad09SPeter Avalos {
9956b384f39SPeter Avalos 	return ((((int64_t)p[0]) << 24) + (p[1] << 16) + (p[2] << 8) + (p[3]));
99660b4ad09SPeter Avalos }
99760b4ad09SPeter Avalos 
99860b4ad09SPeter Avalos /*
99960b4ad09SPeter Avalos  * Note that this implementation does not (and should not!) obey
100060b4ad09SPeter Avalos  * locale settings; you cannot simply substitute strtol here, since
100160b4ad09SPeter Avalos  * it does obey locale.
100260b4ad09SPeter Avalos  */
100360b4ad09SPeter Avalos static int64_t
atol8(const char * p,unsigned char_cnt)100460b4ad09SPeter Avalos atol8(const char *p, unsigned char_cnt)
100560b4ad09SPeter Avalos {
100660b4ad09SPeter Avalos 	int64_t l;
100760b4ad09SPeter Avalos 	int digit;
100860b4ad09SPeter Avalos 
100960b4ad09SPeter Avalos 	l = 0;
101060b4ad09SPeter Avalos 	while (char_cnt-- > 0) {
101160b4ad09SPeter Avalos 		if (*p >= '0' && *p <= '7')
101260b4ad09SPeter Avalos 			digit = *p - '0';
101360b4ad09SPeter Avalos 		else
101460b4ad09SPeter Avalos 			return (l);
101560b4ad09SPeter Avalos 		p++;
101660b4ad09SPeter Avalos 		l <<= 3;
101760b4ad09SPeter Avalos 		l |= digit;
101860b4ad09SPeter Avalos 	}
101960b4ad09SPeter Avalos 	return (l);
102060b4ad09SPeter Avalos }
102160b4ad09SPeter Avalos 
102260b4ad09SPeter Avalos static int64_t
atol16(const char * p,unsigned char_cnt)102360b4ad09SPeter Avalos atol16(const char *p, unsigned char_cnt)
102460b4ad09SPeter Avalos {
102560b4ad09SPeter Avalos 	int64_t l;
102660b4ad09SPeter Avalos 	int digit;
102760b4ad09SPeter Avalos 
102860b4ad09SPeter Avalos 	l = 0;
102960b4ad09SPeter Avalos 	while (char_cnt-- > 0) {
103060b4ad09SPeter Avalos 		if (*p >= 'a' && *p <= 'f')
103160b4ad09SPeter Avalos 			digit = *p - 'a' + 10;
103260b4ad09SPeter Avalos 		else if (*p >= 'A' && *p <= 'F')
103360b4ad09SPeter Avalos 			digit = *p - 'A' + 10;
103460b4ad09SPeter Avalos 		else if (*p >= '0' && *p <= '9')
103560b4ad09SPeter Avalos 			digit = *p - '0';
103660b4ad09SPeter Avalos 		else
103760b4ad09SPeter Avalos 			return (l);
103860b4ad09SPeter Avalos 		p++;
103960b4ad09SPeter Avalos 		l <<= 4;
104060b4ad09SPeter Avalos 		l |= digit;
104160b4ad09SPeter Avalos 	}
104260b4ad09SPeter Avalos 	return (l);
104360b4ad09SPeter Avalos }
104460b4ad09SPeter Avalos 
1045c09f92d2SPeter Avalos static int
record_hardlink(struct archive_read * a,struct cpio * cpio,struct archive_entry * entry)1046c09f92d2SPeter Avalos record_hardlink(struct archive_read *a,
1047c09f92d2SPeter Avalos     struct cpio *cpio, struct archive_entry *entry)
104860b4ad09SPeter Avalos {
104960b4ad09SPeter Avalos 	struct links_entry      *le;
105060b4ad09SPeter Avalos 	dev_t dev;
10519c82a63eSPeter Avalos 	int64_t ino;
10529c82a63eSPeter Avalos 
10539c82a63eSPeter Avalos 	if (archive_entry_nlink(entry) <= 1)
1054c09f92d2SPeter Avalos 		return (ARCHIVE_OK);
105560b4ad09SPeter Avalos 
105660b4ad09SPeter Avalos 	dev = archive_entry_dev(entry);
10579c82a63eSPeter Avalos 	ino = archive_entry_ino64(entry);
105860b4ad09SPeter Avalos 
105960b4ad09SPeter Avalos 	/*
106060b4ad09SPeter Avalos 	 * First look in the list of multiply-linked files.  If we've
106160b4ad09SPeter Avalos 	 * already dumped it, convert this entry to a hard link entry.
106260b4ad09SPeter Avalos 	 */
106360b4ad09SPeter Avalos 	for (le = cpio->links_head; le; le = le->next) {
106460b4ad09SPeter Avalos 		if (le->dev == dev && le->ino == ino) {
106560b4ad09SPeter Avalos 			archive_entry_copy_hardlink(entry, le->name);
106660b4ad09SPeter Avalos 
106760b4ad09SPeter Avalos 			if (--le->links <= 0) {
106860b4ad09SPeter Avalos 				if (le->previous != NULL)
106960b4ad09SPeter Avalos 					le->previous->next = le->next;
107060b4ad09SPeter Avalos 				if (le->next != NULL)
107160b4ad09SPeter Avalos 					le->next->previous = le->previous;
107260b4ad09SPeter Avalos 				if (cpio->links_head == le)
107360b4ad09SPeter Avalos 					cpio->links_head = le->next;
107460b4ad09SPeter Avalos 				free(le->name);
107560b4ad09SPeter Avalos 				free(le);
107660b4ad09SPeter Avalos 			}
107760b4ad09SPeter Avalos 
1078c09f92d2SPeter Avalos 			return (ARCHIVE_OK);
107960b4ad09SPeter Avalos 		}
108060b4ad09SPeter Avalos 	}
108160b4ad09SPeter Avalos 
108260b4ad09SPeter Avalos 	le = (struct links_entry *)malloc(sizeof(struct links_entry));
1083c09f92d2SPeter Avalos 	if (le == NULL) {
1084c09f92d2SPeter Avalos 		archive_set_error(&a->archive,
1085c09f92d2SPeter Avalos 		    ENOMEM, "Out of memory adding file to list");
1086c09f92d2SPeter Avalos 		return (ARCHIVE_FATAL);
1087c09f92d2SPeter Avalos 	}
108860b4ad09SPeter Avalos 	if (cpio->links_head != NULL)
108960b4ad09SPeter Avalos 		cpio->links_head->previous = le;
109060b4ad09SPeter Avalos 	le->next = cpio->links_head;
109160b4ad09SPeter Avalos 	le->previous = NULL;
109260b4ad09SPeter Avalos 	cpio->links_head = le;
109360b4ad09SPeter Avalos 	le->dev = dev;
109460b4ad09SPeter Avalos 	le->ino = ino;
109560b4ad09SPeter Avalos 	le->links = archive_entry_nlink(entry) - 1;
109660b4ad09SPeter Avalos 	le->name = strdup(archive_entry_pathname(entry));
1097c09f92d2SPeter Avalos 	if (le->name == NULL) {
1098c09f92d2SPeter Avalos 		archive_set_error(&a->archive,
1099c09f92d2SPeter Avalos 		    ENOMEM, "Out of memory adding file to list");
1100c09f92d2SPeter Avalos 		return (ARCHIVE_FATAL);
1101c09f92d2SPeter Avalos 	}
1102c09f92d2SPeter Avalos 
1103c09f92d2SPeter Avalos 	return (ARCHIVE_OK);
110460b4ad09SPeter Avalos }
1105