1caf54c4fSMartin Matuska /*-
2caf54c4fSMartin Matuska  * Copyright (c) 2003-2007 Tim Kientzle
36c95142eSMartin Matuska  * Copyright (c) 2011-2012 Michihiro NAKAJIMA
4caf54c4fSMartin Matuska  * All rights reserved.
5caf54c4fSMartin Matuska  *
6caf54c4fSMartin Matuska  * Redistribution and use in source and binary forms, with or without
7caf54c4fSMartin Matuska  * modification, are permitted provided that the following conditions
8caf54c4fSMartin Matuska  * are met:
9caf54c4fSMartin Matuska  * 1. Redistributions of source code must retain the above copyright
10caf54c4fSMartin Matuska  *    notice, this list of conditions and the following disclaimer.
11caf54c4fSMartin Matuska  * 2. Redistributions in binary form must reproduce the above copyright
12caf54c4fSMartin Matuska  *    notice, this list of conditions and the following disclaimer in the
13caf54c4fSMartin Matuska  *    documentation and/or other materials provided with the distribution.
14caf54c4fSMartin Matuska  *
15caf54c4fSMartin Matuska  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16caf54c4fSMartin Matuska  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17caf54c4fSMartin Matuska  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18caf54c4fSMartin Matuska  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19caf54c4fSMartin Matuska  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20caf54c4fSMartin Matuska  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21caf54c4fSMartin Matuska  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22caf54c4fSMartin Matuska  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23caf54c4fSMartin Matuska  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24caf54c4fSMartin Matuska  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25caf54c4fSMartin Matuska  */
26caf54c4fSMartin Matuska 
27caf54c4fSMartin Matuska #include "archive_platform.h"
28caf54c4fSMartin Matuska 
29caf54c4fSMartin Matuska #ifdef HAVE_ERRNO_H
30caf54c4fSMartin Matuska #include <errno.h>
31caf54c4fSMartin Matuska #endif
32caf54c4fSMartin Matuska #include <stdio.h>
33caf54c4fSMartin Matuska #ifdef HAVE_STDLIB_H
34caf54c4fSMartin Matuska #include <stdlib.h>
35caf54c4fSMartin Matuska #endif
36caf54c4fSMartin Matuska #ifdef HAVE_STRING_H
37caf54c4fSMartin Matuska #include <string.h>
38caf54c4fSMartin Matuska #endif
39caf54c4fSMartin Matuska 
40caf54c4fSMartin Matuska #include "archive.h"
41caf54c4fSMartin Matuska #include "archive_entry.h"
426c95142eSMartin Matuska #include "archive_entry_locale.h"
43caf54c4fSMartin Matuska #include "archive_private.h"
44caf54c4fSMartin Matuska #include "archive_write_private.h"
45f9762417SMartin Matuska #include "archive_write_set_format_private.h"
46caf54c4fSMartin Matuska 
47caf54c4fSMartin Matuska struct ustar {
48caf54c4fSMartin Matuska 	uint64_t	entry_bytes_remaining;
49caf54c4fSMartin Matuska 	uint64_t	entry_padding;
506c95142eSMartin Matuska 
516c95142eSMartin Matuska 	struct archive_string_conv *opt_sconv;
526c95142eSMartin Matuska 	struct archive_string_conv *sconv_default;
536c95142eSMartin Matuska 	int	init_default_conversion;
54caf54c4fSMartin Matuska };
55caf54c4fSMartin Matuska 
56caf54c4fSMartin Matuska /*
57caf54c4fSMartin Matuska  * Define structure of POSIX 'ustar' tar header.
58caf54c4fSMartin Matuska  */
59caf54c4fSMartin Matuska #define	USTAR_name_offset 0
60caf54c4fSMartin Matuska #define	USTAR_name_size 100
61caf54c4fSMartin Matuska #define	USTAR_mode_offset 100
62caf54c4fSMartin Matuska #define	USTAR_mode_size 6
63caf54c4fSMartin Matuska #define	USTAR_mode_max_size 8
64caf54c4fSMartin Matuska #define	USTAR_uid_offset 108
65caf54c4fSMartin Matuska #define	USTAR_uid_size 6
66caf54c4fSMartin Matuska #define	USTAR_uid_max_size 8
67caf54c4fSMartin Matuska #define	USTAR_gid_offset 116
68caf54c4fSMartin Matuska #define	USTAR_gid_size 6
69caf54c4fSMartin Matuska #define	USTAR_gid_max_size 8
70caf54c4fSMartin Matuska #define	USTAR_size_offset 124
71caf54c4fSMartin Matuska #define	USTAR_size_size 11
72caf54c4fSMartin Matuska #define	USTAR_size_max_size 12
73caf54c4fSMartin Matuska #define	USTAR_mtime_offset 136
74caf54c4fSMartin Matuska #define	USTAR_mtime_size 11
75caf54c4fSMartin Matuska #define	USTAR_mtime_max_size 11
76caf54c4fSMartin Matuska #define	USTAR_checksum_offset 148
77caf54c4fSMartin Matuska #define	USTAR_checksum_size 8
78caf54c4fSMartin Matuska #define	USTAR_typeflag_offset 156
79caf54c4fSMartin Matuska #define	USTAR_typeflag_size 1
80caf54c4fSMartin Matuska #define	USTAR_linkname_offset 157
81caf54c4fSMartin Matuska #define	USTAR_linkname_size 100
82caf54c4fSMartin Matuska #define	USTAR_magic_offset 257
83caf54c4fSMartin Matuska #define	USTAR_magic_size 6
84caf54c4fSMartin Matuska #define	USTAR_version_offset 263
85caf54c4fSMartin Matuska #define	USTAR_version_size 2
86caf54c4fSMartin Matuska #define	USTAR_uname_offset 265
87caf54c4fSMartin Matuska #define	USTAR_uname_size 32
88caf54c4fSMartin Matuska #define	USTAR_gname_offset 297
89caf54c4fSMartin Matuska #define	USTAR_gname_size 32
90caf54c4fSMartin Matuska #define	USTAR_rdevmajor_offset 329
91caf54c4fSMartin Matuska #define	USTAR_rdevmajor_size 6
92caf54c4fSMartin Matuska #define	USTAR_rdevmajor_max_size 8
93caf54c4fSMartin Matuska #define	USTAR_rdevminor_offset 337
94caf54c4fSMartin Matuska #define	USTAR_rdevminor_size 6
95caf54c4fSMartin Matuska #define	USTAR_rdevminor_max_size 8
96caf54c4fSMartin Matuska #define	USTAR_prefix_offset 345
97caf54c4fSMartin Matuska #define	USTAR_prefix_size 155
98caf54c4fSMartin Matuska #define	USTAR_padding_offset 500
99caf54c4fSMartin Matuska #define	USTAR_padding_size 12
100caf54c4fSMartin Matuska 
101caf54c4fSMartin Matuska /*
102caf54c4fSMartin Matuska  * A filled-in copy of the header for initialization.
103caf54c4fSMartin Matuska  */
104caf54c4fSMartin Matuska static const char template_header[] = {
105caf54c4fSMartin Matuska 	/* name: 100 bytes */
106caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
107caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
108caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
109caf54c4fSMartin Matuska 	0,0,0,0,
110caf54c4fSMartin Matuska 	/* Mode, space-null termination: 8 bytes */
111caf54c4fSMartin Matuska 	'0','0','0','0','0','0', ' ','\0',
112caf54c4fSMartin Matuska 	/* uid, space-null termination: 8 bytes */
113caf54c4fSMartin Matuska 	'0','0','0','0','0','0', ' ','\0',
114caf54c4fSMartin Matuska 	/* gid, space-null termination: 8 bytes */
115caf54c4fSMartin Matuska 	'0','0','0','0','0','0', ' ','\0',
116a2e802b7SMartin Matuska 	/* size, space termination: 12 bytes */
117caf54c4fSMartin Matuska 	'0','0','0','0','0','0','0','0','0','0','0', ' ',
118a2e802b7SMartin Matuska 	/* mtime, space termination: 12 bytes */
119caf54c4fSMartin Matuska 	'0','0','0','0','0','0','0','0','0','0','0', ' ',
120caf54c4fSMartin Matuska 	/* Initial checksum value: 8 spaces */
121caf54c4fSMartin Matuska 	' ',' ',' ',' ',' ',' ',' ',' ',
122caf54c4fSMartin Matuska 	/* Typeflag: 1 byte */
123caf54c4fSMartin Matuska 	'0',			/* '0' = regular file */
124caf54c4fSMartin Matuska 	/* Linkname: 100 bytes */
125caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
126caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
127caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
128caf54c4fSMartin Matuska 	0,0,0,0,
129caf54c4fSMartin Matuska 	/* Magic: 6 bytes, Version: 2 bytes */
130caf54c4fSMartin Matuska 	'u','s','t','a','r','\0', '0','0',
131caf54c4fSMartin Matuska 	/* Uname: 32 bytes */
132caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
133caf54c4fSMartin Matuska 	/* Gname: 32 bytes */
134caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
135caf54c4fSMartin Matuska 	/* rdevmajor + space/null padding: 8 bytes */
136caf54c4fSMartin Matuska 	'0','0','0','0','0','0', ' ','\0',
137caf54c4fSMartin Matuska 	/* rdevminor + space/null padding: 8 bytes */
138caf54c4fSMartin Matuska 	'0','0','0','0','0','0', ' ','\0',
139caf54c4fSMartin Matuska 	/* Prefix: 155 bytes */
140caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
141caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
142caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
143caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
144caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,
145caf54c4fSMartin Matuska 	/* Padding: 12 bytes */
146caf54c4fSMartin Matuska 	0,0,0,0,0,0,0,0, 0,0,0,0
147caf54c4fSMartin Matuska };
148caf54c4fSMartin Matuska 
149caf54c4fSMartin Matuska static ssize_t	archive_write_ustar_data(struct archive_write *a, const void *buff,
150caf54c4fSMartin Matuska 		    size_t s);
1516c95142eSMartin Matuska static int	archive_write_ustar_free(struct archive_write *);
1526c95142eSMartin Matuska static int	archive_write_ustar_close(struct archive_write *);
153caf54c4fSMartin Matuska static int	archive_write_ustar_finish_entry(struct archive_write *);
154caf54c4fSMartin Matuska static int	archive_write_ustar_header(struct archive_write *,
155caf54c4fSMartin Matuska 		    struct archive_entry *entry);
1566c95142eSMartin Matuska static int	archive_write_ustar_options(struct archive_write *,
1576c95142eSMartin Matuska 		    const char *, const char *);
158caf54c4fSMartin Matuska static int	format_256(int64_t, char *, int);
159caf54c4fSMartin Matuska static int	format_number(int64_t, char *, int size, int max, int strict);
160caf54c4fSMartin Matuska static int	format_octal(int64_t, char *, int);
161caf54c4fSMartin Matuska 
162caf54c4fSMartin Matuska /*
163caf54c4fSMartin Matuska  * Set output format to 'ustar' format.
164caf54c4fSMartin Matuska  */
165caf54c4fSMartin Matuska int
archive_write_set_format_ustar(struct archive * _a)166caf54c4fSMartin Matuska archive_write_set_format_ustar(struct archive *_a)
167caf54c4fSMartin Matuska {
168caf54c4fSMartin Matuska 	struct archive_write *a = (struct archive_write *)_a;
169caf54c4fSMartin Matuska 	struct ustar *ustar;
170caf54c4fSMartin Matuska 
1716c95142eSMartin Matuska 	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
1726c95142eSMartin Matuska 	    ARCHIVE_STATE_NEW, "archive_write_set_format_ustar");
1736c95142eSMartin Matuska 
174caf54c4fSMartin Matuska 	/* If someone else was already registered, unregister them. */
1756c95142eSMartin Matuska 	if (a->format_free != NULL)
1766c95142eSMartin Matuska 		(a->format_free)(a);
177caf54c4fSMartin Matuska 
178caf54c4fSMartin Matuska 	/* Basic internal sanity test. */
179caf54c4fSMartin Matuska 	if (sizeof(template_header) != 512) {
1806c95142eSMartin Matuska 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1816c95142eSMartin Matuska 		    "Internal: template_header wrong size: %zu should be 512",
1826c95142eSMartin Matuska 		    sizeof(template_header));
183caf54c4fSMartin Matuska 		return (ARCHIVE_FATAL);
184caf54c4fSMartin Matuska 	}
185caf54c4fSMartin Matuska 
1866a414569SMartin Matuska 	ustar = (struct ustar *)calloc(1, sizeof(*ustar));
187caf54c4fSMartin Matuska 	if (ustar == NULL) {
1886c95142eSMartin Matuska 		archive_set_error(&a->archive, ENOMEM,
1896c95142eSMartin Matuska 		    "Can't allocate ustar data");
190caf54c4fSMartin Matuska 		return (ARCHIVE_FATAL);
191caf54c4fSMartin Matuska 	}
192caf54c4fSMartin Matuska 	a->format_data = ustar;
193caf54c4fSMartin Matuska 	a->format_name = "ustar";
1946c95142eSMartin Matuska 	a->format_options = archive_write_ustar_options;
195caf54c4fSMartin Matuska 	a->format_write_header = archive_write_ustar_header;
196caf54c4fSMartin Matuska 	a->format_write_data = archive_write_ustar_data;
1976c95142eSMartin Matuska 	a->format_close = archive_write_ustar_close;
1986c95142eSMartin Matuska 	a->format_free = archive_write_ustar_free;
199caf54c4fSMartin Matuska 	a->format_finish_entry = archive_write_ustar_finish_entry;
200caf54c4fSMartin Matuska 	a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR;
201caf54c4fSMartin Matuska 	a->archive.archive_format_name = "POSIX ustar";
202caf54c4fSMartin Matuska 	return (ARCHIVE_OK);
203caf54c4fSMartin Matuska }
204caf54c4fSMartin Matuska 
205caf54c4fSMartin Matuska static int
archive_write_ustar_options(struct archive_write * a,const char * key,const char * val)2066c95142eSMartin Matuska archive_write_ustar_options(struct archive_write *a, const char *key,
2076c95142eSMartin Matuska     const char *val)
2086c95142eSMartin Matuska {
2096c95142eSMartin Matuska 	struct ustar *ustar = (struct ustar *)a->format_data;
2106c95142eSMartin Matuska 	int ret = ARCHIVE_FAILED;
2116c95142eSMartin Matuska 
2126c95142eSMartin Matuska 	if (strcmp(key, "hdrcharset")  == 0) {
2136c95142eSMartin Matuska 		if (val == NULL || val[0] == 0)
2146c95142eSMartin Matuska 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2156c95142eSMartin Matuska 			    "%s: hdrcharset option needs a character-set name",
2166c95142eSMartin Matuska 			    a->format_name);
2176c95142eSMartin Matuska 		else {
2186c95142eSMartin Matuska 			ustar->opt_sconv = archive_string_conversion_to_charset(
2196c95142eSMartin Matuska 			    &a->archive, val, 0);
2206c95142eSMartin Matuska 			if (ustar->opt_sconv != NULL)
2216c95142eSMartin Matuska 				ret = ARCHIVE_OK;
2226c95142eSMartin Matuska 			else
2236c95142eSMartin Matuska 				ret = ARCHIVE_FATAL;
2246c95142eSMartin Matuska 		}
2256c95142eSMartin Matuska 		return (ret);
2266c95142eSMartin Matuska 	}
2276c95142eSMartin Matuska 
2286c95142eSMartin Matuska 	/* Note: The "warn" return is just to inform the options
2296c95142eSMartin Matuska 	 * supervisor that we didn't handle it.  It will generate
2306c95142eSMartin Matuska 	 * a suitable error if no one used this option. */
2316c95142eSMartin Matuska 	return (ARCHIVE_WARN);
2326c95142eSMartin Matuska }
2336c95142eSMartin Matuska 
2346c95142eSMartin Matuska static int
archive_write_ustar_header(struct archive_write * a,struct archive_entry * entry)235caf54c4fSMartin Matuska archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
236caf54c4fSMartin Matuska {
237caf54c4fSMartin Matuska 	char buff[512];
238caf54c4fSMartin Matuska 	int ret, ret2;
239caf54c4fSMartin Matuska 	struct ustar *ustar;
2406c95142eSMartin Matuska 	struct archive_entry *entry_main;
2416c95142eSMartin Matuska 	struct archive_string_conv *sconv;
242caf54c4fSMartin Matuska 
243caf54c4fSMartin Matuska 	ustar = (struct ustar *)a->format_data;
244caf54c4fSMartin Matuska 
2456c95142eSMartin Matuska 	/* Setup default string conversion. */
2466c95142eSMartin Matuska 	if (ustar->opt_sconv == NULL) {
2476c95142eSMartin Matuska 		if (!ustar->init_default_conversion) {
2486c95142eSMartin Matuska 			ustar->sconv_default =
2496c95142eSMartin Matuska 			    archive_string_default_conversion_for_write(&(a->archive));
2506c95142eSMartin Matuska 			ustar->init_default_conversion = 1;
2516c95142eSMartin Matuska 		}
2526c95142eSMartin Matuska 		sconv = ustar->sconv_default;
2536c95142eSMartin Matuska 	} else
2546c95142eSMartin Matuska 		sconv = ustar->opt_sconv;
2556c95142eSMartin Matuska 
2566c95142eSMartin Matuska 	/* Sanity check. */
2576c95142eSMartin Matuska 	if (archive_entry_pathname(entry) == NULL) {
2586c95142eSMartin Matuska 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2596c95142eSMartin Matuska 		    "Can't record entry in tar file without pathname");
2606c95142eSMartin Matuska 		return (ARCHIVE_FAILED);
2616c95142eSMartin Matuska 	}
2626c95142eSMartin Matuska 
263caf54c4fSMartin Matuska 	/* Only regular files (not hardlinks) have data. */
264caf54c4fSMartin Matuska 	if (archive_entry_hardlink(entry) != NULL ||
265caf54c4fSMartin Matuska 	    archive_entry_symlink(entry) != NULL ||
266caf54c4fSMartin Matuska 	    !(archive_entry_filetype(entry) == AE_IFREG))
267caf54c4fSMartin Matuska 		archive_entry_set_size(entry, 0);
268caf54c4fSMartin Matuska 
269caf54c4fSMartin Matuska 	if (AE_IFDIR == archive_entry_filetype(entry)) {
270caf54c4fSMartin Matuska 		const char *p;
2716c95142eSMartin Matuska 		size_t path_length;
272caf54c4fSMartin Matuska 		/*
273caf54c4fSMartin Matuska 		 * Ensure a trailing '/'.  Modify the entry so
274caf54c4fSMartin Matuska 		 * the client sees the change.
275caf54c4fSMartin Matuska 		 */
2766c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
2776c95142eSMartin Matuska 		const wchar_t *wp;
2786c95142eSMartin Matuska 
2796c95142eSMartin Matuska 		wp = archive_entry_pathname_w(entry);
2806c95142eSMartin Matuska 		if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
2816c95142eSMartin Matuska 			struct archive_wstring ws;
2826c95142eSMartin Matuska 
2836c95142eSMartin Matuska 			archive_string_init(&ws);
2846c95142eSMartin Matuska 			path_length = wcslen(wp);
2856c95142eSMartin Matuska 			if (archive_wstring_ensure(&ws,
2866c95142eSMartin Matuska 			    path_length + 2) == NULL) {
2876c95142eSMartin Matuska 				archive_set_error(&a->archive, ENOMEM,
2886c95142eSMartin Matuska 				    "Can't allocate ustar data");
2896c95142eSMartin Matuska 				archive_wstring_free(&ws);
2906c95142eSMartin Matuska 				return(ARCHIVE_FATAL);
2916c95142eSMartin Matuska 			}
2926c95142eSMartin Matuska 			/* Should we keep '\' ? */
2936c95142eSMartin Matuska 			if (wp[path_length -1] == L'\\')
2946c95142eSMartin Matuska 				path_length--;
2956c95142eSMartin Matuska 			archive_wstrncpy(&ws, wp, path_length);
2966c95142eSMartin Matuska 			archive_wstrappend_wchar(&ws, L'/');
2976c95142eSMartin Matuska 			archive_entry_copy_pathname_w(entry, ws.s);
2986c95142eSMartin Matuska 			archive_wstring_free(&ws);
2996c95142eSMartin Matuska 			p = NULL;
3006c95142eSMartin Matuska 		} else
3016c95142eSMartin Matuska #endif
302caf54c4fSMartin Matuska 			p = archive_entry_pathname(entry);
3036c95142eSMartin Matuska 		/*
3046c95142eSMartin Matuska 		 * On Windows, this is a backup operation just in
3056c95142eSMartin Matuska 		 * case getting WCS failed. On POSIX, this is a
3066c95142eSMartin Matuska 		 * normal operation.
3076c95142eSMartin Matuska 		 */
308cfa49a9bSMartin Matuska 		if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
3096c95142eSMartin Matuska 			struct archive_string as;
3106c95142eSMartin Matuska 
3116c95142eSMartin Matuska 			archive_string_init(&as);
3126c95142eSMartin Matuska 			path_length = strlen(p);
3136c95142eSMartin Matuska 			if (archive_string_ensure(&as,
3146c95142eSMartin Matuska 			    path_length + 2) == NULL) {
3156c95142eSMartin Matuska 				archive_set_error(&a->archive, ENOMEM,
3166c95142eSMartin Matuska 				    "Can't allocate ustar data");
3176c95142eSMartin Matuska 				archive_string_free(&as);
3186c95142eSMartin Matuska 				return(ARCHIVE_FATAL);
3196c95142eSMartin Matuska 			}
3206c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
3216c95142eSMartin Matuska 			/* NOTE: This might break the pathname
3226c95142eSMartin Matuska 			 * if the current code page is CP932 and
3236c95142eSMartin Matuska 			 * the pathname includes a character '\'
3246c95142eSMartin Matuska 			 * as a part of its multibyte pathname. */
3256c95142eSMartin Matuska 			if (p[strlen(p) -1] == '\\')
3266c95142eSMartin Matuska 				path_length--;
3276c95142eSMartin Matuska 			else
3286c95142eSMartin Matuska #endif
3296c95142eSMartin Matuska 			archive_strncpy(&as, p, path_length);
3306c95142eSMartin Matuska 			archive_strappend_char(&as, '/');
3316c95142eSMartin Matuska 			archive_entry_copy_pathname(entry, as.s);
3326c95142eSMartin Matuska 			archive_string_free(&as);
3336c95142eSMartin Matuska 		}
3346c95142eSMartin Matuska 	}
3356c95142eSMartin Matuska 
3366c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
337a2e802b7SMartin Matuska 	/* Make sure the path separators in pathname, hardlink and symlink
3386c95142eSMartin Matuska 	 * are all slash '/', not the Windows path separator '\'. */
3396c95142eSMartin Matuska 	entry_main = __la_win_entry_in_posix_pathseparator(entry);
3406c95142eSMartin Matuska 	if (entry_main == NULL) {
341caf54c4fSMartin Matuska 		archive_set_error(&a->archive, ENOMEM,
342caf54c4fSMartin Matuska 		    "Can't allocate ustar data");
343caf54c4fSMartin Matuska 		return(ARCHIVE_FATAL);
344caf54c4fSMartin Matuska 	}
3456c95142eSMartin Matuska 	if (entry != entry_main)
3466c95142eSMartin Matuska 		entry = entry_main;
3476c95142eSMartin Matuska 	else
3486c95142eSMartin Matuska 		entry_main = NULL;
3496c95142eSMartin Matuska #else
3506c95142eSMartin Matuska 	entry_main = NULL;
3516c95142eSMartin Matuska #endif
3526c95142eSMartin Matuska 	ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1, sconv);
3536c95142eSMartin Matuska 	if (ret < ARCHIVE_WARN) {
3546c95142eSMartin Matuska 		archive_entry_free(entry_main);
355caf54c4fSMartin Matuska 		return (ret);
3566c95142eSMartin Matuska 	}
3576c95142eSMartin Matuska 	ret2 = __archive_write_output(a, buff, 512);
3586c95142eSMartin Matuska 	if (ret2 < ARCHIVE_WARN) {
3596c95142eSMartin Matuska 		archive_entry_free(entry_main);
360caf54c4fSMartin Matuska 		return (ret2);
3616c95142eSMartin Matuska 	}
362caf54c4fSMartin Matuska 	if (ret2 < ret)
363caf54c4fSMartin Matuska 		ret = ret2;
364caf54c4fSMartin Matuska 
365caf54c4fSMartin Matuska 	ustar->entry_bytes_remaining = archive_entry_size(entry);
366caf54c4fSMartin Matuska 	ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining);
3676c95142eSMartin Matuska 	archive_entry_free(entry_main);
368caf54c4fSMartin Matuska 	return (ret);
369caf54c4fSMartin Matuska }
370caf54c4fSMartin Matuska 
371caf54c4fSMartin Matuska /*
372caf54c4fSMartin Matuska  * Format a basic 512-byte "ustar" header.
373caf54c4fSMartin Matuska  *
374caf54c4fSMartin Matuska  * Returns -1 if format failed (due to field overflow).
375caf54c4fSMartin Matuska  * Note that this always formats as much of the header as possible.
376caf54c4fSMartin Matuska  * If "strict" is set to zero, it will extend numeric fields as
377caf54c4fSMartin Matuska  * necessary (overwriting terminators or using base-256 extensions).
378caf54c4fSMartin Matuska  *
379caf54c4fSMartin Matuska  * This is exported so that other 'tar' formats can use it.
380caf54c4fSMartin Matuska  */
381caf54c4fSMartin Matuska int
__archive_write_format_header_ustar(struct archive_write * a,char h[512],struct archive_entry * entry,int tartype,int strict,struct archive_string_conv * sconv)382caf54c4fSMartin Matuska __archive_write_format_header_ustar(struct archive_write *a, char h[512],
3836c95142eSMartin Matuska     struct archive_entry *entry, int tartype, int strict,
3846c95142eSMartin Matuska     struct archive_string_conv *sconv)
385caf54c4fSMartin Matuska {
386caf54c4fSMartin Matuska 	unsigned int checksum;
3876c95142eSMartin Matuska 	int i, r, ret;
388caf54c4fSMartin Matuska 	size_t copy_length;
389caf54c4fSMartin Matuska 	const char *p, *pp;
390caf54c4fSMartin Matuska 	int mytartype;
391caf54c4fSMartin Matuska 
392caf54c4fSMartin Matuska 	ret = 0;
393caf54c4fSMartin Matuska 	mytartype = -1;
394caf54c4fSMartin Matuska 	/*
395caf54c4fSMartin Matuska 	 * The "template header" already includes the "ustar"
396caf54c4fSMartin Matuska 	 * signature, various end-of-field markers and other required
397caf54c4fSMartin Matuska 	 * elements.
398caf54c4fSMartin Matuska 	 */
399caf54c4fSMartin Matuska 	memcpy(h, &template_header, 512);
400caf54c4fSMartin Matuska 
401caf54c4fSMartin Matuska 	/*
402caf54c4fSMartin Matuska 	 * Because the block is already null-filled, and strings
403caf54c4fSMartin Matuska 	 * are allowed to exactly fill their destination (without null),
404caf54c4fSMartin Matuska 	 * I use memcpy(dest, src, strlen()) here a lot to copy strings.
405caf54c4fSMartin Matuska 	 */
4066c95142eSMartin Matuska 	r = archive_entry_pathname_l(entry, &pp, &copy_length, sconv);
4076c95142eSMartin Matuska 	if (r != 0) {
4086c95142eSMartin Matuska 		if (errno == ENOMEM) {
4096c95142eSMartin Matuska 			archive_set_error(&a->archive, ENOMEM,
4106c95142eSMartin Matuska 			    "Can't allocate memory for Pathname");
4116c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
4126c95142eSMartin Matuska 		}
4136c95142eSMartin Matuska 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
4146c95142eSMartin Matuska 		    "Can't translate pathname '%s' to %s",
4156c95142eSMartin Matuska 		    pp, archive_string_conversion_charset_name(sconv));
4166c95142eSMartin Matuska 		ret = ARCHIVE_WARN;
4176c95142eSMartin Matuska 	}
4186c95142eSMartin Matuska 	if (copy_length <= USTAR_name_size)
4196c95142eSMartin Matuska 		memcpy(h + USTAR_name_offset, pp, copy_length);
420caf54c4fSMartin Matuska 	else {
421caf54c4fSMartin Matuska 		/* Store in two pieces, splitting at a '/'. */
4226c95142eSMartin Matuska 		p = strchr(pp + copy_length - USTAR_name_size - 1, '/');
423caf54c4fSMartin Matuska 		/*
424caf54c4fSMartin Matuska 		 * Look for the next '/' if we chose the first character
425caf54c4fSMartin Matuska 		 * as the separator.  (ustar format doesn't permit
426caf54c4fSMartin Matuska 		 * an empty prefix.)
427caf54c4fSMartin Matuska 		 */
428caf54c4fSMartin Matuska 		if (p == pp)
429caf54c4fSMartin Matuska 			p = strchr(p + 1, '/');
430caf54c4fSMartin Matuska 		/* Fail if the name won't fit. */
431caf54c4fSMartin Matuska 		if (!p) {
432caf54c4fSMartin Matuska 			/* No separator. */
433caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ENAMETOOLONG,
434caf54c4fSMartin Matuska 			    "Pathname too long");
435caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
436caf54c4fSMartin Matuska 		} else if (p[1] == '\0') {
437caf54c4fSMartin Matuska 			/*
438caf54c4fSMartin Matuska 			 * The only feasible separator is a final '/';
439caf54c4fSMartin Matuska 			 * this would result in a non-empty prefix and
440caf54c4fSMartin Matuska 			 * an empty name, which POSIX doesn't
4416c95142eSMartin Matuska 			 * explicitly forbid, but it just feels wrong.
442caf54c4fSMartin Matuska 			 */
443caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ENAMETOOLONG,
444caf54c4fSMartin Matuska 			    "Pathname too long");
445caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
446caf54c4fSMartin Matuska 		} else if (p  > pp + USTAR_prefix_size) {
447caf54c4fSMartin Matuska 			/* Prefix is too long. */
448caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ENAMETOOLONG,
449caf54c4fSMartin Matuska 			    "Pathname too long");
450caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
451caf54c4fSMartin Matuska 		} else {
452caf54c4fSMartin Matuska 			/* Copy prefix and remainder to appropriate places */
453caf54c4fSMartin Matuska 			memcpy(h + USTAR_prefix_offset, pp, p - pp);
4546c95142eSMartin Matuska 			memcpy(h + USTAR_name_offset, p + 1,
4556c95142eSMartin Matuska 			    pp + copy_length - p - 1);
456caf54c4fSMartin Matuska 		}
457caf54c4fSMartin Matuska 	}
458caf54c4fSMartin Matuska 
4596c95142eSMartin Matuska 	r = archive_entry_hardlink_l(entry, &p, &copy_length, sconv);
4606c95142eSMartin Matuska 	if (r != 0) {
4616c95142eSMartin Matuska 		if (errno == ENOMEM) {
4626c95142eSMartin Matuska 			archive_set_error(&a->archive, ENOMEM,
4636c95142eSMartin Matuska 			    "Can't allocate memory for Linkname");
4646c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
4656c95142eSMartin Matuska 		}
4666c95142eSMartin Matuska 		archive_set_error(&a->archive,
4676c95142eSMartin Matuska 		    ARCHIVE_ERRNO_FILE_FORMAT,
4686c95142eSMartin Matuska 		    "Can't translate linkname '%s' to %s",
4696c95142eSMartin Matuska 		    p, archive_string_conversion_charset_name(sconv));
4706c95142eSMartin Matuska 		ret = ARCHIVE_WARN;
4716c95142eSMartin Matuska 	}
4726c95142eSMartin Matuska 	if (copy_length > 0)
473caf54c4fSMartin Matuska 		mytartype = '1';
4746c95142eSMartin Matuska 	else {
4756c95142eSMartin Matuska 		r = archive_entry_symlink_l(entry, &p, &copy_length, sconv);
4766c95142eSMartin Matuska 		if (r != 0) {
4776c95142eSMartin Matuska 			if (errno == ENOMEM) {
4786c95142eSMartin Matuska 				archive_set_error(&a->archive, ENOMEM,
4796c95142eSMartin Matuska 				    "Can't allocate memory for Linkname");
4806c95142eSMartin Matuska 				return (ARCHIVE_FATAL);
4816c95142eSMartin Matuska 			}
4826c95142eSMartin Matuska 			archive_set_error(&a->archive,
4836c95142eSMartin Matuska 			    ARCHIVE_ERRNO_FILE_FORMAT,
4846c95142eSMartin Matuska 			    "Can't translate linkname '%s' to %s",
4856c95142eSMartin Matuska 			    p, archive_string_conversion_charset_name(sconv));
4866c95142eSMartin Matuska 			ret = ARCHIVE_WARN;
4876c95142eSMartin Matuska 		}
4886c95142eSMartin Matuska 	}
4896c95142eSMartin Matuska 	if (copy_length > 0) {
490caf54c4fSMartin Matuska 		if (copy_length > USTAR_linkname_size) {
491caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ENAMETOOLONG,
492caf54c4fSMartin Matuska 			    "Link contents too long");
493caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
494caf54c4fSMartin Matuska 			copy_length = USTAR_linkname_size;
495caf54c4fSMartin Matuska 		}
496caf54c4fSMartin Matuska 		memcpy(h + USTAR_linkname_offset, p, copy_length);
497caf54c4fSMartin Matuska 	}
498caf54c4fSMartin Matuska 
4996c95142eSMartin Matuska 	r = archive_entry_uname_l(entry, &p, &copy_length, sconv);
5006c95142eSMartin Matuska 	if (r != 0) {
5016c95142eSMartin Matuska 		if (errno == ENOMEM) {
5026c95142eSMartin Matuska 			archive_set_error(&a->archive, ENOMEM,
5036c95142eSMartin Matuska 			    "Can't allocate memory for Uname");
5046c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
5056c95142eSMartin Matuska 		}
5066c95142eSMartin Matuska 		archive_set_error(&a->archive,
5076c95142eSMartin Matuska 		    ARCHIVE_ERRNO_FILE_FORMAT,
5086c95142eSMartin Matuska 		    "Can't translate uname '%s' to %s",
5096c95142eSMartin Matuska 		    p, archive_string_conversion_charset_name(sconv));
5106c95142eSMartin Matuska 		ret = ARCHIVE_WARN;
5116c95142eSMartin Matuska 	}
5126c95142eSMartin Matuska 	if (copy_length > 0) {
513caf54c4fSMartin Matuska 		if (copy_length > USTAR_uname_size) {
514f9762417SMartin Matuska 			if (tartype != 'x') {
515f9762417SMartin Matuska 				archive_set_error(&a->archive,
516f9762417SMartin Matuska 				    ARCHIVE_ERRNO_MISC, "Username too long");
517caf54c4fSMartin Matuska 				ret = ARCHIVE_FAILED;
518f9762417SMartin Matuska 			}
519caf54c4fSMartin Matuska 			copy_length = USTAR_uname_size;
520caf54c4fSMartin Matuska 		}
521caf54c4fSMartin Matuska 		memcpy(h + USTAR_uname_offset, p, copy_length);
522caf54c4fSMartin Matuska 	}
523caf54c4fSMartin Matuska 
5246c95142eSMartin Matuska 	r = archive_entry_gname_l(entry, &p, &copy_length, sconv);
5256c95142eSMartin Matuska 	if (r != 0) {
5266c95142eSMartin Matuska 		if (errno == ENOMEM) {
5276c95142eSMartin Matuska 			archive_set_error(&a->archive, ENOMEM,
5286c95142eSMartin Matuska 			    "Can't allocate memory for Gname");
5296c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
5306c95142eSMartin Matuska 		}
5316c95142eSMartin Matuska 		archive_set_error(&a->archive,
5326c95142eSMartin Matuska 		    ARCHIVE_ERRNO_FILE_FORMAT,
5336c95142eSMartin Matuska 		    "Can't translate gname '%s' to %s",
5346c95142eSMartin Matuska 		    p, archive_string_conversion_charset_name(sconv));
5356c95142eSMartin Matuska 		ret = ARCHIVE_WARN;
5366c95142eSMartin Matuska 	}
5376c95142eSMartin Matuska 	if (copy_length > 0) {
538caf54c4fSMartin Matuska 		if (strlen(p) > USTAR_gname_size) {
539f9762417SMartin Matuska 			if (tartype != 'x') {
540f9762417SMartin Matuska 				archive_set_error(&a->archive,
541f9762417SMartin Matuska 				    ARCHIVE_ERRNO_MISC, "Group name too long");
542caf54c4fSMartin Matuska 				ret = ARCHIVE_FAILED;
543f9762417SMartin Matuska 			}
544caf54c4fSMartin Matuska 			copy_length = USTAR_gname_size;
545caf54c4fSMartin Matuska 		}
546caf54c4fSMartin Matuska 		memcpy(h + USTAR_gname_offset, p, copy_length);
547caf54c4fSMartin Matuska 	}
548caf54c4fSMartin Matuska 
5496c95142eSMartin Matuska 	if (format_number(archive_entry_mode(entry) & 07777,
5506c95142eSMartin Matuska 	    h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {
5516c95142eSMartin Matuska 		archive_set_error(&a->archive, ERANGE,
5526c95142eSMartin Matuska 		    "Numeric mode too large");
553caf54c4fSMartin Matuska 		ret = ARCHIVE_FAILED;
554caf54c4fSMartin Matuska 	}
555caf54c4fSMartin Matuska 
5566c95142eSMartin Matuska 	if (format_number(archive_entry_uid(entry),
5576c95142eSMartin Matuska 	    h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {
5586c95142eSMartin Matuska 		archive_set_error(&a->archive, ERANGE,
5596c95142eSMartin Matuska 		    "Numeric user ID too large");
560caf54c4fSMartin Matuska 		ret = ARCHIVE_FAILED;
561caf54c4fSMartin Matuska 	}
562caf54c4fSMartin Matuska 
5636c95142eSMartin Matuska 	if (format_number(archive_entry_gid(entry),
5646c95142eSMartin Matuska 	    h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {
5656c95142eSMartin Matuska 		archive_set_error(&a->archive, ERANGE,
5666c95142eSMartin Matuska 		    "Numeric group ID too large");
567caf54c4fSMartin Matuska 		ret = ARCHIVE_FAILED;
568caf54c4fSMartin Matuska 	}
569caf54c4fSMartin Matuska 
5706c95142eSMartin Matuska 	if (format_number(archive_entry_size(entry),
5716c95142eSMartin Matuska 	    h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {
5726c95142eSMartin Matuska 		archive_set_error(&a->archive, ERANGE,
5736c95142eSMartin Matuska 		    "File size out of range");
574caf54c4fSMartin Matuska 		ret = ARCHIVE_FAILED;
575caf54c4fSMartin Matuska 	}
576caf54c4fSMartin Matuska 
5776c95142eSMartin Matuska 	if (format_number(archive_entry_mtime(entry),
5786c95142eSMartin Matuska 	    h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {
579caf54c4fSMartin Matuska 		archive_set_error(&a->archive, ERANGE,
580caf54c4fSMartin Matuska 		    "File modification time too large");
581caf54c4fSMartin Matuska 		ret = ARCHIVE_FAILED;
582caf54c4fSMartin Matuska 	}
583caf54c4fSMartin Matuska 
584caf54c4fSMartin Matuska 	if (archive_entry_filetype(entry) == AE_IFBLK
585caf54c4fSMartin Matuska 	    || archive_entry_filetype(entry) == AE_IFCHR) {
5866c95142eSMartin Matuska 		if (format_number(archive_entry_rdevmajor(entry),
5876c95142eSMartin Matuska 		    h + USTAR_rdevmajor_offset, USTAR_rdevmajor_size,
5886c95142eSMartin Matuska 		    USTAR_rdevmajor_max_size, strict)) {
589caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ERANGE,
590caf54c4fSMartin Matuska 			    "Major device number too large");
591caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
592caf54c4fSMartin Matuska 		}
593caf54c4fSMartin Matuska 
5946c95142eSMartin Matuska 		if (format_number(archive_entry_rdevminor(entry),
5956c95142eSMartin Matuska 		    h + USTAR_rdevminor_offset, USTAR_rdevminor_size,
5966c95142eSMartin Matuska 		    USTAR_rdevminor_max_size, strict)) {
597caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ERANGE,
598caf54c4fSMartin Matuska 			    "Minor device number too large");
599caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
600caf54c4fSMartin Matuska 		}
601caf54c4fSMartin Matuska 	}
602caf54c4fSMartin Matuska 
603caf54c4fSMartin Matuska 	if (tartype >= 0) {
604caf54c4fSMartin Matuska 		h[USTAR_typeflag_offset] = tartype;
605caf54c4fSMartin Matuska 	} else if (mytartype >= 0) {
606caf54c4fSMartin Matuska 		h[USTAR_typeflag_offset] = mytartype;
607caf54c4fSMartin Matuska 	} else {
608caf54c4fSMartin Matuska 		switch (archive_entry_filetype(entry)) {
609caf54c4fSMartin Matuska 		case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break;
610caf54c4fSMartin Matuska 		case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break;
611caf54c4fSMartin Matuska 		case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break;
612caf54c4fSMartin Matuska 		case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break;
613caf54c4fSMartin Matuska 		case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break;
614caf54c4fSMartin Matuska 		case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break;
615f9762417SMartin Matuska 		default: /* AE_IFSOCK and unknown */
616f9762417SMartin Matuska 			__archive_write_entry_filetype_unsupported(
617f9762417SMartin Matuska 			    &a->archive, entry, "ustar");
618caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
619caf54c4fSMartin Matuska 		}
620caf54c4fSMartin Matuska 	}
621caf54c4fSMartin Matuska 
622caf54c4fSMartin Matuska 	checksum = 0;
623caf54c4fSMartin Matuska 	for (i = 0; i < 512; i++)
624caf54c4fSMartin Matuska 		checksum += 255 & (unsigned int)h[i];
625caf54c4fSMartin Matuska 	h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */
626caf54c4fSMartin Matuska 	/* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */
627caf54c4fSMartin Matuska 	format_octal(checksum, h + USTAR_checksum_offset, 6);
628caf54c4fSMartin Matuska 	return (ret);
629caf54c4fSMartin Matuska }
630caf54c4fSMartin Matuska 
631caf54c4fSMartin Matuska /*
632caf54c4fSMartin Matuska  * Format a number into a field, with some intelligence.
633caf54c4fSMartin Matuska  */
634caf54c4fSMartin Matuska static int
format_number(int64_t v,char * p,int s,int maxsize,int strict)635caf54c4fSMartin Matuska format_number(int64_t v, char *p, int s, int maxsize, int strict)
636caf54c4fSMartin Matuska {
637caf54c4fSMartin Matuska 	int64_t limit;
638caf54c4fSMartin Matuska 
639caf54c4fSMartin Matuska 	limit = ((int64_t)1 << (s*3));
640caf54c4fSMartin Matuska 
641caf54c4fSMartin Matuska 	/* "Strict" only permits octal values with proper termination. */
642caf54c4fSMartin Matuska 	if (strict)
643caf54c4fSMartin Matuska 		return (format_octal(v, p, s));
644caf54c4fSMartin Matuska 
645caf54c4fSMartin Matuska 	/*
646caf54c4fSMartin Matuska 	 * In non-strict mode, we allow the number to overwrite one or
647caf54c4fSMartin Matuska 	 * more bytes of the field termination.  Even old tar
648caf54c4fSMartin Matuska 	 * implementations should be able to handle this with no
649caf54c4fSMartin Matuska 	 * problem.
650caf54c4fSMartin Matuska 	 */
651caf54c4fSMartin Matuska 	if (v >= 0) {
652caf54c4fSMartin Matuska 		while (s <= maxsize) {
653caf54c4fSMartin Matuska 			if (v < limit)
654caf54c4fSMartin Matuska 				return (format_octal(v, p, s));
655caf54c4fSMartin Matuska 			s++;
656caf54c4fSMartin Matuska 			limit <<= 3;
657caf54c4fSMartin Matuska 		}
658caf54c4fSMartin Matuska 	}
659caf54c4fSMartin Matuska 
660caf54c4fSMartin Matuska 	/* Base-256 can handle any number, positive or negative. */
661caf54c4fSMartin Matuska 	return (format_256(v, p, maxsize));
662caf54c4fSMartin Matuska }
663caf54c4fSMartin Matuska 
664caf54c4fSMartin Matuska /*
665caf54c4fSMartin Matuska  * Format a number into the specified field using base-256.
666caf54c4fSMartin Matuska  */
667caf54c4fSMartin Matuska static int
format_256(int64_t v,char * p,int s)668caf54c4fSMartin Matuska format_256(int64_t v, char *p, int s)
669caf54c4fSMartin Matuska {
670caf54c4fSMartin Matuska 	p += s;
671caf54c4fSMartin Matuska 	while (s-- > 0) {
672caf54c4fSMartin Matuska 		*--p = (char)(v & 0xff);
673caf54c4fSMartin Matuska 		v >>= 8;
674caf54c4fSMartin Matuska 	}
675caf54c4fSMartin Matuska 	*p |= 0x80; /* Set the base-256 marker bit. */
676caf54c4fSMartin Matuska 	return (0);
677caf54c4fSMartin Matuska }
678caf54c4fSMartin Matuska 
679caf54c4fSMartin Matuska /*
680caf54c4fSMartin Matuska  * Format a number into the specified field.
681caf54c4fSMartin Matuska  */
682caf54c4fSMartin Matuska static int
format_octal(int64_t v,char * p,int s)683caf54c4fSMartin Matuska format_octal(int64_t v, char *p, int s)
684caf54c4fSMartin Matuska {
685caf54c4fSMartin Matuska 	int len;
686caf54c4fSMartin Matuska 
687caf54c4fSMartin Matuska 	len = s;
688caf54c4fSMartin Matuska 
689caf54c4fSMartin Matuska 	/* Octal values can't be negative, so use 0. */
690caf54c4fSMartin Matuska 	if (v < 0) {
691caf54c4fSMartin Matuska 		while (len-- > 0)
692caf54c4fSMartin Matuska 			*p++ = '0';
693caf54c4fSMartin Matuska 		return (-1);
694caf54c4fSMartin Matuska 	}
695caf54c4fSMartin Matuska 
696caf54c4fSMartin Matuska 	p += s;		/* Start at the end and work backwards. */
697caf54c4fSMartin Matuska 	while (s-- > 0) {
698caf54c4fSMartin Matuska 		*--p = (char)('0' + (v & 7));
699caf54c4fSMartin Matuska 		v >>= 3;
700caf54c4fSMartin Matuska 	}
701caf54c4fSMartin Matuska 
702caf54c4fSMartin Matuska 	if (v == 0)
703caf54c4fSMartin Matuska 		return (0);
704caf54c4fSMartin Matuska 
705caf54c4fSMartin Matuska 	/* If it overflowed, fill field with max value. */
706caf54c4fSMartin Matuska 	while (len-- > 0)
707caf54c4fSMartin Matuska 		*p++ = '7';
708caf54c4fSMartin Matuska 
709caf54c4fSMartin Matuska 	return (-1);
710caf54c4fSMartin Matuska }
711caf54c4fSMartin Matuska 
712caf54c4fSMartin Matuska static int
archive_write_ustar_close(struct archive_write * a)7136c95142eSMartin Matuska archive_write_ustar_close(struct archive_write *a)
714caf54c4fSMartin Matuska {
7156c95142eSMartin Matuska 	return (__archive_write_nulls(a, 512*2));
716caf54c4fSMartin Matuska }
717caf54c4fSMartin Matuska 
718caf54c4fSMartin Matuska static int
archive_write_ustar_free(struct archive_write * a)7196c95142eSMartin Matuska archive_write_ustar_free(struct archive_write *a)
720caf54c4fSMartin Matuska {
721caf54c4fSMartin Matuska 	struct ustar *ustar;
722caf54c4fSMartin Matuska 
723caf54c4fSMartin Matuska 	ustar = (struct ustar *)a->format_data;
724caf54c4fSMartin Matuska 	free(ustar);
725caf54c4fSMartin Matuska 	a->format_data = NULL;
726caf54c4fSMartin Matuska 	return (ARCHIVE_OK);
727caf54c4fSMartin Matuska }
728caf54c4fSMartin Matuska 
729caf54c4fSMartin Matuska static int
archive_write_ustar_finish_entry(struct archive_write * a)730caf54c4fSMartin Matuska archive_write_ustar_finish_entry(struct archive_write *a)
731caf54c4fSMartin Matuska {
732caf54c4fSMartin Matuska 	struct ustar *ustar;
733caf54c4fSMartin Matuska 	int ret;
734caf54c4fSMartin Matuska 
735caf54c4fSMartin Matuska 	ustar = (struct ustar *)a->format_data;
7366c95142eSMartin Matuska 	ret = __archive_write_nulls(a,
737fd082e96SMartin Matuska 	    (size_t)(ustar->entry_bytes_remaining + ustar->entry_padding));
738caf54c4fSMartin Matuska 	ustar->entry_bytes_remaining = ustar->entry_padding = 0;
739caf54c4fSMartin Matuska 	return (ret);
740caf54c4fSMartin Matuska }
741caf54c4fSMartin Matuska 
742caf54c4fSMartin Matuska static ssize_t
archive_write_ustar_data(struct archive_write * a,const void * buff,size_t s)743caf54c4fSMartin Matuska archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
744caf54c4fSMartin Matuska {
745caf54c4fSMartin Matuska 	struct ustar *ustar;
746caf54c4fSMartin Matuska 	int ret;
747caf54c4fSMartin Matuska 
748caf54c4fSMartin Matuska 	ustar = (struct ustar *)a->format_data;
749caf54c4fSMartin Matuska 	if (s > ustar->entry_bytes_remaining)
750fd082e96SMartin Matuska 		s = (size_t)ustar->entry_bytes_remaining;
7516c95142eSMartin Matuska 	ret = __archive_write_output(a, buff, s);
752caf54c4fSMartin Matuska 	ustar->entry_bytes_remaining -= s;
753caf54c4fSMartin Matuska 	if (ret != ARCHIVE_OK)
754caf54c4fSMartin Matuska 		return (ret);
755caf54c4fSMartin Matuska 	return (s);
756caf54c4fSMartin Matuska }
757