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 
47 struct 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  */
88 static 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 
124 static ssize_t	archive_write_v7tar_data(struct archive_write *a, const void *buff,
125 		    size_t s);
126 static int	archive_write_v7tar_free(struct archive_write *);
127 static int	archive_write_v7tar_close(struct archive_write *);
128 static int	archive_write_v7tar_finish_entry(struct archive_write *);
129 static int	archive_write_v7tar_header(struct archive_write *,
130 		    struct archive_entry *entry);
131 static int	archive_write_v7tar_options(struct archive_write *,
132 		    const char *, const char *);
133 static int	format_256(int64_t, char *, int);
134 static int	format_number(int64_t, char *, int size, int max, int strict);
135 static int	format_octal(int64_t, char *, int);
136 static 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  */
142 int
archive_write_set_format_v7tar(struct archive * _a)143 archive_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 
182 static int
archive_write_v7tar_options(struct archive_write * a,const char * key,const char * val)183 archive_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 
211 static int
archive_write_v7tar_header(struct archive_write * a,struct archive_entry * entry)212 archive_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  */
358 static int
format_header_v7tar(struct archive_write * a,char h[512],struct archive_entry * entry,int strict,struct archive_string_conv * sconv)359 format_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  */
514 static int
format_number(int64_t v,char * p,int s,int maxsize,int strict)515 format_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  */
547 static int
format_256(int64_t v,char * p,int s)548 format_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  */
562 static int
format_octal(int64_t v,char * p,int s)563 format_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 
592 static int
archive_write_v7tar_close(struct archive_write * a)593 archive_write_v7tar_close(struct archive_write *a)
594 {
595 	return (__archive_write_nulls(a, 512*2));
596 }
597 
598 static int
archive_write_v7tar_free(struct archive_write * a)599 archive_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 
609 static int
archive_write_v7tar_finish_entry(struct archive_write * a)610 archive_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 
622 static ssize_t
archive_write_v7tar_data(struct archive_write * a,const void * buff,size_t s)623 archive_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