archive_write_set_format_v7tar.c revision 248616
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
48struct v7tar {
49	uint64_t	entry_bytes_remaining;
50	uint64_t	entry_padding;
51
52	struct archive_string_conv *opt_sconv;
53	struct archive_string_conv *sconv_default;
54	int	init_default_conversion;
55};
56
57/*
58 * Define structure of POSIX 'v7tar' tar header.
59 */
60#define	V7TAR_name_offset 0
61#define	V7TAR_name_size 100
62#define	V7TAR_mode_offset 100
63#define	V7TAR_mode_size 6
64#define	V7TAR_mode_max_size 8
65#define	V7TAR_uid_offset 108
66#define	V7TAR_uid_size 6
67#define	V7TAR_uid_max_size 8
68#define	V7TAR_gid_offset 116
69#define	V7TAR_gid_size 6
70#define	V7TAR_gid_max_size 8
71#define	V7TAR_size_offset 124
72#define	V7TAR_size_size 11
73#define	V7TAR_size_max_size 12
74#define	V7TAR_mtime_offset 136
75#define	V7TAR_mtime_size 11
76#define	V7TAR_mtime_max_size 12
77#define	V7TAR_checksum_offset 148
78#define	V7TAR_checksum_size 8
79#define	V7TAR_typeflag_offset 156
80#define	V7TAR_typeflag_size 1
81#define	V7TAR_linkname_offset 157
82#define	V7TAR_linkname_size 100
83#define	V7TAR_padding_offset 257
84#define	V7TAR_padding_size 255
85
86/*
87 * A filled-in copy of the header for initialization.
88 */
89static const char template_header[] = {
90	/* name: 100 bytes */
91	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
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,
95	/* Mode, space-null termination: 8 bytes */
96	'0','0','0','0','0','0', ' ','\0',
97	/* uid, space-null termination: 8 bytes */
98	'0','0','0','0','0','0', ' ','\0',
99	/* gid, space-null termination: 8 bytes */
100	'0','0','0','0','0','0', ' ','\0',
101	/* size, space termation: 12 bytes */
102	'0','0','0','0','0','0','0','0','0','0','0', ' ',
103	/* mtime, space termation: 12 bytes */
104	'0','0','0','0','0','0','0','0','0','0','0', ' ',
105	/* Initial checksum value: 8 spaces */
106	' ',' ',' ',' ',' ',' ',' ',' ',
107	/* Typeflag: 1 byte */
108	0,
109	/* Linkname: 100 bytes */
110	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
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,
114	/* Padding: 255 bytes */
115	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
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
123};
124
125static ssize_t	archive_write_v7tar_data(struct archive_write *a, const void *buff,
126		    size_t s);
127static int	archive_write_v7tar_free(struct archive_write *);
128static int	archive_write_v7tar_close(struct archive_write *);
129static int	archive_write_v7tar_finish_entry(struct archive_write *);
130static int	archive_write_v7tar_header(struct archive_write *,
131		    struct archive_entry *entry);
132static int	archive_write_v7tar_options(struct archive_write *,
133		    const char *, const char *);
134static int	format_256(int64_t, char *, int);
135static int	format_number(int64_t, char *, int size, int max, int strict);
136static int	format_octal(int64_t, char *, int);
137static int	format_header_v7tar(struct archive_write *, char h[512],
138		    struct archive_entry *, int, struct archive_string_conv *);
139
140/*
141 * Set output format to 'v7tar' format.
142 */
143int
144archive_write_set_format_v7tar(struct archive *_a)
145{
146	struct archive_write *a = (struct archive_write *)_a;
147	struct v7tar *v7tar;
148
149	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
150	    ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar");
151
152	/* If someone else was already registered, unregister them. */
153	if (a->format_free != NULL)
154		(a->format_free)(a);
155
156	/* Basic internal sanity test. */
157	if (sizeof(template_header) != 512) {
158		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
159		    "Internal: template_header wrong size: %zu should be 512",
160		    sizeof(template_header));
161		return (ARCHIVE_FATAL);
162	}
163
164	v7tar = (struct v7tar *)malloc(sizeof(*v7tar));
165	if (v7tar == NULL) {
166		archive_set_error(&a->archive, ENOMEM,
167		    "Can't allocate v7tar data");
168		return (ARCHIVE_FATAL);
169	}
170	memset(v7tar, 0, sizeof(*v7tar));
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
184static int
185archive_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
213static int
214archive_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[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 pahtname, 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		if (entry_main)
335			archive_entry_free(entry_main);
336		return (ret);
337	}
338	ret2 = __archive_write_output(a, buff, 512);
339	if (ret2 < ARCHIVE_WARN) {
340		if (entry_main)
341			archive_entry_free(entry_main);
342		return (ret2);
343	}
344	if (ret2 < ret)
345		ret = ret2;
346
347	v7tar->entry_bytes_remaining = archive_entry_size(entry);
348	v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);
349	if (entry_main)
350		archive_entry_free(entry_main);
351	return (ret);
352}
353
354/*
355 * Format a basic 512-byte "v7tar" header.
356 *
357 * Returns -1 if format failed (due to field overflow).
358 * Note that this always formats as much of the header as possible.
359 * If "strict" is set to zero, it will extend numeric fields as
360 * necessary (overwriting terminators or using base-256 extensions).
361 *
362 */
363static int
364format_header_v7tar(struct archive_write *a, char h[512],
365    struct archive_entry *entry, int strict,
366    struct archive_string_conv *sconv)
367{
368	unsigned int checksum;
369	int i, r, ret;
370	size_t copy_length;
371	const char *p, *pp;
372	int mytartype;
373
374	ret = 0;
375	mytartype = -1;
376	/*
377	 * The "template header" already includes the "v7tar"
378	 * signature, various end-of-field markers and other required
379	 * elements.
380	 */
381	memcpy(h, &template_header, 512);
382
383	/*
384	 * Because the block is already null-filled, and strings
385	 * are allowed to exactly fill their destination (without null),
386	 * I use memcpy(dest, src, strlen()) here a lot to copy strings.
387	 */
388	r = archive_entry_pathname_l(entry, &pp, &copy_length, sconv);
389	if (r != 0) {
390		if (errno == ENOMEM) {
391			archive_set_error(&a->archive, ENOMEM,
392			    "Can't allocate memory for Pathname");
393			return (ARCHIVE_FATAL);
394		}
395		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
396		    "Can't translate pathname '%s' to %s",
397		    pp, archive_string_conversion_charset_name(sconv));
398		ret = ARCHIVE_WARN;
399	}
400	if (strict && copy_length < V7TAR_name_size)
401		memcpy(h + V7TAR_name_offset, pp, copy_length);
402	else if (!strict && copy_length <= V7TAR_name_size)
403		memcpy(h + V7TAR_name_offset, pp, copy_length);
404	else {
405		/* Prefix is too long. */
406		archive_set_error(&a->archive, ENAMETOOLONG,
407		    "Pathname too long");
408		ret = ARCHIVE_FAILED;
409	}
410
411	r = archive_entry_hardlink_l(entry, &p, &copy_length, sconv);
412	if (r != 0) {
413		if (errno == ENOMEM) {
414			archive_set_error(&a->archive, ENOMEM,
415			    "Can't allocate memory for Linkname");
416			return (ARCHIVE_FATAL);
417		}
418		archive_set_error(&a->archive,
419		    ARCHIVE_ERRNO_FILE_FORMAT,
420		    "Can't translate linkname '%s' to %s",
421		    p, archive_string_conversion_charset_name(sconv));
422		ret = ARCHIVE_WARN;
423	}
424	if (copy_length > 0)
425		mytartype = '1';
426	else {
427		r = archive_entry_symlink_l(entry, &p, &copy_length, sconv);
428		if (r != 0) {
429			if (errno == ENOMEM) {
430				archive_set_error(&a->archive, ENOMEM,
431				    "Can't allocate memory for Linkname");
432				return (ARCHIVE_FATAL);
433			}
434			archive_set_error(&a->archive,
435			    ARCHIVE_ERRNO_FILE_FORMAT,
436			    "Can't translate linkname '%s' to %s",
437			    p, archive_string_conversion_charset_name(sconv));
438			ret = ARCHIVE_WARN;
439		}
440	}
441	if (copy_length > 0) {
442		if (copy_length >= V7TAR_linkname_size) {
443			archive_set_error(&a->archive, ENAMETOOLONG,
444			    "Link contents too long");
445			ret = ARCHIVE_FAILED;
446			copy_length = V7TAR_linkname_size;
447		}
448		memcpy(h + V7TAR_linkname_offset, p, copy_length);
449	}
450
451	if (format_number(archive_entry_mode(entry) & 07777,
452	    h + V7TAR_mode_offset, V7TAR_mode_size,
453	    V7TAR_mode_max_size, strict)) {
454		archive_set_error(&a->archive, ERANGE,
455		    "Numeric mode too large");
456		ret = ARCHIVE_FAILED;
457	}
458
459	if (format_number(archive_entry_uid(entry),
460	    h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {
461		archive_set_error(&a->archive, ERANGE,
462		    "Numeric user ID too large");
463		ret = ARCHIVE_FAILED;
464	}
465
466	if (format_number(archive_entry_gid(entry),
467	    h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {
468		archive_set_error(&a->archive, ERANGE,
469		    "Numeric group ID too large");
470		ret = ARCHIVE_FAILED;
471	}
472
473	if (format_number(archive_entry_size(entry),
474	    h + V7TAR_size_offset, V7TAR_size_size,
475	    V7TAR_size_max_size, strict)) {
476		archive_set_error(&a->archive, ERANGE,
477		    "File size out of range");
478		ret = ARCHIVE_FAILED;
479	}
480
481	if (format_number(archive_entry_mtime(entry),
482	    h + V7TAR_mtime_offset, V7TAR_mtime_size,
483	    V7TAR_mtime_max_size, strict)) {
484		archive_set_error(&a->archive, ERANGE,
485		    "File modification time too large");
486		ret = ARCHIVE_FAILED;
487	}
488
489	if (mytartype >= 0) {
490		h[V7TAR_typeflag_offset] = mytartype;
491	} else {
492		switch (archive_entry_filetype(entry)) {
493		case AE_IFREG: case AE_IFDIR:
494			break;
495		case AE_IFLNK:
496			h[V7TAR_typeflag_offset] = '2';
497			break;
498		case AE_IFCHR:
499			archive_set_error(&a->archive,
500			    ARCHIVE_ERRNO_FILE_FORMAT,
501			    "tar format cannot archive character device");
502			return (ARCHIVE_FAILED);
503		case AE_IFBLK:
504			archive_set_error(&a->archive,
505			    ARCHIVE_ERRNO_FILE_FORMAT,
506			    "tar format cannot archive block device");
507			return (ARCHIVE_FAILED);
508		case AE_IFIFO:
509			archive_set_error(&a->archive,
510			    ARCHIVE_ERRNO_FILE_FORMAT,
511			    "tar format cannot archive fifo");
512			return (ARCHIVE_FAILED);
513		case AE_IFSOCK:
514			archive_set_error(&a->archive,
515			    ARCHIVE_ERRNO_FILE_FORMAT,
516			    "tar format cannot archive socket");
517			return (ARCHIVE_FAILED);
518		default:
519			archive_set_error(&a->archive,
520			    ARCHIVE_ERRNO_FILE_FORMAT,
521			    "tar format cannot archive this (mode=0%lo)",
522			    (unsigned long)archive_entry_mode(entry));
523			ret = ARCHIVE_FAILED;
524		}
525	}
526
527	checksum = 0;
528	for (i = 0; i < 512; i++)
529		checksum += 255 & (unsigned int)h[i];
530	format_octal(checksum, h + V7TAR_checksum_offset, 6);
531	/* Can't be pre-set in the template. */
532	h[V7TAR_checksum_offset + 6] = '\0';
533	return (ret);
534}
535
536/*
537 * Format a number into a field, with some intelligence.
538 */
539static int
540format_number(int64_t v, char *p, int s, int maxsize, int strict)
541{
542	int64_t limit;
543
544	limit = ((int64_t)1 << (s*3));
545
546	/* "Strict" only permits octal values with proper termination. */
547	if (strict)
548		return (format_octal(v, p, s));
549
550	/*
551	 * In non-strict mode, we allow the number to overwrite one or
552	 * more bytes of the field termination.  Even old tar
553	 * implementations should be able to handle this with no
554	 * problem.
555	 */
556	if (v >= 0) {
557		while (s <= maxsize) {
558			if (v < limit)
559				return (format_octal(v, p, s));
560			s++;
561			limit <<= 3;
562		}
563	}
564
565	/* Base-256 can handle any number, positive or negative. */
566	return (format_256(v, p, maxsize));
567}
568
569/*
570 * Format a number into the specified field using base-256.
571 */
572static int
573format_256(int64_t v, char *p, int s)
574{
575	p += s;
576	while (s-- > 0) {
577		*--p = (char)(v & 0xff);
578		v >>= 8;
579	}
580	*p |= 0x80; /* Set the base-256 marker bit. */
581	return (0);
582}
583
584/*
585 * Format a number into the specified field.
586 */
587static int
588format_octal(int64_t v, char *p, int s)
589{
590	int len;
591
592	len = s;
593
594	/* Octal values can't be negative, so use 0. */
595	if (v < 0) {
596		while (len-- > 0)
597			*p++ = '0';
598		return (-1);
599	}
600
601	p += s;		/* Start at the end and work backwards. */
602	while (s-- > 0) {
603		*--p = (char)('0' + (v & 7));
604		v >>= 3;
605	}
606
607	if (v == 0)
608		return (0);
609
610	/* If it overflowed, fill field with max value. */
611	while (len-- > 0)
612		*p++ = '7';
613
614	return (-1);
615}
616
617static int
618archive_write_v7tar_close(struct archive_write *a)
619{
620	return (__archive_write_nulls(a, 512*2));
621}
622
623static int
624archive_write_v7tar_free(struct archive_write *a)
625{
626	struct v7tar *v7tar;
627
628	v7tar = (struct v7tar *)a->format_data;
629	free(v7tar);
630	a->format_data = NULL;
631	return (ARCHIVE_OK);
632}
633
634static int
635archive_write_v7tar_finish_entry(struct archive_write *a)
636{
637	struct v7tar *v7tar;
638	int ret;
639
640	v7tar = (struct v7tar *)a->format_data;
641	ret = __archive_write_nulls(a,
642	    (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
643	v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
644	return (ret);
645}
646
647static ssize_t
648archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
649{
650	struct v7tar *v7tar;
651	int ret;
652
653	v7tar = (struct v7tar *)a->format_data;
654	if (s > v7tar->entry_bytes_remaining)
655		s = (size_t)v7tar->entry_bytes_remaining;
656	ret = __archive_write_output(a, buff, s);
657	v7tar->entry_bytes_remaining -= s;
658	if (ret != ARCHIVE_OK)
659		return (ret);
660	return (s);
661}
662