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