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