1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3232153Smm * Copyright (c) 2011-2012 Michihiro NAKAJIMA 4228753Smm * All rights reserved. 5228753Smm * 6228753Smm * Redistribution and use in source and binary forms, with or without 7228753Smm * modification, are permitted provided that the following conditions 8228753Smm * are met: 9228753Smm * 1. Redistributions of source code must retain the above copyright 10228753Smm * notice, this list of conditions and the following disclaimer. 11228753Smm * 2. Redistributions in binary form must reproduce the above copyright 12228753Smm * notice, this list of conditions and the following disclaimer in the 13228753Smm * documentation and/or other materials provided with the distribution. 14228753Smm * 15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25228753Smm */ 26228753Smm 27228753Smm#include "archive_platform.h" 28228763Smm__FBSDID("$FreeBSD: releng/10.3/contrib/libarchive/libarchive/archive_write_set_format_cpio.c 238856 2012-07-28 06:38:44Z mm $"); 29228753Smm 30228753Smm#ifdef HAVE_ERRNO_H 31228753Smm#include <errno.h> 32228753Smm#endif 33228753Smm#include <stdio.h> 34228753Smm#ifdef HAVE_STDLIB_H 35228753Smm#include <stdlib.h> 36228753Smm#endif 37228753Smm#ifdef HAVE_STRING_H 38228753Smm#include <string.h> 39228753Smm#endif 40228753Smm 41228753Smm#include "archive.h" 42228753Smm#include "archive_entry.h" 43232153Smm#include "archive_entry_locale.h" 44228753Smm#include "archive_private.h" 45228753Smm#include "archive_write_private.h" 46228753Smm 47228753Smmstatic ssize_t archive_write_cpio_data(struct archive_write *, 48228753Smm const void *buff, size_t s); 49232153Smmstatic int archive_write_cpio_close(struct archive_write *); 50232153Smmstatic int archive_write_cpio_free(struct archive_write *); 51228753Smmstatic int archive_write_cpio_finish_entry(struct archive_write *); 52228753Smmstatic int archive_write_cpio_header(struct archive_write *, 53228753Smm struct archive_entry *); 54232153Smmstatic int archive_write_cpio_options(struct archive_write *, 55232153Smm const char *, const char *); 56228753Smmstatic int format_octal(int64_t, void *, int); 57228753Smmstatic int64_t format_octal_recursive(int64_t, char *, int); 58232153Smmstatic int write_header(struct archive_write *, struct archive_entry *); 59228753Smm 60228753Smmstruct cpio { 61228753Smm uint64_t entry_bytes_remaining; 62228753Smm 63228753Smm int64_t ino_next; 64228753Smm 65228753Smm struct { int64_t old; int new;} *ino_list; 66228753Smm size_t ino_list_size; 67228753Smm size_t ino_list_next; 68232153Smm 69232153Smm struct archive_string_conv *opt_sconv; 70232153Smm struct archive_string_conv *sconv_default; 71232153Smm int init_default_conversion; 72228753Smm}; 73228753Smm 74232153Smm#define c_magic_offset 0 75232153Smm#define c_magic_size 6 76232153Smm#define c_dev_offset 6 77232153Smm#define c_dev_size 6 78232153Smm#define c_ino_offset 12 79232153Smm#define c_ino_size 6 80232153Smm#define c_mode_offset 18 81232153Smm#define c_mode_size 6 82232153Smm#define c_uid_offset 24 83232153Smm#define c_uid_size 6 84232153Smm#define c_gid_offset 30 85232153Smm#define c_gid_size 6 86232153Smm#define c_nlink_offset 36 87232153Smm#define c_nlink_size 6 88232153Smm#define c_rdev_offset 42 89232153Smm#define c_rdev_size 6 90232153Smm#define c_mtime_offset 48 91232153Smm#define c_mtime_size 11 92232153Smm#define c_namesize_offset 59 93232153Smm#define c_namesize_size 6 94232153Smm#define c_filesize_offset 65 95232153Smm#define c_filesize_size 11 96228911Smm 97228753Smm/* 98228753Smm * Set output format to 'cpio' format. 99228753Smm */ 100228753Smmint 101228753Smmarchive_write_set_format_cpio(struct archive *_a) 102228753Smm{ 103228753Smm struct archive_write *a = (struct archive_write *)_a; 104228753Smm struct cpio *cpio; 105228753Smm 106232153Smm archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 107232153Smm ARCHIVE_STATE_NEW, "archive_write_set_format_cpio"); 108232153Smm 109228753Smm /* If someone else was already registered, unregister them. */ 110232153Smm if (a->format_free != NULL) 111232153Smm (a->format_free)(a); 112228753Smm 113232153Smm cpio = (struct cpio *)calloc(1, sizeof(*cpio)); 114228753Smm if (cpio == NULL) { 115228753Smm archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); 116228753Smm return (ARCHIVE_FATAL); 117228753Smm } 118228753Smm a->format_data = cpio; 119228753Smm a->format_name = "cpio"; 120232153Smm a->format_options = archive_write_cpio_options; 121228753Smm a->format_write_header = archive_write_cpio_header; 122228753Smm a->format_write_data = archive_write_cpio_data; 123228753Smm a->format_finish_entry = archive_write_cpio_finish_entry; 124232153Smm a->format_close = archive_write_cpio_close; 125232153Smm a->format_free = archive_write_cpio_free; 126228753Smm a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; 127228753Smm a->archive.archive_format_name = "POSIX cpio"; 128228753Smm return (ARCHIVE_OK); 129228753Smm} 130228753Smm 131232153Smmstatic int 132232153Smmarchive_write_cpio_options(struct archive_write *a, const char *key, 133232153Smm const char *val) 134232153Smm{ 135232153Smm struct cpio *cpio = (struct cpio *)a->format_data; 136232153Smm int ret = ARCHIVE_FAILED; 137232153Smm 138232153Smm if (strcmp(key, "hdrcharset") == 0) { 139232153Smm if (val == NULL || val[0] == 0) 140232153Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 141232153Smm "%s: hdrcharset option needs a character-set name", 142232153Smm a->format_name); 143232153Smm else { 144232153Smm cpio->opt_sconv = archive_string_conversion_to_charset( 145232153Smm &a->archive, val, 0); 146232153Smm if (cpio->opt_sconv != NULL) 147232153Smm ret = ARCHIVE_OK; 148232153Smm else 149232153Smm ret = ARCHIVE_FATAL; 150232153Smm } 151232153Smm return (ret); 152232153Smm } 153232153Smm 154232153Smm /* Note: The "warn" return is just to inform the options 155232153Smm * supervisor that we didn't handle it. It will generate 156232153Smm * a suitable error if no one used this option. */ 157232153Smm return (ARCHIVE_WARN); 158232153Smm} 159232153Smm 160228753Smm/* 161228753Smm * Ino values are as long as 64 bits on some systems; cpio format 162228753Smm * only allows 18 bits and relies on the ino values to identify hardlinked 163228753Smm * files. So, we can't merely "hash" the ino numbers since collisions 164228753Smm * would corrupt the archive. Instead, we generate synthetic ino values 165228753Smm * to store in the archive and maintain a map of original ino values to 166228753Smm * synthetic ones so we can preserve hardlink information. 167228753Smm * 168228753Smm * TODO: Make this more efficient. It's not as bad as it looks (most 169228753Smm * files don't have any hardlinks and we don't do any work here for those), 170228753Smm * but it wouldn't be hard to do better. 171228753Smm * 172228753Smm * TODO: Work with dev/ino pairs here instead of just ino values. 173228753Smm */ 174228753Smmstatic int 175228753Smmsynthesize_ino_value(struct cpio *cpio, struct archive_entry *entry) 176228753Smm{ 177228753Smm int64_t ino = archive_entry_ino64(entry); 178228753Smm int ino_new; 179228753Smm size_t i; 180228753Smm 181228753Smm /* 182228753Smm * If no index number was given, don't assign one. In 183228753Smm * particular, this handles the end-of-archive marker 184228753Smm * correctly by giving it a zero index value. (This is also 185228753Smm * why we start our synthetic index numbers with one below.) 186228753Smm */ 187228753Smm if (ino == 0) 188228753Smm return (0); 189228753Smm 190228753Smm /* Don't store a mapping if we don't need to. */ 191228753Smm if (archive_entry_nlink(entry) < 2) { 192238856Smm return (int)(++cpio->ino_next); 193228753Smm } 194228753Smm 195228753Smm /* Look up old ino; if we have it, this is a hardlink 196228753Smm * and we reuse the same value. */ 197228753Smm for (i = 0; i < cpio->ino_list_next; ++i) { 198228753Smm if (cpio->ino_list[i].old == ino) 199228753Smm return (cpio->ino_list[i].new); 200228753Smm } 201228753Smm 202228753Smm /* Assign a new index number. */ 203238856Smm ino_new = (int)(++cpio->ino_next); 204228753Smm 205228753Smm /* Ensure space for the new mapping. */ 206228753Smm if (cpio->ino_list_size <= cpio->ino_list_next) { 207228753Smm size_t newsize = cpio->ino_list_size < 512 208228753Smm ? 512 : cpio->ino_list_size * 2; 209228753Smm void *newlist = realloc(cpio->ino_list, 210228753Smm sizeof(cpio->ino_list[0]) * newsize); 211228753Smm if (newlist == NULL) 212228753Smm return (-1); 213228753Smm 214228753Smm cpio->ino_list_size = newsize; 215228753Smm cpio->ino_list = newlist; 216228753Smm } 217228753Smm 218228753Smm /* Record and return the new value. */ 219228753Smm cpio->ino_list[cpio->ino_list_next].old = ino; 220228753Smm cpio->ino_list[cpio->ino_list_next].new = ino_new; 221228753Smm ++cpio->ino_list_next; 222228753Smm return (ino_new); 223228753Smm} 224228753Smm 225232153Smm 226232153Smmstatic struct archive_string_conv * 227232153Smmget_sconv(struct archive_write *a) 228232153Smm{ 229232153Smm struct cpio *cpio; 230232153Smm struct archive_string_conv *sconv; 231232153Smm 232232153Smm cpio = (struct cpio *)a->format_data; 233232153Smm sconv = cpio->opt_sconv; 234232153Smm if (sconv == NULL) { 235232153Smm if (!cpio->init_default_conversion) { 236232153Smm cpio->sconv_default = 237232153Smm archive_string_default_conversion_for_write( 238232153Smm &(a->archive)); 239232153Smm cpio->init_default_conversion = 1; 240232153Smm } 241232153Smm sconv = cpio->sconv_default; 242232153Smm } 243232153Smm return (sconv); 244232153Smm} 245232153Smm 246228753Smmstatic int 247228753Smmarchive_write_cpio_header(struct archive_write *a, struct archive_entry *entry) 248228753Smm{ 249232153Smm const char *path; 250232153Smm size_t len; 251232153Smm 252232153Smm if (archive_entry_filetype(entry) == 0) { 253232153Smm archive_set_error(&a->archive, -1, "Filetype required"); 254232153Smm return (ARCHIVE_FAILED); 255232153Smm } 256232153Smm 257232153Smm if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0 258232153Smm && errno == ENOMEM) { 259232153Smm archive_set_error(&a->archive, ENOMEM, 260232153Smm "Can't allocate memory for Pathname"); 261232153Smm return (ARCHIVE_FATAL); 262232153Smm } 263232153Smm if (len == 0 || path == NULL || path[0] == '\0') { 264232153Smm archive_set_error(&a->archive, -1, "Pathname required"); 265232153Smm return (ARCHIVE_FAILED); 266232153Smm } 267232153Smm 268232153Smm if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) { 269232153Smm archive_set_error(&a->archive, -1, "Size required"); 270232153Smm return (ARCHIVE_FAILED); 271232153Smm } 272232153Smm return write_header(a, entry); 273232153Smm} 274232153Smm 275232153Smmstatic int 276232153Smmwrite_header(struct archive_write *a, struct archive_entry *entry) 277232153Smm{ 278228753Smm struct cpio *cpio; 279228753Smm const char *p, *path; 280232153Smm int pathlength, ret, ret_final; 281228753Smm int64_t ino; 282232153Smm char h[76]; 283232153Smm struct archive_string_conv *sconv; 284232153Smm struct archive_entry *entry_main; 285232153Smm size_t len; 286228753Smm 287228753Smm cpio = (struct cpio *)a->format_data; 288232153Smm ret_final = ARCHIVE_OK; 289232153Smm sconv = get_sconv(a); 290228753Smm 291232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 292232153Smm /* Make sure the path separators in pahtname, hardlink and symlink 293232153Smm * are all slash '/', not the Windows path separator '\'. */ 294232153Smm entry_main = __la_win_entry_in_posix_pathseparator(entry); 295232153Smm if (entry_main == NULL) { 296232153Smm archive_set_error(&a->archive, ENOMEM, 297232153Smm "Can't allocate ustar data"); 298232153Smm return(ARCHIVE_FATAL); 299232153Smm } 300232153Smm if (entry != entry_main) 301232153Smm entry = entry_main; 302232153Smm else 303232153Smm entry_main = NULL; 304232153Smm#else 305232153Smm entry_main = NULL; 306232153Smm#endif 307228753Smm 308232153Smm ret = archive_entry_pathname_l(entry, &path, &len, sconv); 309232153Smm if (ret != 0) { 310232153Smm if (errno == ENOMEM) { 311232153Smm archive_set_error(&a->archive, ENOMEM, 312232153Smm "Can't allocate memory for Pathname"); 313232153Smm ret_final = ARCHIVE_FATAL; 314232153Smm goto exit_write_header; 315232153Smm } 316232153Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 317232153Smm "Can't translate pathname '%s' to %s", 318232153Smm archive_entry_pathname(entry), 319232153Smm archive_string_conversion_charset_name(sconv)); 320232153Smm ret_final = ARCHIVE_WARN; 321232153Smm } 322232153Smm /* Include trailing null. */ 323232153Smm pathlength = (int)len + 1; 324228753Smm 325232153Smm memset(h, 0, sizeof(h)); 326232153Smm format_octal(070707, h + c_magic_offset, c_magic_size); 327232153Smm format_octal(archive_entry_dev(entry), h + c_dev_offset, c_dev_size); 328232153Smm 329228753Smm ino = synthesize_ino_value(cpio, entry); 330228753Smm if (ino < 0) { 331228753Smm archive_set_error(&a->archive, ENOMEM, 332228753Smm "No memory for ino translation table"); 333232153Smm ret_final = ARCHIVE_FATAL; 334232153Smm goto exit_write_header; 335228753Smm } else if (ino > 0777777) { 336228753Smm archive_set_error(&a->archive, ERANGE, 337228753Smm "Too many files for this cpio format"); 338232153Smm ret_final = ARCHIVE_FATAL; 339232153Smm goto exit_write_header; 340228753Smm } 341232153Smm format_octal(ino & 0777777, h + c_ino_offset, c_ino_size); 342228753Smm 343232153Smm /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */ 344232153Smm format_octal(archive_entry_mode(entry), h + c_mode_offset, c_mode_size); 345232153Smm format_octal(archive_entry_uid(entry), h + c_uid_offset, c_uid_size); 346232153Smm format_octal(archive_entry_gid(entry), h + c_gid_offset, c_gid_size); 347232153Smm format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size); 348228753Smm if (archive_entry_filetype(entry) == AE_IFBLK 349228753Smm || archive_entry_filetype(entry) == AE_IFCHR) 350232153Smm format_octal(archive_entry_dev(entry), h + c_rdev_offset, c_rdev_size); 351228753Smm else 352232153Smm format_octal(0, h + c_rdev_offset, c_rdev_size); 353232153Smm format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size); 354232153Smm format_octal(pathlength, h + c_namesize_offset, c_namesize_size); 355228753Smm 356228753Smm /* Non-regular files don't store bodies. */ 357228753Smm if (archive_entry_filetype(entry) != AE_IFREG) 358228753Smm archive_entry_set_size(entry, 0); 359228753Smm 360228753Smm /* Symlinks get the link written as the body of the entry. */ 361232153Smm ret = archive_entry_symlink_l(entry, &p, &len, sconv); 362232153Smm if (ret != 0) { 363232153Smm if (errno == ENOMEM) { 364232153Smm archive_set_error(&a->archive, ENOMEM, 365232153Smm "Can't allocate memory for Linkname"); 366232153Smm ret_final = ARCHIVE_FATAL; 367232153Smm goto exit_write_header; 368232153Smm } 369232153Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 370232153Smm "Can't translate linkname '%s' to %s", 371232153Smm archive_entry_symlink(entry), 372232153Smm archive_string_conversion_charset_name(sconv)); 373232153Smm ret_final = ARCHIVE_WARN; 374232153Smm } 375232153Smm if (len > 0 && p != NULL && *p != '\0') 376232153Smm ret = format_octal(strlen(p), h + c_filesize_offset, 377232153Smm c_filesize_size); 378228753Smm else 379232153Smm ret = format_octal(archive_entry_size(entry), 380232153Smm h + c_filesize_offset, c_filesize_size); 381232153Smm if (ret) { 382232153Smm archive_set_error(&a->archive, ERANGE, 383232153Smm "File is too large for cpio format."); 384232153Smm ret_final = ARCHIVE_FAILED; 385232153Smm goto exit_write_header; 386232153Smm } 387228753Smm 388232153Smm ret = __archive_write_output(a, h, sizeof(h)); 389232153Smm if (ret != ARCHIVE_OK) { 390232153Smm ret_final = ARCHIVE_FATAL; 391232153Smm goto exit_write_header; 392232153Smm } 393228753Smm 394232153Smm ret = __archive_write_output(a, path, pathlength); 395232153Smm if (ret != ARCHIVE_OK) { 396232153Smm ret_final = ARCHIVE_FATAL; 397232153Smm goto exit_write_header; 398232153Smm } 399228753Smm 400228753Smm cpio->entry_bytes_remaining = archive_entry_size(entry); 401228753Smm 402228753Smm /* Write the symlink now. */ 403232153Smm if (p != NULL && *p != '\0') { 404232153Smm ret = __archive_write_output(a, p, strlen(p)); 405232153Smm if (ret != ARCHIVE_OK) { 406232153Smm ret_final = ARCHIVE_FATAL; 407232153Smm goto exit_write_header; 408232153Smm } 409232153Smm } 410232153Smmexit_write_header: 411232153Smm if (entry_main) 412232153Smm archive_entry_free(entry_main); 413232153Smm return (ret_final); 414228753Smm} 415228753Smm 416228753Smmstatic ssize_t 417228753Smmarchive_write_cpio_data(struct archive_write *a, const void *buff, size_t s) 418228753Smm{ 419228753Smm struct cpio *cpio; 420228753Smm int ret; 421228753Smm 422228753Smm cpio = (struct cpio *)a->format_data; 423228753Smm if (s > cpio->entry_bytes_remaining) 424238856Smm s = (size_t)cpio->entry_bytes_remaining; 425228753Smm 426232153Smm ret = __archive_write_output(a, buff, s); 427228753Smm cpio->entry_bytes_remaining -= s; 428228753Smm if (ret >= 0) 429228753Smm return (s); 430228753Smm else 431228753Smm return (ret); 432228753Smm} 433228753Smm 434228753Smm/* 435228753Smm * Format a number into the specified field. 436228753Smm */ 437228753Smmstatic int 438228753Smmformat_octal(int64_t v, void *p, int digits) 439228753Smm{ 440228753Smm int64_t max; 441228753Smm int ret; 442228753Smm 443228753Smm max = (((int64_t)1) << (digits * 3)) - 1; 444228753Smm if (v >= 0 && v <= max) { 445228753Smm format_octal_recursive(v, (char *)p, digits); 446228753Smm ret = 0; 447228753Smm } else { 448228753Smm format_octal_recursive(max, (char *)p, digits); 449228753Smm ret = -1; 450228753Smm } 451228753Smm return (ret); 452228753Smm} 453228753Smm 454228753Smmstatic int64_t 455228753Smmformat_octal_recursive(int64_t v, char *p, int s) 456228753Smm{ 457228753Smm if (s == 0) 458228753Smm return (v); 459228753Smm v = format_octal_recursive(v, p+1, s-1); 460238856Smm *p = '0' + ((char)v & 7); 461228753Smm return (v >> 3); 462228753Smm} 463228753Smm 464228753Smmstatic int 465232153Smmarchive_write_cpio_close(struct archive_write *a) 466228753Smm{ 467228753Smm int er; 468228753Smm struct archive_entry *trailer; 469228753Smm 470232153Smm trailer = archive_entry_new2(NULL); 471228753Smm /* nlink = 1 here for GNU cpio compat. */ 472228753Smm archive_entry_set_nlink(trailer, 1); 473232153Smm archive_entry_set_size(trailer, 0); 474228753Smm archive_entry_set_pathname(trailer, "TRAILER!!!"); 475232153Smm er = write_header(a, trailer); 476228753Smm archive_entry_free(trailer); 477228753Smm return (er); 478228753Smm} 479228753Smm 480228753Smmstatic int 481232153Smmarchive_write_cpio_free(struct archive_write *a) 482228753Smm{ 483228753Smm struct cpio *cpio; 484228753Smm 485228753Smm cpio = (struct cpio *)a->format_data; 486228753Smm free(cpio->ino_list); 487228753Smm free(cpio); 488228753Smm a->format_data = NULL; 489228753Smm return (ARCHIVE_OK); 490228753Smm} 491228753Smm 492228753Smmstatic int 493228753Smmarchive_write_cpio_finish_entry(struct archive_write *a) 494228753Smm{ 495228753Smm struct cpio *cpio; 496228753Smm 497228753Smm cpio = (struct cpio *)a->format_data; 498238856Smm return (__archive_write_nulls(a, 499238856Smm (size_t)cpio->entry_bytes_remaining)); 500228753Smm} 501