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: stable/10/contrib/libarchive/libarchive/archive_write_set_format_cpio.c 368708 2020-12-16 22:25:40Z 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" 46358090Smm#include "archive_write_set_format_private.h" 47228753Smm 48228753Smmstatic ssize_t archive_write_cpio_data(struct archive_write *, 49228753Smm const void *buff, size_t s); 50232153Smmstatic int archive_write_cpio_close(struct archive_write *); 51232153Smmstatic int archive_write_cpio_free(struct archive_write *); 52228753Smmstatic int archive_write_cpio_finish_entry(struct archive_write *); 53228753Smmstatic int archive_write_cpio_header(struct archive_write *, 54228753Smm struct archive_entry *); 55232153Smmstatic int archive_write_cpio_options(struct archive_write *, 56232153Smm const char *, const char *); 57228753Smmstatic int format_octal(int64_t, void *, int); 58228753Smmstatic int64_t format_octal_recursive(int64_t, char *, int); 59232153Smmstatic int write_header(struct archive_write *, struct archive_entry *); 60228753Smm 61228753Smmstruct cpio { 62228753Smm uint64_t entry_bytes_remaining; 63228753Smm 64228753Smm int64_t ino_next; 65228753Smm 66228753Smm struct { int64_t old; int new;} *ino_list; 67228753Smm size_t ino_list_size; 68228753Smm size_t ino_list_next; 69232153Smm 70232153Smm struct archive_string_conv *opt_sconv; 71232153Smm struct archive_string_conv *sconv_default; 72232153Smm int init_default_conversion; 73228753Smm}; 74228753Smm 75232153Smm#define c_magic_offset 0 76232153Smm#define c_magic_size 6 77232153Smm#define c_dev_offset 6 78232153Smm#define c_dev_size 6 79232153Smm#define c_ino_offset 12 80232153Smm#define c_ino_size 6 81232153Smm#define c_mode_offset 18 82232153Smm#define c_mode_size 6 83232153Smm#define c_uid_offset 24 84232153Smm#define c_uid_size 6 85232153Smm#define c_gid_offset 30 86232153Smm#define c_gid_size 6 87232153Smm#define c_nlink_offset 36 88232153Smm#define c_nlink_size 6 89232153Smm#define c_rdev_offset 42 90232153Smm#define c_rdev_size 6 91232153Smm#define c_mtime_offset 48 92232153Smm#define c_mtime_size 11 93232153Smm#define c_namesize_offset 59 94232153Smm#define c_namesize_size 6 95232153Smm#define c_filesize_offset 65 96232153Smm#define c_filesize_size 11 97228911Smm 98228753Smm/* 99228753Smm * Set output format to 'cpio' format. 100228753Smm */ 101228753Smmint 102228753Smmarchive_write_set_format_cpio(struct archive *_a) 103228753Smm{ 104228753Smm struct archive_write *a = (struct archive_write *)_a; 105228753Smm struct cpio *cpio; 106228753Smm 107232153Smm archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 108232153Smm ARCHIVE_STATE_NEW, "archive_write_set_format_cpio"); 109232153Smm 110228753Smm /* If someone else was already registered, unregister them. */ 111232153Smm if (a->format_free != NULL) 112232153Smm (a->format_free)(a); 113228753Smm 114232153Smm cpio = (struct cpio *)calloc(1, sizeof(*cpio)); 115228753Smm if (cpio == NULL) { 116228753Smm archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); 117228753Smm return (ARCHIVE_FATAL); 118228753Smm } 119228753Smm a->format_data = cpio; 120228753Smm a->format_name = "cpio"; 121232153Smm a->format_options = archive_write_cpio_options; 122228753Smm a->format_write_header = archive_write_cpio_header; 123228753Smm a->format_write_data = archive_write_cpio_data; 124228753Smm a->format_finish_entry = archive_write_cpio_finish_entry; 125232153Smm a->format_close = archive_write_cpio_close; 126232153Smm a->format_free = archive_write_cpio_free; 127228753Smm a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; 128228753Smm a->archive.archive_format_name = "POSIX cpio"; 129228753Smm return (ARCHIVE_OK); 130228753Smm} 131228753Smm 132232153Smmstatic int 133232153Smmarchive_write_cpio_options(struct archive_write *a, const char *key, 134232153Smm const char *val) 135232153Smm{ 136232153Smm struct cpio *cpio = (struct cpio *)a->format_data; 137232153Smm int ret = ARCHIVE_FAILED; 138232153Smm 139232153Smm if (strcmp(key, "hdrcharset") == 0) { 140232153Smm if (val == NULL || val[0] == 0) 141232153Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 142232153Smm "%s: hdrcharset option needs a character-set name", 143232153Smm a->format_name); 144232153Smm else { 145232153Smm cpio->opt_sconv = archive_string_conversion_to_charset( 146232153Smm &a->archive, val, 0); 147232153Smm if (cpio->opt_sconv != NULL) 148232153Smm ret = ARCHIVE_OK; 149232153Smm else 150232153Smm ret = ARCHIVE_FATAL; 151232153Smm } 152232153Smm return (ret); 153232153Smm } 154232153Smm 155232153Smm /* Note: The "warn" return is just to inform the options 156232153Smm * supervisor that we didn't handle it. It will generate 157232153Smm * a suitable error if no one used this option. */ 158232153Smm return (ARCHIVE_WARN); 159232153Smm} 160232153Smm 161228753Smm/* 162228753Smm * Ino values are as long as 64 bits on some systems; cpio format 163228753Smm * only allows 18 bits and relies on the ino values to identify hardlinked 164228753Smm * files. So, we can't merely "hash" the ino numbers since collisions 165228753Smm * would corrupt the archive. Instead, we generate synthetic ino values 166228753Smm * to store in the archive and maintain a map of original ino values to 167228753Smm * synthetic ones so we can preserve hardlink information. 168228753Smm * 169228753Smm * TODO: Make this more efficient. It's not as bad as it looks (most 170228753Smm * files don't have any hardlinks and we don't do any work here for those), 171228753Smm * but it wouldn't be hard to do better. 172228753Smm * 173228753Smm * TODO: Work with dev/ino pairs here instead of just ino values. 174228753Smm */ 175228753Smmstatic int 176228753Smmsynthesize_ino_value(struct cpio *cpio, struct archive_entry *entry) 177228753Smm{ 178228753Smm int64_t ino = archive_entry_ino64(entry); 179228753Smm int ino_new; 180228753Smm size_t i; 181228753Smm 182228753Smm /* 183228753Smm * If no index number was given, don't assign one. In 184228753Smm * particular, this handles the end-of-archive marker 185228753Smm * correctly by giving it a zero index value. (This is also 186228753Smm * why we start our synthetic index numbers with one below.) 187228753Smm */ 188228753Smm if (ino == 0) 189228753Smm return (0); 190228753Smm 191228753Smm /* Don't store a mapping if we don't need to. */ 192228753Smm if (archive_entry_nlink(entry) < 2) { 193238856Smm return (int)(++cpio->ino_next); 194228753Smm } 195228753Smm 196228753Smm /* Look up old ino; if we have it, this is a hardlink 197228753Smm * and we reuse the same value. */ 198228753Smm for (i = 0; i < cpio->ino_list_next; ++i) { 199228753Smm if (cpio->ino_list[i].old == ino) 200228753Smm return (cpio->ino_list[i].new); 201228753Smm } 202228753Smm 203228753Smm /* Assign a new index number. */ 204238856Smm ino_new = (int)(++cpio->ino_next); 205228753Smm 206228753Smm /* Ensure space for the new mapping. */ 207228753Smm if (cpio->ino_list_size <= cpio->ino_list_next) { 208228753Smm size_t newsize = cpio->ino_list_size < 512 209228753Smm ? 512 : cpio->ino_list_size * 2; 210228753Smm void *newlist = realloc(cpio->ino_list, 211228753Smm sizeof(cpio->ino_list[0]) * newsize); 212228753Smm if (newlist == NULL) 213228753Smm return (-1); 214228753Smm 215228753Smm cpio->ino_list_size = newsize; 216228753Smm cpio->ino_list = newlist; 217228753Smm } 218228753Smm 219228753Smm /* Record and return the new value. */ 220228753Smm cpio->ino_list[cpio->ino_list_next].old = ino; 221228753Smm cpio->ino_list[cpio->ino_list_next].new = ino_new; 222228753Smm ++cpio->ino_list_next; 223228753Smm return (ino_new); 224228753Smm} 225228753Smm 226232153Smm 227232153Smmstatic struct archive_string_conv * 228232153Smmget_sconv(struct archive_write *a) 229232153Smm{ 230232153Smm struct cpio *cpio; 231232153Smm struct archive_string_conv *sconv; 232232153Smm 233232153Smm cpio = (struct cpio *)a->format_data; 234232153Smm sconv = cpio->opt_sconv; 235232153Smm if (sconv == NULL) { 236232153Smm if (!cpio->init_default_conversion) { 237232153Smm cpio->sconv_default = 238232153Smm archive_string_default_conversion_for_write( 239232153Smm &(a->archive)); 240232153Smm cpio->init_default_conversion = 1; 241232153Smm } 242232153Smm sconv = cpio->sconv_default; 243232153Smm } 244232153Smm return (sconv); 245232153Smm} 246232153Smm 247228753Smmstatic int 248228753Smmarchive_write_cpio_header(struct archive_write *a, struct archive_entry *entry) 249228753Smm{ 250232153Smm const char *path; 251232153Smm size_t len; 252232153Smm 253368708Smm if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) { 254232153Smm archive_set_error(&a->archive, -1, "Filetype required"); 255232153Smm return (ARCHIVE_FAILED); 256232153Smm } 257232153Smm 258232153Smm if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0 259232153Smm && errno == ENOMEM) { 260232153Smm archive_set_error(&a->archive, ENOMEM, 261232153Smm "Can't allocate memory for Pathname"); 262232153Smm return (ARCHIVE_FATAL); 263232153Smm } 264232153Smm if (len == 0 || path == NULL || path[0] == '\0') { 265232153Smm archive_set_error(&a->archive, -1, "Pathname required"); 266232153Smm return (ARCHIVE_FAILED); 267232153Smm } 268232153Smm 269232153Smm if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) { 270232153Smm archive_set_error(&a->archive, -1, "Size required"); 271232153Smm return (ARCHIVE_FAILED); 272232153Smm } 273232153Smm return write_header(a, entry); 274232153Smm} 275232153Smm 276232153Smmstatic int 277232153Smmwrite_header(struct archive_write *a, struct archive_entry *entry) 278232153Smm{ 279228753Smm struct cpio *cpio; 280228753Smm const char *p, *path; 281232153Smm int pathlength, ret, ret_final; 282228753Smm int64_t ino; 283232153Smm char h[76]; 284232153Smm struct archive_string_conv *sconv; 285232153Smm struct archive_entry *entry_main; 286232153Smm size_t len; 287228753Smm 288228753Smm cpio = (struct cpio *)a->format_data; 289232153Smm ret_final = ARCHIVE_OK; 290232153Smm sconv = get_sconv(a); 291228753Smm 292232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 293311042Smm /* Make sure the path separators in pathname, hardlink and symlink 294232153Smm * are all slash '/', not the Windows path separator '\'. */ 295232153Smm entry_main = __la_win_entry_in_posix_pathseparator(entry); 296232153Smm if (entry_main == NULL) { 297232153Smm archive_set_error(&a->archive, ENOMEM, 298232153Smm "Can't allocate ustar data"); 299232153Smm return(ARCHIVE_FATAL); 300232153Smm } 301232153Smm if (entry != entry_main) 302232153Smm entry = entry_main; 303232153Smm else 304232153Smm entry_main = NULL; 305232153Smm#else 306232153Smm entry_main = NULL; 307232153Smm#endif 308228753Smm 309232153Smm ret = archive_entry_pathname_l(entry, &path, &len, sconv); 310232153Smm if (ret != 0) { 311232153Smm if (errno == ENOMEM) { 312232153Smm archive_set_error(&a->archive, ENOMEM, 313232153Smm "Can't allocate memory for Pathname"); 314232153Smm ret_final = ARCHIVE_FATAL; 315232153Smm goto exit_write_header; 316232153Smm } 317232153Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 318232153Smm "Can't translate pathname '%s' to %s", 319232153Smm archive_entry_pathname(entry), 320232153Smm archive_string_conversion_charset_name(sconv)); 321232153Smm ret_final = ARCHIVE_WARN; 322232153Smm } 323232153Smm /* Include trailing null. */ 324232153Smm pathlength = (int)len + 1; 325228753Smm 326232153Smm memset(h, 0, sizeof(h)); 327232153Smm format_octal(070707, h + c_magic_offset, c_magic_size); 328232153Smm format_octal(archive_entry_dev(entry), h + c_dev_offset, c_dev_size); 329232153Smm 330228753Smm ino = synthesize_ino_value(cpio, entry); 331228753Smm if (ino < 0) { 332228753Smm archive_set_error(&a->archive, ENOMEM, 333228753Smm "No memory for ino translation table"); 334232153Smm ret_final = ARCHIVE_FATAL; 335232153Smm goto exit_write_header; 336228753Smm } else if (ino > 0777777) { 337228753Smm archive_set_error(&a->archive, ERANGE, 338228753Smm "Too many files for this cpio format"); 339232153Smm ret_final = ARCHIVE_FATAL; 340232153Smm goto exit_write_header; 341228753Smm } 342232153Smm format_octal(ino & 0777777, h + c_ino_offset, c_ino_size); 343228753Smm 344232153Smm /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */ 345232153Smm format_octal(archive_entry_mode(entry), h + c_mode_offset, c_mode_size); 346232153Smm format_octal(archive_entry_uid(entry), h + c_uid_offset, c_uid_size); 347232153Smm format_octal(archive_entry_gid(entry), h + c_gid_offset, c_gid_size); 348232153Smm format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size); 349228753Smm if (archive_entry_filetype(entry) == AE_IFBLK 350228753Smm || archive_entry_filetype(entry) == AE_IFCHR) 351368708Smm format_octal(archive_entry_rdev(entry), h + c_rdev_offset, c_rdev_size); 352228753Smm else 353232153Smm format_octal(0, h + c_rdev_offset, c_rdev_size); 354232153Smm format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size); 355232153Smm format_octal(pathlength, h + c_namesize_offset, c_namesize_size); 356228753Smm 357228753Smm /* Non-regular files don't store bodies. */ 358228753Smm if (archive_entry_filetype(entry) != AE_IFREG) 359228753Smm archive_entry_set_size(entry, 0); 360228753Smm 361228753Smm /* Symlinks get the link written as the body of the entry. */ 362232153Smm ret = archive_entry_symlink_l(entry, &p, &len, sconv); 363232153Smm if (ret != 0) { 364232153Smm if (errno == ENOMEM) { 365232153Smm archive_set_error(&a->archive, ENOMEM, 366232153Smm "Can't allocate memory for Linkname"); 367232153Smm ret_final = ARCHIVE_FATAL; 368232153Smm goto exit_write_header; 369232153Smm } 370232153Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 371232153Smm "Can't translate linkname '%s' to %s", 372232153Smm archive_entry_symlink(entry), 373232153Smm archive_string_conversion_charset_name(sconv)); 374232153Smm ret_final = ARCHIVE_WARN; 375232153Smm } 376232153Smm if (len > 0 && p != NULL && *p != '\0') 377232153Smm ret = format_octal(strlen(p), h + c_filesize_offset, 378232153Smm c_filesize_size); 379228753Smm else 380232153Smm ret = format_octal(archive_entry_size(entry), 381232153Smm h + c_filesize_offset, c_filesize_size); 382232153Smm if (ret) { 383232153Smm archive_set_error(&a->archive, ERANGE, 384232153Smm "File is too large for cpio format."); 385232153Smm ret_final = ARCHIVE_FAILED; 386232153Smm goto exit_write_header; 387232153Smm } 388228753Smm 389232153Smm ret = __archive_write_output(a, h, sizeof(h)); 390232153Smm if (ret != ARCHIVE_OK) { 391232153Smm ret_final = ARCHIVE_FATAL; 392232153Smm goto exit_write_header; 393232153Smm } 394228753Smm 395232153Smm ret = __archive_write_output(a, path, pathlength); 396232153Smm if (ret != ARCHIVE_OK) { 397232153Smm ret_final = ARCHIVE_FATAL; 398232153Smm goto exit_write_header; 399232153Smm } 400228753Smm 401228753Smm cpio->entry_bytes_remaining = archive_entry_size(entry); 402228753Smm 403228753Smm /* Write the symlink now. */ 404232153Smm if (p != NULL && *p != '\0') { 405232153Smm ret = __archive_write_output(a, p, strlen(p)); 406232153Smm if (ret != ARCHIVE_OK) { 407232153Smm ret_final = ARCHIVE_FATAL; 408232153Smm goto exit_write_header; 409232153Smm } 410232153Smm } 411232153Smmexit_write_header: 412344674Smm 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