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[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  */
359 static int
360 format_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  */
535 static int
536 format_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  */
568 static int
569 format_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  */
583 static int
584 format_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 
613 static int
614 archive_write_v7tar_close(struct archive_write *a)
615 {
616 	return (__archive_write_nulls(a, 512*2));
617 }
618 
619 static int
620 archive_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 
630 static int
631 archive_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 
643 static ssize_t
644 archive_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