xref: /freebsd/contrib/libarchive/libarchive/archive_write_set_format_ustar.c (revision bd66c1b43e33540205dbc1187c2f2a15c58b57ba)
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 
186*bd66c1b4SMartin Matuska 	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. */
257*bd66c1b4SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
258*bd66c1b4SMartin Matuska 	if (archive_entry_pathname_w(entry) == NULL) {
259*bd66c1b4SMartin Matuska #else
2606c95142eSMartin Matuska 	if (archive_entry_pathname(entry) == NULL) {
261*bd66c1b4SMartin Matuska #endif
2626c95142eSMartin Matuska 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2636c95142eSMartin Matuska 		    "Can't record entry in tar file without pathname");
2646c95142eSMartin Matuska 		return (ARCHIVE_FAILED);
2656c95142eSMartin Matuska 	}
2666c95142eSMartin Matuska 
267caf54c4fSMartin Matuska 	/* Only regular files (not hardlinks) have data. */
268caf54c4fSMartin Matuska 	if (archive_entry_hardlink(entry) != NULL ||
269caf54c4fSMartin Matuska 	    archive_entry_symlink(entry) != NULL ||
270*bd66c1b4SMartin Matuska 	    archive_entry_filetype(entry) != AE_IFREG)
271caf54c4fSMartin Matuska 		archive_entry_set_size(entry, 0);
272caf54c4fSMartin Matuska 
273caf54c4fSMartin Matuska 	if (AE_IFDIR == archive_entry_filetype(entry)) {
274caf54c4fSMartin Matuska 		const char *p;
2756c95142eSMartin Matuska 		size_t path_length;
276caf54c4fSMartin Matuska 		/*
277caf54c4fSMartin Matuska 		 * Ensure a trailing '/'.  Modify the entry so
278caf54c4fSMartin Matuska 		 * the client sees the change.
279caf54c4fSMartin Matuska 		 */
2806c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
2816c95142eSMartin Matuska 		const wchar_t *wp;
2826c95142eSMartin Matuska 
2836c95142eSMartin Matuska 		wp = archive_entry_pathname_w(entry);
2846c95142eSMartin Matuska 		if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
2856c95142eSMartin Matuska 			struct archive_wstring ws;
2866c95142eSMartin Matuska 
2876c95142eSMartin Matuska 			archive_string_init(&ws);
2886c95142eSMartin Matuska 			path_length = wcslen(wp);
2896c95142eSMartin Matuska 			if (archive_wstring_ensure(&ws,
2906c95142eSMartin Matuska 			    path_length + 2) == NULL) {
2916c95142eSMartin Matuska 				archive_set_error(&a->archive, ENOMEM,
2926c95142eSMartin Matuska 				    "Can't allocate ustar data");
2936c95142eSMartin Matuska 				archive_wstring_free(&ws);
2946c95142eSMartin Matuska 				return(ARCHIVE_FATAL);
2956c95142eSMartin Matuska 			}
2966c95142eSMartin Matuska 			/* Should we keep '\' ? */
2976c95142eSMartin Matuska 			if (wp[path_length -1] == L'\\')
2986c95142eSMartin Matuska 				path_length--;
2996c95142eSMartin Matuska 			archive_wstrncpy(&ws, wp, path_length);
3006c95142eSMartin Matuska 			archive_wstrappend_wchar(&ws, L'/');
3016c95142eSMartin Matuska 			archive_entry_copy_pathname_w(entry, ws.s);
3026c95142eSMartin Matuska 			archive_wstring_free(&ws);
3036c95142eSMartin Matuska 			p = NULL;
3046c95142eSMartin Matuska 		} else
3056c95142eSMartin Matuska #endif
306caf54c4fSMartin Matuska 			p = archive_entry_pathname(entry);
3076c95142eSMartin Matuska 		/*
3086c95142eSMartin Matuska 		 * On Windows, this is a backup operation just in
3096c95142eSMartin Matuska 		 * case getting WCS failed. On POSIX, this is a
3106c95142eSMartin Matuska 		 * normal operation.
3116c95142eSMartin Matuska 		 */
312cfa49a9bSMartin Matuska 		if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
3136c95142eSMartin Matuska 			struct archive_string as;
3146c95142eSMartin Matuska 
3156c95142eSMartin Matuska 			archive_string_init(&as);
3166c95142eSMartin Matuska 			path_length = strlen(p);
3176c95142eSMartin Matuska 			if (archive_string_ensure(&as,
3186c95142eSMartin Matuska 			    path_length + 2) == NULL) {
3196c95142eSMartin Matuska 				archive_set_error(&a->archive, ENOMEM,
3206c95142eSMartin Matuska 				    "Can't allocate ustar data");
3216c95142eSMartin Matuska 				archive_string_free(&as);
3226c95142eSMartin Matuska 				return(ARCHIVE_FATAL);
3236c95142eSMartin Matuska 			}
3246c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
3256c95142eSMartin Matuska 			/* NOTE: This might break the pathname
3266c95142eSMartin Matuska 			 * if the current code page is CP932 and
3276c95142eSMartin Matuska 			 * the pathname includes a character '\'
3286c95142eSMartin Matuska 			 * as a part of its multibyte pathname. */
3296c95142eSMartin Matuska 			if (p[strlen(p) -1] == '\\')
3306c95142eSMartin Matuska 				path_length--;
3316c95142eSMartin Matuska 			else
3326c95142eSMartin Matuska #endif
3336c95142eSMartin Matuska 			archive_strncpy(&as, p, path_length);
3346c95142eSMartin Matuska 			archive_strappend_char(&as, '/');
3356c95142eSMartin Matuska 			archive_entry_copy_pathname(entry, as.s);
3366c95142eSMartin Matuska 			archive_string_free(&as);
3376c95142eSMartin Matuska 		}
3386c95142eSMartin Matuska 	}
3396c95142eSMartin Matuska 
3406c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
341a2e802b7SMartin Matuska 	/* Make sure the path separators in pathname, hardlink and symlink
3426c95142eSMartin Matuska 	 * are all slash '/', not the Windows path separator '\'. */
3436c95142eSMartin Matuska 	entry_main = __la_win_entry_in_posix_pathseparator(entry);
3446c95142eSMartin Matuska 	if (entry_main == NULL) {
345caf54c4fSMartin Matuska 		archive_set_error(&a->archive, ENOMEM,
346caf54c4fSMartin Matuska 		    "Can't allocate ustar data");
347caf54c4fSMartin Matuska 		return(ARCHIVE_FATAL);
348caf54c4fSMartin Matuska 	}
3496c95142eSMartin Matuska 	if (entry != entry_main)
3506c95142eSMartin Matuska 		entry = entry_main;
3516c95142eSMartin Matuska 	else
3526c95142eSMartin Matuska 		entry_main = NULL;
3536c95142eSMartin Matuska #else
3546c95142eSMartin Matuska 	entry_main = NULL;
3556c95142eSMartin Matuska #endif
3566c95142eSMartin Matuska 	ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1, sconv);
3576c95142eSMartin Matuska 	if (ret < ARCHIVE_WARN) {
3586c95142eSMartin Matuska 		archive_entry_free(entry_main);
359caf54c4fSMartin Matuska 		return (ret);
3606c95142eSMartin Matuska 	}
3616c95142eSMartin Matuska 	ret2 = __archive_write_output(a, buff, 512);
3626c95142eSMartin Matuska 	if (ret2 < ARCHIVE_WARN) {
3636c95142eSMartin Matuska 		archive_entry_free(entry_main);
364caf54c4fSMartin Matuska 		return (ret2);
3656c95142eSMartin Matuska 	}
366caf54c4fSMartin Matuska 	if (ret2 < ret)
367caf54c4fSMartin Matuska 		ret = ret2;
368caf54c4fSMartin Matuska 
369caf54c4fSMartin Matuska 	ustar->entry_bytes_remaining = archive_entry_size(entry);
370caf54c4fSMartin Matuska 	ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining);
3716c95142eSMartin Matuska 	archive_entry_free(entry_main);
372caf54c4fSMartin Matuska 	return (ret);
373caf54c4fSMartin Matuska }
374caf54c4fSMartin Matuska 
375caf54c4fSMartin Matuska /*
376caf54c4fSMartin Matuska  * Format a basic 512-byte "ustar" header.
377caf54c4fSMartin Matuska  *
378caf54c4fSMartin Matuska  * Returns -1 if format failed (due to field overflow).
379caf54c4fSMartin Matuska  * Note that this always formats as much of the header as possible.
380caf54c4fSMartin Matuska  * If "strict" is set to zero, it will extend numeric fields as
381caf54c4fSMartin Matuska  * necessary (overwriting terminators or using base-256 extensions).
382caf54c4fSMartin Matuska  *
383caf54c4fSMartin Matuska  * This is exported so that other 'tar' formats can use it.
384caf54c4fSMartin Matuska  */
385caf54c4fSMartin Matuska int
386caf54c4fSMartin Matuska __archive_write_format_header_ustar(struct archive_write *a, char h[512],
3876c95142eSMartin Matuska     struct archive_entry *entry, int tartype, int strict,
3886c95142eSMartin Matuska     struct archive_string_conv *sconv)
389caf54c4fSMartin Matuska {
390caf54c4fSMartin Matuska 	unsigned int checksum;
3916c95142eSMartin Matuska 	int i, r, ret;
392caf54c4fSMartin Matuska 	size_t copy_length;
393caf54c4fSMartin Matuska 	const char *p, *pp;
394caf54c4fSMartin Matuska 	int mytartype;
395caf54c4fSMartin Matuska 
396caf54c4fSMartin Matuska 	ret = 0;
397caf54c4fSMartin Matuska 	mytartype = -1;
398caf54c4fSMartin Matuska 	/*
399caf54c4fSMartin Matuska 	 * The "template header" already includes the "ustar"
400caf54c4fSMartin Matuska 	 * signature, various end-of-field markers and other required
401caf54c4fSMartin Matuska 	 * elements.
402caf54c4fSMartin Matuska 	 */
403caf54c4fSMartin Matuska 	memcpy(h, &template_header, 512);
404caf54c4fSMartin Matuska 
405caf54c4fSMartin Matuska 	/*
406caf54c4fSMartin Matuska 	 * Because the block is already null-filled, and strings
407caf54c4fSMartin Matuska 	 * are allowed to exactly fill their destination (without null),
408caf54c4fSMartin Matuska 	 * I use memcpy(dest, src, strlen()) here a lot to copy strings.
409caf54c4fSMartin Matuska 	 */
4106c95142eSMartin Matuska 	r = archive_entry_pathname_l(entry, &pp, &copy_length, sconv);
4116c95142eSMartin Matuska 	if (r != 0) {
4126c95142eSMartin Matuska 		if (errno == ENOMEM) {
4136c95142eSMartin Matuska 			archive_set_error(&a->archive, ENOMEM,
4146c95142eSMartin Matuska 			    "Can't allocate memory for Pathname");
4156c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
4166c95142eSMartin Matuska 		}
4176c95142eSMartin Matuska 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
4186c95142eSMartin Matuska 		    "Can't translate pathname '%s' to %s",
4196c95142eSMartin Matuska 		    pp, archive_string_conversion_charset_name(sconv));
4206c95142eSMartin Matuska 		ret = ARCHIVE_WARN;
4216c95142eSMartin Matuska 	}
4226c95142eSMartin Matuska 	if (copy_length <= USTAR_name_size)
4236c95142eSMartin Matuska 		memcpy(h + USTAR_name_offset, pp, copy_length);
424caf54c4fSMartin Matuska 	else {
425caf54c4fSMartin Matuska 		/* Store in two pieces, splitting at a '/'. */
4266c95142eSMartin Matuska 		p = strchr(pp + copy_length - USTAR_name_size - 1, '/');
427caf54c4fSMartin Matuska 		/*
428caf54c4fSMartin Matuska 		 * Look for the next '/' if we chose the first character
429caf54c4fSMartin Matuska 		 * as the separator.  (ustar format doesn't permit
430caf54c4fSMartin Matuska 		 * an empty prefix.)
431caf54c4fSMartin Matuska 		 */
432caf54c4fSMartin Matuska 		if (p == pp)
433caf54c4fSMartin Matuska 			p = strchr(p + 1, '/');
434caf54c4fSMartin Matuska 		/* Fail if the name won't fit. */
435caf54c4fSMartin Matuska 		if (!p) {
436caf54c4fSMartin Matuska 			/* No separator. */
437caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ENAMETOOLONG,
438caf54c4fSMartin Matuska 			    "Pathname too long");
439caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
440caf54c4fSMartin Matuska 		} else if (p[1] == '\0') {
441caf54c4fSMartin Matuska 			/*
442caf54c4fSMartin Matuska 			 * The only feasible separator is a final '/';
443caf54c4fSMartin Matuska 			 * this would result in a non-empty prefix and
444caf54c4fSMartin Matuska 			 * an empty name, which POSIX doesn't
4456c95142eSMartin Matuska 			 * explicitly forbid, but it just feels wrong.
446caf54c4fSMartin Matuska 			 */
447caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ENAMETOOLONG,
448caf54c4fSMartin Matuska 			    "Pathname too long");
449caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
450caf54c4fSMartin Matuska 		} else if (p  > pp + USTAR_prefix_size) {
451caf54c4fSMartin Matuska 			/* Prefix is too long. */
452caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ENAMETOOLONG,
453caf54c4fSMartin Matuska 			    "Pathname too long");
454caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
455caf54c4fSMartin Matuska 		} else {
456caf54c4fSMartin Matuska 			/* Copy prefix and remainder to appropriate places */
457caf54c4fSMartin Matuska 			memcpy(h + USTAR_prefix_offset, pp, p - pp);
4586c95142eSMartin Matuska 			memcpy(h + USTAR_name_offset, p + 1,
4596c95142eSMartin Matuska 			    pp + copy_length - p - 1);
460caf54c4fSMartin Matuska 		}
461caf54c4fSMartin Matuska 	}
462caf54c4fSMartin Matuska 
4636c95142eSMartin Matuska 	r = archive_entry_hardlink_l(entry, &p, &copy_length, sconv);
4646c95142eSMartin Matuska 	if (r != 0) {
4656c95142eSMartin Matuska 		if (errno == ENOMEM) {
4666c95142eSMartin Matuska 			archive_set_error(&a->archive, ENOMEM,
4676c95142eSMartin Matuska 			    "Can't allocate memory for Linkname");
4686c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
4696c95142eSMartin Matuska 		}
4706c95142eSMartin Matuska 		archive_set_error(&a->archive,
4716c95142eSMartin Matuska 		    ARCHIVE_ERRNO_FILE_FORMAT,
4726c95142eSMartin Matuska 		    "Can't translate linkname '%s' to %s",
4736c95142eSMartin Matuska 		    p, archive_string_conversion_charset_name(sconv));
4746c95142eSMartin Matuska 		ret = ARCHIVE_WARN;
4756c95142eSMartin Matuska 	}
4766c95142eSMartin Matuska 	if (copy_length > 0)
477caf54c4fSMartin Matuska 		mytartype = '1';
4786c95142eSMartin Matuska 	else {
4796c95142eSMartin Matuska 		r = archive_entry_symlink_l(entry, &p, &copy_length, sconv);
4806c95142eSMartin Matuska 		if (r != 0) {
4816c95142eSMartin Matuska 			if (errno == ENOMEM) {
4826c95142eSMartin Matuska 				archive_set_error(&a->archive, ENOMEM,
4836c95142eSMartin Matuska 				    "Can't allocate memory for Linkname");
4846c95142eSMartin Matuska 				return (ARCHIVE_FATAL);
4856c95142eSMartin Matuska 			}
4866c95142eSMartin Matuska 			archive_set_error(&a->archive,
4876c95142eSMartin Matuska 			    ARCHIVE_ERRNO_FILE_FORMAT,
4886c95142eSMartin Matuska 			    "Can't translate linkname '%s' to %s",
4896c95142eSMartin Matuska 			    p, archive_string_conversion_charset_name(sconv));
4906c95142eSMartin Matuska 			ret = ARCHIVE_WARN;
4916c95142eSMartin Matuska 		}
4926c95142eSMartin Matuska 	}
4936c95142eSMartin Matuska 	if (copy_length > 0) {
494caf54c4fSMartin Matuska 		if (copy_length > USTAR_linkname_size) {
495caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ENAMETOOLONG,
496caf54c4fSMartin Matuska 			    "Link contents too long");
497caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
498caf54c4fSMartin Matuska 			copy_length = USTAR_linkname_size;
499caf54c4fSMartin Matuska 		}
500caf54c4fSMartin Matuska 		memcpy(h + USTAR_linkname_offset, p, copy_length);
501caf54c4fSMartin Matuska 	}
502caf54c4fSMartin Matuska 
5036c95142eSMartin Matuska 	r = archive_entry_uname_l(entry, &p, &copy_length, sconv);
5046c95142eSMartin Matuska 	if (r != 0) {
5056c95142eSMartin Matuska 		if (errno == ENOMEM) {
5066c95142eSMartin Matuska 			archive_set_error(&a->archive, ENOMEM,
5076c95142eSMartin Matuska 			    "Can't allocate memory for Uname");
5086c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
5096c95142eSMartin Matuska 		}
5106c95142eSMartin Matuska 		archive_set_error(&a->archive,
5116c95142eSMartin Matuska 		    ARCHIVE_ERRNO_FILE_FORMAT,
5126c95142eSMartin Matuska 		    "Can't translate uname '%s' to %s",
5136c95142eSMartin Matuska 		    p, archive_string_conversion_charset_name(sconv));
5146c95142eSMartin Matuska 		ret = ARCHIVE_WARN;
5156c95142eSMartin Matuska 	}
5166c95142eSMartin Matuska 	if (copy_length > 0) {
517caf54c4fSMartin Matuska 		if (copy_length > USTAR_uname_size) {
518f9762417SMartin Matuska 			if (tartype != 'x') {
519f9762417SMartin Matuska 				archive_set_error(&a->archive,
520f9762417SMartin Matuska 				    ARCHIVE_ERRNO_MISC, "Username too long");
521caf54c4fSMartin Matuska 				ret = ARCHIVE_FAILED;
522f9762417SMartin Matuska 			}
523caf54c4fSMartin Matuska 			copy_length = USTAR_uname_size;
524caf54c4fSMartin Matuska 		}
525caf54c4fSMartin Matuska 		memcpy(h + USTAR_uname_offset, p, copy_length);
526caf54c4fSMartin Matuska 	}
527caf54c4fSMartin Matuska 
5286c95142eSMartin Matuska 	r = archive_entry_gname_l(entry, &p, &copy_length, sconv);
5296c95142eSMartin Matuska 	if (r != 0) {
5306c95142eSMartin Matuska 		if (errno == ENOMEM) {
5316c95142eSMartin Matuska 			archive_set_error(&a->archive, ENOMEM,
5326c95142eSMartin Matuska 			    "Can't allocate memory for Gname");
5336c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
5346c95142eSMartin Matuska 		}
5356c95142eSMartin Matuska 		archive_set_error(&a->archive,
5366c95142eSMartin Matuska 		    ARCHIVE_ERRNO_FILE_FORMAT,
5376c95142eSMartin Matuska 		    "Can't translate gname '%s' to %s",
5386c95142eSMartin Matuska 		    p, archive_string_conversion_charset_name(sconv));
5396c95142eSMartin Matuska 		ret = ARCHIVE_WARN;
5406c95142eSMartin Matuska 	}
5416c95142eSMartin Matuska 	if (copy_length > 0) {
542caf54c4fSMartin Matuska 		if (strlen(p) > USTAR_gname_size) {
543f9762417SMartin Matuska 			if (tartype != 'x') {
544f9762417SMartin Matuska 				archive_set_error(&a->archive,
545f9762417SMartin Matuska 				    ARCHIVE_ERRNO_MISC, "Group name too long");
546caf54c4fSMartin Matuska 				ret = ARCHIVE_FAILED;
547f9762417SMartin Matuska 			}
548caf54c4fSMartin Matuska 			copy_length = USTAR_gname_size;
549caf54c4fSMartin Matuska 		}
550caf54c4fSMartin Matuska 		memcpy(h + USTAR_gname_offset, p, copy_length);
551caf54c4fSMartin Matuska 	}
552caf54c4fSMartin Matuska 
5536c95142eSMartin Matuska 	if (format_number(archive_entry_mode(entry) & 07777,
5546c95142eSMartin Matuska 	    h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {
5556c95142eSMartin Matuska 		archive_set_error(&a->archive, ERANGE,
5566c95142eSMartin Matuska 		    "Numeric mode too large");
557caf54c4fSMartin Matuska 		ret = ARCHIVE_FAILED;
558caf54c4fSMartin Matuska 	}
559caf54c4fSMartin Matuska 
5606c95142eSMartin Matuska 	if (format_number(archive_entry_uid(entry),
5616c95142eSMartin Matuska 	    h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {
5626c95142eSMartin Matuska 		archive_set_error(&a->archive, ERANGE,
5636c95142eSMartin Matuska 		    "Numeric user ID too large");
564caf54c4fSMartin Matuska 		ret = ARCHIVE_FAILED;
565caf54c4fSMartin Matuska 	}
566caf54c4fSMartin Matuska 
5676c95142eSMartin Matuska 	if (format_number(archive_entry_gid(entry),
5686c95142eSMartin Matuska 	    h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {
5696c95142eSMartin Matuska 		archive_set_error(&a->archive, ERANGE,
5706c95142eSMartin Matuska 		    "Numeric group ID too large");
571caf54c4fSMartin Matuska 		ret = ARCHIVE_FAILED;
572caf54c4fSMartin Matuska 	}
573caf54c4fSMartin Matuska 
5746c95142eSMartin Matuska 	if (format_number(archive_entry_size(entry),
5756c95142eSMartin Matuska 	    h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {
5766c95142eSMartin Matuska 		archive_set_error(&a->archive, ERANGE,
5776c95142eSMartin Matuska 		    "File size out of range");
578caf54c4fSMartin Matuska 		ret = ARCHIVE_FAILED;
579caf54c4fSMartin Matuska 	}
580caf54c4fSMartin Matuska 
5816c95142eSMartin Matuska 	if (format_number(archive_entry_mtime(entry),
5826c95142eSMartin Matuska 	    h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {
583caf54c4fSMartin Matuska 		archive_set_error(&a->archive, ERANGE,
584caf54c4fSMartin Matuska 		    "File modification time too large");
585caf54c4fSMartin Matuska 		ret = ARCHIVE_FAILED;
586caf54c4fSMartin Matuska 	}
587caf54c4fSMartin Matuska 
588caf54c4fSMartin Matuska 	if (archive_entry_filetype(entry) == AE_IFBLK
589caf54c4fSMartin Matuska 	    || archive_entry_filetype(entry) == AE_IFCHR) {
5906c95142eSMartin Matuska 		if (format_number(archive_entry_rdevmajor(entry),
5916c95142eSMartin Matuska 		    h + USTAR_rdevmajor_offset, USTAR_rdevmajor_size,
5926c95142eSMartin Matuska 		    USTAR_rdevmajor_max_size, strict)) {
593caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ERANGE,
594caf54c4fSMartin Matuska 			    "Major device number too large");
595caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
596caf54c4fSMartin Matuska 		}
597caf54c4fSMartin Matuska 
5986c95142eSMartin Matuska 		if (format_number(archive_entry_rdevminor(entry),
5996c95142eSMartin Matuska 		    h + USTAR_rdevminor_offset, USTAR_rdevminor_size,
6006c95142eSMartin Matuska 		    USTAR_rdevminor_max_size, strict)) {
601caf54c4fSMartin Matuska 			archive_set_error(&a->archive, ERANGE,
602caf54c4fSMartin Matuska 			    "Minor device number too large");
603caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
604caf54c4fSMartin Matuska 		}
605caf54c4fSMartin Matuska 	}
606caf54c4fSMartin Matuska 
607caf54c4fSMartin Matuska 	if (tartype >= 0) {
608caf54c4fSMartin Matuska 		h[USTAR_typeflag_offset] = tartype;
609caf54c4fSMartin Matuska 	} else if (mytartype >= 0) {
610caf54c4fSMartin Matuska 		h[USTAR_typeflag_offset] = mytartype;
611caf54c4fSMartin Matuska 	} else {
612caf54c4fSMartin Matuska 		switch (archive_entry_filetype(entry)) {
613caf54c4fSMartin Matuska 		case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break;
614caf54c4fSMartin Matuska 		case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break;
615caf54c4fSMartin Matuska 		case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break;
616caf54c4fSMartin Matuska 		case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break;
617caf54c4fSMartin Matuska 		case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break;
618caf54c4fSMartin Matuska 		case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break;
619f9762417SMartin Matuska 		default: /* AE_IFSOCK and unknown */
620f9762417SMartin Matuska 			__archive_write_entry_filetype_unsupported(
621f9762417SMartin Matuska 			    &a->archive, entry, "ustar");
622caf54c4fSMartin Matuska 			ret = ARCHIVE_FAILED;
623caf54c4fSMartin Matuska 		}
624caf54c4fSMartin Matuska 	}
625caf54c4fSMartin Matuska 
626caf54c4fSMartin Matuska 	checksum = 0;
627caf54c4fSMartin Matuska 	for (i = 0; i < 512; i++)
628caf54c4fSMartin Matuska 		checksum += 255 & (unsigned int)h[i];
629caf54c4fSMartin Matuska 	h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */
630caf54c4fSMartin Matuska 	/* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */
631caf54c4fSMartin Matuska 	format_octal(checksum, h + USTAR_checksum_offset, 6);
632caf54c4fSMartin Matuska 	return (ret);
633caf54c4fSMartin Matuska }
634caf54c4fSMartin Matuska 
635caf54c4fSMartin Matuska /*
636caf54c4fSMartin Matuska  * Format a number into a field, with some intelligence.
637caf54c4fSMartin Matuska  */
638caf54c4fSMartin Matuska static int
639caf54c4fSMartin Matuska format_number(int64_t v, char *p, int s, int maxsize, int strict)
640caf54c4fSMartin Matuska {
641caf54c4fSMartin Matuska 	int64_t limit;
642caf54c4fSMartin Matuska 
643caf54c4fSMartin Matuska 	limit = ((int64_t)1 << (s*3));
644caf54c4fSMartin Matuska 
645caf54c4fSMartin Matuska 	/* "Strict" only permits octal values with proper termination. */
646caf54c4fSMartin Matuska 	if (strict)
647caf54c4fSMartin Matuska 		return (format_octal(v, p, s));
648caf54c4fSMartin Matuska 
649caf54c4fSMartin Matuska 	/*
650caf54c4fSMartin Matuska 	 * In non-strict mode, we allow the number to overwrite one or
651caf54c4fSMartin Matuska 	 * more bytes of the field termination.  Even old tar
652caf54c4fSMartin Matuska 	 * implementations should be able to handle this with no
653caf54c4fSMartin Matuska 	 * problem.
654caf54c4fSMartin Matuska 	 */
655caf54c4fSMartin Matuska 	if (v >= 0) {
656caf54c4fSMartin Matuska 		while (s <= maxsize) {
657caf54c4fSMartin Matuska 			if (v < limit)
658caf54c4fSMartin Matuska 				return (format_octal(v, p, s));
659caf54c4fSMartin Matuska 			s++;
660caf54c4fSMartin Matuska 			limit <<= 3;
661caf54c4fSMartin Matuska 		}
662caf54c4fSMartin Matuska 	}
663caf54c4fSMartin Matuska 
664caf54c4fSMartin Matuska 	/* Base-256 can handle any number, positive or negative. */
665caf54c4fSMartin Matuska 	return (format_256(v, p, maxsize));
666caf54c4fSMartin Matuska }
667caf54c4fSMartin Matuska 
668caf54c4fSMartin Matuska /*
669caf54c4fSMartin Matuska  * Format a number into the specified field using base-256.
670caf54c4fSMartin Matuska  */
671caf54c4fSMartin Matuska static int
672caf54c4fSMartin Matuska format_256(int64_t v, char *p, int s)
673caf54c4fSMartin Matuska {
674caf54c4fSMartin Matuska 	p += s;
675caf54c4fSMartin Matuska 	while (s-- > 0) {
676caf54c4fSMartin Matuska 		*--p = (char)(v & 0xff);
677caf54c4fSMartin Matuska 		v >>= 8;
678caf54c4fSMartin Matuska 	}
679caf54c4fSMartin Matuska 	*p |= 0x80; /* Set the base-256 marker bit. */
680caf54c4fSMartin Matuska 	return (0);
681caf54c4fSMartin Matuska }
682caf54c4fSMartin Matuska 
683caf54c4fSMartin Matuska /*
684caf54c4fSMartin Matuska  * Format a number into the specified field.
685caf54c4fSMartin Matuska  */
686caf54c4fSMartin Matuska static int
687caf54c4fSMartin Matuska format_octal(int64_t v, char *p, int s)
688caf54c4fSMartin Matuska {
689caf54c4fSMartin Matuska 	int len;
690caf54c4fSMartin Matuska 
691caf54c4fSMartin Matuska 	len = s;
692caf54c4fSMartin Matuska 
693caf54c4fSMartin Matuska 	/* Octal values can't be negative, so use 0. */
694caf54c4fSMartin Matuska 	if (v < 0) {
695caf54c4fSMartin Matuska 		while (len-- > 0)
696caf54c4fSMartin Matuska 			*p++ = '0';
697caf54c4fSMartin Matuska 		return (-1);
698caf54c4fSMartin Matuska 	}
699caf54c4fSMartin Matuska 
700caf54c4fSMartin Matuska 	p += s;		/* Start at the end and work backwards. */
701caf54c4fSMartin Matuska 	while (s-- > 0) {
702caf54c4fSMartin Matuska 		*--p = (char)('0' + (v & 7));
703caf54c4fSMartin Matuska 		v >>= 3;
704caf54c4fSMartin Matuska 	}
705caf54c4fSMartin Matuska 
706caf54c4fSMartin Matuska 	if (v == 0)
707caf54c4fSMartin Matuska 		return (0);
708caf54c4fSMartin Matuska 
709caf54c4fSMartin Matuska 	/* If it overflowed, fill field with max value. */
710caf54c4fSMartin Matuska 	while (len-- > 0)
711caf54c4fSMartin Matuska 		*p++ = '7';
712caf54c4fSMartin Matuska 
713caf54c4fSMartin Matuska 	return (-1);
714caf54c4fSMartin Matuska }
715caf54c4fSMartin Matuska 
716caf54c4fSMartin Matuska static int
7176c95142eSMartin Matuska archive_write_ustar_close(struct archive_write *a)
718caf54c4fSMartin Matuska {
7196c95142eSMartin Matuska 	return (__archive_write_nulls(a, 512*2));
720caf54c4fSMartin Matuska }
721caf54c4fSMartin Matuska 
722caf54c4fSMartin Matuska static int
7236c95142eSMartin Matuska archive_write_ustar_free(struct archive_write *a)
724caf54c4fSMartin Matuska {
725caf54c4fSMartin Matuska 	struct ustar *ustar;
726caf54c4fSMartin Matuska 
727caf54c4fSMartin Matuska 	ustar = (struct ustar *)a->format_data;
728caf54c4fSMartin Matuska 	free(ustar);
729caf54c4fSMartin Matuska 	a->format_data = NULL;
730caf54c4fSMartin Matuska 	return (ARCHIVE_OK);
731caf54c4fSMartin Matuska }
732caf54c4fSMartin Matuska 
733caf54c4fSMartin Matuska static int
734caf54c4fSMartin Matuska archive_write_ustar_finish_entry(struct archive_write *a)
735caf54c4fSMartin Matuska {
736caf54c4fSMartin Matuska 	struct ustar *ustar;
737caf54c4fSMartin Matuska 	int ret;
738caf54c4fSMartin Matuska 
739caf54c4fSMartin Matuska 	ustar = (struct ustar *)a->format_data;
7406c95142eSMartin Matuska 	ret = __archive_write_nulls(a,
741fd082e96SMartin Matuska 	    (size_t)(ustar->entry_bytes_remaining + ustar->entry_padding));
742caf54c4fSMartin Matuska 	ustar->entry_bytes_remaining = ustar->entry_padding = 0;
743caf54c4fSMartin Matuska 	return (ret);
744caf54c4fSMartin Matuska }
745caf54c4fSMartin Matuska 
746caf54c4fSMartin Matuska static ssize_t
747caf54c4fSMartin Matuska archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
748caf54c4fSMartin Matuska {
749caf54c4fSMartin Matuska 	struct ustar *ustar;
750caf54c4fSMartin Matuska 	int ret;
751caf54c4fSMartin Matuska 
752caf54c4fSMartin Matuska 	ustar = (struct ustar *)a->format_data;
753caf54c4fSMartin Matuska 	if (s > ustar->entry_bytes_remaining)
754fd082e96SMartin Matuska 		s = (size_t)ustar->entry_bytes_remaining;
7556c95142eSMartin Matuska 	ret = __archive_write_output(a, buff, s);
756caf54c4fSMartin Matuska 	ustar->entry_bytes_remaining -= s;
757caf54c4fSMartin Matuska 	if (ret != ARCHIVE_OK)
758caf54c4fSMartin Matuska 		return (ret);
759caf54c4fSMartin Matuska 	return (s);
760caf54c4fSMartin Matuska }
761