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" 28370535Sgit2svn__FBSDID("$FreeBSD: stable/11/contrib/libarchive/libarchive/archive_write_set_format_cpio_binary.c 370535 2021-09-10 08:34:36Z git2svn $"); 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" 46358088Smm#include "archive_write_set_format_private.h" 47228753Smm 48370535Sgit2svnstatic ssize_t archive_write_binary_data(struct archive_write *, 49228753Smm const void *buff, size_t s); 50370535Sgit2svnstatic int archive_write_binary_close(struct archive_write *); 51370535Sgit2svnstatic int archive_write_binary_free(struct archive_write *); 52370535Sgit2svnstatic int archive_write_binary_finish_entry(struct archive_write *); 53370535Sgit2svnstatic int archive_write_binary_header(struct archive_write *, 54228753Smm struct archive_entry *); 55370535Sgit2svnstatic int archive_write_binary_options(struct archive_write *, 56232153Smm const char *, const char *); 57232153Smmstatic int write_header(struct archive_write *, struct archive_entry *); 58228753Smm 59228753Smmstruct cpio { 60228753Smm uint64_t entry_bytes_remaining; 61228753Smm 62228753Smm int64_t ino_next; 63228753Smm 64228753Smm struct { int64_t old; int new;} *ino_list; 65228753Smm size_t ino_list_size; 66228753Smm size_t ino_list_next; 67232153Smm 68232153Smm struct archive_string_conv *opt_sconv; 69232153Smm struct archive_string_conv *sconv_default; 70232153Smm int init_default_conversion; 71228753Smm}; 72228753Smm 73370535Sgit2svn/* This struct needs to be packed to get the header right */ 74228911Smm 75370535Sgit2svn#if defined(__GNUC__) 76370535Sgit2svn#define PACKED(x) x __attribute__((packed)) 77370535Sgit2svn#elif defined(_MSC_VER) 78370535Sgit2svn#define PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) 79370535Sgit2svn#else 80370535Sgit2svn#define PACKED(x) x 81370535Sgit2svn#endif 82370535Sgit2svn 83370535Sgit2svn#define HSIZE 26 84370535Sgit2svn 85370535Sgit2svnPACKED(struct cpio_binary_header { 86370535Sgit2svn uint16_t h_magic; 87370535Sgit2svn uint16_t h_dev; 88370535Sgit2svn uint16_t h_ino; 89370535Sgit2svn uint16_t h_mode; 90370535Sgit2svn uint16_t h_uid; 91370535Sgit2svn uint16_t h_gid; 92370535Sgit2svn uint16_t h_nlink; 93370535Sgit2svn uint16_t h_majmin; 94370535Sgit2svn uint32_t h_mtime; 95370535Sgit2svn uint16_t h_namesize; 96370535Sgit2svn uint32_t h_filesize; 97370535Sgit2svn}); 98370535Sgit2svn 99370535Sgit2svn/* Back in the day, the 7th Edition cpio.c had this, to 100370535Sgit2svn * adapt to, as the comment said, "VAX, Interdata, ...": 101370535Sgit2svn * 102370535Sgit2svn * union { long l; short s[2]; char c[4]; } U; 103370535Sgit2svn * #define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];} 104370535Sgit2svn * long mklong(v) 105370535Sgit2svn * short v[]; 106370535Sgit2svn * { 107370535Sgit2svn * U.l = 1; 108370535Sgit2svn * if(U.c[0]) 109370535Sgit2svn * U.s[0] = v[1], U.s[1] = v[0]; 110370535Sgit2svn * else 111370535Sgit2svn * U.s[0] = v[0], U.s[1] = v[1]; 112370535Sgit2svn * return U.l; 113370535Sgit2svn * } 114370535Sgit2svn * 115370535Sgit2svn * Of course, that assumes that all machines have little-endian shorts, 116370535Sgit2svn * and just adapts the others to the special endianness of the PDP-11. 117370535Sgit2svn * 118370535Sgit2svn * Now, we could do this: 119370535Sgit2svn * 120370535Sgit2svn * union { uint32_t l; uint16_t s[2]; uint8_t c[4]; } U; 121370535Sgit2svn * #define PUTI16(v,sv) {U.s[0]=1;if(U.c[0]) v=sv; else U.s[0]=sv,U.c[2]=U.c[1],U.c[3]=U.c[0],v=U.s[1];} 122370535Sgit2svn * #define PUTI32(v,lv) {char_t Ut;U.l=1;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,Ut=U.c[0],U.c[0]=U.c[1],U.c[1]=Ut,Ut=U.c[2],U.c[2]=U.c[3],U.c[3]=Ut,v[0]=U.s[0],v[1]=U.s[1];} 123370535Sgit2svn * 124370535Sgit2svn * ...but it feels a little better to do it like this: 125370535Sgit2svn */ 126370535Sgit2svn 127370535Sgit2svnstatic uint16_t swap16(uint16_t in) { 128370535Sgit2svn union { 129370535Sgit2svn uint16_t s[2]; 130370535Sgit2svn uint8_t c[4]; 131370535Sgit2svn } U; 132370535Sgit2svn U.s[0] = 1; 133370535Sgit2svn if (U.c[0]) 134370535Sgit2svn return in; 135370535Sgit2svn else { 136370535Sgit2svn U.s[0] = in; 137370535Sgit2svn U.c[2] = U.c[1]; 138370535Sgit2svn U.c[3] = U.c[0]; 139370535Sgit2svn return U.s[1]; 140370535Sgit2svn } 141370535Sgit2svn /* NOTREACHED */ 142370535Sgit2svn} 143370535Sgit2svn 144370535Sgit2svnstatic uint32_t swap32(uint32_t in) { 145370535Sgit2svn union { 146370535Sgit2svn uint32_t l; 147370535Sgit2svn uint16_t s[2]; 148370535Sgit2svn uint8_t c[4]; 149370535Sgit2svn } U; 150370535Sgit2svn U.l = 1; 151370535Sgit2svn if (U.c[0]) { /* Little-endian */ 152370535Sgit2svn uint16_t t; 153370535Sgit2svn U.l = in; 154370535Sgit2svn t = U.s[0]; 155370535Sgit2svn U.s[0] = U.s[1]; 156370535Sgit2svn U.s[1] = t; 157370535Sgit2svn } else if (U.c[3]) { /* Big-endian */ 158370535Sgit2svn U.l = in; 159370535Sgit2svn U.s[0] = swap16(U.s[0]); 160370535Sgit2svn U.s[1] = swap16(U.s[1]); 161370535Sgit2svn } else { /* PDP-endian */ 162370535Sgit2svn U.l = in; 163370535Sgit2svn } 164370535Sgit2svn return U.l; 165370535Sgit2svn} 166370535Sgit2svn 167228753Smm/* 168370535Sgit2svn * Set output format to the selected binary variant 169228753Smm */ 170370535Sgit2svnstatic int 171370535Sgit2svnarchive_write_set_format_cpio_binary(struct archive *_a, int format) 172228753Smm{ 173228753Smm struct archive_write *a = (struct archive_write *)_a; 174228753Smm struct cpio *cpio; 175228753Smm 176370535Sgit2svn if (sizeof(struct cpio_binary_header) != HSIZE) { 177370535Sgit2svn archive_set_error(&a->archive, EINVAL, 178370535Sgit2svn "Binary cpio format not supported on this platform"); 179370535Sgit2svn return (ARCHIVE_FATAL); 180370535Sgit2svn } 181370535Sgit2svn 182232153Smm archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 183370535Sgit2svn ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_binary"); 184232153Smm 185228753Smm /* If someone else was already registered, unregister them. */ 186232153Smm if (a->format_free != NULL) 187232153Smm (a->format_free)(a); 188228753Smm 189232153Smm cpio = (struct cpio *)calloc(1, sizeof(*cpio)); 190228753Smm if (cpio == NULL) { 191228753Smm archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); 192228753Smm return (ARCHIVE_FATAL); 193228753Smm } 194228753Smm a->format_data = cpio; 195228753Smm a->format_name = "cpio"; 196370535Sgit2svn a->format_options = archive_write_binary_options; 197370535Sgit2svn a->format_write_header = archive_write_binary_header; 198370535Sgit2svn a->format_write_data = archive_write_binary_data; 199370535Sgit2svn a->format_finish_entry = archive_write_binary_finish_entry; 200370535Sgit2svn a->format_close = archive_write_binary_close; 201370535Sgit2svn a->format_free = archive_write_binary_free; 202370535Sgit2svn a->archive.archive_format = format; 203370535Sgit2svn switch (format) { 204370535Sgit2svn case ARCHIVE_FORMAT_CPIO_PWB: 205370535Sgit2svn a->archive.archive_format_name = "PWB cpio"; 206370535Sgit2svn break; 207370535Sgit2svn case ARCHIVE_FORMAT_CPIO_BIN_LE: 208370535Sgit2svn a->archive.archive_format_name = "7th Edition cpio"; 209370535Sgit2svn break; 210370535Sgit2svn default: 211370535Sgit2svn archive_set_error(&a->archive, EINVAL, "binary format must be 'pwb' or 'bin'"); 212370535Sgit2svn return (ARCHIVE_FATAL); 213370535Sgit2svn } 214228753Smm return (ARCHIVE_OK); 215228753Smm} 216228753Smm 217370535Sgit2svn/* 218370535Sgit2svn * Set output format to PWB (6th Edition) binary format 219370535Sgit2svn */ 220370535Sgit2svnint 221370535Sgit2svnarchive_write_set_format_cpio_pwb(struct archive *_a) 222370535Sgit2svn{ 223370535Sgit2svn return archive_write_set_format_cpio_binary(_a, ARCHIVE_FORMAT_CPIO_PWB); 224370535Sgit2svn} 225370535Sgit2svn 226370535Sgit2svn/* 227370535Sgit2svn * Set output format to 7th Edition binary format 228370535Sgit2svn */ 229370535Sgit2svnint 230370535Sgit2svnarchive_write_set_format_cpio_bin(struct archive *_a) 231370535Sgit2svn{ 232370535Sgit2svn return archive_write_set_format_cpio_binary(_a, ARCHIVE_FORMAT_CPIO_BIN_LE); 233370535Sgit2svn} 234370535Sgit2svn 235232153Smmstatic int 236370535Sgit2svnarchive_write_binary_options(struct archive_write *a, const char *key, 237232153Smm const char *val) 238232153Smm{ 239232153Smm struct cpio *cpio = (struct cpio *)a->format_data; 240232153Smm int ret = ARCHIVE_FAILED; 241232153Smm 242232153Smm if (strcmp(key, "hdrcharset") == 0) { 243232153Smm if (val == NULL || val[0] == 0) 244232153Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 245232153Smm "%s: hdrcharset option needs a character-set name", 246232153Smm a->format_name); 247232153Smm else { 248232153Smm cpio->opt_sconv = archive_string_conversion_to_charset( 249232153Smm &a->archive, val, 0); 250232153Smm if (cpio->opt_sconv != NULL) 251232153Smm ret = ARCHIVE_OK; 252232153Smm else 253232153Smm ret = ARCHIVE_FATAL; 254232153Smm } 255232153Smm return (ret); 256232153Smm } 257232153Smm 258232153Smm /* Note: The "warn" return is just to inform the options 259232153Smm * supervisor that we didn't handle it. It will generate 260232153Smm * a suitable error if no one used this option. */ 261232153Smm return (ARCHIVE_WARN); 262232153Smm} 263232153Smm 264228753Smm/* 265228753Smm * Ino values are as long as 64 bits on some systems; cpio format 266370535Sgit2svn * only allows 16 bits and relies on the ino values to identify hardlinked 267228753Smm * files. So, we can't merely "hash" the ino numbers since collisions 268228753Smm * would corrupt the archive. Instead, we generate synthetic ino values 269228753Smm * to store in the archive and maintain a map of original ino values to 270228753Smm * synthetic ones so we can preserve hardlink information. 271228753Smm * 272228753Smm * TODO: Make this more efficient. It's not as bad as it looks (most 273228753Smm * files don't have any hardlinks and we don't do any work here for those), 274228753Smm * but it wouldn't be hard to do better. 275228753Smm * 276228753Smm * TODO: Work with dev/ino pairs here instead of just ino values. 277228753Smm */ 278228753Smmstatic int 279228753Smmsynthesize_ino_value(struct cpio *cpio, struct archive_entry *entry) 280228753Smm{ 281228753Smm int64_t ino = archive_entry_ino64(entry); 282228753Smm int ino_new; 283228753Smm size_t i; 284228753Smm 285228753Smm /* 286228753Smm * If no index number was given, don't assign one. In 287228753Smm * particular, this handles the end-of-archive marker 288228753Smm * correctly by giving it a zero index value. (This is also 289228753Smm * why we start our synthetic index numbers with one below.) 290228753Smm */ 291228753Smm if (ino == 0) 292228753Smm return (0); 293228753Smm 294228753Smm /* Don't store a mapping if we don't need to. */ 295228753Smm if (archive_entry_nlink(entry) < 2) { 296238856Smm return (int)(++cpio->ino_next); 297228753Smm } 298228753Smm 299228753Smm /* Look up old ino; if we have it, this is a hardlink 300228753Smm * and we reuse the same value. */ 301228753Smm for (i = 0; i < cpio->ino_list_next; ++i) { 302228753Smm if (cpio->ino_list[i].old == ino) 303228753Smm return (cpio->ino_list[i].new); 304228753Smm } 305228753Smm 306228753Smm /* Assign a new index number. */ 307238856Smm ino_new = (int)(++cpio->ino_next); 308228753Smm 309228753Smm /* Ensure space for the new mapping. */ 310228753Smm if (cpio->ino_list_size <= cpio->ino_list_next) { 311228753Smm size_t newsize = cpio->ino_list_size < 512 312228753Smm ? 512 : cpio->ino_list_size * 2; 313228753Smm void *newlist = realloc(cpio->ino_list, 314228753Smm sizeof(cpio->ino_list[0]) * newsize); 315228753Smm if (newlist == NULL) 316228753Smm return (-1); 317228753Smm 318228753Smm cpio->ino_list_size = newsize; 319228753Smm cpio->ino_list = newlist; 320228753Smm } 321228753Smm 322228753Smm /* Record and return the new value. */ 323228753Smm cpio->ino_list[cpio->ino_list_next].old = ino; 324228753Smm cpio->ino_list[cpio->ino_list_next].new = ino_new; 325228753Smm ++cpio->ino_list_next; 326228753Smm return (ino_new); 327228753Smm} 328228753Smm 329232153Smm 330232153Smmstatic struct archive_string_conv * 331232153Smmget_sconv(struct archive_write *a) 332232153Smm{ 333232153Smm struct cpio *cpio; 334232153Smm struct archive_string_conv *sconv; 335232153Smm 336232153Smm cpio = (struct cpio *)a->format_data; 337232153Smm sconv = cpio->opt_sconv; 338232153Smm if (sconv == NULL) { 339232153Smm if (!cpio->init_default_conversion) { 340232153Smm cpio->sconv_default = 341232153Smm archive_string_default_conversion_for_write( 342232153Smm &(a->archive)); 343232153Smm cpio->init_default_conversion = 1; 344232153Smm } 345232153Smm sconv = cpio->sconv_default; 346232153Smm } 347232153Smm return (sconv); 348232153Smm} 349232153Smm 350228753Smmstatic int 351370535Sgit2svnarchive_write_binary_header(struct archive_write *a, struct archive_entry *entry) 352228753Smm{ 353232153Smm const char *path; 354232153Smm size_t len; 355232153Smm 356368707Smm if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) { 357232153Smm archive_set_error(&a->archive, -1, "Filetype required"); 358232153Smm return (ARCHIVE_FAILED); 359232153Smm } 360232153Smm 361232153Smm if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0 362232153Smm && errno == ENOMEM) { 363232153Smm archive_set_error(&a->archive, ENOMEM, 364232153Smm "Can't allocate memory for Pathname"); 365232153Smm return (ARCHIVE_FATAL); 366232153Smm } 367232153Smm if (len == 0 || path == NULL || path[0] == '\0') { 368232153Smm archive_set_error(&a->archive, -1, "Pathname required"); 369232153Smm return (ARCHIVE_FAILED); 370232153Smm } 371232153Smm 372232153Smm if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) { 373232153Smm archive_set_error(&a->archive, -1, "Size required"); 374232153Smm return (ARCHIVE_FAILED); 375232153Smm } 376232153Smm return write_header(a, entry); 377232153Smm} 378232153Smm 379232153Smmstatic int 380232153Smmwrite_header(struct archive_write *a, struct archive_entry *entry) 381232153Smm{ 382228753Smm struct cpio *cpio; 383228753Smm const char *p, *path; 384232153Smm int pathlength, ret, ret_final; 385228753Smm int64_t ino; 386370535Sgit2svn struct cpio_binary_header h; 387232153Smm struct archive_string_conv *sconv; 388232153Smm struct archive_entry *entry_main; 389232153Smm size_t len; 390228753Smm 391228753Smm cpio = (struct cpio *)a->format_data; 392232153Smm ret_final = ARCHIVE_OK; 393232153Smm sconv = get_sconv(a); 394228753Smm 395232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 396311041Smm /* Make sure the path separators in pathname, hardlink and symlink 397232153Smm * are all slash '/', not the Windows path separator '\'. */ 398232153Smm entry_main = __la_win_entry_in_posix_pathseparator(entry); 399232153Smm if (entry_main == NULL) { 400232153Smm archive_set_error(&a->archive, ENOMEM, 401232153Smm "Can't allocate ustar data"); 402232153Smm return(ARCHIVE_FATAL); 403232153Smm } 404232153Smm if (entry != entry_main) 405232153Smm entry = entry_main; 406232153Smm else 407232153Smm entry_main = NULL; 408232153Smm#else 409232153Smm entry_main = NULL; 410232153Smm#endif 411228753Smm 412232153Smm ret = archive_entry_pathname_l(entry, &path, &len, sconv); 413232153Smm if (ret != 0) { 414232153Smm if (errno == ENOMEM) { 415232153Smm archive_set_error(&a->archive, ENOMEM, 416232153Smm "Can't allocate memory for Pathname"); 417232153Smm ret_final = ARCHIVE_FATAL; 418232153Smm goto exit_write_header; 419232153Smm } 420232153Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 421232153Smm "Can't translate pathname '%s' to %s", 422232153Smm archive_entry_pathname(entry), 423232153Smm archive_string_conversion_charset_name(sconv)); 424232153Smm ret_final = ARCHIVE_WARN; 425232153Smm } 426370535Sgit2svn /* Include trailing null */ 427232153Smm pathlength = (int)len + 1; 428228753Smm 429370535Sgit2svn h.h_magic = swap16(070707); 430370535Sgit2svn h.h_dev = swap16(archive_entry_dev(entry)); 431232153Smm 432228753Smm ino = synthesize_ino_value(cpio, entry); 433228753Smm if (ino < 0) { 434228753Smm archive_set_error(&a->archive, ENOMEM, 435228753Smm "No memory for ino translation table"); 436232153Smm ret_final = ARCHIVE_FATAL; 437232153Smm goto exit_write_header; 438370535Sgit2svn } else if (ino > 077777) { 439228753Smm archive_set_error(&a->archive, ERANGE, 440228753Smm "Too many files for this cpio format"); 441232153Smm ret_final = ARCHIVE_FATAL; 442232153Smm goto exit_write_header; 443228753Smm } 444370535Sgit2svn h.h_ino = swap16(ino); 445228753Smm 446370535Sgit2svn h.h_mode = archive_entry_mode(entry); 447370535Sgit2svn if (((h.h_mode & AE_IFMT) == AE_IFSOCK) || ((h.h_mode & AE_IFMT) == AE_IFIFO)) { 448370535Sgit2svn archive_set_error(&a->archive, EINVAL, 449370535Sgit2svn "sockets and fifos cannot be represented in the binary cpio formats"); 450370535Sgit2svn ret_final = ARCHIVE_FATAL; 451370535Sgit2svn goto exit_write_header; 452370535Sgit2svn } 453370535Sgit2svn if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) { 454370535Sgit2svn if ((h.h_mode & AE_IFMT) == AE_IFLNK) { 455370535Sgit2svn archive_set_error(&a->archive, EINVAL, 456370535Sgit2svn "symbolic links cannot be represented in the PWB cpio format"); 457370535Sgit2svn ret_final = ARCHIVE_FATAL; 458370535Sgit2svn goto exit_write_header; 459370535Sgit2svn } 460370535Sgit2svn /* we could turn off AE_IFREG here, but it does no harm, */ 461370535Sgit2svn /* and allows v7 cpio to read the entry without confusion */ 462370535Sgit2svn } 463370535Sgit2svn h.h_mode = swap16(h.h_mode); 464370535Sgit2svn 465370535Sgit2svn h.h_uid = swap16(archive_entry_uid(entry)); 466370535Sgit2svn h.h_gid = swap16(archive_entry_gid(entry)); 467370535Sgit2svn h.h_nlink = swap16(archive_entry_nlink(entry)); 468370535Sgit2svn 469228753Smm if (archive_entry_filetype(entry) == AE_IFBLK 470228753Smm || archive_entry_filetype(entry) == AE_IFCHR) 471370535Sgit2svn h.h_majmin = swap16(archive_entry_rdev(entry)); 472228753Smm else 473370535Sgit2svn h.h_majmin = 0; 474228753Smm 475370535Sgit2svn h.h_mtime = swap32(archive_entry_mtime(entry)); 476370535Sgit2svn h.h_namesize = swap16(pathlength); 477370535Sgit2svn 478228753Smm /* Non-regular files don't store bodies. */ 479228753Smm if (archive_entry_filetype(entry) != AE_IFREG) 480228753Smm archive_entry_set_size(entry, 0); 481228753Smm 482228753Smm /* Symlinks get the link written as the body of the entry. */ 483232153Smm ret = archive_entry_symlink_l(entry, &p, &len, sconv); 484232153Smm if (ret != 0) { 485232153Smm if (errno == ENOMEM) { 486232153Smm archive_set_error(&a->archive, ENOMEM, 487232153Smm "Can't allocate memory for Linkname"); 488232153Smm ret_final = ARCHIVE_FATAL; 489232153Smm goto exit_write_header; 490232153Smm } 491232153Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 492232153Smm "Can't translate linkname '%s' to %s", 493232153Smm archive_entry_symlink(entry), 494232153Smm archive_string_conversion_charset_name(sconv)); 495232153Smm ret_final = ARCHIVE_WARN; 496232153Smm } 497370535Sgit2svn 498370535Sgit2svn if (len > 0 && p != NULL && *p != '\0') { 499370535Sgit2svn if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) { 500370535Sgit2svn archive_set_error(&a->archive, EINVAL, 501370535Sgit2svn "symlinks are not supported by UNIX V6 or by PWB cpio"); 502370535Sgit2svn ret_final = ARCHIVE_FATAL; 503370535Sgit2svn goto exit_write_header; 504370535Sgit2svn } 505370535Sgit2svn h.h_filesize = swap32(strlen(p)); /* symlink */ 506370535Sgit2svn } else { 507370535Sgit2svn if ((a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) && 508370535Sgit2svn (archive_entry_size(entry) > 256*256*256-1)) { 509370535Sgit2svn archive_set_error(&a->archive, ERANGE, 510370535Sgit2svn "File is too large for PWB binary cpio format."); 511370535Sgit2svn ret_final = ARCHIVE_FAILED; 512370535Sgit2svn goto exit_write_header; 513370535Sgit2svn } else if (archive_entry_size(entry) > INT32_MAX) { 514370535Sgit2svn archive_set_error(&a->archive, ERANGE, 515370535Sgit2svn "File is too large for binary cpio format."); 516370535Sgit2svn ret_final = ARCHIVE_FAILED; 517370535Sgit2svn goto exit_write_header; 518370535Sgit2svn } 519370535Sgit2svn h.h_filesize = swap32(archive_entry_size(entry)); /* file */ 520232153Smm } 521228753Smm 522370535Sgit2svn ret = __archive_write_output(a, &h, HSIZE); 523232153Smm if (ret != ARCHIVE_OK) { 524232153Smm ret_final = ARCHIVE_FATAL; 525232153Smm goto exit_write_header; 526232153Smm } 527228753Smm 528232153Smm ret = __archive_write_output(a, path, pathlength); 529370535Sgit2svn if ((ret == ARCHIVE_OK) && ((pathlength % 2) != 0)) 530370535Sgit2svn ret = __archive_write_nulls(a, 1); 531232153Smm if (ret != ARCHIVE_OK) { 532232153Smm ret_final = ARCHIVE_FATAL; 533232153Smm goto exit_write_header; 534232153Smm } 535228753Smm 536228753Smm cpio->entry_bytes_remaining = archive_entry_size(entry); 537370535Sgit2svn if ((cpio->entry_bytes_remaining % 2) != 0) 538370535Sgit2svn cpio->entry_bytes_remaining++; 539228753Smm 540228753Smm /* Write the symlink now. */ 541232153Smm if (p != NULL && *p != '\0') { 542232153Smm ret = __archive_write_output(a, p, strlen(p)); 543370535Sgit2svn if ((ret == ARCHIVE_OK) && ((strlen(p) % 2) != 0)) 544370535Sgit2svn ret = __archive_write_nulls(a, 1); 545232153Smm if (ret != ARCHIVE_OK) { 546232153Smm ret_final = ARCHIVE_FATAL; 547232153Smm goto exit_write_header; 548232153Smm } 549232153Smm } 550370535Sgit2svn 551232153Smmexit_write_header: 552344673Smm archive_entry_free(entry_main); 553232153Smm return (ret_final); 554228753Smm} 555228753Smm 556228753Smmstatic ssize_t 557370535Sgit2svnarchive_write_binary_data(struct archive_write *a, const void *buff, size_t s) 558228753Smm{ 559228753Smm struct cpio *cpio; 560228753Smm int ret; 561228753Smm 562228753Smm cpio = (struct cpio *)a->format_data; 563228753Smm if (s > cpio->entry_bytes_remaining) 564238856Smm s = (size_t)cpio->entry_bytes_remaining; 565228753Smm 566232153Smm ret = __archive_write_output(a, buff, s); 567228753Smm cpio->entry_bytes_remaining -= s; 568228753Smm if (ret >= 0) 569228753Smm return (s); 570228753Smm else 571228753Smm return (ret); 572228753Smm} 573228753Smm 574228753Smmstatic int 575370535Sgit2svnarchive_write_binary_close(struct archive_write *a) 576228753Smm{ 577228753Smm int er; 578228753Smm struct archive_entry *trailer; 579228753Smm 580232153Smm trailer = archive_entry_new2(NULL); 581228753Smm /* nlink = 1 here for GNU cpio compat. */ 582228753Smm archive_entry_set_nlink(trailer, 1); 583232153Smm archive_entry_set_size(trailer, 0); 584228753Smm archive_entry_set_pathname(trailer, "TRAILER!!!"); 585232153Smm er = write_header(a, trailer); 586228753Smm archive_entry_free(trailer); 587228753Smm return (er); 588228753Smm} 589228753Smm 590228753Smmstatic int 591370535Sgit2svnarchive_write_binary_free(struct archive_write *a) 592228753Smm{ 593228753Smm struct cpio *cpio; 594228753Smm 595228753Smm cpio = (struct cpio *)a->format_data; 596228753Smm free(cpio->ino_list); 597228753Smm free(cpio); 598228753Smm a->format_data = NULL; 599228753Smm return (ARCHIVE_OK); 600228753Smm} 601228753Smm 602228753Smmstatic int 603370535Sgit2svnarchive_write_binary_finish_entry(struct archive_write *a) 604228753Smm{ 605228753Smm struct cpio *cpio; 606228753Smm 607228753Smm cpio = (struct cpio *)a->format_data; 608238856Smm return (__archive_write_nulls(a, 609238856Smm (size_t)cpio->entry_bytes_remaining)); 610228753Smm} 611