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