archive_write_set_format_cpio.c revision 228753
1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "archive_platform.h" 27228753Smm__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $"); 28228753Smm 29228753Smm#ifdef HAVE_ERRNO_H 30228753Smm#include <errno.h> 31228753Smm#endif 32228753Smm#include <stdio.h> 33228753Smm#ifdef HAVE_STDLIB_H 34228753Smm#include <stdlib.h> 35228753Smm#endif 36228753Smm#ifdef HAVE_STRING_H 37228753Smm#include <string.h> 38228753Smm#endif 39228753Smm 40228753Smm#include "archive.h" 41228753Smm#include "archive_entry.h" 42228753Smm#include "archive_private.h" 43228753Smm#include "archive_write_private.h" 44228753Smm 45228753Smmstatic ssize_t archive_write_cpio_data(struct archive_write *, 46228753Smm const void *buff, size_t s); 47228753Smmstatic int archive_write_cpio_finish(struct archive_write *); 48228753Smmstatic int archive_write_cpio_destroy(struct archive_write *); 49228753Smmstatic int archive_write_cpio_finish_entry(struct archive_write *); 50228753Smmstatic int archive_write_cpio_header(struct archive_write *, 51228753Smm struct archive_entry *); 52228753Smmstatic int format_octal(int64_t, void *, int); 53228753Smmstatic int64_t format_octal_recursive(int64_t, char *, int); 54228753Smm 55228753Smmstruct cpio { 56228753Smm uint64_t entry_bytes_remaining; 57228753Smm 58228753Smm int64_t ino_next; 59228753Smm 60228753Smm struct { int64_t old; int new;} *ino_list; 61228753Smm size_t ino_list_size; 62228753Smm size_t ino_list_next; 63228753Smm}; 64228753Smm 65228753Smmstruct cpio_header { 66228753Smm char c_magic[6]; 67228753Smm char c_dev[6]; 68228753Smm char c_ino[6]; 69228753Smm char c_mode[6]; 70228753Smm char c_uid[6]; 71228753Smm char c_gid[6]; 72228753Smm char c_nlink[6]; 73228753Smm char c_rdev[6]; 74228753Smm char c_mtime[11]; 75228753Smm char c_namesize[6]; 76228753Smm char c_filesize[11]; 77228753Smm}; 78228753Smm 79228753Smm/* 80228753Smm * Set output format to 'cpio' format. 81228753Smm */ 82228753Smmint 83228753Smmarchive_write_set_format_cpio(struct archive *_a) 84228753Smm{ 85228753Smm struct archive_write *a = (struct archive_write *)_a; 86228753Smm struct cpio *cpio; 87228753Smm 88228753Smm /* If someone else was already registered, unregister them. */ 89228753Smm if (a->format_destroy != NULL) 90228753Smm (a->format_destroy)(a); 91228753Smm 92228753Smm cpio = (struct cpio *)malloc(sizeof(*cpio)); 93228753Smm if (cpio == NULL) { 94228753Smm archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); 95228753Smm return (ARCHIVE_FATAL); 96228753Smm } 97228753Smm memset(cpio, 0, sizeof(*cpio)); 98228753Smm a->format_data = cpio; 99228753Smm 100228753Smm a->pad_uncompressed = 1; 101228753Smm a->format_name = "cpio"; 102228753Smm a->format_write_header = archive_write_cpio_header; 103228753Smm a->format_write_data = archive_write_cpio_data; 104228753Smm a->format_finish_entry = archive_write_cpio_finish_entry; 105228753Smm a->format_finish = archive_write_cpio_finish; 106228753Smm a->format_destroy = archive_write_cpio_destroy; 107228753Smm a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; 108228753Smm a->archive.archive_format_name = "POSIX cpio"; 109228753Smm return (ARCHIVE_OK); 110228753Smm} 111228753Smm 112228753Smm/* 113228753Smm * Ino values are as long as 64 bits on some systems; cpio format 114228753Smm * only allows 18 bits and relies on the ino values to identify hardlinked 115228753Smm * files. So, we can't merely "hash" the ino numbers since collisions 116228753Smm * would corrupt the archive. Instead, we generate synthetic ino values 117228753Smm * to store in the archive and maintain a map of original ino values to 118228753Smm * synthetic ones so we can preserve hardlink information. 119228753Smm * 120228753Smm * TODO: Make this more efficient. It's not as bad as it looks (most 121228753Smm * files don't have any hardlinks and we don't do any work here for those), 122228753Smm * but it wouldn't be hard to do better. 123228753Smm * 124228753Smm * TODO: Work with dev/ino pairs here instead of just ino values. 125228753Smm */ 126228753Smmstatic int 127228753Smmsynthesize_ino_value(struct cpio *cpio, struct archive_entry *entry) 128228753Smm{ 129228753Smm int64_t ino = archive_entry_ino64(entry); 130228753Smm int ino_new; 131228753Smm size_t i; 132228753Smm 133228753Smm /* 134228753Smm * If no index number was given, don't assign one. In 135228753Smm * particular, this handles the end-of-archive marker 136228753Smm * correctly by giving it a zero index value. (This is also 137228753Smm * why we start our synthetic index numbers with one below.) 138228753Smm */ 139228753Smm if (ino == 0) 140228753Smm return (0); 141228753Smm 142228753Smm /* Don't store a mapping if we don't need to. */ 143228753Smm if (archive_entry_nlink(entry) < 2) { 144228753Smm return ++cpio->ino_next; 145228753Smm } 146228753Smm 147228753Smm /* Look up old ino; if we have it, this is a hardlink 148228753Smm * and we reuse the same value. */ 149228753Smm for (i = 0; i < cpio->ino_list_next; ++i) { 150228753Smm if (cpio->ino_list[i].old == ino) 151228753Smm return (cpio->ino_list[i].new); 152228753Smm } 153228753Smm 154228753Smm /* Assign a new index number. */ 155228753Smm ino_new = ++cpio->ino_next; 156228753Smm 157228753Smm /* Ensure space for the new mapping. */ 158228753Smm if (cpio->ino_list_size <= cpio->ino_list_next) { 159228753Smm size_t newsize = cpio->ino_list_size < 512 160228753Smm ? 512 : cpio->ino_list_size * 2; 161228753Smm void *newlist = realloc(cpio->ino_list, 162228753Smm sizeof(cpio->ino_list[0]) * newsize); 163228753Smm if (newlist == NULL) 164228753Smm return (-1); 165228753Smm 166228753Smm cpio->ino_list_size = newsize; 167228753Smm cpio->ino_list = newlist; 168228753Smm } 169228753Smm 170228753Smm /* Record and return the new value. */ 171228753Smm cpio->ino_list[cpio->ino_list_next].old = ino; 172228753Smm cpio->ino_list[cpio->ino_list_next].new = ino_new; 173228753Smm ++cpio->ino_list_next; 174228753Smm return (ino_new); 175228753Smm} 176228753Smm 177228753Smmstatic int 178228753Smmarchive_write_cpio_header(struct archive_write *a, struct archive_entry *entry) 179228753Smm{ 180228753Smm struct cpio *cpio; 181228753Smm const char *p, *path; 182228753Smm int pathlength, ret, ret2; 183228753Smm int64_t ino; 184228753Smm struct cpio_header h; 185228753Smm 186228753Smm cpio = (struct cpio *)a->format_data; 187228753Smm ret2 = ARCHIVE_OK; 188228753Smm 189228753Smm path = archive_entry_pathname(entry); 190228753Smm pathlength = (int)strlen(path) + 1; /* Include trailing null. */ 191228753Smm 192228753Smm memset(&h, 0, sizeof(h)); 193228753Smm format_octal(070707, &h.c_magic, sizeof(h.c_magic)); 194228753Smm format_octal(archive_entry_dev(entry), &h.c_dev, sizeof(h.c_dev)); 195228753Smm 196228753Smm ino = synthesize_ino_value(cpio, entry); 197228753Smm if (ino < 0) { 198228753Smm archive_set_error(&a->archive, ENOMEM, 199228753Smm "No memory for ino translation table"); 200228753Smm return (ARCHIVE_FATAL); 201228753Smm } else if (ino > 0777777) { 202228753Smm archive_set_error(&a->archive, ERANGE, 203228753Smm "Too many files for this cpio format"); 204228753Smm return (ARCHIVE_FATAL); 205228753Smm } 206228753Smm format_octal(ino & 0777777, &h.c_ino, sizeof(h.c_ino)); 207228753Smm 208228753Smm format_octal(archive_entry_mode(entry), &h.c_mode, sizeof(h.c_mode)); 209228753Smm format_octal(archive_entry_uid(entry), &h.c_uid, sizeof(h.c_uid)); 210228753Smm format_octal(archive_entry_gid(entry), &h.c_gid, sizeof(h.c_gid)); 211228753Smm format_octal(archive_entry_nlink(entry), &h.c_nlink, sizeof(h.c_nlink)); 212228753Smm if (archive_entry_filetype(entry) == AE_IFBLK 213228753Smm || archive_entry_filetype(entry) == AE_IFCHR) 214228753Smm format_octal(archive_entry_dev(entry), &h.c_rdev, sizeof(h.c_rdev)); 215228753Smm else 216228753Smm format_octal(0, &h.c_rdev, sizeof(h.c_rdev)); 217228753Smm format_octal(archive_entry_mtime(entry), &h.c_mtime, sizeof(h.c_mtime)); 218228753Smm format_octal(pathlength, &h.c_namesize, sizeof(h.c_namesize)); 219228753Smm 220228753Smm /* Non-regular files don't store bodies. */ 221228753Smm if (archive_entry_filetype(entry) != AE_IFREG) 222228753Smm archive_entry_set_size(entry, 0); 223228753Smm 224228753Smm /* Symlinks get the link written as the body of the entry. */ 225228753Smm p = archive_entry_symlink(entry); 226228753Smm if (p != NULL && *p != '\0') 227228753Smm format_octal(strlen(p), &h.c_filesize, sizeof(h.c_filesize)); 228228753Smm else 229228753Smm format_octal(archive_entry_size(entry), 230228753Smm &h.c_filesize, sizeof(h.c_filesize)); 231228753Smm 232228753Smm ret = (a->compressor.write)(a, &h, sizeof(h)); 233228753Smm if (ret != ARCHIVE_OK) 234228753Smm return (ARCHIVE_FATAL); 235228753Smm 236228753Smm ret = (a->compressor.write)(a, path, pathlength); 237228753Smm if (ret != ARCHIVE_OK) 238228753Smm return (ARCHIVE_FATAL); 239228753Smm 240228753Smm cpio->entry_bytes_remaining = archive_entry_size(entry); 241228753Smm 242228753Smm /* Write the symlink now. */ 243228753Smm if (p != NULL && *p != '\0') 244228753Smm ret = (a->compressor.write)(a, p, strlen(p)); 245228753Smm 246228753Smm if (ret == ARCHIVE_OK) 247228753Smm ret = ret2; 248228753Smm return (ret); 249228753Smm} 250228753Smm 251228753Smmstatic ssize_t 252228753Smmarchive_write_cpio_data(struct archive_write *a, const void *buff, size_t s) 253228753Smm{ 254228753Smm struct cpio *cpio; 255228753Smm int ret; 256228753Smm 257228753Smm cpio = (struct cpio *)a->format_data; 258228753Smm if (s > cpio->entry_bytes_remaining) 259228753Smm s = cpio->entry_bytes_remaining; 260228753Smm 261228753Smm ret = (a->compressor.write)(a, buff, s); 262228753Smm cpio->entry_bytes_remaining -= s; 263228753Smm if (ret >= 0) 264228753Smm return (s); 265228753Smm else 266228753Smm return (ret); 267228753Smm} 268228753Smm 269228753Smm/* 270228753Smm * Format a number into the specified field. 271228753Smm */ 272228753Smmstatic int 273228753Smmformat_octal(int64_t v, void *p, int digits) 274228753Smm{ 275228753Smm int64_t max; 276228753Smm int ret; 277228753Smm 278228753Smm max = (((int64_t)1) << (digits * 3)) - 1; 279228753Smm if (v >= 0 && v <= max) { 280228753Smm format_octal_recursive(v, (char *)p, digits); 281228753Smm ret = 0; 282228753Smm } else { 283228753Smm format_octal_recursive(max, (char *)p, digits); 284228753Smm ret = -1; 285228753Smm } 286228753Smm return (ret); 287228753Smm} 288228753Smm 289228753Smmstatic int64_t 290228753Smmformat_octal_recursive(int64_t v, char *p, int s) 291228753Smm{ 292228753Smm if (s == 0) 293228753Smm return (v); 294228753Smm v = format_octal_recursive(v, p+1, s-1); 295228753Smm *p = '0' + (v & 7); 296228753Smm return (v >> 3); 297228753Smm} 298228753Smm 299228753Smmstatic int 300228753Smmarchive_write_cpio_finish(struct archive_write *a) 301228753Smm{ 302228753Smm int er; 303228753Smm struct archive_entry *trailer; 304228753Smm 305228753Smm trailer = archive_entry_new(); 306228753Smm /* nlink = 1 here for GNU cpio compat. */ 307228753Smm archive_entry_set_nlink(trailer, 1); 308228753Smm archive_entry_set_pathname(trailer, "TRAILER!!!"); 309228753Smm er = archive_write_cpio_header(a, trailer); 310228753Smm archive_entry_free(trailer); 311228753Smm return (er); 312228753Smm} 313228753Smm 314228753Smmstatic int 315228753Smmarchive_write_cpio_destroy(struct archive_write *a) 316228753Smm{ 317228753Smm struct cpio *cpio; 318228753Smm 319228753Smm cpio = (struct cpio *)a->format_data; 320228753Smm free(cpio->ino_list); 321228753Smm free(cpio); 322228753Smm a->format_data = NULL; 323228753Smm return (ARCHIVE_OK); 324228753Smm} 325228753Smm 326228753Smmstatic int 327228753Smmarchive_write_cpio_finish_entry(struct archive_write *a) 328228753Smm{ 329228753Smm struct cpio *cpio; 330228753Smm size_t to_write; 331228753Smm int ret; 332228753Smm 333228753Smm cpio = (struct cpio *)a->format_data; 334228753Smm ret = ARCHIVE_OK; 335228753Smm while (cpio->entry_bytes_remaining > 0) { 336228753Smm to_write = cpio->entry_bytes_remaining < a->null_length ? 337228753Smm cpio->entry_bytes_remaining : a->null_length; 338228753Smm ret = (a->compressor.write)(a, a->nulls, to_write); 339228753Smm if (ret != ARCHIVE_OK) 340228753Smm return (ret); 341228753Smm cpio->entry_bytes_remaining -= to_write; 342228753Smm } 343228753Smm return (ret); 344228753Smm} 345