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 
48 struct 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  */
89 static 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 
125 static ssize_t	archive_write_v7tar_data(struct archive_write *a, const void *buff,
126 		    size_t s);
127 static int	archive_write_v7tar_free(struct archive_write *);
128 static int	archive_write_v7tar_close(struct archive_write *);
129 static int	archive_write_v7tar_finish_entry(struct archive_write *);
130 static int	archive_write_v7tar_header(struct archive_write *,
131 		    struct archive_entry *entry);
132 static int	archive_write_v7tar_options(struct archive_write *,
133 		    const char *, const char *);
134 static int	format_256(int64_t, char *, int);
135 static int	format_number(int64_t, char *, int size, int max, int strict);
136 static int	format_octal(int64_t, char *, int);
137 static 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  */
143 int
144 archive_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 
183 static int
184 archive_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 
212 static int
213 archive_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[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  */
362 static int
363 format_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  */
538 static int
539 format_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  */
571 static int
572 format_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  */
586 static int
587 format_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 
616 static int
617 archive_write_v7tar_close(struct archive_write *a)
618 {
619 	return (__archive_write_nulls(a, 512*2));
620 }
621 
622 static int
623 archive_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 
633 static int
634 archive_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 
646 static ssize_t
647 archive_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