Blame libarchive/archive_write_set_format_ustar.c

Packit Service 1d0348
/*-
Packit Service 1d0348
 * Copyright (c) 2003-2007 Tim Kientzle
Packit Service 1d0348
 * Copyright (c) 2011-2012 Michihiro NAKAJIMA
Packit Service 1d0348
 * All rights reserved.
Packit Service 1d0348
 *
Packit Service 1d0348
 * Redistribution and use in source and binary forms, with or without
Packit Service 1d0348
 * modification, are permitted provided that the following conditions
Packit Service 1d0348
 * are met:
Packit Service 1d0348
 * 1. Redistributions of source code must retain the above copyright
Packit Service 1d0348
 *    notice, this list of conditions and the following disclaimer.
Packit Service 1d0348
 * 2. Redistributions in binary form must reproduce the above copyright
Packit Service 1d0348
 *    notice, this list of conditions and the following disclaimer in the
Packit Service 1d0348
 *    documentation and/or other materials provided with the distribution.
Packit Service 1d0348
 *
Packit Service 1d0348
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
Packit Service 1d0348
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit Service 1d0348
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit Service 1d0348
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit Service 1d0348
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit Service 1d0348
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit Service 1d0348
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit Service 1d0348
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit Service 1d0348
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit Service 1d0348
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit Service 1d0348
 */
Packit Service 1d0348
Packit Service 1d0348
#include "archive_platform.h"
Packit Service 1d0348
__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_ustar.c 191579 2009-04-27 18:35:03Z kientzle $");
Packit Service 1d0348
Packit Service 1d0348
Packit Service 1d0348
#ifdef HAVE_ERRNO_H
Packit Service 1d0348
#include <errno.h>
Packit Service 1d0348
#endif
Packit Service 1d0348
#include <stdio.h>
Packit Service 1d0348
#ifdef HAVE_STDLIB_H
Packit Service 1d0348
#include <stdlib.h>
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef HAVE_STRING_H
Packit Service 1d0348
#include <string.h>
Packit Service 1d0348
#endif
Packit Service 1d0348
Packit Service 1d0348
#include "archive.h"
Packit Service 1d0348
#include "archive_entry.h"
Packit Service 1d0348
#include "archive_entry_locale.h"
Packit Service 1d0348
#include "archive_private.h"
Packit Service 1d0348
#include "archive_write_private.h"
Packit Service 1d0348
Packit Service 1d0348
struct ustar {
Packit Service 1d0348
	uint64_t	entry_bytes_remaining;
Packit Service 1d0348
	uint64_t	entry_padding;
Packit Service 1d0348
Packit Service 1d0348
	struct archive_string_conv *opt_sconv;
Packit Service 1d0348
	struct archive_string_conv *sconv_default;
Packit Service 1d0348
	int	init_default_conversion;
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Define structure of POSIX 'ustar' tar header.
Packit Service 1d0348
 */
Packit Service 1d0348
#define	USTAR_name_offset 0
Packit Service 1d0348
#define	USTAR_name_size 100
Packit Service 1d0348
#define	USTAR_mode_offset 100
Packit Service 1d0348
#define	USTAR_mode_size 6
Packit Service 1d0348
#define	USTAR_mode_max_size 8
Packit Service 1d0348
#define	USTAR_uid_offset 108
Packit Service 1d0348
#define	USTAR_uid_size 6
Packit Service 1d0348
#define	USTAR_uid_max_size 8
Packit Service 1d0348
#define	USTAR_gid_offset 116
Packit Service 1d0348
#define	USTAR_gid_size 6
Packit Service 1d0348
#define	USTAR_gid_max_size 8
Packit Service 1d0348
#define	USTAR_size_offset 124
Packit Service 1d0348
#define	USTAR_size_size 11
Packit Service 1d0348
#define	USTAR_size_max_size 12
Packit Service 1d0348
#define	USTAR_mtime_offset 136
Packit Service 1d0348
#define	USTAR_mtime_size 11
Packit Service 1d0348
#define	USTAR_mtime_max_size 11
Packit Service 1d0348
#define	USTAR_checksum_offset 148
Packit Service 1d0348
#define	USTAR_checksum_size 8
Packit Service 1d0348
#define	USTAR_typeflag_offset 156
Packit Service 1d0348
#define	USTAR_typeflag_size 1
Packit Service 1d0348
#define	USTAR_linkname_offset 157
Packit Service 1d0348
#define	USTAR_linkname_size 100
Packit Service 1d0348
#define	USTAR_magic_offset 257
Packit Service 1d0348
#define	USTAR_magic_size 6
Packit Service 1d0348
#define	USTAR_version_offset 263
Packit Service 1d0348
#define	USTAR_version_size 2
Packit Service 1d0348
#define	USTAR_uname_offset 265
Packit Service 1d0348
#define	USTAR_uname_size 32
Packit Service 1d0348
#define	USTAR_gname_offset 297
Packit Service 1d0348
#define	USTAR_gname_size 32
Packit Service 1d0348
#define	USTAR_rdevmajor_offset 329
Packit Service 1d0348
#define	USTAR_rdevmajor_size 6
Packit Service 1d0348
#define	USTAR_rdevmajor_max_size 8
Packit Service 1d0348
#define	USTAR_rdevminor_offset 337
Packit Service 1d0348
#define	USTAR_rdevminor_size 6
Packit Service 1d0348
#define	USTAR_rdevminor_max_size 8
Packit Service 1d0348
#define	USTAR_prefix_offset 345
Packit Service 1d0348
#define	USTAR_prefix_size 155
Packit Service 1d0348
#define	USTAR_padding_offset 500
Packit Service 1d0348
#define	USTAR_padding_size 12
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * A filled-in copy of the header for initialization.
Packit Service 1d0348
 */
Packit Service 1d0348
static const char template_header[] = {
Packit Service 1d0348
	/* name: 100 bytes */
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,
Packit Service 1d0348
	/* Mode, space-null termination: 8 bytes */
Packit Service 1d0348
	'0','0','0','0','0','0', ' ','\0',
Packit Service 1d0348
	/* uid, space-null termination: 8 bytes */
Packit Service 1d0348
	'0','0','0','0','0','0', ' ','\0',
Packit Service 1d0348
	/* gid, space-null termination: 8 bytes */
Packit Service 1d0348
	'0','0','0','0','0','0', ' ','\0',
Packit Service 1d0348
	/* size, space termination: 12 bytes */
Packit Service 1d0348
	'0','0','0','0','0','0','0','0','0','0','0', ' ',
Packit Service 1d0348
	/* mtime, space termination: 12 bytes */
Packit Service 1d0348
	'0','0','0','0','0','0','0','0','0','0','0', ' ',
Packit Service 1d0348
	/* Initial checksum value: 8 spaces */
Packit Service 1d0348
	' ',' ',' ',' ',' ',' ',' ',' ',
Packit Service 1d0348
	/* Typeflag: 1 byte */
Packit Service 1d0348
	'0',			/* '0' = regular file */
Packit Service 1d0348
	/* Linkname: 100 bytes */
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,
Packit Service 1d0348
	/* Magic: 6 bytes, Version: 2 bytes */
Packit Service 1d0348
	'u','s','t','a','r','\0', '0','0',
Packit Service 1d0348
	/* Uname: 32 bytes */
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	/* Gname: 32 bytes */
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	/* rdevmajor + space/null padding: 8 bytes */
Packit Service 1d0348
	'0','0','0','0','0','0', ' ','\0',
Packit Service 1d0348
	/* rdevminor + space/null padding: 8 bytes */
Packit Service 1d0348
	'0','0','0','0','0','0', ' ','\0',
Packit Service 1d0348
	/* Prefix: 155 bytes */
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,
Packit Service 1d0348
	/* Padding: 12 bytes */
Packit Service 1d0348
	0,0,0,0,0,0,0,0, 0,0,0,0
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
static ssize_t	archive_write_ustar_data(struct archive_write *a, const void *buff,
Packit Service 1d0348
		    size_t s);
Packit Service 1d0348
static int	archive_write_ustar_free(struct archive_write *);
Packit Service 1d0348
static int	archive_write_ustar_close(struct archive_write *);
Packit Service 1d0348
static int	archive_write_ustar_finish_entry(struct archive_write *);
Packit Service 1d0348
static int	archive_write_ustar_header(struct archive_write *,
Packit Service 1d0348
		    struct archive_entry *entry);
Packit Service 1d0348
static int	archive_write_ustar_options(struct archive_write *,
Packit Service 1d0348
		    const char *, const char *);
Packit Service 1d0348
static int	format_256(int64_t, char *, int);
Packit Service 1d0348
static int	format_number(int64_t, char *, int size, int max, int strict);
Packit Service 1d0348
static int	format_octal(int64_t, char *, int);
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Set output format to 'ustar' format.
Packit Service 1d0348
 */
Packit Service 1d0348
int
Packit Service 1d0348
archive_write_set_format_ustar(struct archive *_a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct archive_write *a = (struct archive_write *)_a;
Packit Service 1d0348
	struct ustar *ustar;
Packit Service 1d0348
Packit Service 1d0348
	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
Packit Service 1d0348
	    ARCHIVE_STATE_NEW, "archive_write_set_format_ustar");
Packit Service 1d0348
Packit Service 1d0348
	/* If someone else was already registered, unregister them. */
Packit Service 1d0348
	if (a->format_free != NULL)
Packit Service 1d0348
		(a->format_free)(a);
Packit Service 1d0348
Packit Service 1d0348
	/* Basic internal sanity test. */
Packit Service 1d0348
	if (sizeof(template_header) != 512) {
Packit Service 1d0348
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Internal: template_header wrong size: %zu should be 512",
Packit Service 1d0348
		    sizeof(template_header));
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	ustar = (struct ustar *)calloc(1, sizeof(*ustar));
Packit Service 1d0348
	if (ustar == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
		    "Can't allocate ustar data");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	a->format_data = ustar;
Packit Service 1d0348
	a->format_name = "ustar";
Packit Service 1d0348
	a->format_options = archive_write_ustar_options;
Packit Service 1d0348
	a->format_write_header = archive_write_ustar_header;
Packit Service 1d0348
	a->format_write_data = archive_write_ustar_data;
Packit Service 1d0348
	a->format_close = archive_write_ustar_close;
Packit Service 1d0348
	a->format_free = archive_write_ustar_free;
Packit Service 1d0348
	a->format_finish_entry = archive_write_ustar_finish_entry;
Packit Service 1d0348
	a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR;
Packit Service 1d0348
	a->archive.archive_format_name = "POSIX ustar";
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_ustar_options(struct archive_write *a, const char *key,
Packit Service 1d0348
    const char *val)
Packit Service 1d0348
{
Packit Service 1d0348
	struct ustar *ustar = (struct ustar *)a->format_data;
Packit Service 1d0348
	int ret = ARCHIVE_FAILED;
Packit Service 1d0348
Packit Service 1d0348
	if (strcmp(key, "hdrcharset")  == 0) {
Packit Service 1d0348
		if (val == NULL || val[0] == 0)
Packit Service 1d0348
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "%s: hdrcharset option needs a character-set name",
Packit Service 1d0348
			    a->format_name);
Packit Service 1d0348
		else {
Packit Service 1d0348
			ustar->opt_sconv = archive_string_conversion_to_charset(
Packit Service 1d0348
			    &a->archive, val, 0);
Packit Service 1d0348
			if (ustar->opt_sconv != NULL)
Packit Service 1d0348
				ret = ARCHIVE_OK;
Packit Service 1d0348
			else
Packit Service 1d0348
				ret = ARCHIVE_FATAL;
Packit Service 1d0348
		}
Packit Service 1d0348
		return (ret);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Note: The "warn" return is just to inform the options
Packit Service 1d0348
	 * supervisor that we didn't handle it.  It will generate
Packit Service 1d0348
	 * a suitable error if no one used this option. */
Packit Service 1d0348
	return (ARCHIVE_WARN);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
Packit Service 1d0348
{
Packit Service 1d0348
	char buff[512];
Packit Service 1d0348
	int ret, ret2;
Packit Service 1d0348
	struct ustar *ustar;
Packit Service 1d0348
	struct archive_entry *entry_main;
Packit Service 1d0348
	struct archive_string_conv *sconv;
Packit Service 1d0348
Packit Service 1d0348
	ustar = (struct ustar *)a->format_data;
Packit Service 1d0348
Packit Service 1d0348
	/* Setup default string conversion. */
Packit Service 1d0348
	if (ustar->opt_sconv == NULL) {
Packit Service 1d0348
		if (!ustar->init_default_conversion) {
Packit Service 1d0348
			ustar->sconv_default =
Packit Service 1d0348
			    archive_string_default_conversion_for_write(&(a->archive));
Packit Service 1d0348
			ustar->init_default_conversion = 1;
Packit Service 1d0348
		}
Packit Service 1d0348
		sconv = ustar->sconv_default;
Packit Service 1d0348
	} else
Packit Service 1d0348
		sconv = ustar->opt_sconv;
Packit Service 1d0348
Packit Service 1d0348
	/* Sanity check. */
Packit Service 1d0348
	if (archive_entry_pathname(entry) == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Can't record entry in tar file without pathname");
Packit Service 1d0348
		return (ARCHIVE_FAILED);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Only regular files (not hardlinks) have data. */
Packit Service 1d0348
	if (archive_entry_hardlink(entry) != NULL ||
Packit Service 1d0348
	    archive_entry_symlink(entry) != NULL ||
Packit Service 1d0348
	    !(archive_entry_filetype(entry) == AE_IFREG))
Packit Service 1d0348
		archive_entry_set_size(entry, 0);
Packit Service 1d0348
Packit Service 1d0348
	if (AE_IFDIR == archive_entry_filetype(entry)) {
Packit Service 1d0348
		const char *p;
Packit Service 1d0348
		size_t path_length;
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Ensure a trailing '/'.  Modify the entry so
Packit Service 1d0348
		 * the client sees the change.
Packit Service 1d0348
		 */
Packit Service 1d0348
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit Service 1d0348
		const wchar_t *wp;
Packit Service 1d0348
Packit Service 1d0348
		wp = archive_entry_pathname_w(entry);
Packit Service 1d0348
		if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
Packit Service 1d0348
			struct archive_wstring ws;
Packit Service 1d0348
Packit Service 1d0348
			archive_string_init(&ws);
Packit Service 1d0348
			path_length = wcslen(wp);
Packit Service 1d0348
			if (archive_wstring_ensure(&ws,
Packit Service 1d0348
			    path_length + 2) == NULL) {
Packit Service 1d0348
				archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
				    "Can't allocate ustar data");
Packit Service 1d0348
				archive_wstring_free(&ws);
Packit Service 1d0348
				return(ARCHIVE_FATAL);
Packit Service 1d0348
			}
Packit Service 1d0348
			/* Should we keep '\' ? */
Packit Service 1d0348
			if (wp[path_length -1] == L'\\')
Packit Service 1d0348
				path_length--;
Packit Service 1d0348
			archive_wstrncpy(&ws, wp, path_length);
Packit Service 1d0348
			archive_wstrappend_wchar(&ws, L'/');
Packit Service 1d0348
			archive_entry_copy_pathname_w(entry, ws.s);
Packit Service 1d0348
			archive_wstring_free(&ws);
Packit Service 1d0348
			p = NULL;
Packit Service 1d0348
		} else
Packit Service 1d0348
#endif
Packit Service 1d0348
			p = archive_entry_pathname(entry);
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * On Windows, this is a backup operation just in
Packit Service 1d0348
		 * case getting WCS failed. On POSIX, this is a
Packit Service 1d0348
		 * normal operation.
Packit Service 1d0348
		 */
Packit Service 1d0348
		if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
Packit Service 1d0348
			struct archive_string as;
Packit Service 1d0348
Packit Service 1d0348
			archive_string_init(&as);
Packit Service 1d0348
			path_length = strlen(p);
Packit Service 1d0348
			if (archive_string_ensure(&as,
Packit Service 1d0348
			    path_length + 2) == NULL) {
Packit Service 1d0348
				archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
				    "Can't allocate ustar data");
Packit Service 1d0348
				archive_string_free(&as);
Packit Service 1d0348
				return(ARCHIVE_FATAL);
Packit Service 1d0348
			}
Packit Service 1d0348
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit Service 1d0348
			/* NOTE: This might break the pathname
Packit Service 1d0348
			 * if the current code page is CP932 and
Packit Service 1d0348
			 * the pathname includes a character '\'
Packit Service 1d0348
			 * as a part of its multibyte pathname. */
Packit Service 1d0348
			if (p[strlen(p) -1] == '\\')
Packit Service 1d0348
				path_length--;
Packit Service 1d0348
			else
Packit Service 1d0348
#endif
Packit Service 1d0348
			archive_strncpy(&as, p, path_length);
Packit Service 1d0348
			archive_strappend_char(&as, '/');
Packit Service 1d0348
			archive_entry_copy_pathname(entry, as.s);
Packit Service 1d0348
			archive_string_free(&as);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit Service 1d0348
	/* Make sure the path separators in pathname, hardlink and symlink
Packit Service 1d0348
	 * are all slash '/', not the Windows path separator '\'. */
Packit Service 1d0348
	entry_main = __la_win_entry_in_posix_pathseparator(entry);
Packit Service 1d0348
	if (entry_main == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
		    "Can't allocate ustar data");
Packit Service 1d0348
		return(ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	if (entry != entry_main)
Packit Service 1d0348
		entry = entry_main;
Packit Service 1d0348
	else
Packit Service 1d0348
		entry_main = NULL;
Packit Service 1d0348
#else
Packit Service 1d0348
	entry_main = NULL;
Packit Service 1d0348
#endif
Packit Service 1d0348
	ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1, sconv);
Packit Service 1d0348
	if (ret < ARCHIVE_WARN) {
Packit Service 1d0348
		if (entry_main)
Packit Service 1d0348
			archive_entry_free(entry_main);
Packit Service 1d0348
		return (ret);
Packit Service 1d0348
	}
Packit Service 1d0348
	ret2 = __archive_write_output(a, buff, 512);
Packit Service 1d0348
	if (ret2 < ARCHIVE_WARN) {
Packit Service 1d0348
		if (entry_main)
Packit Service 1d0348
			archive_entry_free(entry_main);
Packit Service 1d0348
		return (ret2);
Packit Service 1d0348
	}
Packit Service 1d0348
	if (ret2 < ret)
Packit Service 1d0348
		ret = ret2;
Packit Service 1d0348
Packit Service 1d0348
	ustar->entry_bytes_remaining = archive_entry_size(entry);
Packit Service 1d0348
	ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining);
Packit Service 1d0348
	if (entry_main)
Packit Service 1d0348
		archive_entry_free(entry_main);
Packit Service 1d0348
	return (ret);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Format a basic 512-byte "ustar" header.
Packit Service 1d0348
 *
Packit Service 1d0348
 * Returns -1 if format failed (due to field overflow).
Packit Service 1d0348
 * Note that this always formats as much of the header as possible.
Packit Service 1d0348
 * If "strict" is set to zero, it will extend numeric fields as
Packit Service 1d0348
 * necessary (overwriting terminators or using base-256 extensions).
Packit Service 1d0348
 *
Packit Service 1d0348
 * This is exported so that other 'tar' formats can use it.
Packit Service 1d0348
 */
Packit Service 1d0348
int
Packit Service 1d0348
__archive_write_format_header_ustar(struct archive_write *a, char h[512],
Packit Service 1d0348
    struct archive_entry *entry, int tartype, int strict,
Packit Service 1d0348
    struct archive_string_conv *sconv)
Packit Service 1d0348
{
Packit Service 1d0348
	unsigned int checksum;
Packit Service 1d0348
	int i, r, ret;
Packit Service 1d0348
	size_t copy_length;
Packit Service 1d0348
	const char *p, *pp;
Packit Service 1d0348
	int mytartype;
Packit Service 1d0348
Packit Service 1d0348
	ret = 0;
Packit Service 1d0348
	mytartype = -1;
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * The "template header" already includes the "ustar"
Packit Service 1d0348
	 * signature, various end-of-field markers and other required
Packit Service 1d0348
	 * elements.
Packit Service 1d0348
	 */
Packit Service 1d0348
	memcpy(h, &template_header, 512);
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Because the block is already null-filled, and strings
Packit Service 1d0348
	 * are allowed to exactly fill their destination (without null),
Packit Service 1d0348
	 * I use memcpy(dest, src, strlen()) here a lot to copy strings.
Packit Service 1d0348
	 */
Packit Service 1d0348
	r = archive_entry_pathname_l(entry, &pp, &copy_length, sconv);
Packit Service 1d0348
	if (r != 0) {
Packit Service 1d0348
		if (errno == ENOMEM) {
Packit Service 1d0348
			archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
			    "Can't allocate memory for Pathname");
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit Service 1d0348
		    "Can't translate pathname '%s' to %s",
Packit Service 1d0348
		    pp, archive_string_conversion_charset_name(sconv));
Packit Service 1d0348
		ret = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (copy_length <= USTAR_name_size)
Packit Service 1d0348
		memcpy(h + USTAR_name_offset, pp, copy_length);
Packit Service 1d0348
	else {
Packit Service 1d0348
		/* Store in two pieces, splitting at a '/'. */
Packit Service 1d0348
		p = strchr(pp + copy_length - USTAR_name_size - 1, '/');
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Look for the next '/' if we chose the first character
Packit Service 1d0348
		 * as the separator.  (ustar format doesn't permit
Packit Service 1d0348
		 * an empty prefix.)
Packit Service 1d0348
		 */
Packit Service 1d0348
		if (p == pp)
Packit Service 1d0348
			p = strchr(p + 1, '/');
Packit Service 1d0348
		/* Fail if the name won't fit. */
Packit Service 1d0348
		if (!p) {
Packit Service 1d0348
			/* No separator. */
Packit Service 1d0348
			archive_set_error(&a->archive, ENAMETOOLONG,
Packit Service 1d0348
			    "Pathname too long");
Packit Service 1d0348
			ret = ARCHIVE_FAILED;
Packit Service 1d0348
		} else if (p[1] == '\0') {
Packit Service 1d0348
			/*
Packit Service 1d0348
			 * The only feasible separator is a final '/';
Packit Service 1d0348
			 * this would result in a non-empty prefix and
Packit Service 1d0348
			 * an empty name, which POSIX doesn't
Packit Service 1d0348
			 * explicitly forbid, but it just feels wrong.
Packit Service 1d0348
			 */
Packit Service 1d0348
			archive_set_error(&a->archive, ENAMETOOLONG,
Packit Service 1d0348
			    "Pathname too long");
Packit Service 1d0348
			ret = ARCHIVE_FAILED;
Packit Service 1d0348
		} else if (p  > pp + USTAR_prefix_size) {
Packit Service 1d0348
			/* Prefix is too long. */
Packit Service 1d0348
			archive_set_error(&a->archive, ENAMETOOLONG,
Packit Service 1d0348
			    "Pathname too long");
Packit Service 1d0348
			ret = ARCHIVE_FAILED;
Packit Service 1d0348
		} else {
Packit Service 1d0348
			/* Copy prefix and remainder to appropriate places */
Packit Service 1d0348
			memcpy(h + USTAR_prefix_offset, pp, p - pp);
Packit Service 1d0348
			memcpy(h + USTAR_name_offset, p + 1,
Packit Service 1d0348
			    pp + copy_length - p - 1);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	r = archive_entry_hardlink_l(entry, &p, &copy_length, sconv);
Packit Service 1d0348
	if (r != 0) {
Packit Service 1d0348
		if (errno == ENOMEM) {
Packit Service 1d0348
			archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
			    "Can't allocate memory for Linkname");
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_FILE_FORMAT,
Packit Service 1d0348
		    "Can't translate linkname '%s' to %s",
Packit Service 1d0348
		    p, archive_string_conversion_charset_name(sconv));
Packit Service 1d0348
		ret = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (copy_length > 0)
Packit Service 1d0348
		mytartype = '1';
Packit Service 1d0348
	else {
Packit Service 1d0348
		r = archive_entry_symlink_l(entry, &p, &copy_length, sconv);
Packit Service 1d0348
		if (r != 0) {
Packit Service 1d0348
			if (errno == ENOMEM) {
Packit Service 1d0348
				archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
				    "Can't allocate memory for Linkname");
Packit Service 1d0348
				return (ARCHIVE_FATAL);
Packit Service 1d0348
			}
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit Service 1d0348
			    "Can't translate linkname '%s' to %s",
Packit Service 1d0348
			    p, archive_string_conversion_charset_name(sconv));
Packit Service 1d0348
			ret = ARCHIVE_WARN;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if (copy_length > 0) {
Packit Service 1d0348
		if (copy_length > USTAR_linkname_size) {
Packit Service 1d0348
			archive_set_error(&a->archive, ENAMETOOLONG,
Packit Service 1d0348
			    "Link contents too long");
Packit Service 1d0348
			ret = ARCHIVE_FAILED;
Packit Service 1d0348
			copy_length = USTAR_linkname_size;
Packit Service 1d0348
		}
Packit Service 1d0348
		memcpy(h + USTAR_linkname_offset, p, copy_length);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	r = archive_entry_uname_l(entry, &p, &copy_length, sconv);
Packit Service 1d0348
	if (r != 0) {
Packit Service 1d0348
		if (errno == ENOMEM) {
Packit Service 1d0348
			archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
			    "Can't allocate memory for Uname");
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_FILE_FORMAT,
Packit Service 1d0348
		    "Can't translate uname '%s' to %s",
Packit Service 1d0348
		    p, archive_string_conversion_charset_name(sconv));
Packit Service 1d0348
		ret = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (copy_length > 0) {
Packit Service 1d0348
		if (copy_length > USTAR_uname_size) {
Packit Service 1d0348
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "Username too long");
Packit Service 1d0348
			ret = ARCHIVE_FAILED;
Packit Service 1d0348
			copy_length = USTAR_uname_size;
Packit Service 1d0348
		}
Packit Service 1d0348
		memcpy(h + USTAR_uname_offset, p, copy_length);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	r = archive_entry_gname_l(entry, &p, &copy_length, sconv);
Packit Service 1d0348
	if (r != 0) {
Packit Service 1d0348
		if (errno == ENOMEM) {
Packit Service 1d0348
			archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
			    "Can't allocate memory for Gname");
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_FILE_FORMAT,
Packit Service 1d0348
		    "Can't translate gname '%s' to %s",
Packit Service 1d0348
		    p, archive_string_conversion_charset_name(sconv));
Packit Service 1d0348
		ret = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (copy_length > 0) {
Packit Service 1d0348
		if (strlen(p) > USTAR_gname_size) {
Packit Service 1d0348
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "Group name too long");
Packit Service 1d0348
			ret = ARCHIVE_FAILED;
Packit Service 1d0348
			copy_length = USTAR_gname_size;
Packit Service 1d0348
		}
Packit Service 1d0348
		memcpy(h + USTAR_gname_offset, p, copy_length);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (format_number(archive_entry_mode(entry) & 07777,
Packit Service 1d0348
	    h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {
Packit Service 1d0348
		archive_set_error(&a->archive, ERANGE,
Packit Service 1d0348
		    "Numeric mode too large");
Packit Service 1d0348
		ret = ARCHIVE_FAILED;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (format_number(archive_entry_uid(entry),
Packit Service 1d0348
	    h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {
Packit Service 1d0348
		archive_set_error(&a->archive, ERANGE,
Packit Service 1d0348
		    "Numeric user ID too large");
Packit Service 1d0348
		ret = ARCHIVE_FAILED;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (format_number(archive_entry_gid(entry),
Packit Service 1d0348
	    h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {
Packit Service 1d0348
		archive_set_error(&a->archive, ERANGE,
Packit Service 1d0348
		    "Numeric group ID too large");
Packit Service 1d0348
		ret = ARCHIVE_FAILED;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (format_number(archive_entry_size(entry),
Packit Service 1d0348
	    h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {
Packit Service 1d0348
		archive_set_error(&a->archive, ERANGE,
Packit Service 1d0348
		    "File size out of range");
Packit Service 1d0348
		ret = ARCHIVE_FAILED;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (format_number(archive_entry_mtime(entry),
Packit Service 1d0348
	    h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {
Packit Service 1d0348
		archive_set_error(&a->archive, ERANGE,
Packit Service 1d0348
		    "File modification time too large");
Packit Service 1d0348
		ret = ARCHIVE_FAILED;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (archive_entry_filetype(entry) == AE_IFBLK
Packit Service 1d0348
	    || archive_entry_filetype(entry) == AE_IFCHR) {
Packit Service 1d0348
		if (format_number(archive_entry_rdevmajor(entry),
Packit Service 1d0348
		    h + USTAR_rdevmajor_offset, USTAR_rdevmajor_size,
Packit Service 1d0348
		    USTAR_rdevmajor_max_size, strict)) {
Packit Service 1d0348
			archive_set_error(&a->archive, ERANGE,
Packit Service 1d0348
			    "Major device number too large");
Packit Service 1d0348
			ret = ARCHIVE_FAILED;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		if (format_number(archive_entry_rdevminor(entry),
Packit Service 1d0348
		    h + USTAR_rdevminor_offset, USTAR_rdevminor_size,
Packit Service 1d0348
		    USTAR_rdevminor_max_size, strict)) {
Packit Service 1d0348
			archive_set_error(&a->archive, ERANGE,
Packit Service 1d0348
			    "Minor device number too large");
Packit Service 1d0348
			ret = ARCHIVE_FAILED;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (tartype >= 0) {
Packit Service 1d0348
		h[USTAR_typeflag_offset] = tartype;
Packit Service 1d0348
	} else if (mytartype >= 0) {
Packit Service 1d0348
		h[USTAR_typeflag_offset] = mytartype;
Packit Service 1d0348
	} else {
Packit Service 1d0348
		switch (archive_entry_filetype(entry)) {
Packit Service 1d0348
		case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break;
Packit Service 1d0348
		case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break;
Packit Service 1d0348
		case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break;
Packit Service 1d0348
		case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break;
Packit Service 1d0348
		case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break;
Packit Service 1d0348
		case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break;
Packit Service 1d0348
		case AE_IFSOCK:
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit Service 1d0348
			    "tar format cannot archive socket");
Packit Service 1d0348
			return (ARCHIVE_FAILED);
Packit Service 1d0348
		default:
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit Service 1d0348
			    "tar format cannot archive this (mode=0%lo)",
Packit Service 1d0348
			    (unsigned long)archive_entry_mode(entry));
Packit Service 1d0348
			ret = ARCHIVE_FAILED;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	checksum = 0;
Packit Service 1d0348
	for (i = 0; i < 512; i++)
Packit Service 1d0348
		checksum += 255 & (unsigned int)h[i];
Packit Service 1d0348
	h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */
Packit Service 1d0348
	/* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */
Packit Service 1d0348
	format_octal(checksum, h + USTAR_checksum_offset, 6);
Packit Service 1d0348
	return (ret);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Format a number into a field, with some intelligence.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
format_number(int64_t v, char *p, int s, int maxsize, int strict)
Packit Service 1d0348
{
Packit Service 1d0348
	int64_t limit;
Packit Service 1d0348
Packit Service 1d0348
	limit = ((int64_t)1 << (s*3));
Packit Service 1d0348
Packit Service 1d0348
	/* "Strict" only permits octal values with proper termination. */
Packit Service 1d0348
	if (strict)
Packit Service 1d0348
		return (format_octal(v, p, s));
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * In non-strict mode, we allow the number to overwrite one or
Packit Service 1d0348
	 * more bytes of the field termination.  Even old tar
Packit Service 1d0348
	 * implementations should be able to handle this with no
Packit Service 1d0348
	 * problem.
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (v >= 0) {
Packit Service 1d0348
		while (s <= maxsize) {
Packit Service 1d0348
			if (v < limit)
Packit Service 1d0348
				return (format_octal(v, p, s));
Packit Service 1d0348
			s++;
Packit Service 1d0348
			limit <<= 3;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Base-256 can handle any number, positive or negative. */
Packit Service 1d0348
	return (format_256(v, p, maxsize));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Format a number into the specified field using base-256.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
format_256(int64_t v, char *p, int s)
Packit Service 1d0348
{
Packit Service 1d0348
	p += s;
Packit Service 1d0348
	while (s-- > 0) {
Packit Service 1d0348
		*--p = (char)(v & 0xff);
Packit Service 1d0348
		v >>= 8;
Packit Service 1d0348
	}
Packit Service 1d0348
	*p |= 0x80; /* Set the base-256 marker bit. */
Packit Service 1d0348
	return (0);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Format a number into the specified field.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
format_octal(int64_t v, char *p, int s)
Packit Service 1d0348
{
Packit Service 1d0348
	int len;
Packit Service 1d0348
Packit Service 1d0348
	len = s;
Packit Service 1d0348
Packit Service 1d0348
	/* Octal values can't be negative, so use 0. */
Packit Service 1d0348
	if (v < 0) {
Packit Service 1d0348
		while (len-- > 0)
Packit Service 1d0348
			*p++ = '0';
Packit Service 1d0348
		return (-1);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	p += s;		/* Start at the end and work backwards. */
Packit Service 1d0348
	while (s-- > 0) {
Packit Service 1d0348
		*--p = (char)('0' + (v & 7));
Packit Service 1d0348
		v >>= 3;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (v == 0)
Packit Service 1d0348
		return (0);
Packit Service 1d0348
Packit Service 1d0348
	/* If it overflowed, fill field with max value. */
Packit Service 1d0348
	while (len-- > 0)
Packit Service 1d0348
		*p++ = '7';
Packit Service 1d0348
Packit Service 1d0348
	return (-1);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_ustar_close(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	return (__archive_write_nulls(a, 512*2));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_ustar_free(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct ustar *ustar;
Packit Service 1d0348
Packit Service 1d0348
	ustar = (struct ustar *)a->format_data;
Packit Service 1d0348
	free(ustar);
Packit Service 1d0348
	a->format_data = NULL;
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_ustar_finish_entry(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct ustar *ustar;
Packit Service 1d0348
	int ret;
Packit Service 1d0348
Packit Service 1d0348
	ustar = (struct ustar *)a->format_data;
Packit Service 1d0348
	ret = __archive_write_nulls(a,
Packit Service 1d0348
	    (size_t)(ustar->entry_bytes_remaining + ustar->entry_padding));
Packit Service 1d0348
	ustar->entry_bytes_remaining = ustar->entry_padding = 0;
Packit Service 1d0348
	return (ret);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static ssize_t
Packit Service 1d0348
archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
Packit Service 1d0348
{
Packit Service 1d0348
	struct ustar *ustar;
Packit Service 1d0348
	int ret;
Packit Service 1d0348
Packit Service 1d0348
	ustar = (struct ustar *)a->format_data;
Packit Service 1d0348
	if (s > ustar->entry_bytes_remaining)
Packit Service 1d0348
		s = (size_t)ustar->entry_bytes_remaining;
Packit Service 1d0348
	ret = __archive_write_output(a, buff, s);
Packit Service 1d0348
	ustar->entry_bytes_remaining -= s;
Packit Service 1d0348
	if (ret != ARCHIVE_OK)
Packit Service 1d0348
		return (ret);
Packit Service 1d0348
	return (s);
Packit Service 1d0348
}