archive_write_set_format_v7tar.c revision 358088
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
49struct 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 */
90static 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
126static ssize_t	archive_write_v7tar_data(struct archive_write *a, const void *buff,
127		    size_t s);
128static int	archive_write_v7tar_free(struct archive_write *);
129static int	archive_write_v7tar_close(struct archive_write *);
130static int	archive_write_v7tar_finish_entry(struct archive_write *);
131static int	archive_write_v7tar_header(struct archive_write *,
132		    struct archive_entry *entry);
133static int	archive_write_v7tar_options(struct archive_write *,
134		    const char *, const char *);
135static int	format_256(int64_t, char *, int);
136static int	format_number(int64_t, char *, int size, int max, int strict);
137static int	format_octal(int64_t, char *, int);
138static 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 */
144int
145archive_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
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[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 */
360static int
361format_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 */
516static int
517format_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 */
549static int
550format_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 */
564static int
565format_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
594static int
595archive_write_v7tar_close(struct archive_write *a)
596{
597	return (__archive_write_nulls(a, 512*2));
598}
599
600static int
601archive_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
611static int
612archive_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
624static ssize_t
625archive_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