Home | History | Annotate | Line # | Download | only in libarchive
      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
    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 = 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
    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
    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 #if defined(_WIN32) && !defined(__CYGWIN__)
    237 	    && archive_entry_pathname_w(entry) == NULL
    238 #endif
    239 	    ) {
    240 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
    241 		    "Can't record entry in tar file without pathname");
    242 		return (ARCHIVE_FAILED);
    243 	}
    244 
    245 	/* Only regular files (not hardlinks) have data. */
    246 	if (archive_entry_hardlink(entry) != NULL ||
    247 	    archive_entry_symlink(entry) != NULL ||
    248 	    archive_entry_filetype(entry) != AE_IFREG)
    249 		archive_entry_set_size(entry, 0);
    250 
    251 	if (AE_IFDIR == archive_entry_filetype(entry)) {
    252 		const char *p;
    253 		size_t path_length;
    254 		/*
    255 		 * Ensure a trailing '/'.  Modify the entry so
    256 		 * the client sees the change.
    257 		 */
    258 #if defined(_WIN32) && !defined(__CYGWIN__)
    259 		const wchar_t *wp;
    260 
    261 		wp = archive_entry_pathname_w(entry);
    262 		if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
    263 			struct archive_wstring ws;
    264 
    265 			archive_string_init(&ws);
    266 			path_length = wcslen(wp);
    267 			if (archive_wstring_ensure(&ws,
    268 			    path_length + 2) == NULL) {
    269 				archive_set_error(&a->archive, ENOMEM,
    270 				    "Can't allocate v7tar data");
    271 				archive_wstring_free(&ws);
    272 				return(ARCHIVE_FATAL);
    273 			}
    274 			/* Should we keep '\' ? */
    275 			if (wp[path_length -1] == L'\\')
    276 				path_length--;
    277 			archive_wstrncpy(&ws, wp, path_length);
    278 			archive_wstrappend_wchar(&ws, L'/');
    279 			archive_entry_copy_pathname_w(entry, ws.s);
    280 			archive_wstring_free(&ws);
    281 			p = NULL;
    282 		} else
    283 #endif
    284 			p = archive_entry_pathname(entry);
    285 		/*
    286 		 * On Windows, this is a backup operation just in
    287 		 * case getting WCS failed. On POSIX, this is a
    288 		 * normal operation.
    289 		 */
    290 		if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
    291 			struct archive_string as;
    292 
    293 			archive_string_init(&as);
    294 			path_length = strlen(p);
    295 			if (archive_string_ensure(&as,
    296 			    path_length + 2) == NULL) {
    297 				archive_set_error(&a->archive, ENOMEM,
    298 				    "Can't allocate v7tar data");
    299 				archive_string_free(&as);
    300 				return(ARCHIVE_FATAL);
    301 			}
    302 #if defined(_WIN32) && !defined(__CYGWIN__)
    303 			/* NOTE: This might break the pathname
    304 			 * if the current code page is CP932 and
    305 			 * the pathname includes a character '\'
    306 			 * as a part of its multibyte pathname. */
    307 			if (p[strlen(p) -1] == '\\')
    308 				path_length--;
    309 			else
    310 #endif
    311 			archive_strncpy(&as, p, path_length);
    312 			archive_strappend_char(&as, '/');
    313 			archive_entry_copy_pathname(entry, as.s);
    314 			archive_string_free(&as);
    315 		}
    316 	}
    317 
    318 #if defined(_WIN32) && !defined(__CYGWIN__)
    319 	/* Make sure the path separators in pathname, hardlink and symlink
    320 	 * are all slash '/', not the Windows path separator '\'. */
    321 	entry_main = __la_win_entry_in_posix_pathseparator(entry);
    322 	if (entry_main == NULL) {
    323 		archive_set_error(&a->archive, ENOMEM,
    324 		    "Can't allocate v7tar data");
    325 		return(ARCHIVE_FATAL);
    326 	}
    327 	if (entry != entry_main)
    328 		entry = entry_main;
    329 	else
    330 		entry_main = NULL;
    331 #else
    332 	entry_main = NULL;
    333 #endif
    334 	ret = format_header_v7tar(a, buff, entry, 1, sconv);
    335 	if (ret < ARCHIVE_WARN) {
    336 		archive_entry_free(entry_main);
    337 		return (ret);
    338 	}
    339 	ret2 = __archive_write_output(a, buff, 512);
    340 	if (ret2 < ARCHIVE_WARN) {
    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 	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 		const char* p_mbs;
    390 		if (errno == ENOMEM) {
    391 			archive_set_error(&a->archive, ENOMEM,
    392 			    "Can't allocate memory for Pathname");
    393 			return (ARCHIVE_FATAL);
    394 		}
    395 		p_mbs = archive_entry_pathname(entry);
    396 		if (p_mbs) {
    397 			/* We have a wrongly-encoded MBS pathname.
    398 			 * Warn and use it.  */
    399 			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
    400 			    "Can't translate pathname '%s' to %s", p_mbs,
    401 			    archive_string_conversion_charset_name(sconv));
    402 			ret = ARCHIVE_WARN;
    403 		} else {
    404 			/* We have no MBS pathname.  Fail.  */
    405 			archive_set_error(&a->archive,
    406 			    ARCHIVE_ERRNO_FILE_FORMAT,
    407 			    "Can't translate pathname to %s",
    408 			    archive_string_conversion_charset_name(sconv));
    409 			return ARCHIVE_FAILED;
    410 		}
    411 	}
    412 	if (strict && copy_length < V7TAR_name_size)
    413 		memcpy(h + V7TAR_name_offset, pp, copy_length);
    414 	else if (!strict && copy_length <= V7TAR_name_size)
    415 		memcpy(h + V7TAR_name_offset, pp, copy_length);
    416 	else {
    417 		/* Prefix is too long. */
    418 		archive_set_error(&a->archive, ENAMETOOLONG,
    419 		    "Pathname too long");
    420 		ret = ARCHIVE_FAILED;
    421 	}
    422 
    423 	r = archive_entry_hardlink_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 	if (copy_length > 0)
    437 		mytartype = '1';
    438 	else {
    439 		r = archive_entry_symlink_l(entry, &p, &copy_length, sconv);
    440 		if (r != 0) {
    441 			if (errno == ENOMEM) {
    442 				archive_set_error(&a->archive, ENOMEM,
    443 				    "Can't allocate memory for Linkname");
    444 				return (ARCHIVE_FATAL);
    445 			}
    446 			archive_set_error(&a->archive,
    447 			    ARCHIVE_ERRNO_FILE_FORMAT,
    448 			    "Can't translate linkname '%s' to %s",
    449 			    p, archive_string_conversion_charset_name(sconv));
    450 			ret = ARCHIVE_WARN;
    451 		}
    452 	}
    453 	if (copy_length > 0) {
    454 		if (copy_length >= V7TAR_linkname_size) {
    455 			archive_set_error(&a->archive, ENAMETOOLONG,
    456 			    "Link contents too long");
    457 			ret = ARCHIVE_FAILED;
    458 			copy_length = V7TAR_linkname_size;
    459 		}
    460 		memcpy(h + V7TAR_linkname_offset, p, copy_length);
    461 	}
    462 
    463 	if (format_number(archive_entry_mode(entry) & 07777,
    464 	    h + V7TAR_mode_offset, V7TAR_mode_size,
    465 	    V7TAR_mode_max_size, strict)) {
    466 		archive_set_error(&a->archive, ERANGE,
    467 		    "Numeric mode too large");
    468 		ret = ARCHIVE_FAILED;
    469 	}
    470 
    471 	if (format_number(archive_entry_uid(entry),
    472 	    h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {
    473 		archive_set_error(&a->archive, ERANGE,
    474 		    "Numeric user ID too large");
    475 		ret = ARCHIVE_FAILED;
    476 	}
    477 
    478 	if (format_number(archive_entry_gid(entry),
    479 	    h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {
    480 		archive_set_error(&a->archive, ERANGE,
    481 		    "Numeric group ID too large");
    482 		ret = ARCHIVE_FAILED;
    483 	}
    484 
    485 	if (format_number(archive_entry_size(entry),
    486 	    h + V7TAR_size_offset, V7TAR_size_size,
    487 	    V7TAR_size_max_size, strict)) {
    488 		archive_set_error(&a->archive, ERANGE,
    489 		    "File size out of range");
    490 		ret = ARCHIVE_FAILED;
    491 	}
    492 
    493 	if (format_number(archive_entry_mtime(entry),
    494 	    h + V7TAR_mtime_offset, V7TAR_mtime_size,
    495 	    V7TAR_mtime_max_size, strict)) {
    496 		archive_set_error(&a->archive, ERANGE,
    497 		    "File modification time too large");
    498 		ret = ARCHIVE_FAILED;
    499 	}
    500 
    501 	if (mytartype >= 0) {
    502 		h[V7TAR_typeflag_offset] = mytartype;
    503 	} else {
    504 		switch (archive_entry_filetype(entry)) {
    505 		case AE_IFREG: case AE_IFDIR:
    506 			break;
    507 		case AE_IFLNK:
    508 			h[V7TAR_typeflag_offset] = '2';
    509 			break;
    510 		default:
    511 			/* AE_IFBLK, AE_IFCHR, AE_IFIFO, AE_IFSOCK
    512 			 * and unknown */
    513 			__archive_write_entry_filetype_unsupported(
    514 			    &a->archive, entry, "v7tar");
    515 			ret = ARCHIVE_FAILED;
    516 		}
    517 	}
    518 
    519 	checksum = 0;
    520 	for (i = 0; i < 512; i++)
    521 		checksum += 255 & (unsigned int)h[i];
    522 	format_octal(checksum, h + V7TAR_checksum_offset, 6);
    523 	/* Can't be pre-set in the template. */
    524 	h[V7TAR_checksum_offset + 6] = '\0';
    525 	return (ret);
    526 }
    527 
    528 /*
    529  * Format a number into a field, with some intelligence.
    530  */
    531 static int
    532 format_number(int64_t v, char *p, int s, int maxsize, int strict)
    533 {
    534 	int64_t limit;
    535 
    536 	limit = ((int64_t)1 << (s*3));
    537 
    538 	/* "Strict" only permits octal values with proper termination. */
    539 	if (strict)
    540 		return (format_octal(v, p, s));
    541 
    542 	/*
    543 	 * In non-strict mode, we allow the number to overwrite one or
    544 	 * more bytes of the field termination.  Even old tar
    545 	 * implementations should be able to handle this with no
    546 	 * problem.
    547 	 */
    548 	if (v >= 0) {
    549 		while (s <= maxsize) {
    550 			if (v < limit)
    551 				return (format_octal(v, p, s));
    552 			s++;
    553 			limit <<= 3;
    554 		}
    555 	}
    556 
    557 	/* Base-256 can handle any number, positive or negative. */
    558 	return (format_256(v, p, maxsize));
    559 }
    560 
    561 /*
    562  * Format a number into the specified field using base-256.
    563  */
    564 static int
    565 format_256(int64_t v, char *p, int s)
    566 {
    567 	p += s;
    568 	while (s-- > 0) {
    569 		*--p = (char)(v & 0xff);
    570 		v >>= 8;
    571 	}
    572 	*p |= 0x80; /* Set the base-256 marker bit. */
    573 	return (0);
    574 }
    575 
    576 /*
    577  * Format a number into the specified field.
    578  */
    579 static int
    580 format_octal(int64_t v, char *p, int s)
    581 {
    582 	int len;
    583 
    584 	len = s;
    585 
    586 	/* Octal values can't be negative, so use 0. */
    587 	if (v < 0) {
    588 		while (len-- > 0)
    589 			*p++ = '0';
    590 		return (-1);
    591 	}
    592 
    593 	p += s;		/* Start at the end and work backwards. */
    594 	while (s-- > 0) {
    595 		*--p = (char)('0' + (v & 7));
    596 		v >>= 3;
    597 	}
    598 
    599 	if (v == 0)
    600 		return (0);
    601 
    602 	/* If it overflowed, fill field with max value. */
    603 	while (len-- > 0)
    604 		*p++ = '7';
    605 
    606 	return (-1);
    607 }
    608 
    609 static int
    610 archive_write_v7tar_close(struct archive_write *a)
    611 {
    612 	return (__archive_write_nulls(a, 512*2));
    613 }
    614 
    615 static int
    616 archive_write_v7tar_free(struct archive_write *a)
    617 {
    618 	struct v7tar *v7tar;
    619 
    620 	v7tar = (struct v7tar *)a->format_data;
    621 	free(v7tar);
    622 	a->format_data = NULL;
    623 	return (ARCHIVE_OK);
    624 }
    625 
    626 static int
    627 archive_write_v7tar_finish_entry(struct archive_write *a)
    628 {
    629 	struct v7tar *v7tar;
    630 	int ret;
    631 
    632 	v7tar = (struct v7tar *)a->format_data;
    633 	ret = __archive_write_nulls(a,
    634 	    (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
    635 	v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
    636 	return (ret);
    637 }
    638 
    639 static ssize_t
    640 archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
    641 {
    642 	struct v7tar *v7tar;
    643 	int ret;
    644 
    645 	v7tar = (struct v7tar *)a->format_data;
    646 	if (s > v7tar->entry_bytes_remaining)
    647 		s = (size_t)v7tar->entry_bytes_remaining;
    648 	ret = __archive_write_output(a, buff, s);
    649 	v7tar->entry_bytes_remaining -= s;
    650 	if (ret != ARCHIVE_OK)
    651 		return (ret);
    652 	return (s);
    653 }
    654