archive_write_set_format_cpio_newc.c revision 344673
1/*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * Copyright (c) 2006 Rudolf Marek SYSGO s.r.o. 4 * Copyright (c) 2011-2012 Michihiro NAKAJIMA 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "archive_platform.h" 29__FBSDID("$FreeBSD: stable/11/contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c 344673 2019-02-28 22:56:15Z mm $"); 30 31#ifdef HAVE_ERRNO_H 32#include <errno.h> 33#endif 34#include <stdio.h> 35#ifdef HAVE_STDLIB_H 36#include <stdlib.h> 37#endif 38#ifdef HAVE_STRING_H 39#include <string.h> 40#endif 41 42#include "archive.h" 43#include "archive_entry.h" 44#include "archive_entry_locale.h" 45#include "archive_private.h" 46#include "archive_write_private.h" 47 48static ssize_t archive_write_newc_data(struct archive_write *, 49 const void *buff, size_t s); 50static int archive_write_newc_close(struct archive_write *); 51static int archive_write_newc_free(struct archive_write *); 52static int archive_write_newc_finish_entry(struct archive_write *); 53static int archive_write_newc_header(struct archive_write *, 54 struct archive_entry *); 55static int archive_write_newc_options(struct archive_write *, 56 const char *, const char *); 57static int format_hex(int64_t, void *, int); 58static int64_t format_hex_recursive(int64_t, char *, int); 59static int write_header(struct archive_write *, struct archive_entry *); 60 61struct cpio { 62 uint64_t entry_bytes_remaining; 63 int padding; 64 65 struct archive_string_conv *opt_sconv; 66 struct archive_string_conv *sconv_default; 67 int init_default_conversion; 68}; 69 70#define c_magic_offset 0 71#define c_magic_size 6 72#define c_ino_offset 6 73#define c_ino_size 8 74#define c_mode_offset 14 75#define c_mode_size 8 76#define c_uid_offset 22 77#define c_uid_size 8 78#define c_gid_offset 30 79#define c_gid_size 8 80#define c_nlink_offset 38 81#define c_nlink_size 8 82#define c_mtime_offset 46 83#define c_mtime_size 8 84#define c_filesize_offset 54 85#define c_filesize_size 8 86#define c_devmajor_offset 62 87#define c_devmajor_size 8 88#define c_devminor_offset 70 89#define c_devminor_size 8 90#define c_rdevmajor_offset 78 91#define c_rdevmajor_size 8 92#define c_rdevminor_offset 86 93#define c_rdevminor_size 8 94#define c_namesize_offset 94 95#define c_namesize_size 8 96#define c_checksum_offset 102 97#define c_checksum_size 8 98#define c_header_size 110 99 100/* Logic trick: difference between 'n' and next multiple of 4 */ 101#define PAD4(n) (3 & (1 + ~(n))) 102 103/* 104 * Set output format to 'cpio' format. 105 */ 106int 107archive_write_set_format_cpio_newc(struct archive *_a) 108{ 109 struct archive_write *a = (struct archive_write *)_a; 110 struct cpio *cpio; 111 112 archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 113 ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_newc"); 114 115 /* If someone else was already registered, unregister them. */ 116 if (a->format_free != NULL) 117 (a->format_free)(a); 118 119 cpio = (struct cpio *)calloc(1, sizeof(*cpio)); 120 if (cpio == NULL) { 121 archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); 122 return (ARCHIVE_FATAL); 123 } 124 a->format_data = cpio; 125 a->format_name = "cpio"; 126 a->format_options = archive_write_newc_options; 127 a->format_write_header = archive_write_newc_header; 128 a->format_write_data = archive_write_newc_data; 129 a->format_finish_entry = archive_write_newc_finish_entry; 130 a->format_close = archive_write_newc_close; 131 a->format_free = archive_write_newc_free; 132 a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC; 133 a->archive.archive_format_name = "SVR4 cpio nocrc"; 134 return (ARCHIVE_OK); 135} 136 137static int 138archive_write_newc_options(struct archive_write *a, const char *key, 139 const char *val) 140{ 141 struct cpio *cpio = (struct cpio *)a->format_data; 142 int ret = ARCHIVE_FAILED; 143 144 if (strcmp(key, "hdrcharset") == 0) { 145 if (val == NULL || val[0] == 0) 146 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 147 "%s: hdrcharset option needs a character-set name", 148 a->format_name); 149 else { 150 cpio->opt_sconv = archive_string_conversion_to_charset( 151 &a->archive, val, 0); 152 if (cpio->opt_sconv != NULL) 153 ret = ARCHIVE_OK; 154 else 155 ret = ARCHIVE_FATAL; 156 } 157 return (ret); 158 } 159 160 /* Note: The "warn" return is just to inform the options 161 * supervisor that we didn't handle it. It will generate 162 * a suitable error if no one used this option. */ 163 return (ARCHIVE_WARN); 164} 165 166static struct archive_string_conv * 167get_sconv(struct archive_write *a) 168{ 169 struct cpio *cpio; 170 struct archive_string_conv *sconv; 171 172 cpio = (struct cpio *)a->format_data; 173 sconv = cpio->opt_sconv; 174 if (sconv == NULL) { 175 if (!cpio->init_default_conversion) { 176 cpio->sconv_default = 177 archive_string_default_conversion_for_write( 178 &(a->archive)); 179 cpio->init_default_conversion = 1; 180 } 181 sconv = cpio->sconv_default; 182 } 183 return (sconv); 184} 185 186static int 187archive_write_newc_header(struct archive_write *a, struct archive_entry *entry) 188{ 189 const char *path; 190 size_t len; 191 192 if (archive_entry_filetype(entry) == 0) { 193 archive_set_error(&a->archive, -1, "Filetype required"); 194 return (ARCHIVE_FAILED); 195 } 196 197 if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0 198 && errno == ENOMEM) { 199 archive_set_error(&a->archive, ENOMEM, 200 "Can't allocate memory for Pathname"); 201 return (ARCHIVE_FATAL); 202 } 203 if (len == 0 || path == NULL || path[0] == '\0') { 204 archive_set_error(&a->archive, -1, "Pathname required"); 205 return (ARCHIVE_FAILED); 206 } 207 208 if (archive_entry_hardlink(entry) == NULL 209 && (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0)) { 210 archive_set_error(&a->archive, -1, "Size required"); 211 return (ARCHIVE_FAILED); 212 } 213 return write_header(a, entry); 214} 215 216static int 217write_header(struct archive_write *a, struct archive_entry *entry) 218{ 219 int64_t ino; 220 struct cpio *cpio; 221 const char *p, *path; 222 int pathlength, ret, ret_final; 223 char h[c_header_size]; 224 struct archive_string_conv *sconv; 225 struct archive_entry *entry_main; 226 size_t len; 227 int pad; 228 229 cpio = (struct cpio *)a->format_data; 230 ret_final = ARCHIVE_OK; 231 sconv = get_sconv(a); 232 233#if defined(_WIN32) && !defined(__CYGWIN__) 234 /* Make sure the path separators in pathname, hardlink and symlink 235 * are all slash '/', not the Windows path separator '\'. */ 236 entry_main = __la_win_entry_in_posix_pathseparator(entry); 237 if (entry_main == NULL) { 238 archive_set_error(&a->archive, ENOMEM, 239 "Can't allocate ustar data"); 240 return(ARCHIVE_FATAL); 241 } 242 if (entry != entry_main) 243 entry = entry_main; 244 else 245 entry_main = NULL; 246#else 247 entry_main = NULL; 248#endif 249 250 ret = archive_entry_pathname_l(entry, &path, &len, sconv); 251 if (ret != 0) { 252 if (errno == ENOMEM) { 253 archive_set_error(&a->archive, ENOMEM, 254 "Can't allocate memory for Pathname"); 255 ret_final = ARCHIVE_FATAL; 256 goto exit_write_header; 257 } 258 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 259 "Can't translate pathname '%s' to %s", 260 archive_entry_pathname(entry), 261 archive_string_conversion_charset_name(sconv)); 262 ret_final = ARCHIVE_WARN; 263 } 264 pathlength = (int)len + 1; /* Include trailing null. */ 265 266 memset(h, 0, c_header_size); 267 format_hex(0x070701, h + c_magic_offset, c_magic_size); 268 format_hex(archive_entry_devmajor(entry), h + c_devmajor_offset, 269 c_devmajor_size); 270 format_hex(archive_entry_devminor(entry), h + c_devminor_offset, 271 c_devminor_size); 272 273 ino = archive_entry_ino64(entry); 274 if (ino > 0xffffffff) { 275 archive_set_error(&a->archive, ERANGE, 276 "large inode number truncated"); 277 ret_final = ARCHIVE_WARN; 278 } 279 280 /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */ 281 format_hex(ino & 0xffffffff, h + c_ino_offset, c_ino_size); 282 format_hex(archive_entry_mode(entry), h + c_mode_offset, c_mode_size); 283 format_hex(archive_entry_uid(entry), h + c_uid_offset, c_uid_size); 284 format_hex(archive_entry_gid(entry), h + c_gid_offset, c_gid_size); 285 format_hex(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size); 286 if (archive_entry_filetype(entry) == AE_IFBLK 287 || archive_entry_filetype(entry) == AE_IFCHR) { 288 format_hex(archive_entry_rdevmajor(entry), h + c_rdevmajor_offset, c_rdevmajor_size); 289 format_hex(archive_entry_rdevminor(entry), h + c_rdevminor_offset, c_rdevminor_size); 290 } else { 291 format_hex(0, h + c_rdevmajor_offset, c_rdevmajor_size); 292 format_hex(0, h + c_rdevminor_offset, c_rdevminor_size); 293 } 294 format_hex(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size); 295 format_hex(pathlength, h + c_namesize_offset, c_namesize_size); 296 format_hex(0, h + c_checksum_offset, c_checksum_size); 297 298 /* Non-regular files don't store bodies. */ 299 if (archive_entry_filetype(entry) != AE_IFREG) 300 archive_entry_set_size(entry, 0); 301 302 /* Symlinks get the link written as the body of the entry. */ 303 ret = archive_entry_symlink_l(entry, &p, &len, sconv); 304 if (ret != 0) { 305 if (errno == ENOMEM) { 306 archive_set_error(&a->archive, ENOMEM, 307 "Can't allocate memory for Likname"); 308 ret_final = ARCHIVE_FATAL; 309 goto exit_write_header; 310 } 311 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 312 "Can't translate linkname '%s' to %s", 313 archive_entry_symlink(entry), 314 archive_string_conversion_charset_name(sconv)); 315 ret_final = ARCHIVE_WARN; 316 } 317 if (len > 0 && p != NULL && *p != '\0') 318 ret = format_hex(strlen(p), h + c_filesize_offset, 319 c_filesize_size); 320 else 321 ret = format_hex(archive_entry_size(entry), 322 h + c_filesize_offset, c_filesize_size); 323 if (ret) { 324 archive_set_error(&a->archive, ERANGE, 325 "File is too large for this format."); 326 ret_final = ARCHIVE_FAILED; 327 goto exit_write_header; 328 } 329 330 ret = __archive_write_output(a, h, c_header_size); 331 if (ret != ARCHIVE_OK) { 332 ret_final = ARCHIVE_FATAL; 333 goto exit_write_header; 334 } 335 336 /* Pad pathname to even length. */ 337 ret = __archive_write_output(a, path, pathlength); 338 if (ret != ARCHIVE_OK) { 339 ret_final = ARCHIVE_FATAL; 340 goto exit_write_header; 341 } 342 pad = PAD4(pathlength + c_header_size); 343 if (pad) { 344 ret = __archive_write_output(a, "\0\0\0", pad); 345 if (ret != ARCHIVE_OK) { 346 ret_final = ARCHIVE_FATAL; 347 goto exit_write_header; 348 } 349 } 350 351 cpio->entry_bytes_remaining = archive_entry_size(entry); 352 cpio->padding = (int)PAD4(cpio->entry_bytes_remaining); 353 354 /* Write the symlink now. */ 355 if (p != NULL && *p != '\0') { 356 ret = __archive_write_output(a, p, strlen(p)); 357 if (ret != ARCHIVE_OK) { 358 ret_final = ARCHIVE_FATAL; 359 goto exit_write_header; 360 } 361 pad = PAD4(strlen(p)); 362 ret = __archive_write_output(a, "\0\0\0", pad); 363 if (ret != ARCHIVE_OK) { 364 ret_final = ARCHIVE_FATAL; 365 goto exit_write_header; 366 } 367 } 368exit_write_header: 369 archive_entry_free(entry_main); 370 return (ret_final); 371} 372 373static ssize_t 374archive_write_newc_data(struct archive_write *a, const void *buff, size_t s) 375{ 376 struct cpio *cpio; 377 int ret; 378 379 cpio = (struct cpio *)a->format_data; 380 if (s > cpio->entry_bytes_remaining) 381 s = (size_t)cpio->entry_bytes_remaining; 382 383 ret = __archive_write_output(a, buff, s); 384 cpio->entry_bytes_remaining -= s; 385 if (ret >= 0) 386 return (s); 387 else 388 return (ret); 389} 390 391/* 392 * Format a number into the specified field. 393 */ 394static int 395format_hex(int64_t v, void *p, int digits) 396{ 397 int64_t max; 398 int ret; 399 400 max = (((int64_t)1) << (digits * 4)) - 1; 401 if (v >= 0 && v <= max) { 402 format_hex_recursive(v, (char *)p, digits); 403 ret = 0; 404 } else { 405 format_hex_recursive(max, (char *)p, digits); 406 ret = -1; 407 } 408 return (ret); 409} 410 411static int64_t 412format_hex_recursive(int64_t v, char *p, int s) 413{ 414 if (s == 0) 415 return (v); 416 v = format_hex_recursive(v, p+1, s-1); 417 *p = "0123456789abcdef"[v & 0xf]; 418 return (v >> 4); 419} 420 421static int 422archive_write_newc_close(struct archive_write *a) 423{ 424 int er; 425 struct archive_entry *trailer; 426 427 trailer = archive_entry_new(); 428 archive_entry_set_nlink(trailer, 1); 429 archive_entry_set_size(trailer, 0); 430 archive_entry_set_pathname(trailer, "TRAILER!!!"); 431 /* Bypass the required data checks. */ 432 er = write_header(a, trailer); 433 archive_entry_free(trailer); 434 return (er); 435} 436 437static int 438archive_write_newc_free(struct archive_write *a) 439{ 440 struct cpio *cpio; 441 442 cpio = (struct cpio *)a->format_data; 443 free(cpio); 444 a->format_data = NULL; 445 return (ARCHIVE_OK); 446} 447 448static int 449archive_write_newc_finish_entry(struct archive_write *a) 450{ 451 struct cpio *cpio; 452 453 cpio = (struct cpio *)a->format_data; 454 return (__archive_write_nulls(a, 455 (size_t)cpio->entry_bytes_remaining + cpio->padding)); 456} 457