archive_write_set_format_v7tar.c revision 344674
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		archive_entry_free(entry_main);
334		return (ret);
335	}
336	ret2 = __archive_write_output(a, buff, 512);
337	if (ret2 < ARCHIVE_WARN) {
338		archive_entry_free(entry_main);
339		return (ret2);
340	}
341	if (ret2 < ret)
342		ret = ret2;
343
344	v7tar->entry_bytes_remaining = archive_entry_size(entry);
345	v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);
346	archive_entry_free(entry_main);
347	return (ret);
348}
349
350/*
351 * Format a basic 512-byte "v7tar" header.
352 *
353 * Returns -1 if format failed (due to field overflow).
354 * Note that this always formats as much of the header as possible.
355 * If "strict" is set to zero, it will extend numeric fields as
356 * necessary (overwriting terminators or using base-256 extensions).
357 *
358 */
359static int
360format_header_v7tar(struct archive_write *a, char h[512],
361    struct archive_entry *entry, int strict,
362    struct archive_string_conv *sconv)
363{
364	unsigned int checksum;
365	int i, r, ret;
366	size_t copy_length;
367	const char *p, *pp;
368	int mytartype;
369
370	ret = 0;
371	mytartype = -1;
372	/*
373	 * The "template header" already includes the "v7tar"
374	 * signature, various end-of-field markers and other required
375	 * elements.
376	 */
377	memcpy(h, &template_header, 512);
378
379	/*
380	 * Because the block is already null-filled, and strings
381	 * are allowed to exactly fill their destination (without null),
382	 * I use memcpy(dest, src, strlen()) here a lot to copy strings.
383	 */
384	r = archive_entry_pathname_l(entry, &pp, &copy_length, sconv);
385	if (r != 0) {
386		if (errno == ENOMEM) {
387			archive_set_error(&a->archive, ENOMEM,
388			    "Can't allocate memory for Pathname");
389			return (ARCHIVE_FATAL);
390		}
391		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
392		    "Can't translate pathname '%s' to %s",
393		    pp, archive_string_conversion_charset_name(sconv));
394		ret = ARCHIVE_WARN;
395	}
396	if (strict && copy_length < V7TAR_name_size)
397		memcpy(h + V7TAR_name_offset, pp, copy_length);
398	else if (!strict && copy_length <= V7TAR_name_size)
399		memcpy(h + V7TAR_name_offset, pp, copy_length);
400	else {
401		/* Prefix is too long. */
402		archive_set_error(&a->archive, ENAMETOOLONG,
403		    "Pathname too long");
404		ret = ARCHIVE_FAILED;
405	}
406
407	r = archive_entry_hardlink_l(entry, &p, &copy_length, sconv);
408	if (r != 0) {
409		if (errno == ENOMEM) {
410			archive_set_error(&a->archive, ENOMEM,
411			    "Can't allocate memory for Linkname");
412			return (ARCHIVE_FATAL);
413		}
414		archive_set_error(&a->archive,
415		    ARCHIVE_ERRNO_FILE_FORMAT,
416		    "Can't translate linkname '%s' to %s",
417		    p, archive_string_conversion_charset_name(sconv));
418		ret = ARCHIVE_WARN;
419	}
420	if (copy_length > 0)
421		mytartype = '1';
422	else {
423		r = archive_entry_symlink_l(entry, &p, &copy_length, sconv);
424		if (r != 0) {
425			if (errno == ENOMEM) {
426				archive_set_error(&a->archive, ENOMEM,
427				    "Can't allocate memory for Linkname");
428				return (ARCHIVE_FATAL);
429			}
430			archive_set_error(&a->archive,
431			    ARCHIVE_ERRNO_FILE_FORMAT,
432			    "Can't translate linkname '%s' to %s",
433			    p, archive_string_conversion_charset_name(sconv));
434			ret = ARCHIVE_WARN;
435		}
436	}
437	if (copy_length > 0) {
438		if (copy_length >= V7TAR_linkname_size) {
439			archive_set_error(&a->archive, ENAMETOOLONG,
440			    "Link contents too long");
441			ret = ARCHIVE_FAILED;
442			copy_length = V7TAR_linkname_size;
443		}
444		memcpy(h + V7TAR_linkname_offset, p, copy_length);
445	}
446
447	if (format_number(archive_entry_mode(entry) & 07777,
448	    h + V7TAR_mode_offset, V7TAR_mode_size,
449	    V7TAR_mode_max_size, strict)) {
450		archive_set_error(&a->archive, ERANGE,
451		    "Numeric mode too large");
452		ret = ARCHIVE_FAILED;
453	}
454
455	if (format_number(archive_entry_uid(entry),
456	    h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {
457		archive_set_error(&a->archive, ERANGE,
458		    "Numeric user ID too large");
459		ret = ARCHIVE_FAILED;
460	}
461
462	if (format_number(archive_entry_gid(entry),
463	    h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {
464		archive_set_error(&a->archive, ERANGE,
465		    "Numeric group ID too large");
466		ret = ARCHIVE_FAILED;
467	}
468
469	if (format_number(archive_entry_size(entry),
470	    h + V7TAR_size_offset, V7TAR_size_size,
471	    V7TAR_size_max_size, strict)) {
472		archive_set_error(&a->archive, ERANGE,
473		    "File size out of range");
474		ret = ARCHIVE_FAILED;
475	}
476
477	if (format_number(archive_entry_mtime(entry),
478	    h + V7TAR_mtime_offset, V7TAR_mtime_size,
479	    V7TAR_mtime_max_size, strict)) {
480		archive_set_error(&a->archive, ERANGE,
481		    "File modification time too large");
482		ret = ARCHIVE_FAILED;
483	}
484
485	if (mytartype >= 0) {
486		h[V7TAR_typeflag_offset] = mytartype;
487	} else {
488		switch (archive_entry_filetype(entry)) {
489		case AE_IFREG: case AE_IFDIR:
490			break;
491		case AE_IFLNK:
492			h[V7TAR_typeflag_offset] = '2';
493			break;
494		case AE_IFCHR:
495			archive_set_error(&a->archive,
496			    ARCHIVE_ERRNO_FILE_FORMAT,
497			    "tar format cannot archive character device");
498			return (ARCHIVE_FAILED);
499		case AE_IFBLK:
500			archive_set_error(&a->archive,
501			    ARCHIVE_ERRNO_FILE_FORMAT,
502			    "tar format cannot archive block device");
503			return (ARCHIVE_FAILED);
504		case AE_IFIFO:
505			archive_set_error(&a->archive,
506			    ARCHIVE_ERRNO_FILE_FORMAT,
507			    "tar format cannot archive fifo");
508			return (ARCHIVE_FAILED);
509		case AE_IFSOCK:
510			archive_set_error(&a->archive,
511			    ARCHIVE_ERRNO_FILE_FORMAT,
512			    "tar format cannot archive socket");
513			return (ARCHIVE_FAILED);
514		default:
515			archive_set_error(&a->archive,
516			    ARCHIVE_ERRNO_FILE_FORMAT,
517			    "tar format cannot archive this (mode=0%lo)",
518			    (unsigned long)archive_entry_mode(entry));
519			ret = ARCHIVE_FAILED;
520		}
521	}
522
523	checksum = 0;
524	for (i = 0; i < 512; i++)
525		checksum += 255 & (unsigned int)h[i];
526	format_octal(checksum, h + V7TAR_checksum_offset, 6);
527	/* Can't be pre-set in the template. */
528	h[V7TAR_checksum_offset + 6] = '\0';
529	return (ret);
530}
531
532/*
533 * Format a number into a field, with some intelligence.
534 */
535static int
536format_number(int64_t v, char *p, int s, int maxsize, int strict)
537{
538	int64_t limit;
539
540	limit = ((int64_t)1 << (s*3));
541
542	/* "Strict" only permits octal values with proper termination. */
543	if (strict)
544		return (format_octal(v, p, s));
545
546	/*
547	 * In non-strict mode, we allow the number to overwrite one or
548	 * more bytes of the field termination.  Even old tar
549	 * implementations should be able to handle this with no
550	 * problem.
551	 */
552	if (v >= 0) {
553		while (s <= maxsize) {
554			if (v < limit)
555				return (format_octal(v, p, s));
556			s++;
557			limit <<= 3;
558		}
559	}
560
561	/* Base-256 can handle any number, positive or negative. */
562	return (format_256(v, p, maxsize));
563}
564
565/*
566 * Format a number into the specified field using base-256.
567 */
568static int
569format_256(int64_t v, char *p, int s)
570{
571	p += s;
572	while (s-- > 0) {
573		*--p = (char)(v & 0xff);
574		v >>= 8;
575	}
576	*p |= 0x80; /* Set the base-256 marker bit. */
577	return (0);
578}
579
580/*
581 * Format a number into the specified field.
582 */
583static int
584format_octal(int64_t v, char *p, int s)
585{
586	int len;
587
588	len = s;
589
590	/* Octal values can't be negative, so use 0. */
591	if (v < 0) {
592		while (len-- > 0)
593			*p++ = '0';
594		return (-1);
595	}
596
597	p += s;		/* Start at the end and work backwards. */
598	while (s-- > 0) {
599		*--p = (char)('0' + (v & 7));
600		v >>= 3;
601	}
602
603	if (v == 0)
604		return (0);
605
606	/* If it overflowed, fill field with max value. */
607	while (len-- > 0)
608		*p++ = '7';
609
610	return (-1);
611}
612
613static int
614archive_write_v7tar_close(struct archive_write *a)
615{
616	return (__archive_write_nulls(a, 512*2));
617}
618
619static int
620archive_write_v7tar_free(struct archive_write *a)
621{
622	struct v7tar *v7tar;
623
624	v7tar = (struct v7tar *)a->format_data;
625	free(v7tar);
626	a->format_data = NULL;
627	return (ARCHIVE_OK);
628}
629
630static int
631archive_write_v7tar_finish_entry(struct archive_write *a)
632{
633	struct v7tar *v7tar;
634	int ret;
635
636	v7tar = (struct v7tar *)a->format_data;
637	ret = __archive_write_nulls(a,
638	    (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
639	v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
640	return (ret);
641}
642
643static ssize_t
644archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
645{
646	struct v7tar *v7tar;
647	int ret;
648
649	v7tar = (struct v7tar *)a->format_data;
650	if (s > v7tar->entry_bytes_remaining)
651		s = (size_t)v7tar->entry_bytes_remaining;
652	ret = __archive_write_output(a, buff, s);
653	v7tar->entry_bytes_remaining -= s;
654	if (ret != ARCHIVE_OK)
655		return (ret);
656	return (s);
657}
658