Blame libarchive/archive_write_set_format_gnutar.c

Packit Service 1d0348
/*-
Packit Service 1d0348
 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
Packit Service 1d0348
 * Author: Jonas Gastal <jgastal@profusion.mobi>
Packit Service 1d0348
 * Copyright (c) 2011-2012 Michihiro NAKAJIMA
Packit Service 1d0348
 *
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_gnu_tar.c 191579 2009-04-27 18:35:03Z gastal $");
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 gnutar {
Packit Service 1d0348
	uint64_t	entry_bytes_remaining;
Packit Service 1d0348
	uint64_t	entry_padding;
Packit Service 1d0348
	const char *	linkname;
Packit Service 1d0348
	size_t		linkname_length;
Packit Service 1d0348
	const char *	pathname;
Packit Service 1d0348
	size_t		pathname_length;
Packit Service 1d0348
	const char *	uname;
Packit Service 1d0348
	size_t		uname_length;
Packit Service 1d0348
	const char *	gname;
Packit Service 1d0348
	size_t		gname_length;
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 GNU tar header.
Packit Service 1d0348
 */
Packit Service 1d0348
#define	GNUTAR_name_offset 0
Packit Service 1d0348
#define	GNUTAR_name_size 100
Packit Service 1d0348
#define	GNUTAR_mode_offset 100
Packit Service 1d0348
#define	GNUTAR_mode_size 7
Packit Service 1d0348
#define	GNUTAR_mode_max_size 8
Packit Service 1d0348
#define	GNUTAR_uid_offset 108
Packit Service 1d0348
#define	GNUTAR_uid_size 7
Packit Service 1d0348
#define	GNUTAR_uid_max_size 8
Packit Service 1d0348
#define	GNUTAR_gid_offset 116
Packit Service 1d0348
#define	GNUTAR_gid_size 7
Packit Service 1d0348
#define	GNUTAR_gid_max_size 8
Packit Service 1d0348
#define	GNUTAR_size_offset 124
Packit Service 1d0348
#define	GNUTAR_size_size 11
Packit Service 1d0348
#define	GNUTAR_size_max_size 12
Packit Service 1d0348
#define	GNUTAR_mtime_offset 136
Packit Service 1d0348
#define	GNUTAR_mtime_size 11
Packit Service 1d0348
#define	GNUTAR_mtime_max_size 11
Packit Service 1d0348
#define	GNUTAR_checksum_offset 148
Packit Service 1d0348
#define	GNUTAR_checksum_size 8
Packit Service 1d0348
#define	GNUTAR_typeflag_offset 156
Packit Service 1d0348
#define	GNUTAR_typeflag_size 1
Packit Service 1d0348
#define	GNUTAR_linkname_offset 157
Packit Service 1d0348
#define	GNUTAR_linkname_size 100
Packit Service 1d0348
#define	GNUTAR_magic_offset 257
Packit Service 1d0348
#define	GNUTAR_magic_size 6
Packit Service 1d0348
#define	GNUTAR_version_offset 263
Packit Service 1d0348
#define	GNUTAR_version_size 2
Packit Service 1d0348
#define	GNUTAR_uname_offset 265
Packit Service 1d0348
#define	GNUTAR_uname_size 32
Packit Service 1d0348
#define	GNUTAR_gname_offset 297
Packit Service 1d0348
#define	GNUTAR_gname_size 32
Packit Service 1d0348
#define	GNUTAR_rdevmajor_offset 329
Packit Service 1d0348
#define	GNUTAR_rdevmajor_size 6
Packit Service 1d0348
#define	GNUTAR_rdevmajor_max_size 8
Packit Service 1d0348
#define	GNUTAR_rdevminor_offset 337
Packit Service 1d0348
#define	GNUTAR_rdevminor_size 6
Packit Service 1d0348
#define	GNUTAR_rdevminor_max_size 8
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, null termination: 8 bytes */
Packit Service 1d0348
	'0','0','0','0','0','0', '0','\0',
Packit Service 1d0348
	/* uid, null termination: 8 bytes */
Packit Service 1d0348
	'0','0','0','0','0','0', '0','\0',
Packit Service 1d0348
	/* gid, null termination: 8 bytes */
Packit Service 1d0348
	'0','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', '\0',
Packit Service 1d0348
	/* mtime, space termination: 12 bytes */
Packit Service 1d0348
	'0','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: 8 bytes */
Packit Service 1d0348
	'u','s','t','a','r',' ', ' ','\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 + null padding: 8 bytes */
Packit Service 1d0348
	'\0','\0','\0','\0','\0','\0', '\0','\0',
Packit Service 1d0348
	/* rdevminor + null padding: 8 bytes */
Packit Service 1d0348
	'\0','\0','\0','\0','\0','\0', '\0','\0',
Packit Service 1d0348
	/* Padding: 167 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,0,0,0,0,0,
Packit Service 1d0348
	0,0,0,0,0,0,0
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
static int      archive_write_gnutar_options(struct archive_write *,
Packit Service 1d0348
		    const char *, const char *);
Packit Service 1d0348
static int	archive_format_gnutar_header(struct archive_write *, char h[512],
Packit Service 1d0348
		    struct archive_entry *, int tartype);
Packit Service 1d0348
static int      archive_write_gnutar_header(struct archive_write *,
Packit Service 1d0348
		    struct archive_entry *entry);
Packit Service 1d0348
static ssize_t	archive_write_gnutar_data(struct archive_write *a, const void *buff,
Packit Service 1d0348
		    size_t s);
Packit Service 1d0348
static int	archive_write_gnutar_free(struct archive_write *);
Packit Service 1d0348
static int	archive_write_gnutar_close(struct archive_write *);
Packit Service 1d0348
static int	archive_write_gnutar_finish_entry(struct archive_write *);
Packit Service 1d0348
static int	format_256(int64_t, char *, int);
Packit Service 1d0348
static int	format_number(int64_t, char *, int size, int maxsize);
Packit Service 1d0348
static int	format_octal(int64_t, char *, int);
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Set output format to 'GNU tar' format.
Packit Service 1d0348
 */
Packit Service 1d0348
int
Packit Service 1d0348
archive_write_set_format_gnutar(struct archive *_a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct archive_write *a = (struct archive_write *)_a;
Packit Service 1d0348
	struct gnutar *gnutar;
Packit Service 1d0348
Packit Service 1d0348
	gnutar = (struct gnutar *)calloc(1, sizeof(*gnutar));
Packit Service 1d0348
	if (gnutar == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
		    "Can't allocate gnutar data");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	a->format_data = gnutar;
Packit Service 1d0348
	a->format_name = "gnutar";
Packit Service 1d0348
	a->format_options = archive_write_gnutar_options;
Packit Service 1d0348
	a->format_write_header = archive_write_gnutar_header;
Packit Service 1d0348
	a->format_write_data = archive_write_gnutar_data;
Packit Service 1d0348
	a->format_close = archive_write_gnutar_close;
Packit Service 1d0348
	a->format_free = archive_write_gnutar_free;
Packit Service 1d0348
	a->format_finish_entry = archive_write_gnutar_finish_entry;
Packit Service 1d0348
	a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
Packit Service 1d0348
	a->archive.archive_format_name = "GNU tar";
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_gnutar_options(struct archive_write *a, const char *key,
Packit Service 1d0348
    const char *val)
Packit Service 1d0348
{
Packit Service 1d0348
	struct gnutar *gnutar = (struct gnutar *)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
			gnutar->opt_sconv = archive_string_conversion_to_charset(
Packit Service 1d0348
			    &a->archive, val, 0);
Packit Service 1d0348
			if (gnutar->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_gnutar_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_gnutar_free(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct gnutar *gnutar;
Packit Service 1d0348
Packit Service 1d0348
	gnutar = (struct gnutar *)a->format_data;
Packit Service 1d0348
	free(gnutar);
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_gnutar_finish_entry(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct gnutar *gnutar;
Packit Service 1d0348
	int ret;
Packit Service 1d0348
Packit Service 1d0348
	gnutar = (struct gnutar *)a->format_data;
Packit Service 1d0348
	ret = __archive_write_nulls(a, (size_t)
Packit Service 1d0348
	    (gnutar->entry_bytes_remaining + gnutar->entry_padding));
Packit Service 1d0348
	gnutar->entry_bytes_remaining = gnutar->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_gnutar_data(struct archive_write *a, const void *buff, size_t s)
Packit Service 1d0348
{
Packit Service 1d0348
	struct gnutar *gnutar;
Packit Service 1d0348
	int ret;
Packit Service 1d0348
Packit Service 1d0348
	gnutar = (struct gnutar *)a->format_data;
Packit Service 1d0348
	if (s > gnutar->entry_bytes_remaining)
Packit Service 1d0348
		s = (size_t)gnutar->entry_bytes_remaining;
Packit Service 1d0348
	ret = __archive_write_output(a, buff, s);
Packit Service 1d0348
	gnutar->entry_bytes_remaining -= s;
Packit Service 1d0348
	if (ret != ARCHIVE_OK)
Packit Service 1d0348
		return (ret);
Packit Service 1d0348
	return (s);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_gnutar_header(struct archive_write *a,
Packit Service 1d0348
     struct archive_entry *entry)
Packit Service 1d0348
{
Packit Service 1d0348
	char buff[512];
Packit Service 1d0348
	int r, ret, ret2 = ARCHIVE_OK;
Packit Service 1d0348
	int tartype;
Packit Service 1d0348
	struct gnutar *gnutar;
Packit Service 1d0348
	struct archive_string_conv *sconv;
Packit Service 1d0348
	struct archive_entry *entry_main;
Packit Service 1d0348
Packit Service 1d0348
	gnutar = (struct gnutar *)a->format_data;
Packit Service 1d0348
Packit Service 1d0348
	/* Setup default string conversion. */
Packit Service 1d0348
	if (gnutar->opt_sconv == NULL) {
Packit Service 1d0348
		if (!gnutar->init_default_conversion) {
Packit Service 1d0348
			gnutar->sconv_default =
Packit Service 1d0348
			    archive_string_default_conversion_for_write(
Packit Service 1d0348
				&(a->archive));
Packit Service 1d0348
			gnutar->init_default_conversion = 1;
Packit Service 1d0348
		}
Packit Service 1d0348
		sconv = gnutar->sconv_default;
Packit Service 1d0348
	} else
Packit Service 1d0348
		sconv = gnutar->opt_sconv;
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[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
	r = archive_entry_pathname_l(entry, &(gnutar->pathname),
Packit Service 1d0348
	    &(gnutar->pathname_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 Pathame");
Packit Service 1d0348
			ret = ARCHIVE_FATAL;
Packit Service 1d0348
			goto exit_write_header;
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
		    archive_entry_pathname(entry),
Packit Service 1d0348
		    archive_string_conversion_charset_name(sconv));
Packit Service 1d0348
		ret2 = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
	r = archive_entry_uname_l(entry, &(gnutar->uname),
Packit Service 1d0348
	    &(gnutar->uname_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
			ret = ARCHIVE_FATAL;
Packit Service 1d0348
			goto exit_write_header;
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
		    archive_entry_uname(entry),
Packit Service 1d0348
		    archive_string_conversion_charset_name(sconv));
Packit Service 1d0348
		ret2 = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
	r = archive_entry_gname_l(entry, &(gnutar->gname),
Packit Service 1d0348
	    &(gnutar->gname_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
			ret = ARCHIVE_FATAL;
Packit Service 1d0348
			goto exit_write_header;
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
		    archive_entry_gname(entry),
Packit Service 1d0348
		    archive_string_conversion_charset_name(sconv));
Packit Service 1d0348
		ret2 = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* If linkname is longer than 100 chars we need to add a 'K' header. */
Packit Service 1d0348
	r = archive_entry_hardlink_l(entry, &(gnutar->linkname),
Packit Service 1d0348
	    &(gnutar->linkname_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
			ret = ARCHIVE_FATAL;
Packit Service 1d0348
			goto exit_write_header;
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
		    archive_entry_hardlink(entry),
Packit Service 1d0348
		    archive_string_conversion_charset_name(sconv));
Packit Service 1d0348
		ret2 = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gnutar->linkname_length == 0) {
Packit Service 1d0348
		r = archive_entry_symlink_l(entry, &(gnutar->linkname),
Packit Service 1d0348
		    &(gnutar->linkname_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
				ret = ARCHIVE_FATAL;
Packit Service 1d0348
				goto exit_write_header;
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
			    archive_entry_hardlink(entry),
Packit Service 1d0348
			    archive_string_conversion_charset_name(sconv));
Packit Service 1d0348
			ret2 = ARCHIVE_WARN;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gnutar->linkname_length > GNUTAR_linkname_size) {
Packit Service 1d0348
		size_t length = gnutar->linkname_length + 1;
Packit Service 1d0348
		struct archive_entry *temp = archive_entry_new2(&a->archive);
Packit Service 1d0348
Packit Service 1d0348
		/* Uname/gname here don't really matter since no one reads them;
Packit Service 1d0348
		 * these are the values that GNU tar happens to use on FreeBSD. */
Packit Service 1d0348
		archive_entry_set_uname(temp, "root");
Packit Service 1d0348
		archive_entry_set_gname(temp, "wheel");
Packit Service 1d0348
Packit Service 1d0348
		archive_entry_set_pathname(temp, "././@LongLink");
Packit Service 1d0348
		archive_entry_set_size(temp, length);
Packit Service 1d0348
		ret = archive_format_gnutar_header(a, buff, temp, 'K');
Packit Service 1d0348
		archive_entry_free(temp);
Packit Service 1d0348
		if (ret < ARCHIVE_WARN)
Packit Service 1d0348
			goto exit_write_header;
Packit Service 1d0348
		ret = __archive_write_output(a, buff, 512);
Packit Service 1d0348
		if (ret < ARCHIVE_WARN)
Packit Service 1d0348
			goto exit_write_header;
Packit Service 1d0348
		/* Write name and trailing null byte. */
Packit Service 1d0348
		ret = __archive_write_output(a, gnutar->linkname, length);
Packit Service 1d0348
		if (ret < ARCHIVE_WARN)
Packit Service 1d0348
			goto exit_write_header;
Packit Service 1d0348
		/* Pad to 512 bytes */
Packit Service 1d0348
		ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));
Packit Service 1d0348
		if (ret < ARCHIVE_WARN)
Packit Service 1d0348
			goto exit_write_header;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* If pathname is longer than 100 chars we need to add an 'L' header. */
Packit Service 1d0348
	if (gnutar->pathname_length > GNUTAR_name_size) {
Packit Service 1d0348
		const char *pathname = gnutar->pathname;
Packit Service 1d0348
		size_t length = gnutar->pathname_length + 1;
Packit Service 1d0348
		struct archive_entry *temp = archive_entry_new2(&a->archive);
Packit Service 1d0348
Packit Service 1d0348
		/* Uname/gname here don't really matter since no one reads them;
Packit Service 1d0348
		 * these are the values that GNU tar happens to use on FreeBSD. */
Packit Service 1d0348
		archive_entry_set_uname(temp, "root");
Packit Service 1d0348
		archive_entry_set_gname(temp, "wheel");
Packit Service 1d0348
Packit Service 1d0348
		archive_entry_set_pathname(temp, "././@LongLink");
Packit Service 1d0348
		archive_entry_set_size(temp, length);
Packit Service 1d0348
		ret = archive_format_gnutar_header(a, buff, temp, 'L');
Packit Service 1d0348
		archive_entry_free(temp);
Packit Service 1d0348
		if (ret < ARCHIVE_WARN)
Packit Service 1d0348
			goto exit_write_header;
Packit Service 1d0348
		ret = __archive_write_output(a, buff, 512);
Packit Service 1d0348
		if(ret < ARCHIVE_WARN)
Packit Service 1d0348
			goto exit_write_header;
Packit Service 1d0348
		/* Write pathname + trailing null byte. */
Packit Service 1d0348
		ret = __archive_write_output(a, pathname, length);
Packit Service 1d0348
		if(ret < ARCHIVE_WARN)
Packit Service 1d0348
			goto exit_write_header;
Packit Service 1d0348
		/* Pad to multiple of 512 bytes. */
Packit Service 1d0348
		ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));
Packit Service 1d0348
		if (ret < ARCHIVE_WARN)
Packit Service 1d0348
			goto exit_write_header;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (archive_entry_hardlink(entry) != NULL) {
Packit Service 1d0348
		tartype = '1';
Packit Service 1d0348
	} else
Packit Service 1d0348
		switch (archive_entry_filetype(entry)) {
Packit Service 1d0348
		case AE_IFREG: tartype = '0' ; break;
Packit Service 1d0348
		case AE_IFLNK: tartype = '2' ; break;
Packit Service 1d0348
		case AE_IFCHR: tartype = '3' ; break;
Packit Service 1d0348
		case AE_IFBLK: tartype = '4' ; break;
Packit Service 1d0348
		case AE_IFDIR: tartype = '5' ; break;
Packit Service 1d0348
		case AE_IFIFO: tartype = '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
			ret = ARCHIVE_FAILED;
Packit Service 1d0348
			goto exit_write_header;
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
			goto exit_write_header;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
	ret = archive_format_gnutar_header(a, buff, entry, tartype);
Packit Service 1d0348
	if (ret < ARCHIVE_WARN)
Packit Service 1d0348
		goto exit_write_header;
Packit Service 1d0348
	if (ret2 < ret)
Packit Service 1d0348
		ret = ret2;
Packit Service 1d0348
	ret2 = __archive_write_output(a, buff, 512);
Packit Service 1d0348
	if (ret2 < ARCHIVE_WARN) {
Packit Service 1d0348
		ret = ret2;
Packit Service 1d0348
		goto exit_write_header;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (ret2 < ret)
Packit Service 1d0348
		ret = ret2;
Packit Service 1d0348
Packit Service 1d0348
	gnutar->entry_bytes_remaining = archive_entry_size(entry);
Packit Service 1d0348
	gnutar->entry_padding = 0x1ff & (-(int64_t)gnutar->entry_bytes_remaining);
Packit Service 1d0348
exit_write_header:
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
static int
Packit Service 1d0348
archive_format_gnutar_header(struct archive_write *a, char h[512],
Packit Service 1d0348
    struct archive_entry *entry, int tartype)
Packit Service 1d0348
{
Packit Service 1d0348
	unsigned int checksum;
Packit Service 1d0348
	int i, ret;
Packit Service 1d0348
	size_t copy_length;
Packit Service 1d0348
	const char *p;
Packit Service 1d0348
	struct gnutar *gnutar;
Packit Service 1d0348
Packit Service 1d0348
	gnutar = (struct gnutar *)a->format_data;
Packit Service 1d0348
Packit Service 1d0348
	ret = 0;
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * The "template header" already includes the signature,
Packit Service 1d0348
	 * various end-of-field markers, and other required 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
Packit Service 1d0348
	if (tartype == 'K' || tartype == 'L') {
Packit Service 1d0348
		p = archive_entry_pathname(entry);
Packit Service 1d0348
		copy_length = strlen(p);
Packit Service 1d0348
	} else {
Packit Service 1d0348
		p = gnutar->pathname;
Packit Service 1d0348
		copy_length = gnutar->pathname_length;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (copy_length > GNUTAR_name_size)
Packit Service 1d0348
		copy_length = GNUTAR_name_size;
Packit Service 1d0348
	memcpy(h + GNUTAR_name_offset, p, copy_length);
Packit Service 1d0348
Packit Service 1d0348
	if ((copy_length = gnutar->linkname_length) > 0) {
Packit Service 1d0348
		if (copy_length > GNUTAR_linkname_size)
Packit Service 1d0348
			copy_length = GNUTAR_linkname_size;
Packit Service 1d0348
		memcpy(h + GNUTAR_linkname_offset, gnutar->linkname,
Packit Service 1d0348
		    copy_length);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* TODO: How does GNU tar handle unames longer than GNUTAR_uname_size? */
Packit Service 1d0348
	if (tartype == 'K' || tartype == 'L') {
Packit Service 1d0348
		p = archive_entry_uname(entry);
Packit Service 1d0348
		copy_length = strlen(p);
Packit Service 1d0348
	} else {
Packit Service 1d0348
		p = gnutar->uname;
Packit Service 1d0348
		copy_length = gnutar->uname_length;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (copy_length > 0) {
Packit Service 1d0348
		if (copy_length > GNUTAR_uname_size)
Packit Service 1d0348
			copy_length = GNUTAR_uname_size;
Packit Service 1d0348
		memcpy(h + GNUTAR_uname_offset, p, copy_length);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* TODO: How does GNU tar handle gnames longer than GNUTAR_gname_size? */
Packit Service 1d0348
	if (tartype == 'K' || tartype == 'L') {
Packit Service 1d0348
		p = archive_entry_gname(entry);
Packit Service 1d0348
		copy_length = strlen(p);
Packit Service 1d0348
	} else {
Packit Service 1d0348
		p = gnutar->gname;
Packit Service 1d0348
		copy_length = gnutar->gname_length;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (copy_length > 0) {
Packit Service 1d0348
		if (strlen(p) > GNUTAR_gname_size)
Packit Service 1d0348
			copy_length = GNUTAR_gname_size;
Packit Service 1d0348
		memcpy(h + GNUTAR_gname_offset, p, copy_length);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* By truncating the mode here, we ensure it always fits. */
Packit Service 1d0348
	format_octal(archive_entry_mode(entry) & 07777,
Packit Service 1d0348
	    h + GNUTAR_mode_offset, GNUTAR_mode_size);
Packit Service 1d0348
Packit Service 1d0348
	/* GNU tar supports base-256 here, so should never overflow. */
Packit Service 1d0348
	if (format_number(archive_entry_uid(entry), h + GNUTAR_uid_offset,
Packit Service 1d0348
		GNUTAR_uid_size, GNUTAR_uid_max_size)) {
Packit Service 1d0348
		archive_set_error(&a->archive, ERANGE,
Packit Service 1d0348
		    "Numeric user ID %jd too large",
Packit Service 1d0348
		    (intmax_t)archive_entry_uid(entry));
Packit Service 1d0348
		ret = ARCHIVE_FAILED;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* GNU tar supports base-256 here, so should never overflow. */
Packit Service 1d0348
	if (format_number(archive_entry_gid(entry), h + GNUTAR_gid_offset,
Packit Service 1d0348
		GNUTAR_gid_size, GNUTAR_gid_max_size)) {
Packit Service 1d0348
		archive_set_error(&a->archive, ERANGE,
Packit Service 1d0348
		    "Numeric group ID %jd too large",
Packit Service 1d0348
		    (intmax_t)archive_entry_gid(entry));
Packit Service 1d0348
		ret = ARCHIVE_FAILED;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* GNU tar supports base-256 here, so should never overflow. */
Packit Service 1d0348
	if (format_number(archive_entry_size(entry), h + GNUTAR_size_offset,
Packit Service 1d0348
		GNUTAR_size_size, GNUTAR_size_max_size)) {
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
	/* Shouldn't overflow before 2106, since mtime field is 33 bits. */
Packit Service 1d0348
	format_octal(archive_entry_mtime(entry),
Packit Service 1d0348
	    h + GNUTAR_mtime_offset, GNUTAR_mtime_size);
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_octal(archive_entry_rdevmajor(entry),
Packit Service 1d0348
		    h + GNUTAR_rdevmajor_offset,
Packit Service 1d0348
			GNUTAR_rdevmajor_size)) {
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_octal(archive_entry_rdevminor(entry),
Packit Service 1d0348
		    h + GNUTAR_rdevminor_offset,
Packit Service 1d0348
			GNUTAR_rdevminor_size)) {
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
	h[GNUTAR_typeflag_offset] = tartype;
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[GNUTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */
Packit Service 1d0348
	/* h[GNUTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */
Packit Service 1d0348
	format_octal(checksum, h + GNUTAR_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, falling back to base-256 if necessary.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
format_number(int64_t v, char *p, int s, int maxsize)
Packit Service 1d0348
{
Packit Service 1d0348
	int64_t limit = ((int64_t)1 << (s*3));
Packit Service 1d0348
Packit Service 1d0348
	if (v < limit)
Packit Service 1d0348
		return (format_octal(v, p, s));
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 using octal.
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 = 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
		v = 0;
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
}