archive_write_set_format_v7tar.c revision 342360
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 termination: 12 bytes */
102	'0','0','0','0','0','0','0','0','0','0','0', ' ',
103	/* mtime, space termination: 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 *)calloc(1, 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	a->format_data = v7tar;
171	a->format_name = "tar (non-POSIX)";
172	a->format_options = archive_write_v7tar_options;
173	a->format_write_header = archive_write_v7tar_header;
174	a->format_write_data = archive_write_v7tar_data;
175	a->format_close = archive_write_v7tar_close;
176	a->format_free = archive_write_v7tar_free;
177	a->format_finish_entry = archive_write_v7tar_finish_entry;
178	a->archive.archive_format = ARCHIVE_FORMAT_TAR;
179	a->archive.archive_format_name = "tar (non-POSIX)";
180	return (ARCHIVE_OK);
181}
182
183static int
184archive_write_v7tar_options(struct archive_write *a, const char *key,
185    const char *val)
186{
187	struct v7tar *v7tar = (struct v7tar *)a->format_data;
188	int ret = ARCHIVE_FAILED;
189
190	if (strcmp(key, "hdrcharset")  == 0) {
191		if (val == NULL || val[0] == 0)
192			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
193			    "%s: hdrcharset option needs a character-set name",
194			    a->format_name);
195		else {
196			v7tar->opt_sconv = archive_string_conversion_to_charset(
197			    &a->archive, val, 0);
198			if (v7tar->opt_sconv != NULL)
199				ret = ARCHIVE_OK;
200			else
201				ret = ARCHIVE_FATAL;
202		}
203		return (ret);
204	}
205
206	/* Note: The "warn" return is just to inform the options
207	 * supervisor that we didn't handle it.  It will generate
208	 * a suitable error if no one used this option. */
209	return (ARCHIVE_WARN);
210}
211
212static int
213archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)
214{
215	char buff[512];
216	int ret, ret2;
217	struct v7tar *v7tar;
218	struct archive_entry *entry_main;
219	struct archive_string_conv *sconv;
220
221	v7tar = (struct v7tar *)a->format_data;
222
223	/* Setup default string conversion. */
224	if (v7tar->opt_sconv == NULL) {
225		if (!v7tar->init_default_conversion) {
226			v7tar->sconv_default =
227			    archive_string_default_conversion_for_write(
228				&(a->archive));
229			v7tar->init_default_conversion = 1;
230		}
231		sconv = v7tar->sconv_default;
232	} else
233		sconv = v7tar->opt_sconv;
234
235	/* Sanity check. */
236	if (archive_entry_pathname(entry) == NULL) {
237		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
238		    "Can't record entry in tar file without pathname");
239		return (ARCHIVE_FAILED);
240	}
241
242	/* Only regular files (not hardlinks) have data. */
243	if (archive_entry_hardlink(entry) != NULL ||
244	    archive_entry_symlink(entry) != NULL ||
245	    !(archive_entry_filetype(entry) == AE_IFREG))
246		archive_entry_set_size(entry, 0);
247
248	if (AE_IFDIR == archive_entry_filetype(entry)) {
249		const char *p;
250		size_t path_length;
251		/*
252		 * Ensure a trailing '/'.  Modify the entry so
253		 * the client sees the change.
254		 */
255#if defined(_WIN32) && !defined(__CYGWIN__)
256		const wchar_t *wp;
257
258		wp = archive_entry_pathname_w(entry);
259		if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
260			struct archive_wstring ws;
261
262			archive_string_init(&ws);
263			path_length = wcslen(wp);
264			if (archive_wstring_ensure(&ws,
265			    path_length + 2) == NULL) {
266				archive_set_error(&a->archive, ENOMEM,
267				    "Can't allocate v7tar data");
268				archive_wstring_free(&ws);
269				return(ARCHIVE_FATAL);
270			}
271			/* Should we keep '\' ? */
272			if (wp[path_length -1] == L'\\')
273				path_length--;
274			archive_wstrncpy(&ws, wp, path_length);
275			archive_wstrappend_wchar(&ws, L'/');
276			archive_entry_copy_pathname_w(entry, ws.s);
277			archive_wstring_free(&ws);
278			p = NULL;
279		} else
280#endif
281			p = archive_entry_pathname(entry);
282		/*
283		 * On Windows, this is a backup operation just in
284		 * case getting WCS failed. On POSIX, this is a
285		 * normal operation.
286		 */
287		if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
288			struct archive_string as;
289
290			archive_string_init(&as);
291			path_length = strlen(p);
292			if (archive_string_ensure(&as,
293			    path_length + 2) == NULL) {
294				archive_set_error(&a->archive, ENOMEM,
295				    "Can't allocate v7tar data");
296				archive_string_free(&as);
297				return(ARCHIVE_FATAL);
298			}
299#if defined(_WIN32) && !defined(__CYGWIN__)
300			/* NOTE: This might break the pathname
301			 * if the current code page is CP932 and
302			 * the pathname includes a character '\'
303			 * as a part of its multibyte pathname. */
304			if (p[strlen(p) -1] == '\\')
305				path_length--;
306			else
307#endif
308			archive_strncpy(&as, p, path_length);
309			archive_strappend_char(&as, '/');
310			archive_entry_copy_pathname(entry, as.s);
311			archive_string_free(&as);
312		}
313	}
314
315#if defined(_WIN32) && !defined(__CYGWIN__)
316	/* Make sure the path separators in pathname, hardlink and symlink
317	 * are all slash '/', not the Windows path separator '\'. */
318	entry_main = __la_win_entry_in_posix_pathseparator(entry);
319	if (entry_main == NULL) {
320		archive_set_error(&a->archive, ENOMEM,
321		    "Can't allocate v7tar data");
322		return(ARCHIVE_FATAL);
323	}
324	if (entry != entry_main)
325		entry = entry_main;
326	else
327		entry_main = NULL;
328#else
329	entry_main = NULL;
330#endif
331	ret = format_header_v7tar(a, buff, entry, 1, sconv);
332	if (ret < ARCHIVE_WARN) {
333		if (entry_main)
334			archive_entry_free(entry_main);
335		return (ret);
336	}
337	ret2 = __archive_write_output(a, buff, 512);
338	if (ret2 < ARCHIVE_WARN) {
339		if (entry_main)
340			archive_entry_free(entry_main);
341		return (ret2);
342	}
343	if (ret2 < ret)
344		ret = ret2;
345
346	v7tar->entry_bytes_remaining = archive_entry_size(entry);
347	v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);
348	if (entry_main)
349		archive_entry_free(entry_main);
350	return (ret);
351}
352
353/*
354 * Format a basic 512-byte "v7tar" header.
355 *
356 * Returns -1 if format failed (due to field overflow).
357 * Note that this always formats as much of the header as possible.
358 * If "strict" is set to zero, it will extend numeric fields as
359 * necessary (overwriting terminators or using base-256 extensions).
360 *
361 */
362static int
363format_header_v7tar(struct archive_write *a, char h[512],
364    struct archive_entry *entry, int strict,
365    struct archive_string_conv *sconv)
366{
367	unsigned int checksum;
368	int i, r, ret;
369	size_t copy_length;
370	const char *p, *pp;
371	int mytartype;
372
373	ret = 0;
374	mytartype = -1;
375	/*
376	 * The "template header" already includes the "v7tar"
377	 * signature, various end-of-field markers and other required
378	 * elements.
379	 */
380	memcpy(h, &template_header, 512);
381
382	/*
383	 * Because the block is already null-filled, and strings
384	 * are allowed to exactly fill their destination (without null),
385	 * I use memcpy(dest, src, strlen()) here a lot to copy strings.
386	 */
387	r = archive_entry_pathname_l(entry, &pp, &copy_length, sconv);
388	if (r != 0) {
389		if (errno == ENOMEM) {
390			archive_set_error(&a->archive, ENOMEM,
391			    "Can't allocate memory for Pathname");
392			return (ARCHIVE_FATAL);
393		}
394		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
395		    "Can't translate pathname '%s' to %s",
396		    pp, archive_string_conversion_charset_name(sconv));
397		ret = ARCHIVE_WARN;
398	}
399	if (strict && copy_length < V7TAR_name_size)
400		memcpy(h + V7TAR_name_offset, pp, copy_length);
401	else if (!strict && copy_length <= V7TAR_name_size)
402		memcpy(h + V7TAR_name_offset, pp, copy_length);
403	else {
404		/* Prefix is too long. */
405		archive_set_error(&a->archive, ENAMETOOLONG,
406		    "Pathname too long");
407		ret = ARCHIVE_FAILED;
408	}
409
410	r = archive_entry_hardlink_l(entry, &p, &copy_length, sconv);
411	if (r != 0) {
412		if (errno == ENOMEM) {
413			archive_set_error(&a->archive, ENOMEM,
414			    "Can't allocate memory for Linkname");
415			return (ARCHIVE_FATAL);
416		}
417		archive_set_error(&a->archive,
418		    ARCHIVE_ERRNO_FILE_FORMAT,
419		    "Can't translate linkname '%s' to %s",
420		    p, archive_string_conversion_charset_name(sconv));
421		ret = ARCHIVE_WARN;
422	}
423	if (copy_length > 0)
424		mytartype = '1';
425	else {
426		r = archive_entry_symlink_l(entry, &p, &copy_length, sconv);
427		if (r != 0) {
428			if (errno == ENOMEM) {
429				archive_set_error(&a->archive, ENOMEM,
430				    "Can't allocate memory for Linkname");
431				return (ARCHIVE_FATAL);
432			}
433			archive_set_error(&a->archive,
434			    ARCHIVE_ERRNO_FILE_FORMAT,
435			    "Can't translate linkname '%s' to %s",
436			    p, archive_string_conversion_charset_name(sconv));
437			ret = ARCHIVE_WARN;
438		}
439	}
440	if (copy_length > 0) {
441		if (copy_length >= V7TAR_linkname_size) {
442			archive_set_error(&a->archive, ENAMETOOLONG,
443			    "Link contents too long");
444			ret = ARCHIVE_FAILED;
445			copy_length = V7TAR_linkname_size;
446		}
447		memcpy(h + V7TAR_linkname_offset, p, copy_length);
448	}
449
450	if (format_number(archive_entry_mode(entry) & 07777,
451	    h + V7TAR_mode_offset, V7TAR_mode_size,
452	    V7TAR_mode_max_size, strict)) {
453		archive_set_error(&a->archive, ERANGE,
454		    "Numeric mode too large");
455		ret = ARCHIVE_FAILED;
456	}
457
458	if (format_number(archive_entry_uid(entry),
459	    h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {
460		archive_set_error(&a->archive, ERANGE,
461		    "Numeric user ID too large");
462		ret = ARCHIVE_FAILED;
463	}
464
465	if (format_number(archive_entry_gid(entry),
466	    h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {
467		archive_set_error(&a->archive, ERANGE,
468		    "Numeric group ID too large");
469		ret = ARCHIVE_FAILED;
470	}
471
472	if (format_number(archive_entry_size(entry),
473	    h + V7TAR_size_offset, V7TAR_size_size,
474	    V7TAR_size_max_size, strict)) {
475		archive_set_error(&a->archive, ERANGE,
476		    "File size out of range");
477		ret = ARCHIVE_FAILED;
478	}
479
480	if (format_number(archive_entry_mtime(entry),
481	    h + V7TAR_mtime_offset, V7TAR_mtime_size,
482	    V7TAR_mtime_max_size, strict)) {
483		archive_set_error(&a->archive, ERANGE,
484		    "File modification time too large");
485		ret = ARCHIVE_FAILED;
486	}
487
488	if (mytartype >= 0) {
489		h[V7TAR_typeflag_offset] = mytartype;
490	} else {
491		switch (archive_entry_filetype(entry)) {
492		case AE_IFREG: case AE_IFDIR:
493			break;
494		case AE_IFLNK:
495			h[V7TAR_typeflag_offset] = '2';
496			break;
497		case AE_IFCHR:
498			archive_set_error(&a->archive,
499			    ARCHIVE_ERRNO_FILE_FORMAT,
500			    "tar format cannot archive character device");
501			return (ARCHIVE_FAILED);
502		case AE_IFBLK:
503			archive_set_error(&a->archive,
504			    ARCHIVE_ERRNO_FILE_FORMAT,
505			    "tar format cannot archive block device");
506			return (ARCHIVE_FAILED);
507		case AE_IFIFO:
508			archive_set_error(&a->archive,
509			    ARCHIVE_ERRNO_FILE_FORMAT,
510			    "tar format cannot archive fifo");
511			return (ARCHIVE_FAILED);
512		case AE_IFSOCK:
513			archive_set_error(&a->archive,
514			    ARCHIVE_ERRNO_FILE_FORMAT,
515			    "tar format cannot archive socket");
516			return (ARCHIVE_FAILED);
517		default:
518			archive_set_error(&a->archive,
519			    ARCHIVE_ERRNO_FILE_FORMAT,
520			    "tar format cannot archive this (mode=0%lo)",
521			    (unsigned long)archive_entry_mode(entry));
522			ret = ARCHIVE_FAILED;
523		}
524	}
525
526	checksum = 0;
527	for (i = 0; i < 512; i++)
528		checksum += 255 & (unsigned int)h[i];
529	format_octal(checksum, h + V7TAR_checksum_offset, 6);
530	/* Can't be pre-set in the template. */
531	h[V7TAR_checksum_offset + 6] = '\0';
532	return (ret);
533}
534
535/*
536 * Format a number into a field, with some intelligence.
537 */
538static int
539format_number(int64_t v, char *p, int s, int maxsize, int strict)
540{
541	int64_t limit;
542
543	limit = ((int64_t)1 << (s*3));
544
545	/* "Strict" only permits octal values with proper termination. */
546	if (strict)
547		return (format_octal(v, p, s));
548
549	/*
550	 * In non-strict mode, we allow the number to overwrite one or
551	 * more bytes of the field termination.  Even old tar
552	 * implementations should be able to handle this with no
553	 * problem.
554	 */
555	if (v >= 0) {
556		while (s <= maxsize) {
557			if (v < limit)
558				return (format_octal(v, p, s));
559			s++;
560			limit <<= 3;
561		}
562	}
563
564	/* Base-256 can handle any number, positive or negative. */
565	return (format_256(v, p, maxsize));
566}
567
568/*
569 * Format a number into the specified field using base-256.
570 */
571static int
572format_256(int64_t v, char *p, int s)
573{
574	p += s;
575	while (s-- > 0) {
576		*--p = (char)(v & 0xff);
577		v >>= 8;
578	}
579	*p |= 0x80; /* Set the base-256 marker bit. */
580	return (0);
581}
582
583/*
584 * Format a number into the specified field.
585 */
586static int
587format_octal(int64_t v, char *p, int s)
588{
589	int len;
590
591	len = s;
592
593	/* Octal values can't be negative, so use 0. */
594	if (v < 0) {
595		while (len-- > 0)
596			*p++ = '0';
597		return (-1);
598	}
599
600	p += s;		/* Start at the end and work backwards. */
601	while (s-- > 0) {
602		*--p = (char)('0' + (v & 7));
603		v >>= 3;
604	}
605
606	if (v == 0)
607		return (0);
608
609	/* If it overflowed, fill field with max value. */
610	while (len-- > 0)
611		*p++ = '7';
612
613	return (-1);
614}
615
616static int
617archive_write_v7tar_close(struct archive_write *a)
618{
619	return (__archive_write_nulls(a, 512*2));
620}
621
622static int
623archive_write_v7tar_free(struct archive_write *a)
624{
625	struct v7tar *v7tar;
626
627	v7tar = (struct v7tar *)a->format_data;
628	free(v7tar);
629	a->format_data = NULL;
630	return (ARCHIVE_OK);
631}
632
633static int
634archive_write_v7tar_finish_entry(struct archive_write *a)
635{
636	struct v7tar *v7tar;
637	int ret;
638
639	v7tar = (struct v7tar *)a->format_data;
640	ret = __archive_write_nulls(a,
641	    (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
642	v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
643	return (ret);
644}
645
646static ssize_t
647archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
648{
649	struct v7tar *v7tar;
650	int ret;
651
652	v7tar = (struct v7tar *)a->format_data;
653	if (s > v7tar->entry_bytes_remaining)
654		s = (size_t)v7tar->entry_bytes_remaining;
655	ret = __archive_write_output(a, buff, s);
656	v7tar->entry_bytes_remaining -= s;
657	if (ret != ARCHIVE_OK)
658		return (ret);
659	return (s);
660}
661