archive_write_set_format_cpio.c revision 228761
1235783Skib/*- 2235783Skib * Copyright (c) 2003-2007 Tim Kientzle 3235783Skib * All rights reserved. 4235783Skib * 5235783Skib * Redistribution and use in source and binary forms, with or without 6235783Skib * modification, are permitted provided that the following conditions 7235783Skib * are met: 8235783Skib * 1. Redistributions of source code must retain the above copyright 9235783Skib * notice, this list of conditions and the following disclaimer. 10235783Skib * 2. Redistributions in binary form must reproduce the above copyright 11235783Skib * notice, this list of conditions and the following disclaimer in the 12235783Skib * documentation and/or other materials provided with the distribution. 13235783Skib * 14235783Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15235783Skib * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16235783Skib * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17235783Skib * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18235783Skib * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19235783Skib * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20235783Skib * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21235783Skib * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22235783Skib * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23235783Skib * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24235783Skib */ 25235783Skib 26235783Skib#include "archive_platform.h" 27235783Skib__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $"); 28235783Skib 29235783Skib#ifdef HAVE_ERRNO_H 30235783Skib#include <errno.h> 31235783Skib#endif 32235783Skib#include <stdio.h> 33235783Skib#ifdef HAVE_STDLIB_H 34235783Skib#include <stdlib.h> 35235783Skib#endif 36235783Skib#ifdef HAVE_STRING_H 37235783Skib#include <string.h> 38235783Skib#endif 39235783Skib 40235783Skib#include "archive.h" 41235783Skib#include "archive_entry.h" 42235783Skib#include "archive_private.h" 43235783Skib#include "archive_write_private.h" 44235783Skib 45235783Skibstatic ssize_t archive_write_cpio_data(struct archive_write *, 46235783Skib const void *buff, size_t s); 47235783Skibstatic int archive_write_cpio_finish(struct archive_write *); 48235783Skibstatic int archive_write_cpio_destroy(struct archive_write *); 49235783Skibstatic int archive_write_cpio_finish_entry(struct archive_write *); 50235783Skibstatic int archive_write_cpio_header(struct archive_write *, 51235783Skib struct archive_entry *); 52235783Skibstatic int format_octal(int64_t, void *, int); 53235783Skibstatic int64_t format_octal_recursive(int64_t, char *, int); 54235783Skib 55235783Skibstruct cpio { 56235783Skib uint64_t entry_bytes_remaining; 57235783Skib 58235783Skib int64_t ino_next; 59235783Skib 60235783Skib struct { int64_t old; int new;} *ino_list; 61235783Skib size_t ino_list_size; 62235783Skib size_t ino_list_next; 63235783Skib}; 64235783Skib 65235783Skibstruct cpio_header { 66235783Skib char c_magic[6]; 67235783Skib char c_dev[6]; 68235783Skib char c_ino[6]; 69235783Skib char c_mode[6]; 70235783Skib char c_uid[6]; 71235783Skib char c_gid[6]; 72235783Skib char c_nlink[6]; 73235783Skib char c_rdev[6]; 74235783Skib char c_mtime[11]; 75235783Skib char c_namesize[6]; 76235783Skib char c_filesize[11]; 77235783Skib}; 78235783Skib 79235783Skib/* 80235783Skib * Set output format to 'cpio' format. 81235783Skib */ 82235783Skibint 83235783Skibarchive_write_set_format_cpio(struct archive *_a) 84235783Skib{ 85235783Skib struct archive_write *a = (struct archive_write *)_a; 86235783Skib struct cpio *cpio; 87235783Skib 88235783Skib /* If someone else was already registered, unregister them. */ 89235783Skib if (a->format_destroy != NULL) 90235783Skib (a->format_destroy)(a); 91235783Skib 92235783Skib cpio = (struct cpio *)malloc(sizeof(*cpio)); 93235783Skib if (cpio == NULL) { 94235783Skib archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); 95235783Skib return (ARCHIVE_FATAL); 96235783Skib } 97235783Skib memset(cpio, 0, sizeof(*cpio)); 98235783Skib a->format_data = cpio; 99235783Skib 100235783Skib a->pad_uncompressed = 1; 101235783Skib a->format_name = "cpio"; 102235783Skib a->format_write_header = archive_write_cpio_header; 103235783Skib a->format_write_data = archive_write_cpio_data; 104235783Skib a->format_finish_entry = archive_write_cpio_finish_entry; 105235783Skib a->format_finish = archive_write_cpio_finish; 106235783Skib a->format_destroy = archive_write_cpio_destroy; 107235783Skib a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; 108235783Skib a->archive.archive_format_name = "POSIX cpio"; 109235783Skib return (ARCHIVE_OK); 110235783Skib} 111235783Skib 112235783Skib/* 113235783Skib * Ino values are as long as 64 bits on some systems; cpio format 114235783Skib * only allows 18 bits and relies on the ino values to identify hardlinked 115235783Skib * files. So, we can't merely "hash" the ino numbers since collisions 116235783Skib * would corrupt the archive. Instead, we generate synthetic ino values 117235783Skib * to store in the archive and maintain a map of original ino values to 118235783Skib * synthetic ones so we can preserve hardlink information. 119235783Skib * 120235783Skib * TODO: Make this more efficient. It's not as bad as it looks (most 121235783Skib * files don't have any hardlinks and we don't do any work here for those), 122235783Skib * but it wouldn't be hard to do better. 123235783Skib * 124235783Skib * TODO: Work with dev/ino pairs here instead of just ino values. 125235783Skib */ 126235783Skibstatic int 127235783Skibsynthesize_ino_value(struct cpio *cpio, struct archive_entry *entry) 128235783Skib{ 129235783Skib int64_t ino = archive_entry_ino64(entry); 130235783Skib int ino_new; 131235783Skib size_t i; 132235783Skib 133235783Skib /* 134235783Skib * If no index number was given, don't assign one. In 135235783Skib * particular, this handles the end-of-archive marker 136235783Skib * correctly by giving it a zero index value. (This is also 137235783Skib * why we start our synthetic index numbers with one below.) 138235783Skib */ 139235783Skib if (ino == 0) 140235783Skib return (0); 141235783Skib 142235783Skib /* Don't store a mapping if we don't need to. */ 143235783Skib if (archive_entry_nlink(entry) < 2) { 144235783Skib return ++cpio->ino_next; 145235783Skib } 146235783Skib 147235783Skib /* Look up old ino; if we have it, this is a hardlink 148235783Skib * and we reuse the same value. */ 149235783Skib for (i = 0; i < cpio->ino_list_next; ++i) { 150235783Skib if (cpio->ino_list[i].old == ino) 151235783Skib return (cpio->ino_list[i].new); 152235783Skib } 153235783Skib 154235783Skib /* Assign a new index number. */ 155235783Skib ino_new = ++cpio->ino_next; 156235783Skib 157235783Skib /* Ensure space for the new mapping. */ 158235783Skib if (cpio->ino_list_size <= cpio->ino_list_next) { 159235783Skib size_t newsize = cpio->ino_list_size < 512 160235783Skib ? 512 : cpio->ino_list_size * 2; 161235783Skib void *newlist = realloc(cpio->ino_list, 162235783Skib sizeof(cpio->ino_list[0]) * newsize); 163235783Skib if (newlist == NULL) 164235783Skib return (-1); 165235783Skib 166235783Skib cpio->ino_list_size = newsize; 167235783Skib cpio->ino_list = newlist; 168235783Skib } 169235783Skib 170235783Skib /* Record and return the new value. */ 171235783Skib cpio->ino_list[cpio->ino_list_next].old = ino; 172235783Skib cpio->ino_list[cpio->ino_list_next].new = ino_new; 173235783Skib ++cpio->ino_list_next; 174235783Skib return (ino_new); 175235783Skib} 176235783Skib 177235783Skibstatic int 178235783Skibarchive_write_cpio_header(struct archive_write *a, struct archive_entry *entry) 179235783Skib{ 180235783Skib struct cpio *cpio; 181235783Skib const char *p, *path; 182235783Skib int pathlength, ret, ret2; 183235783Skib int64_t ino; 184235783Skib struct cpio_header h; 185235783Skib 186235783Skib cpio = (struct cpio *)a->format_data; 187235783Skib ret2 = ARCHIVE_OK; 188235783Skib 189235783Skib path = archive_entry_pathname(entry); 190235783Skib pathlength = (int)strlen(path) + 1; /* Include trailing null. */ 191235783Skib 192235783Skib memset(&h, 0, sizeof(h)); 193235783Skib format_octal(070707, &h.c_magic, sizeof(h.c_magic)); 194235783Skib format_octal(archive_entry_dev(entry), &h.c_dev, sizeof(h.c_dev)); 195255013Sjkim 196235783Skib ino = synthesize_ino_value(cpio, entry); 197235783Skib if (ino < 0) { 198235783Skib archive_set_error(&a->archive, ENOMEM, 199235783Skib "No memory for ino translation table"); 200235783Skib return (ARCHIVE_FATAL); 201235783Skib } else if (ino > 0777777) { 202235783Skib archive_set_error(&a->archive, ERANGE, 203235783Skib "Too many files for this cpio format"); 204235783Skib return (ARCHIVE_FATAL); 205235783Skib } 206235783Skib format_octal(ino & 0777777, &h.c_ino, sizeof(h.c_ino)); 207235783Skib 208235783Skib format_octal(archive_entry_mode(entry), &h.c_mode, sizeof(h.c_mode)); 209235783Skib format_octal(archive_entry_uid(entry), &h.c_uid, sizeof(h.c_uid)); 210235783Skib format_octal(archive_entry_gid(entry), &h.c_gid, sizeof(h.c_gid)); 211235783Skib format_octal(archive_entry_nlink(entry), &h.c_nlink, sizeof(h.c_nlink)); 212235783Skib if (archive_entry_filetype(entry) == AE_IFBLK 213235783Skib || archive_entry_filetype(entry) == AE_IFCHR) 214235783Skib format_octal(archive_entry_dev(entry), &h.c_rdev, sizeof(h.c_rdev)); 215235783Skib else 216235783Skib format_octal(0, &h.c_rdev, sizeof(h.c_rdev)); 217235783Skib format_octal(archive_entry_mtime(entry), &h.c_mtime, sizeof(h.c_mtime)); 218235783Skib format_octal(pathlength, &h.c_namesize, sizeof(h.c_namesize)); 219235783Skib 220235783Skib /* Non-regular files don't store bodies. */ 221235783Skib if (archive_entry_filetype(entry) != AE_IFREG) 222235783Skib archive_entry_set_size(entry, 0); 223235783Skib 224235783Skib /* Symlinks get the link written as the body of the entry. */ 225235783Skib p = archive_entry_symlink(entry); 226235783Skib if (p != NULL && *p != '\0') 227235783Skib format_octal(strlen(p), &h.c_filesize, sizeof(h.c_filesize)); 228235783Skib else 229235783Skib format_octal(archive_entry_size(entry), 230235783Skib &h.c_filesize, sizeof(h.c_filesize)); 231235783Skib 232235783Skib ret = (a->compressor.write)(a, &h, sizeof(h)); 233235783Skib if (ret != ARCHIVE_OK) 234235783Skib return (ARCHIVE_FATAL); 235235783Skib 236235783Skib ret = (a->compressor.write)(a, path, pathlength); 237235783Skib if (ret != ARCHIVE_OK) 238235783Skib return (ARCHIVE_FATAL); 239235783Skib 240235783Skib cpio->entry_bytes_remaining = archive_entry_size(entry); 241235783Skib 242235783Skib /* Write the symlink now. */ 243235783Skib if (p != NULL && *p != '\0') 244235783Skib ret = (a->compressor.write)(a, p, strlen(p)); 245235783Skib 246235783Skib if (ret == ARCHIVE_OK) 247235783Skib ret = ret2; 248235783Skib return (ret); 249235783Skib} 250235783Skib 251235783Skibstatic ssize_t 252235783Skibarchive_write_cpio_data(struct archive_write *a, const void *buff, size_t s) 253235783Skib{ 254235783Skib struct cpio *cpio; 255235783Skib int ret; 256235783Skib 257235783Skib cpio = (struct cpio *)a->format_data; 258235783Skib if (s > cpio->entry_bytes_remaining) 259235783Skib s = cpio->entry_bytes_remaining; 260235783Skib 261235783Skib ret = (a->compressor.write)(a, buff, s); 262235783Skib cpio->entry_bytes_remaining -= s; 263235783Skib if (ret >= 0) 264235783Skib return (s); 265235783Skib else 266235783Skib return (ret); 267235783Skib} 268235783Skib 269235783Skib/* 270235783Skib * Format a number into the specified field. 271235783Skib */ 272235783Skibstatic int 273235783Skibformat_octal(int64_t v, void *p, int digits) 274235783Skib{ 275235783Skib int64_t max; 276235783Skib int ret; 277235783Skib 278235783Skib max = (((int64_t)1) << (digits * 3)) - 1; 279235783Skib if (v >= 0 && v <= max) { 280235783Skib format_octal_recursive(v, (char *)p, digits); 281235783Skib ret = 0; 282235783Skib } else { 283235783Skib format_octal_recursive(max, (char *)p, digits); 284235783Skib ret = -1; 285235783Skib } 286235783Skib return (ret); 287235783Skib} 288235783Skib 289235783Skibstatic int64_t 290235783Skibformat_octal_recursive(int64_t v, char *p, int s) 291235783Skib{ 292235783Skib if (s == 0) 293235783Skib return (v); 294235783Skib v = format_octal_recursive(v, p+1, s-1); 295235783Skib *p = '0' + (v & 7); 296235783Skib return (v >> 3); 297235783Skib} 298235783Skib 299235783Skibstatic int 300235783Skibarchive_write_cpio_finish(struct archive_write *a) 301235783Skib{ 302235783Skib int er; 303235783Skib struct archive_entry *trailer; 304235783Skib 305235783Skib trailer = archive_entry_new(); 306235783Skib /* nlink = 1 here for GNU cpio compat. */ 307235783Skib archive_entry_set_nlink(trailer, 1); 308235783Skib archive_entry_set_pathname(trailer, "TRAILER!!!"); 309235783Skib er = archive_write_cpio_header(a, trailer); 310235783Skib archive_entry_free(trailer); 311235783Skib return (er); 312235783Skib} 313235783Skib 314235783Skibstatic int 315235783Skibarchive_write_cpio_destroy(struct archive_write *a) 316235783Skib{ 317235783Skib struct cpio *cpio; 318235783Skib 319235783Skib cpio = (struct cpio *)a->format_data; 320235783Skib free(cpio->ino_list); 321235783Skib free(cpio); 322235783Skib a->format_data = NULL; 323235783Skib return (ARCHIVE_OK); 324235783Skib} 325235783Skib 326235783Skibstatic int 327235783Skibarchive_write_cpio_finish_entry(struct archive_write *a) 328235783Skib{ 329235783Skib struct cpio *cpio; 330235783Skib size_t to_write; 331235783Skib int ret; 332235783Skib 333235783Skib cpio = (struct cpio *)a->format_data; 334235783Skib ret = ARCHIVE_OK; 335235783Skib while (cpio->entry_bytes_remaining > 0) { 336235783Skib to_write = cpio->entry_bytes_remaining < a->null_length ? 337235783Skib cpio->entry_bytes_remaining : a->null_length; 338235783Skib ret = (a->compressor.write)(a, a->nulls, to_write); 339235783Skib if (ret != ARCHIVE_OK) 340235783Skib return (ret); 341235783Skib cpio->entry_bytes_remaining -= to_write; 342235783Skib } 343235783Skib return (ret); 344235783Skib} 345235783Skib