archive_write_set_format_cpio_newc.c revision 344673
1/*-
2 * Copyright (c) 2003-2007 Tim Kientzle
3 * Copyright (c) 2006 Rudolf Marek SYSGO s.r.o.
4 * Copyright (c) 2011-2012 Michihiro NAKAJIMA
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "archive_platform.h"
29__FBSDID("$FreeBSD: stable/11/contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c 344673 2019-02-28 22:56:15Z mm $");
30
31#ifdef HAVE_ERRNO_H
32#include <errno.h>
33#endif
34#include <stdio.h>
35#ifdef HAVE_STDLIB_H
36#include <stdlib.h>
37#endif
38#ifdef HAVE_STRING_H
39#include <string.h>
40#endif
41
42#include "archive.h"
43#include "archive_entry.h"
44#include "archive_entry_locale.h"
45#include "archive_private.h"
46#include "archive_write_private.h"
47
48static ssize_t	archive_write_newc_data(struct archive_write *,
49		    const void *buff, size_t s);
50static int	archive_write_newc_close(struct archive_write *);
51static int	archive_write_newc_free(struct archive_write *);
52static int	archive_write_newc_finish_entry(struct archive_write *);
53static int	archive_write_newc_header(struct archive_write *,
54		    struct archive_entry *);
55static int      archive_write_newc_options(struct archive_write *,
56		    const char *, const char *);
57static int	format_hex(int64_t, void *, int);
58static int64_t	format_hex_recursive(int64_t, char *, int);
59static int	write_header(struct archive_write *, struct archive_entry *);
60
61struct cpio {
62	uint64_t	  entry_bytes_remaining;
63	int		  padding;
64
65	struct archive_string_conv *opt_sconv;
66	struct archive_string_conv *sconv_default;
67	int		  init_default_conversion;
68};
69
70#define	c_magic_offset 0
71#define	c_magic_size 6
72#define	c_ino_offset 6
73#define	c_ino_size 8
74#define	c_mode_offset 14
75#define	c_mode_size 8
76#define	c_uid_offset 22
77#define	c_uid_size 8
78#define	c_gid_offset 30
79#define	c_gid_size 8
80#define	c_nlink_offset 38
81#define	c_nlink_size 8
82#define	c_mtime_offset 46
83#define	c_mtime_size 8
84#define	c_filesize_offset 54
85#define	c_filesize_size 8
86#define	c_devmajor_offset 62
87#define	c_devmajor_size 8
88#define	c_devminor_offset 70
89#define	c_devminor_size 8
90#define	c_rdevmajor_offset 78
91#define	c_rdevmajor_size 8
92#define	c_rdevminor_offset 86
93#define	c_rdevminor_size 8
94#define	c_namesize_offset 94
95#define	c_namesize_size 8
96#define	c_checksum_offset 102
97#define	c_checksum_size 8
98#define	c_header_size 110
99
100/* Logic trick: difference between 'n' and next multiple of 4 */
101#define PAD4(n)	(3 & (1 + ~(n)))
102
103/*
104 * Set output format to 'cpio' format.
105 */
106int
107archive_write_set_format_cpio_newc(struct archive *_a)
108{
109	struct archive_write *a = (struct archive_write *)_a;
110	struct cpio *cpio;
111
112	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
113	    ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_newc");
114
115	/* If someone else was already registered, unregister them. */
116	if (a->format_free != NULL)
117		(a->format_free)(a);
118
119	cpio = (struct cpio *)calloc(1, sizeof(*cpio));
120	if (cpio == NULL) {
121		archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
122		return (ARCHIVE_FATAL);
123	}
124	a->format_data = cpio;
125	a->format_name = "cpio";
126	a->format_options = archive_write_newc_options;
127	a->format_write_header = archive_write_newc_header;
128	a->format_write_data = archive_write_newc_data;
129	a->format_finish_entry = archive_write_newc_finish_entry;
130	a->format_close = archive_write_newc_close;
131	a->format_free = archive_write_newc_free;
132	a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
133	a->archive.archive_format_name = "SVR4 cpio nocrc";
134	return (ARCHIVE_OK);
135}
136
137static int
138archive_write_newc_options(struct archive_write *a, const char *key,
139    const char *val)
140{
141	struct cpio *cpio = (struct cpio *)a->format_data;
142	int ret = ARCHIVE_FAILED;
143
144	if (strcmp(key, "hdrcharset")  == 0) {
145		if (val == NULL || val[0] == 0)
146			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
147			    "%s: hdrcharset option needs a character-set name",
148			    a->format_name);
149		else {
150			cpio->opt_sconv = archive_string_conversion_to_charset(
151			    &a->archive, val, 0);
152			if (cpio->opt_sconv != NULL)
153				ret = ARCHIVE_OK;
154			else
155				ret = ARCHIVE_FATAL;
156		}
157		return (ret);
158	}
159
160	/* Note: The "warn" return is just to inform the options
161	 * supervisor that we didn't handle it.  It will generate
162	 * a suitable error if no one used this option. */
163	return (ARCHIVE_WARN);
164}
165
166static struct archive_string_conv *
167get_sconv(struct archive_write *a)
168{
169	struct cpio *cpio;
170	struct archive_string_conv *sconv;
171
172	cpio = (struct cpio *)a->format_data;
173	sconv = cpio->opt_sconv;
174	if (sconv == NULL) {
175		if (!cpio->init_default_conversion) {
176			cpio->sconv_default =
177			    archive_string_default_conversion_for_write(
178			      &(a->archive));
179			cpio->init_default_conversion = 1;
180		}
181		sconv = cpio->sconv_default;
182	}
183	return (sconv);
184}
185
186static int
187archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)
188{
189	const char *path;
190	size_t len;
191
192	if (archive_entry_filetype(entry) == 0) {
193		archive_set_error(&a->archive, -1, "Filetype required");
194		return (ARCHIVE_FAILED);
195	}
196
197	if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0
198	    && errno == ENOMEM) {
199		archive_set_error(&a->archive, ENOMEM,
200		    "Can't allocate memory for Pathname");
201		return (ARCHIVE_FATAL);
202	}
203	if (len == 0 || path == NULL || path[0] == '\0') {
204		archive_set_error(&a->archive, -1, "Pathname required");
205		return (ARCHIVE_FAILED);
206	}
207
208	if (archive_entry_hardlink(entry) == NULL
209	    && (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0)) {
210		archive_set_error(&a->archive, -1, "Size required");
211		return (ARCHIVE_FAILED);
212	}
213	return write_header(a, entry);
214}
215
216static int
217write_header(struct archive_write *a, struct archive_entry *entry)
218{
219	int64_t ino;
220	struct cpio *cpio;
221	const char *p, *path;
222	int pathlength, ret, ret_final;
223	char h[c_header_size];
224	struct archive_string_conv *sconv;
225	struct archive_entry *entry_main;
226	size_t len;
227	int pad;
228
229	cpio = (struct cpio *)a->format_data;
230	ret_final = ARCHIVE_OK;
231	sconv = get_sconv(a);
232
233#if defined(_WIN32) && !defined(__CYGWIN__)
234	/* Make sure the path separators in pathname, hardlink and symlink
235	 * are all slash '/', not the Windows path separator '\'. */
236	entry_main = __la_win_entry_in_posix_pathseparator(entry);
237	if (entry_main == NULL) {
238		archive_set_error(&a->archive, ENOMEM,
239		    "Can't allocate ustar data");
240		return(ARCHIVE_FATAL);
241	}
242	if (entry != entry_main)
243		entry = entry_main;
244	else
245		entry_main = NULL;
246#else
247	entry_main = NULL;
248#endif
249
250	ret = archive_entry_pathname_l(entry, &path, &len, sconv);
251	if (ret != 0) {
252		if (errno == ENOMEM) {
253			archive_set_error(&a->archive, ENOMEM,
254			    "Can't allocate memory for Pathname");
255			ret_final = ARCHIVE_FATAL;
256			goto exit_write_header;
257		}
258		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
259		    "Can't translate pathname '%s' to %s",
260		    archive_entry_pathname(entry),
261		    archive_string_conversion_charset_name(sconv));
262		ret_final = ARCHIVE_WARN;
263	}
264	pathlength = (int)len + 1; /* Include trailing null. */
265
266	memset(h, 0, c_header_size);
267	format_hex(0x070701, h + c_magic_offset, c_magic_size);
268	format_hex(archive_entry_devmajor(entry), h + c_devmajor_offset,
269	    c_devmajor_size);
270	format_hex(archive_entry_devminor(entry), h + c_devminor_offset,
271	    c_devminor_size);
272
273	ino = archive_entry_ino64(entry);
274	if (ino > 0xffffffff) {
275		archive_set_error(&a->archive, ERANGE,
276		    "large inode number truncated");
277		ret_final = ARCHIVE_WARN;
278	}
279
280	/* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */
281	format_hex(ino & 0xffffffff, h + c_ino_offset, c_ino_size);
282	format_hex(archive_entry_mode(entry), h + c_mode_offset, c_mode_size);
283	format_hex(archive_entry_uid(entry), h + c_uid_offset, c_uid_size);
284	format_hex(archive_entry_gid(entry), h + c_gid_offset, c_gid_size);
285	format_hex(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);
286	if (archive_entry_filetype(entry) == AE_IFBLK
287	    || archive_entry_filetype(entry) == AE_IFCHR) {
288	    format_hex(archive_entry_rdevmajor(entry), h + c_rdevmajor_offset, c_rdevmajor_size);
289	    format_hex(archive_entry_rdevminor(entry), h + c_rdevminor_offset, c_rdevminor_size);
290	} else {
291	    format_hex(0, h + c_rdevmajor_offset, c_rdevmajor_size);
292	    format_hex(0, h + c_rdevminor_offset, c_rdevminor_size);
293	}
294	format_hex(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
295	format_hex(pathlength, h + c_namesize_offset, c_namesize_size);
296	format_hex(0, h + c_checksum_offset, c_checksum_size);
297
298	/* Non-regular files don't store bodies. */
299	if (archive_entry_filetype(entry) != AE_IFREG)
300		archive_entry_set_size(entry, 0);
301
302	/* Symlinks get the link written as the body of the entry. */
303	ret = archive_entry_symlink_l(entry, &p, &len, sconv);
304	if (ret != 0) {
305		if (errno == ENOMEM) {
306			archive_set_error(&a->archive, ENOMEM,
307			    "Can't allocate memory for Likname");
308			ret_final = ARCHIVE_FATAL;
309			goto exit_write_header;
310		}
311		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
312		    "Can't translate linkname '%s' to %s",
313		    archive_entry_symlink(entry),
314		    archive_string_conversion_charset_name(sconv));
315		ret_final = ARCHIVE_WARN;
316	}
317	if (len > 0 && p != NULL  &&  *p != '\0')
318		ret = format_hex(strlen(p), h + c_filesize_offset,
319		    c_filesize_size);
320	else
321		ret = format_hex(archive_entry_size(entry),
322		    h + c_filesize_offset, c_filesize_size);
323	if (ret) {
324		archive_set_error(&a->archive, ERANGE,
325		    "File is too large for this format.");
326		ret_final = ARCHIVE_FAILED;
327		goto exit_write_header;
328	}
329
330	ret = __archive_write_output(a, h, c_header_size);
331	if (ret != ARCHIVE_OK) {
332		ret_final = ARCHIVE_FATAL;
333		goto exit_write_header;
334	}
335
336	/* Pad pathname to even length. */
337	ret = __archive_write_output(a, path, pathlength);
338	if (ret != ARCHIVE_OK) {
339		ret_final = ARCHIVE_FATAL;
340		goto exit_write_header;
341	}
342	pad = PAD4(pathlength + c_header_size);
343	if (pad) {
344		ret = __archive_write_output(a, "\0\0\0", pad);
345		if (ret != ARCHIVE_OK) {
346			ret_final = ARCHIVE_FATAL;
347			goto exit_write_header;
348		}
349	}
350
351	cpio->entry_bytes_remaining = archive_entry_size(entry);
352	cpio->padding = (int)PAD4(cpio->entry_bytes_remaining);
353
354	/* Write the symlink now. */
355	if (p != NULL  &&  *p != '\0') {
356		ret = __archive_write_output(a, p, strlen(p));
357		if (ret != ARCHIVE_OK) {
358			ret_final = ARCHIVE_FATAL;
359			goto exit_write_header;
360		}
361		pad = PAD4(strlen(p));
362		ret = __archive_write_output(a, "\0\0\0", pad);
363		if (ret != ARCHIVE_OK) {
364			ret_final = ARCHIVE_FATAL;
365			goto exit_write_header;
366		}
367	}
368exit_write_header:
369	archive_entry_free(entry_main);
370	return (ret_final);
371}
372
373static ssize_t
374archive_write_newc_data(struct archive_write *a, const void *buff, size_t s)
375{
376	struct cpio *cpio;
377	int ret;
378
379	cpio = (struct cpio *)a->format_data;
380	if (s > cpio->entry_bytes_remaining)
381		s = (size_t)cpio->entry_bytes_remaining;
382
383	ret = __archive_write_output(a, buff, s);
384	cpio->entry_bytes_remaining -= s;
385	if (ret >= 0)
386		return (s);
387	else
388		return (ret);
389}
390
391/*
392 * Format a number into the specified field.
393 */
394static int
395format_hex(int64_t v, void *p, int digits)
396{
397	int64_t	max;
398	int	ret;
399
400	max = (((int64_t)1) << (digits * 4)) - 1;
401	if (v >= 0  &&  v <= max) {
402	    format_hex_recursive(v, (char *)p, digits);
403	    ret = 0;
404	} else {
405	    format_hex_recursive(max, (char *)p, digits);
406	    ret = -1;
407	}
408	return (ret);
409}
410
411static int64_t
412format_hex_recursive(int64_t v, char *p, int s)
413{
414	if (s == 0)
415		return (v);
416	v = format_hex_recursive(v, p+1, s-1);
417	*p = "0123456789abcdef"[v & 0xf];
418	return (v >> 4);
419}
420
421static int
422archive_write_newc_close(struct archive_write *a)
423{
424	int er;
425	struct archive_entry *trailer;
426
427	trailer = archive_entry_new();
428	archive_entry_set_nlink(trailer, 1);
429	archive_entry_set_size(trailer, 0);
430	archive_entry_set_pathname(trailer, "TRAILER!!!");
431	/* Bypass the required data checks. */
432	er = write_header(a, trailer);
433	archive_entry_free(trailer);
434	return (er);
435}
436
437static int
438archive_write_newc_free(struct archive_write *a)
439{
440	struct cpio *cpio;
441
442	cpio = (struct cpio *)a->format_data;
443	free(cpio);
444	a->format_data = NULL;
445	return (ARCHIVE_OK);
446}
447
448static int
449archive_write_newc_finish_entry(struct archive_write *a)
450{
451	struct cpio *cpio;
452
453	cpio = (struct cpio *)a->format_data;
454	return (__archive_write_nulls(a,
455		(size_t)cpio->entry_bytes_remaining + cpio->padding));
456}
457