1 /*-
2  * Copyright (c) 2003-2007 Tim Kientzle
3  * Copyright (c) 2011-2012 Michihiro NAKAJIMA
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD$");
29 
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 #include "archive_write_set_format_private.h"
48 
49 struct v7tar {
50 	uint64_t	entry_bytes_remaining;
51 	uint64_t	entry_padding;
52 
53 	struct archive_string_conv *opt_sconv;
54 	struct archive_string_conv *sconv_default;
55 	int	init_default_conversion;
56 };
57 
58 /*
59  * Define structure of POSIX 'v7tar' tar header.
60  */
61 #define	V7TAR_name_offset 0
62 #define	V7TAR_name_size 100
63 #define	V7TAR_mode_offset 100
64 #define	V7TAR_mode_size 6
65 #define	V7TAR_mode_max_size 8
66 #define	V7TAR_uid_offset 108
67 #define	V7TAR_uid_size 6
68 #define	V7TAR_uid_max_size 8
69 #define	V7TAR_gid_offset 116
70 #define	V7TAR_gid_size 6
71 #define	V7TAR_gid_max_size 8
72 #define	V7TAR_size_offset 124
73 #define	V7TAR_size_size 11
74 #define	V7TAR_size_max_size 12
75 #define	V7TAR_mtime_offset 136
76 #define	V7TAR_mtime_size 11
77 #define	V7TAR_mtime_max_size 12
78 #define	V7TAR_checksum_offset 148
79 #define	V7TAR_checksum_size 8
80 #define	V7TAR_typeflag_offset 156
81 #define	V7TAR_typeflag_size 1
82 #define	V7TAR_linkname_offset 157
83 #define	V7TAR_linkname_size 100
84 #define	V7TAR_padding_offset 257
85 #define	V7TAR_padding_size 255
86 
87 /*
88  * A filled-in copy of the header for initialization.
89  */
90 static const char template_header[] = {
91 	/* name: 100 bytes */
92 	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,
93 	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,
94 	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,
95 	0,0,0,0,
96 	/* Mode, space-null termination: 8 bytes */
97 	'0','0','0','0','0','0', ' ','\0',
98 	/* uid, space-null termination: 8 bytes */
99 	'0','0','0','0','0','0', ' ','\0',
100 	/* gid, space-null termination: 8 bytes */
101 	'0','0','0','0','0','0', ' ','\0',
102 	/* size, space termination: 12 bytes */
103 	'0','0','0','0','0','0','0','0','0','0','0', ' ',
104 	/* mtime, space termination: 12 bytes */
105 	'0','0','0','0','0','0','0','0','0','0','0', ' ',
106 	/* Initial checksum value: 8 spaces */
107 	' ',' ',' ',' ',' ',' ',' ',' ',
108 	/* Typeflag: 1 byte */
109 	0,
110 	/* Linkname: 100 bytes */
111 	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,
112 	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,
113 	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,
114 	0,0,0,0,
115 	/* Padding: 255 bytes */
116 	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,
117 	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,
118 	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,
119 	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,
120 	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,
121 	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,
122 	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,
123 	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
124 };
125 
126 static ssize_t	archive_write_v7tar_data(struct archive_write *a, const void *buff,
127 		    size_t s);
128 static int	archive_write_v7tar_free(struct archive_write *);
129 static int	archive_write_v7tar_close(struct archive_write *);
130 static int	archive_write_v7tar_finish_entry(struct archive_write *);
131 static int	archive_write_v7tar_header(struct archive_write *,
132 		    struct archive_entry *entry);
133 static int	archive_write_v7tar_options(struct archive_write *,
134 		    const char *, const char *);
135 static int	format_256(int64_t, char *, int);
136 static int	format_number(int64_t, char *, int size, int max, int strict);
137 static int	format_octal(int64_t, char *, int);
138 static int	format_header_v7tar(struct archive_write *, char h[512],
139 		    struct archive_entry *, int, struct archive_string_conv *);
140 
141 /*
142  * Set output format to 'v7tar' format.
143  */
144 int
145 archive_write_set_format_v7tar(struct archive *_a)
146 {
147 	struct archive_write *a = (struct archive_write *)_a;
148 	struct v7tar *v7tar;
149 
150 	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
151 	    ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar");
152 
153 	/* If someone else was already registered, unregister them. */
154 	if (a->format_free != NULL)
155 		(a->format_free)(a);
156 
157 	/* Basic internal sanity test. */
158 	if (sizeof(template_header) != 512) {
159 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
160 		    "Internal: template_header wrong size: %zu should be 512",
161 		    sizeof(template_header));
162 		return (ARCHIVE_FATAL);
163 	}
164 
165 	v7tar = (struct v7tar *)calloc(1, sizeof(*v7tar));
166 	if (v7tar == NULL) {
167 		archive_set_error(&a->archive, ENOMEM,
168 		    "Can't allocate v7tar data");
169 		return (ARCHIVE_FATAL);
170 	}
171 	a->format_data = v7tar;
172 	a->format_name = "tar (non-POSIX)";
173 	a->format_options = archive_write_v7tar_options;
174 	a->format_write_header = archive_write_v7tar_header;
175 	a->format_write_data = archive_write_v7tar_data;
176 	a->format_close = archive_write_v7tar_close;
177 	a->format_free = archive_write_v7tar_free;
178 	a->format_finish_entry = archive_write_v7tar_finish_entry;
179 	a->archive.archive_format = ARCHIVE_FORMAT_TAR;
180 	a->archive.archive_format_name = "tar (non-POSIX)";
181 	return (ARCHIVE_OK);
182 }
183 
184 static int
185 archive_write_v7tar_options(struct archive_write *a, const char *key,
186     const char *val)
187 {
188 	struct v7tar *v7tar = (struct v7tar *)a->format_data;
189 	int ret = ARCHIVE_FAILED;
190 
191 	if (strcmp(key, "hdrcharset")  == 0) {
192 		if (val == NULL || val[0] == 0)
193 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
194 			    "%s: hdrcharset option needs a character-set name",
195 			    a->format_name);
196 		else {
197 			v7tar->opt_sconv = archive_string_conversion_to_charset(
198 			    &a->archive, val, 0);
199 			if (v7tar->opt_sconv != NULL)
200 				ret = ARCHIVE_OK;
201 			else
202 				ret = ARCHIVE_FATAL;
203 		}
204 		return (ret);
205 	}
206 
207 	/* Note: The "warn" return is just to inform the options
208 	 * supervisor that we didn't handle it.  It will generate
209 	 * a suitable error if no one used this option. */
210 	return (ARCHIVE_WARN);
211 }
212 
213 static int
214 archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)
215 {
216 	char buff[512];
217 	int ret, ret2;
218 	struct v7tar *v7tar;
219 	struct archive_entry *entry_main;
220 	struct archive_string_conv *sconv;
221 
222 	v7tar = (struct v7tar *)a->format_data;
223 
224 	/* Setup default string conversion. */
225 	if (v7tar->opt_sconv == NULL) {
226 		if (!v7tar->init_default_conversion) {
227 			v7tar->sconv_default =
228 			    archive_string_default_conversion_for_write(
229 				&(a->archive));
230 			v7tar->init_default_conversion = 1;
231 		}
232 		sconv = v7tar->sconv_default;
233 	} else
234 		sconv = v7tar->opt_sconv;
235 
236 	/* Sanity check. */
237 	if (archive_entry_pathname(entry) == NULL) {
238 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
239 		    "Can't record entry in tar file without pathname");
240 		return (ARCHIVE_FAILED);
241 	}
242 
243 	/* Only regular files (not hardlinks) have data. */
244 	if (archive_entry_hardlink(entry) != NULL ||
245 	    archive_entry_symlink(entry) != NULL ||
246 	    !(archive_entry_filetype(entry) == AE_IFREG))
247 		archive_entry_set_size(entry, 0);
248 
249 	if (AE_IFDIR == archive_entry_filetype(entry)) {
250 		const char *p;
251 		size_t path_length;
252 		/*
253 		 * Ensure a trailing '/'.  Modify the entry so
254 		 * the client sees the change.
255 		 */
256 #if defined(_WIN32) && !defined(__CYGWIN__)
257 		const wchar_t *wp;
258 
259 		wp = archive_entry_pathname_w(entry);
260 		if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
261 			struct archive_wstring ws;
262 
263 			archive_string_init(&ws);
264 			path_length = wcslen(wp);
265 			if (archive_wstring_ensure(&ws,
266 			    path_length + 2) == NULL) {
267 				archive_set_error(&a->archive, ENOMEM,
268 				    "Can't allocate v7tar data");
269 				archive_wstring_free(&ws);
270 				return(ARCHIVE_FATAL);
271 			}
272 			/* Should we keep '\' ? */
273 			if (wp[path_length -1] == L'\\')
274 				path_length--;
275 			archive_wstrncpy(&ws, wp, path_length);
276 			archive_wstrappend_wchar(&ws, L'/');
277 			archive_entry_copy_pathname_w(entry, ws.s);
278 			archive_wstring_free(&ws);
279 			p = NULL;
280 		} else
281 #endif
282 			p = archive_entry_pathname(entry);
283 		/*
284 		 * On Windows, this is a backup operation just in
285 		 * case getting WCS failed. On POSIX, this is a
286 		 * normal operation.
287 		 */
288 		if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
289 			struct archive_string as;
290 
291 			archive_string_init(&as);
292 			path_length = strlen(p);
293 			if (archive_string_ensure(&as,
294 			    path_length + 2) == NULL) {
295 				archive_set_error(&a->archive, ENOMEM,
296 				    "Can't allocate v7tar data");
297 				archive_string_free(&as);
298 				return(ARCHIVE_FATAL);
299 			}
300 #if defined(_WIN32) && !defined(__CYGWIN__)
301 			/* NOTE: This might break the pathname
302 			 * if the current code page is CP932 and
303 			 * the pathname includes a character '\'
304 			 * as a part of its multibyte pathname. */
305 			if (p[strlen(p) -1] == '\\')
306 				path_length--;
307 			else
308 #endif
309 			archive_strncpy(&as, p, path_length);
310 			archive_strappend_char(&as, '/');
311 			archive_entry_copy_pathname(entry, as.s);
312 			archive_string_free(&as);
313 		}
314 	}
315 
316 #if defined(_WIN32) && !defined(__CYGWIN__)
317 	/* Make sure the path separators in pathname, hardlink and symlink
318 	 * are all slash '/', not the Windows path separator '\'. */
319 	entry_main = __la_win_entry_in_posix_pathseparator(entry);
320 	if (entry_main == NULL) {
321 		archive_set_error(&a->archive, ENOMEM,
322 		    "Can't allocate v7tar data");
323 		return(ARCHIVE_FATAL);
324 	}
325 	if (entry != entry_main)
326 		entry = entry_main;
327 	else
328 		entry_main = NULL;
329 #else
330 	entry_main = NULL;
331 #endif
332 	ret = format_header_v7tar(a, buff, entry, 1, sconv);
333 	if (ret < ARCHIVE_WARN) {
334 		archive_entry_free(entry_main);
335 		return (ret);
336 	}
337 	ret2 = __archive_write_output(a, buff, 512);
338 	if (ret2 < ARCHIVE_WARN) {
339 		archive_entry_free(entry_main);
340 		return (ret2);
341 	}
342 	if (ret2 < ret)
343 		ret = ret2;
344 
345 	v7tar->entry_bytes_remaining = archive_entry_size(entry);
346 	v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);
347 	archive_entry_free(entry_main);
348 	return (ret);
349 }
350 
351 /*
352  * Format a basic 512-byte "v7tar" header.
353  *
354  * Returns -1 if format failed (due to field overflow).
355  * Note that this always formats as much of the header as possible.
356  * If "strict" is set to zero, it will extend numeric fields as
357  * necessary (overwriting terminators or using base-256 extensions).
358  *
359  */
360 static int
361 format_header_v7tar(struct archive_write *a, char h[512],
362     struct archive_entry *entry, int strict,
363     struct archive_string_conv *sconv)
364 {
365 	unsigned int checksum;
366 	int i, r, ret;
367 	size_t copy_length;
368 	const char *p, *pp;
369 	int mytartype;
370 
371 	ret = 0;
372 	mytartype = -1;
373 	/*
374 	 * The "template header" already includes the "v7tar"
375 	 * signature, various end-of-field markers and other required
376 	 * elements.
377 	 */
378 	memcpy(h, &template_header, 512);
379 
380 	/*
381 	 * Because the block is already null-filled, and strings
382 	 * are allowed to exactly fill their destination (without null),
383 	 * I use memcpy(dest, src, strlen()) here a lot to copy strings.
384 	 */
385 	r = archive_entry_pathname_l(entry, &pp, &copy_length, sconv);
386 	if (r != 0) {
387 		if (errno == ENOMEM) {
388 			archive_set_error(&a->archive, ENOMEM,
389 			    "Can't allocate memory for Pathname");
390 			return (ARCHIVE_FATAL);
391 		}
392 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
393 		    "Can't translate pathname '%s' to %s",
394 		    pp, archive_string_conversion_charset_name(sconv));
395 		ret = ARCHIVE_WARN;
396 	}
397 	if (strict && copy_length < V7TAR_name_size)
398 		memcpy(h + V7TAR_name_offset, pp, copy_length);
399 	else if (!strict && copy_length <= V7TAR_name_size)
400 		memcpy(h + V7TAR_name_offset, pp, copy_length);
401 	else {
402 		/* Prefix is too long. */
403 		archive_set_error(&a->archive, ENAMETOOLONG,
404 		    "Pathname too long");
405 		ret = ARCHIVE_FAILED;
406 	}
407 
408 	r = archive_entry_hardlink_l(entry, &p, &copy_length, sconv);
409 	if (r != 0) {
410 		if (errno == ENOMEM) {
411 			archive_set_error(&a->archive, ENOMEM,
412 			    "Can't allocate memory for Linkname");
413 			return (ARCHIVE_FATAL);
414 		}
415 		archive_set_error(&a->archive,
416 		    ARCHIVE_ERRNO_FILE_FORMAT,
417 		    "Can't translate linkname '%s' to %s",
418 		    p, archive_string_conversion_charset_name(sconv));
419 		ret = ARCHIVE_WARN;
420 	}
421 	if (copy_length > 0)
422 		mytartype = '1';
423 	else {
424 		r = archive_entry_symlink_l(entry, &p, &copy_length, sconv);
425 		if (r != 0) {
426 			if (errno == ENOMEM) {
427 				archive_set_error(&a->archive, ENOMEM,
428 				    "Can't allocate memory for Linkname");
429 				return (ARCHIVE_FATAL);
430 			}
431 			archive_set_error(&a->archive,
432 			    ARCHIVE_ERRNO_FILE_FORMAT,
433 			    "Can't translate linkname '%s' to %s",
434 			    p, archive_string_conversion_charset_name(sconv));
435 			ret = ARCHIVE_WARN;
436 		}
437 	}
438 	if (copy_length > 0) {
439 		if (copy_length >= V7TAR_linkname_size) {
440 			archive_set_error(&a->archive, ENAMETOOLONG,
441 			    "Link contents too long");
442 			ret = ARCHIVE_FAILED;
443 			copy_length = V7TAR_linkname_size;
444 		}
445 		memcpy(h + V7TAR_linkname_offset, p, copy_length);
446 	}
447 
448 	if (format_number(archive_entry_mode(entry) & 07777,
449 	    h + V7TAR_mode_offset, V7TAR_mode_size,
450 	    V7TAR_mode_max_size, strict)) {
451 		archive_set_error(&a->archive, ERANGE,
452 		    "Numeric mode too large");
453 		ret = ARCHIVE_FAILED;
454 	}
455 
456 	if (format_number(archive_entry_uid(entry),
457 	    h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {
458 		archive_set_error(&a->archive, ERANGE,
459 		    "Numeric user ID too large");
460 		ret = ARCHIVE_FAILED;
461 	}
462 
463 	if (format_number(archive_entry_gid(entry),
464 	    h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {
465 		archive_set_error(&a->archive, ERANGE,
466 		    "Numeric group ID too large");
467 		ret = ARCHIVE_FAILED;
468 	}
469 
470 	if (format_number(archive_entry_size(entry),
471 	    h + V7TAR_size_offset, V7TAR_size_size,
472 	    V7TAR_size_max_size, strict)) {
473 		archive_set_error(&a->archive, ERANGE,
474 		    "File size out of range");
475 		ret = ARCHIVE_FAILED;
476 	}
477 
478 	if (format_number(archive_entry_mtime(entry),
479 	    h + V7TAR_mtime_offset, V7TAR_mtime_size,
480 	    V7TAR_mtime_max_size, strict)) {
481 		archive_set_error(&a->archive, ERANGE,
482 		    "File modification time too large");
483 		ret = ARCHIVE_FAILED;
484 	}
485 
486 	if (mytartype >= 0) {
487 		h[V7TAR_typeflag_offset] = mytartype;
488 	} else {
489 		switch (archive_entry_filetype(entry)) {
490 		case AE_IFREG: case AE_IFDIR:
491 			break;
492 		case AE_IFLNK:
493 			h[V7TAR_typeflag_offset] = '2';
494 			break;
495 		default:
496 			/* AE_IFBLK, AE_IFCHR, AE_IFIFO, AE_IFSOCK
497 			 * and unknown */
498 			__archive_write_entry_filetype_unsupported(
499 			    &a->archive, entry, "v7tar");
500 			ret = ARCHIVE_FAILED;
501 		}
502 	}
503 
504 	checksum = 0;
505 	for (i = 0; i < 512; i++)
506 		checksum += 255 & (unsigned int)h[i];
507 	format_octal(checksum, h + V7TAR_checksum_offset, 6);
508 	/* Can't be pre-set in the template. */
509 	h[V7TAR_checksum_offset + 6] = '\0';
510 	return (ret);
511 }
512 
513 /*
514  * Format a number into a field, with some intelligence.
515  */
516 static int
517 format_number(int64_t v, char *p, int s, int maxsize, int strict)
518 {
519 	int64_t limit;
520 
521 	limit = ((int64_t)1 << (s*3));
522 
523 	/* "Strict" only permits octal values with proper termination. */
524 	if (strict)
525 		return (format_octal(v, p, s));
526 
527 	/*
528 	 * In non-strict mode, we allow the number to overwrite one or
529 	 * more bytes of the field termination.  Even old tar
530 	 * implementations should be able to handle this with no
531 	 * problem.
532 	 */
533 	if (v >= 0) {
534 		while (s <= maxsize) {
535 			if (v < limit)
536 				return (format_octal(v, p, s));
537 			s++;
538 			limit <<= 3;
539 		}
540 	}
541 
542 	/* Base-256 can handle any number, positive or negative. */
543 	return (format_256(v, p, maxsize));
544 }
545 
546 /*
547  * Format a number into the specified field using base-256.
548  */
549 static int
550 format_256(int64_t v, char *p, int s)
551 {
552 	p += s;
553 	while (s-- > 0) {
554 		*--p = (char)(v & 0xff);
555 		v >>= 8;
556 	}
557 	*p |= 0x80; /* Set the base-256 marker bit. */
558 	return (0);
559 }
560 
561 /*
562  * Format a number into the specified field.
563  */
564 static int
565 format_octal(int64_t v, char *p, int s)
566 {
567 	int len;
568 
569 	len = s;
570 
571 	/* Octal values can't be negative, so use 0. */
572 	if (v < 0) {
573 		while (len-- > 0)
574 			*p++ = '0';
575 		return (-1);
576 	}
577 
578 	p += s;		/* Start at the end and work backwards. */
579 	while (s-- > 0) {
580 		*--p = (char)('0' + (v & 7));
581 		v >>= 3;
582 	}
583 
584 	if (v == 0)
585 		return (0);
586 
587 	/* If it overflowed, fill field with max value. */
588 	while (len-- > 0)
589 		*p++ = '7';
590 
591 	return (-1);
592 }
593 
594 static int
595 archive_write_v7tar_close(struct archive_write *a)
596 {
597 	return (__archive_write_nulls(a, 512*2));
598 }
599 
600 static int
601 archive_write_v7tar_free(struct archive_write *a)
602 {
603 	struct v7tar *v7tar;
604 
605 	v7tar = (struct v7tar *)a->format_data;
606 	free(v7tar);
607 	a->format_data = NULL;
608 	return (ARCHIVE_OK);
609 }
610 
611 static int
612 archive_write_v7tar_finish_entry(struct archive_write *a)
613 {
614 	struct v7tar *v7tar;
615 	int ret;
616 
617 	v7tar = (struct v7tar *)a->format_data;
618 	ret = __archive_write_nulls(a,
619 	    (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
620 	v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
621 	return (ret);
622 }
623 
624 static ssize_t
625 archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
626 {
627 	struct v7tar *v7tar;
628 	int ret;
629 
630 	v7tar = (struct v7tar *)a->format_data;
631 	if (s > v7tar->entry_bytes_remaining)
632 		s = (size_t)v7tar->entry_bytes_remaining;
633 	ret = __archive_write_output(a, buff, s);
634 	v7tar->entry_bytes_remaining -= s;
635 	if (ret != ARCHIVE_OK)
636 		return (ret);
637 	return (s);
638 }
639