1caf54c4fSMartin Matuska /*- 2caf54c4fSMartin Matuska * Copyright (c) 2003-2007 Tim Kientzle 3caf54c4fSMartin Matuska * Copyright (c) 2006 Rudolf Marek SYSGO s.r.o. 46c95142eSMartin Matuska * Copyright (c) 2011-2012 Michihiro NAKAJIMA 5caf54c4fSMartin Matuska * All rights reserved. 6caf54c4fSMartin Matuska * 7caf54c4fSMartin Matuska * Redistribution and use in source and binary forms, with or without 8caf54c4fSMartin Matuska * modification, are permitted provided that the following conditions 9caf54c4fSMartin Matuska * are met: 10caf54c4fSMartin Matuska * 1. Redistributions of source code must retain the above copyright 11caf54c4fSMartin Matuska * notice, this list of conditions and the following disclaimer. 12caf54c4fSMartin Matuska * 2. Redistributions in binary form must reproduce the above copyright 13caf54c4fSMartin Matuska * notice, this list of conditions and the following disclaimer in the 14caf54c4fSMartin Matuska * documentation and/or other materials provided with the distribution. 15caf54c4fSMartin Matuska * 16caf54c4fSMartin Matuska * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17caf54c4fSMartin Matuska * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18caf54c4fSMartin Matuska * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19caf54c4fSMartin Matuska * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20caf54c4fSMartin Matuska * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21caf54c4fSMartin Matuska * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22caf54c4fSMartin Matuska * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23caf54c4fSMartin Matuska * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24caf54c4fSMartin Matuska * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25caf54c4fSMartin Matuska * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26caf54c4fSMartin Matuska */ 27caf54c4fSMartin Matuska 28caf54c4fSMartin Matuska #include "archive_platform.h" 296c22d9efSMartin Matuska __FBSDID("$FreeBSD$"); 30caf54c4fSMartin Matuska 31caf54c4fSMartin Matuska #ifdef HAVE_ERRNO_H 32caf54c4fSMartin Matuska #include <errno.h> 33caf54c4fSMartin Matuska #endif 34caf54c4fSMartin Matuska #include <stdio.h> 35caf54c4fSMartin Matuska #ifdef HAVE_STDLIB_H 36caf54c4fSMartin Matuska #include <stdlib.h> 37caf54c4fSMartin Matuska #endif 38caf54c4fSMartin Matuska #ifdef HAVE_STRING_H 39caf54c4fSMartin Matuska #include <string.h> 40caf54c4fSMartin Matuska #endif 41caf54c4fSMartin Matuska 42caf54c4fSMartin Matuska #include "archive.h" 43caf54c4fSMartin Matuska #include "archive_entry.h" 446c95142eSMartin Matuska #include "archive_entry_locale.h" 45caf54c4fSMartin Matuska #include "archive_private.h" 46caf54c4fSMartin Matuska #include "archive_write_private.h" 47caf54c4fSMartin Matuska 48caf54c4fSMartin Matuska static ssize_t archive_write_newc_data(struct archive_write *, 49caf54c4fSMartin Matuska const void *buff, size_t s); 506c95142eSMartin Matuska static int archive_write_newc_close(struct archive_write *); 516c95142eSMartin Matuska static int archive_write_newc_free(struct archive_write *); 52caf54c4fSMartin Matuska static int archive_write_newc_finish_entry(struct archive_write *); 53caf54c4fSMartin Matuska static int archive_write_newc_header(struct archive_write *, 54caf54c4fSMartin Matuska struct archive_entry *); 556c95142eSMartin Matuska static int archive_write_newc_options(struct archive_write *, 566c95142eSMartin Matuska const char *, const char *); 57caf54c4fSMartin Matuska static int format_hex(int64_t, void *, int); 58caf54c4fSMartin Matuska static int64_t format_hex_recursive(int64_t, char *, int); 596c95142eSMartin Matuska static int write_header(struct archive_write *, struct archive_entry *); 60caf54c4fSMartin Matuska 61caf54c4fSMartin Matuska struct cpio { 62caf54c4fSMartin Matuska uint64_t entry_bytes_remaining; 63caf54c4fSMartin Matuska int padding; 646c95142eSMartin Matuska 656c95142eSMartin Matuska struct archive_string_conv *opt_sconv; 666c95142eSMartin Matuska struct archive_string_conv *sconv_default; 676c95142eSMartin Matuska int init_default_conversion; 68caf54c4fSMartin Matuska }; 69caf54c4fSMartin Matuska 706c95142eSMartin Matuska #define c_magic_offset 0 716c95142eSMartin Matuska #define c_magic_size 6 726c95142eSMartin Matuska #define c_ino_offset 6 736c95142eSMartin Matuska #define c_ino_size 8 746c95142eSMartin Matuska #define c_mode_offset 14 756c95142eSMartin Matuska #define c_mode_size 8 766c95142eSMartin Matuska #define c_uid_offset 22 776c95142eSMartin Matuska #define c_uid_size 8 786c95142eSMartin Matuska #define c_gid_offset 30 796c95142eSMartin Matuska #define c_gid_size 8 806c95142eSMartin Matuska #define c_nlink_offset 38 816c95142eSMartin Matuska #define c_nlink_size 8 826c95142eSMartin Matuska #define c_mtime_offset 46 836c95142eSMartin Matuska #define c_mtime_size 8 846c95142eSMartin Matuska #define c_filesize_offset 54 856c95142eSMartin Matuska #define c_filesize_size 8 866c95142eSMartin Matuska #define c_devmajor_offset 62 876c95142eSMartin Matuska #define c_devmajor_size 8 886c95142eSMartin Matuska #define c_devminor_offset 70 896c95142eSMartin Matuska #define c_devminor_size 8 906c95142eSMartin Matuska #define c_rdevmajor_offset 78 916c95142eSMartin Matuska #define c_rdevmajor_size 8 926c95142eSMartin Matuska #define c_rdevminor_offset 86 936c95142eSMartin Matuska #define c_rdevminor_size 8 946c95142eSMartin Matuska #define c_namesize_offset 94 956c95142eSMartin Matuska #define c_namesize_size 8 966c95142eSMartin Matuska #define c_checksum_offset 102 976c95142eSMartin Matuska #define c_checksum_size 8 986c95142eSMartin Matuska #define c_header_size 110 99caf54c4fSMartin Matuska 100caf54c4fSMartin Matuska /* Logic trick: difference between 'n' and next multiple of 4 */ 101caf54c4fSMartin Matuska #define PAD4(n) (3 & (1 + ~(n))) 102caf54c4fSMartin Matuska 103caf54c4fSMartin Matuska /* 104caf54c4fSMartin Matuska * Set output format to 'cpio' format. 105caf54c4fSMartin Matuska */ 106caf54c4fSMartin Matuska int 107caf54c4fSMartin Matuska archive_write_set_format_cpio_newc(struct archive *_a) 108caf54c4fSMartin Matuska { 109caf54c4fSMartin Matuska struct archive_write *a = (struct archive_write *)_a; 110caf54c4fSMartin Matuska struct cpio *cpio; 111caf54c4fSMartin Matuska 1126c95142eSMartin Matuska archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 1136c95142eSMartin Matuska ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_newc"); 1146c95142eSMartin Matuska 115caf54c4fSMartin Matuska /* If someone else was already registered, unregister them. */ 1166c95142eSMartin Matuska if (a->format_free != NULL) 1176c95142eSMartin Matuska (a->format_free)(a); 118caf54c4fSMartin Matuska 119caf54c4fSMartin Matuska cpio = (struct cpio *)malloc(sizeof(*cpio)); 120caf54c4fSMartin Matuska if (cpio == NULL) { 121caf54c4fSMartin Matuska archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); 122caf54c4fSMartin Matuska return (ARCHIVE_FATAL); 123caf54c4fSMartin Matuska } 124caf54c4fSMartin Matuska memset(cpio, 0, sizeof(*cpio)); 125caf54c4fSMartin Matuska a->format_data = cpio; 126caf54c4fSMartin Matuska a->format_name = "cpio"; 1276c95142eSMartin Matuska a->format_options = archive_write_newc_options; 128caf54c4fSMartin Matuska a->format_write_header = archive_write_newc_header; 129caf54c4fSMartin Matuska a->format_write_data = archive_write_newc_data; 130caf54c4fSMartin Matuska a->format_finish_entry = archive_write_newc_finish_entry; 1316c95142eSMartin Matuska a->format_close = archive_write_newc_close; 1326c95142eSMartin Matuska a->format_free = archive_write_newc_free; 133caf54c4fSMartin Matuska a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC; 134caf54c4fSMartin Matuska a->archive.archive_format_name = "SVR4 cpio nocrc"; 135caf54c4fSMartin Matuska return (ARCHIVE_OK); 136caf54c4fSMartin Matuska } 137caf54c4fSMartin Matuska 138caf54c4fSMartin Matuska static int 1396c95142eSMartin Matuska archive_write_newc_options(struct archive_write *a, const char *key, 1406c95142eSMartin Matuska const char *val) 1416c95142eSMartin Matuska { 1426c95142eSMartin Matuska struct cpio *cpio = (struct cpio *)a->format_data; 1436c95142eSMartin Matuska int ret = ARCHIVE_FAILED; 1446c95142eSMartin Matuska 1456c95142eSMartin Matuska if (strcmp(key, "hdrcharset") == 0) { 1466c95142eSMartin Matuska if (val == NULL || val[0] == 0) 1476c95142eSMartin Matuska archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1486c95142eSMartin Matuska "%s: hdrcharset option needs a character-set name", 1496c95142eSMartin Matuska a->format_name); 1506c95142eSMartin Matuska else { 1516c95142eSMartin Matuska cpio->opt_sconv = archive_string_conversion_to_charset( 1526c95142eSMartin Matuska &a->archive, val, 0); 1536c95142eSMartin Matuska if (cpio->opt_sconv != NULL) 1546c95142eSMartin Matuska ret = ARCHIVE_OK; 1556c95142eSMartin Matuska else 1566c95142eSMartin Matuska ret = ARCHIVE_FATAL; 1576c95142eSMartin Matuska } 1586c95142eSMartin Matuska return (ret); 1596c95142eSMartin Matuska } 1606c95142eSMartin Matuska 1616c95142eSMartin Matuska /* Note: The "warn" return is just to inform the options 1626c95142eSMartin Matuska * supervisor that we didn't handle it. It will generate 1636c95142eSMartin Matuska * a suitable error if no one used this option. */ 1646c95142eSMartin Matuska return (ARCHIVE_WARN); 1656c95142eSMartin Matuska } 1666c95142eSMartin Matuska 1676c95142eSMartin Matuska static struct archive_string_conv * 1686c95142eSMartin Matuska get_sconv(struct archive_write *a) 1696c95142eSMartin Matuska { 1706c95142eSMartin Matuska struct cpio *cpio; 1716c95142eSMartin Matuska struct archive_string_conv *sconv; 1726c95142eSMartin Matuska 1736c95142eSMartin Matuska cpio = (struct cpio *)a->format_data; 1746c95142eSMartin Matuska sconv = cpio->opt_sconv; 1756c95142eSMartin Matuska if (sconv == NULL) { 1766c95142eSMartin Matuska if (!cpio->init_default_conversion) { 1776c95142eSMartin Matuska cpio->sconv_default = 1786c95142eSMartin Matuska archive_string_default_conversion_for_write( 1796c95142eSMartin Matuska &(a->archive)); 1806c95142eSMartin Matuska cpio->init_default_conversion = 1; 1816c95142eSMartin Matuska } 1826c95142eSMartin Matuska sconv = cpio->sconv_default; 1836c95142eSMartin Matuska } 1846c95142eSMartin Matuska return (sconv); 1856c95142eSMartin Matuska } 1866c95142eSMartin Matuska 1876c95142eSMartin Matuska static int 188caf54c4fSMartin Matuska archive_write_newc_header(struct archive_write *a, struct archive_entry *entry) 189caf54c4fSMartin Matuska { 1906c95142eSMartin Matuska const char *path; 1916c95142eSMartin Matuska size_t len; 1926c95142eSMartin Matuska 1936c95142eSMartin Matuska if (archive_entry_filetype(entry) == 0) { 1946c95142eSMartin Matuska archive_set_error(&a->archive, -1, "Filetype required"); 1956c95142eSMartin Matuska return (ARCHIVE_FAILED); 1966c95142eSMartin Matuska } 1976c95142eSMartin Matuska 1986c95142eSMartin Matuska if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0 1996c95142eSMartin Matuska && errno == ENOMEM) { 2006c95142eSMartin Matuska archive_set_error(&a->archive, ENOMEM, 2016c95142eSMartin Matuska "Can't allocate memory for Pathname"); 2026c95142eSMartin Matuska return (ARCHIVE_FATAL); 2036c95142eSMartin Matuska } 2046c95142eSMartin Matuska if (len == 0 || path == NULL || path[0] == '\0') { 2056c95142eSMartin Matuska archive_set_error(&a->archive, -1, "Pathname required"); 2066c95142eSMartin Matuska return (ARCHIVE_FAILED); 2076c95142eSMartin Matuska } 2086c95142eSMartin Matuska 2096c95142eSMartin Matuska if (archive_entry_hardlink(entry) == NULL 2106c95142eSMartin Matuska && (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0)) { 2116c95142eSMartin Matuska archive_set_error(&a->archive, -1, "Size required"); 2126c95142eSMartin Matuska return (ARCHIVE_FAILED); 2136c95142eSMartin Matuska } 2146c95142eSMartin Matuska return write_header(a, entry); 2156c95142eSMartin Matuska } 2166c95142eSMartin Matuska 2176c95142eSMartin Matuska static int 2186c95142eSMartin Matuska write_header(struct archive_write *a, struct archive_entry *entry) 2196c95142eSMartin Matuska { 220caf54c4fSMartin Matuska int64_t ino; 221caf54c4fSMartin Matuska struct cpio *cpio; 222caf54c4fSMartin Matuska const char *p, *path; 2236c95142eSMartin Matuska int pathlength, ret, ret_final; 2246c95142eSMartin Matuska char h[c_header_size]; 2256c95142eSMartin Matuska struct archive_string_conv *sconv; 2266c95142eSMartin Matuska struct archive_entry *entry_main; 2276c95142eSMartin Matuska size_t len; 228caf54c4fSMartin Matuska int pad; 229caf54c4fSMartin Matuska 230caf54c4fSMartin Matuska cpio = (struct cpio *)a->format_data; 2316c95142eSMartin Matuska ret_final = ARCHIVE_OK; 2326c95142eSMartin Matuska sconv = get_sconv(a); 233caf54c4fSMartin Matuska 2346c95142eSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__) 2356c95142eSMartin Matuska /* Make sure the path separators in pahtname, hardlink and symlink 2366c95142eSMartin Matuska * are all slash '/', not the Windows path separator '\'. */ 2376c95142eSMartin Matuska entry_main = __la_win_entry_in_posix_pathseparator(entry); 2386c95142eSMartin Matuska if (entry_main == NULL) { 2396c95142eSMartin Matuska archive_set_error(&a->archive, ENOMEM, 2406c95142eSMartin Matuska "Can't allocate ustar data"); 2416c95142eSMartin Matuska return(ARCHIVE_FATAL); 2426c95142eSMartin Matuska } 2436c95142eSMartin Matuska if (entry != entry_main) 2446c95142eSMartin Matuska entry = entry_main; 2456c95142eSMartin Matuska else 2466c95142eSMartin Matuska entry_main = NULL; 2476c95142eSMartin Matuska #else 2486c95142eSMartin Matuska entry_main = NULL; 2496c95142eSMartin Matuska #endif 250caf54c4fSMartin Matuska 2516c95142eSMartin Matuska ret = archive_entry_pathname_l(entry, &path, &len, sconv); 2526c95142eSMartin Matuska if (ret != 0) { 2536c95142eSMartin Matuska if (errno == ENOMEM) { 2546c95142eSMartin Matuska archive_set_error(&a->archive, ENOMEM, 2556c95142eSMartin Matuska "Can't allocate memory for Pathname"); 2566c95142eSMartin Matuska ret_final = ARCHIVE_FATAL; 2576c95142eSMartin Matuska goto exit_write_header; 2586c95142eSMartin Matuska } 2596c95142eSMartin Matuska archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 2606c95142eSMartin Matuska "Can't translate pathname '%s' to %s", 2616c95142eSMartin Matuska archive_entry_pathname(entry), 2626c95142eSMartin Matuska archive_string_conversion_charset_name(sconv)); 2636c95142eSMartin Matuska ret_final = ARCHIVE_WARN; 2646c95142eSMartin Matuska } 2656c95142eSMartin Matuska pathlength = (int)len + 1; /* Include trailing null. */ 2666c95142eSMartin Matuska 2676c95142eSMartin Matuska memset(h, 0, c_header_size); 2686c95142eSMartin Matuska format_hex(0x070701, h + c_magic_offset, c_magic_size); 2696c95142eSMartin Matuska format_hex(archive_entry_devmajor(entry), h + c_devmajor_offset, 2706c95142eSMartin Matuska c_devmajor_size); 2716c95142eSMartin Matuska format_hex(archive_entry_devminor(entry), h + c_devminor_offset, 2726c95142eSMartin Matuska c_devminor_size); 273caf54c4fSMartin Matuska 274caf54c4fSMartin Matuska ino = archive_entry_ino64(entry); 275caf54c4fSMartin Matuska if (ino > 0xffffffff) { 276caf54c4fSMartin Matuska archive_set_error(&a->archive, ERANGE, 277caf54c4fSMartin Matuska "large inode number truncated"); 2786c95142eSMartin Matuska ret_final = ARCHIVE_WARN; 279caf54c4fSMartin Matuska } 280caf54c4fSMartin Matuska 2816c95142eSMartin Matuska /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */ 2826c95142eSMartin Matuska format_hex(ino & 0xffffffff, h + c_ino_offset, c_ino_size); 2836c95142eSMartin Matuska format_hex(archive_entry_mode(entry), h + c_mode_offset, c_mode_size); 2846c95142eSMartin Matuska format_hex(archive_entry_uid(entry), h + c_uid_offset, c_uid_size); 2856c95142eSMartin Matuska format_hex(archive_entry_gid(entry), h + c_gid_offset, c_gid_size); 2866c95142eSMartin Matuska format_hex(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size); 287caf54c4fSMartin Matuska if (archive_entry_filetype(entry) == AE_IFBLK 288caf54c4fSMartin Matuska || archive_entry_filetype(entry) == AE_IFCHR) { 2896c95142eSMartin Matuska format_hex(archive_entry_rdevmajor(entry), h + c_rdevmajor_offset, c_rdevmajor_size); 2906c95142eSMartin Matuska format_hex(archive_entry_rdevminor(entry), h + c_rdevminor_offset, c_rdevminor_size); 291caf54c4fSMartin Matuska } else { 2926c95142eSMartin Matuska format_hex(0, h + c_rdevmajor_offset, c_rdevmajor_size); 2936c95142eSMartin Matuska format_hex(0, h + c_rdevminor_offset, c_rdevminor_size); 294caf54c4fSMartin Matuska } 2956c95142eSMartin Matuska format_hex(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size); 2966c95142eSMartin Matuska format_hex(pathlength, h + c_namesize_offset, c_namesize_size); 2976c95142eSMartin Matuska format_hex(0, h + c_checksum_offset, c_checksum_size); 298caf54c4fSMartin Matuska 299caf54c4fSMartin Matuska /* Non-regular files don't store bodies. */ 300caf54c4fSMartin Matuska if (archive_entry_filetype(entry) != AE_IFREG) 301caf54c4fSMartin Matuska archive_entry_set_size(entry, 0); 302caf54c4fSMartin Matuska 303caf54c4fSMartin Matuska /* Symlinks get the link written as the body of the entry. */ 3046c95142eSMartin Matuska ret = archive_entry_symlink_l(entry, &p, &len, sconv); 3056c95142eSMartin Matuska if (ret != 0) { 3066c95142eSMartin Matuska if (errno == ENOMEM) { 3076c95142eSMartin Matuska archive_set_error(&a->archive, ENOMEM, 3086c95142eSMartin Matuska "Can't allocate memory for Likname"); 3096c95142eSMartin Matuska ret_final = ARCHIVE_FATAL; 3106c95142eSMartin Matuska goto exit_write_header; 3116c95142eSMartin Matuska } 3126c95142eSMartin Matuska archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 3136c95142eSMartin Matuska "Can't translate linkname '%s' to %s", 3146c95142eSMartin Matuska archive_entry_symlink(entry), 3156c95142eSMartin Matuska archive_string_conversion_charset_name(sconv)); 3166c95142eSMartin Matuska ret_final = ARCHIVE_WARN; 3176c95142eSMartin Matuska } 3186c95142eSMartin Matuska if (len > 0 && p != NULL && *p != '\0') 3196c95142eSMartin Matuska ret = format_hex(strlen(p), h + c_filesize_offset, 3206c95142eSMartin Matuska c_filesize_size); 321caf54c4fSMartin Matuska else 3226c95142eSMartin Matuska ret = format_hex(archive_entry_size(entry), 3236c95142eSMartin Matuska h + c_filesize_offset, c_filesize_size); 3246c95142eSMartin Matuska if (ret) { 3256c95142eSMartin Matuska archive_set_error(&a->archive, ERANGE, 3266c95142eSMartin Matuska "File is too large for this format."); 3276c95142eSMartin Matuska ret_final = ARCHIVE_FAILED; 3286c95142eSMartin Matuska goto exit_write_header; 3296c95142eSMartin Matuska } 330caf54c4fSMartin Matuska 3316c95142eSMartin Matuska ret = __archive_write_output(a, h, c_header_size); 3326c95142eSMartin Matuska if (ret != ARCHIVE_OK) { 3336c95142eSMartin Matuska ret_final = ARCHIVE_FATAL; 3346c95142eSMartin Matuska goto exit_write_header; 3356c95142eSMartin Matuska } 336caf54c4fSMartin Matuska 337caf54c4fSMartin Matuska /* Pad pathname to even length. */ 3386c95142eSMartin Matuska ret = __archive_write_output(a, path, pathlength); 3396c95142eSMartin Matuska if (ret != ARCHIVE_OK) { 3406c95142eSMartin Matuska ret_final = ARCHIVE_FATAL; 3416c95142eSMartin Matuska goto exit_write_header; 3426c95142eSMartin Matuska } 3436c95142eSMartin Matuska pad = PAD4(pathlength + c_header_size); 3446c95142eSMartin Matuska if (pad) { 3456c95142eSMartin Matuska ret = __archive_write_output(a, "\0\0\0", pad); 3466c95142eSMartin Matuska if (ret != ARCHIVE_OK) { 3476c95142eSMartin Matuska ret_final = ARCHIVE_FATAL; 3486c95142eSMartin Matuska goto exit_write_header; 3496c95142eSMartin Matuska } 3506c95142eSMartin Matuska } 351caf54c4fSMartin Matuska 352caf54c4fSMartin Matuska cpio->entry_bytes_remaining = archive_entry_size(entry); 353fd082e96SMartin Matuska cpio->padding = (int)PAD4(cpio->entry_bytes_remaining); 354caf54c4fSMartin Matuska 355caf54c4fSMartin Matuska /* Write the symlink now. */ 356caf54c4fSMartin Matuska if (p != NULL && *p != '\0') { 3576c95142eSMartin Matuska ret = __archive_write_output(a, p, strlen(p)); 3586c95142eSMartin Matuska if (ret != ARCHIVE_OK) { 3596c95142eSMartin Matuska ret_final = ARCHIVE_FATAL; 3606c95142eSMartin Matuska goto exit_write_header; 361caf54c4fSMartin Matuska } 3626c95142eSMartin Matuska pad = PAD4(strlen(p)); 3636c95142eSMartin Matuska ret = __archive_write_output(a, "\0\0\0", pad); 3646c95142eSMartin Matuska if (ret != ARCHIVE_OK) { 3656c95142eSMartin Matuska ret_final = ARCHIVE_FATAL; 3666c95142eSMartin Matuska goto exit_write_header; 3676c95142eSMartin Matuska } 3686c95142eSMartin Matuska } 3696c95142eSMartin Matuska exit_write_header: 3706c95142eSMartin Matuska if (entry_main) 3716c95142eSMartin Matuska archive_entry_free(entry_main); 3726c95142eSMartin Matuska return (ret_final); 373caf54c4fSMartin Matuska } 374caf54c4fSMartin Matuska 375caf54c4fSMartin Matuska static ssize_t 376caf54c4fSMartin Matuska archive_write_newc_data(struct archive_write *a, const void *buff, size_t s) 377caf54c4fSMartin Matuska { 378caf54c4fSMartin Matuska struct cpio *cpio; 379caf54c4fSMartin Matuska int ret; 380caf54c4fSMartin Matuska 381caf54c4fSMartin Matuska cpio = (struct cpio *)a->format_data; 382caf54c4fSMartin Matuska if (s > cpio->entry_bytes_remaining) 383fd082e96SMartin Matuska s = (size_t)cpio->entry_bytes_remaining; 384caf54c4fSMartin Matuska 3856c95142eSMartin Matuska ret = __archive_write_output(a, buff, s); 386caf54c4fSMartin Matuska cpio->entry_bytes_remaining -= s; 387caf54c4fSMartin Matuska if (ret >= 0) 388caf54c4fSMartin Matuska return (s); 389caf54c4fSMartin Matuska else 390caf54c4fSMartin Matuska return (ret); 391caf54c4fSMartin Matuska } 392caf54c4fSMartin Matuska 393caf54c4fSMartin Matuska /* 394caf54c4fSMartin Matuska * Format a number into the specified field. 395caf54c4fSMartin Matuska */ 396caf54c4fSMartin Matuska static int 397caf54c4fSMartin Matuska format_hex(int64_t v, void *p, int digits) 398caf54c4fSMartin Matuska { 399caf54c4fSMartin Matuska int64_t max; 400caf54c4fSMartin Matuska int ret; 401caf54c4fSMartin Matuska 402caf54c4fSMartin Matuska max = (((int64_t)1) << (digits * 4)) - 1; 403caf54c4fSMartin Matuska if (v >= 0 && v <= max) { 404caf54c4fSMartin Matuska format_hex_recursive(v, (char *)p, digits); 405caf54c4fSMartin Matuska ret = 0; 406caf54c4fSMartin Matuska } else { 407caf54c4fSMartin Matuska format_hex_recursive(max, (char *)p, digits); 408caf54c4fSMartin Matuska ret = -1; 409caf54c4fSMartin Matuska } 410caf54c4fSMartin Matuska return (ret); 411caf54c4fSMartin Matuska } 412caf54c4fSMartin Matuska 413caf54c4fSMartin Matuska static int64_t 414caf54c4fSMartin Matuska format_hex_recursive(int64_t v, char *p, int s) 415caf54c4fSMartin Matuska { 416caf54c4fSMartin Matuska if (s == 0) 417caf54c4fSMartin Matuska return (v); 418caf54c4fSMartin Matuska v = format_hex_recursive(v, p+1, s-1); 419caf54c4fSMartin Matuska *p = "0123456789abcdef"[v & 0xf]; 420caf54c4fSMartin Matuska return (v >> 4); 421caf54c4fSMartin Matuska } 422caf54c4fSMartin Matuska 423caf54c4fSMartin Matuska static int 4246c95142eSMartin Matuska archive_write_newc_close(struct archive_write *a) 425caf54c4fSMartin Matuska { 426caf54c4fSMartin Matuska int er; 427caf54c4fSMartin Matuska struct archive_entry *trailer; 428caf54c4fSMartin Matuska 429caf54c4fSMartin Matuska trailer = archive_entry_new(); 430caf54c4fSMartin Matuska archive_entry_set_nlink(trailer, 1); 4316c95142eSMartin Matuska archive_entry_set_size(trailer, 0); 432caf54c4fSMartin Matuska archive_entry_set_pathname(trailer, "TRAILER!!!"); 4336c95142eSMartin Matuska /* Bypass the required data checks. */ 4346c95142eSMartin Matuska er = write_header(a, trailer); 435caf54c4fSMartin Matuska archive_entry_free(trailer); 436caf54c4fSMartin Matuska return (er); 437caf54c4fSMartin Matuska } 438caf54c4fSMartin Matuska 439caf54c4fSMartin Matuska static int 4406c95142eSMartin Matuska archive_write_newc_free(struct archive_write *a) 441caf54c4fSMartin Matuska { 442caf54c4fSMartin Matuska struct cpio *cpio; 443caf54c4fSMartin Matuska 444caf54c4fSMartin Matuska cpio = (struct cpio *)a->format_data; 445caf54c4fSMartin Matuska free(cpio); 446caf54c4fSMartin Matuska a->format_data = NULL; 447caf54c4fSMartin Matuska return (ARCHIVE_OK); 448caf54c4fSMartin Matuska } 449caf54c4fSMartin Matuska 450caf54c4fSMartin Matuska static int 451caf54c4fSMartin Matuska archive_write_newc_finish_entry(struct archive_write *a) 452caf54c4fSMartin Matuska { 453caf54c4fSMartin Matuska struct cpio *cpio; 454caf54c4fSMartin Matuska 455caf54c4fSMartin Matuska cpio = (struct cpio *)a->format_data; 456fd082e96SMartin Matuska return (__archive_write_nulls(a, 457fd082e96SMartin Matuska (size_t)cpio->entry_bytes_remaining + cpio->padding)); 458caf54c4fSMartin Matuska } 459