1 /*- 2 * Copyright (c) 2007 Kai Wang 3 * Copyright (c) 2007 Tim Kientzle 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 * in this position and unchanged. 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: head/lib/libarchive/archive_write_set_format_ar.c 201108 2009-12-28 03:28:21Z kientzle $"); 30 31 #ifdef HAVE_ERRNO_H 32 #include <errno.h> 33 #endif 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_private.h" 44 #include "archive_write_private.h" 45 #include "archive_write_set_format_private.h" 46 47 struct ar_w { 48 uint64_t entry_bytes_remaining; 49 uint64_t entry_padding; 50 int is_strtab; 51 int has_strtab; 52 char wrote_global_header; 53 char *strtab; 54 }; 55 56 /* 57 * Define structure of the "ar" header. 58 */ 59 #define AR_name_offset 0 60 #define AR_name_size 16 61 #define AR_date_offset 16 62 #define AR_date_size 12 63 #define AR_uid_offset 28 64 #define AR_uid_size 6 65 #define AR_gid_offset 34 66 #define AR_gid_size 6 67 #define AR_mode_offset 40 68 #define AR_mode_size 8 69 #define AR_size_offset 48 70 #define AR_size_size 10 71 #define AR_fmag_offset 58 72 #define AR_fmag_size 2 73 74 static int archive_write_set_format_ar(struct archive_write *); 75 static int archive_write_ar_header(struct archive_write *, 76 struct archive_entry *); 77 static ssize_t archive_write_ar_data(struct archive_write *, 78 const void *buff, size_t s); 79 static int archive_write_ar_free(struct archive_write *); 80 static int archive_write_ar_close(struct archive_write *); 81 static int archive_write_ar_finish_entry(struct archive_write *); 82 static const char *ar_basename(const char *path); 83 static int format_octal(int64_t v, char *p, int s); 84 static int format_decimal(int64_t v, char *p, int s); 85 86 int 87 archive_write_set_format_ar_bsd(struct archive *_a) 88 { 89 struct archive_write *a = (struct archive_write *)_a; 90 int r; 91 92 archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 93 ARCHIVE_STATE_NEW, "archive_write_set_format_ar_bsd"); 94 r = archive_write_set_format_ar(a); 95 if (r == ARCHIVE_OK) { 96 a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD; 97 a->archive.archive_format_name = "ar (BSD)"; 98 } 99 return (r); 100 } 101 102 int 103 archive_write_set_format_ar_svr4(struct archive *_a) 104 { 105 struct archive_write *a = (struct archive_write *)_a; 106 int r; 107 108 archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 109 ARCHIVE_STATE_NEW, "archive_write_set_format_ar_svr4"); 110 r = archive_write_set_format_ar(a); 111 if (r == ARCHIVE_OK) { 112 a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU; 113 a->archive.archive_format_name = "ar (GNU/SVR4)"; 114 } 115 return (r); 116 } 117 118 /* 119 * Generic initialization. 120 */ 121 static int 122 archive_write_set_format_ar(struct archive_write *a) 123 { 124 struct ar_w *ar; 125 126 /* If someone else was already registered, unregister them. */ 127 if (a->format_free != NULL) 128 (a->format_free)(a); 129 130 ar = (struct ar_w *)calloc(1, sizeof(*ar)); 131 if (ar == NULL) { 132 archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data"); 133 return (ARCHIVE_FATAL); 134 } 135 a->format_data = ar; 136 137 a->format_name = "ar"; 138 a->format_write_header = archive_write_ar_header; 139 a->format_write_data = archive_write_ar_data; 140 a->format_close = archive_write_ar_close; 141 a->format_free = archive_write_ar_free; 142 a->format_finish_entry = archive_write_ar_finish_entry; 143 return (ARCHIVE_OK); 144 } 145 146 static int 147 archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) 148 { 149 int ret, append_fn; 150 char buff[60]; 151 char *ss, *se; 152 struct ar_w *ar; 153 const char *pathname; 154 const char *filename; 155 int64_t size; 156 157 append_fn = 0; 158 ar = (struct ar_w *)a->format_data; 159 ar->is_strtab = 0; 160 filename = NULL; 161 size = archive_entry_size(entry); 162 163 164 /* 165 * Reject files with empty name. 166 */ 167 pathname = archive_entry_pathname(entry); 168 if (pathname == NULL || *pathname == '\0') { 169 archive_set_error(&a->archive, EINVAL, 170 "Invalid filename"); 171 return (ARCHIVE_WARN); 172 } 173 174 /* 175 * If we are now at the beginning of the archive, 176 * we need first write the ar global header. 177 */ 178 if (!ar->wrote_global_header) { 179 __archive_write_output(a, "!<arch>\n", 8); 180 ar->wrote_global_header = 1; 181 } 182 183 memset(buff, ' ', 60); 184 memcpy(&buff[AR_fmag_offset], "`\n", 2); 185 186 if (strcmp(pathname, "/") == 0 ) { 187 /* Entry is archive symbol table in GNU format */ 188 buff[AR_name_offset] = '/'; 189 goto stat; 190 } 191 if (strcmp(pathname, "/SYM64/") == 0) { 192 /* Entry is archive symbol table in GNU 64-bit format */ 193 memcpy(buff + AR_name_offset, "/SYM64/", 7); 194 goto stat; 195 } 196 if (strcmp(pathname, "__.SYMDEF") == 0) { 197 /* Entry is archive symbol table in BSD format */ 198 memcpy(buff + AR_name_offset, "__.SYMDEF", 9); 199 goto stat; 200 } 201 if (strcmp(pathname, "//") == 0) { 202 /* 203 * Entry is archive filename table, inform that we should 204 * collect strtab in next _data call. 205 */ 206 ar->is_strtab = 1; 207 buff[AR_name_offset] = buff[AR_name_offset + 1] = '/'; 208 /* 209 * For archive string table, only ar_size field should 210 * be set. 211 */ 212 goto size; 213 } 214 215 /* 216 * Otherwise, entry is a normal archive member. 217 * Strip leading paths from filenames, if any. 218 */ 219 if ((filename = ar_basename(pathname)) == NULL) { 220 /* Reject filenames with trailing "/" */ 221 archive_set_error(&a->archive, EINVAL, 222 "Invalid filename"); 223 return (ARCHIVE_WARN); 224 } 225 226 if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) { 227 /* 228 * SVR4/GNU variant use a "/" to mark then end of the filename, 229 * make it possible to have embedded spaces in the filename. 230 * So, the longest filename here (without extension) is 231 * actually 15 bytes. 232 */ 233 if (strlen(filename) <= 15) { 234 memcpy(&buff[AR_name_offset], 235 filename, strlen(filename)); 236 buff[AR_name_offset + strlen(filename)] = '/'; 237 } else { 238 /* 239 * For filename longer than 15 bytes, GNU variant 240 * makes use of a string table and instead stores the 241 * offset of the real filename to in the ar_name field. 242 * The string table should have been written before. 243 */ 244 if (ar->has_strtab <= 0) { 245 archive_set_error(&a->archive, EINVAL, 246 "Can't find string table"); 247 return (ARCHIVE_WARN); 248 } 249 250 se = (char *)malloc(strlen(filename) + 3); 251 if (se == NULL) { 252 archive_set_error(&a->archive, ENOMEM, 253 "Can't allocate filename buffer"); 254 return (ARCHIVE_FATAL); 255 } 256 257 memcpy(se, filename, strlen(filename)); 258 strcpy(se + strlen(filename), "/\n"); 259 260 ss = strstr(ar->strtab, se); 261 free(se); 262 263 if (ss == NULL) { 264 archive_set_error(&a->archive, EINVAL, 265 "Invalid string table"); 266 return (ARCHIVE_WARN); 267 } 268 269 /* 270 * GNU variant puts "/" followed by digits into 271 * ar_name field. These digits indicates the real 272 * filename string's offset to the string table. 273 */ 274 buff[AR_name_offset] = '/'; 275 if (format_decimal(ss - ar->strtab, 276 buff + AR_name_offset + 1, 277 AR_name_size - 1)) { 278 archive_set_error(&a->archive, ERANGE, 279 "string table offset too large"); 280 return (ARCHIVE_WARN); 281 } 282 } 283 } else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) { 284 /* 285 * BSD variant: for any file name which is more than 286 * 16 chars or contains one or more embedded space(s), the 287 * string "#1/" followed by the ASCII length of the name is 288 * put into the ar_name field. The file size (stored in the 289 * ar_size field) is incremented by the length of the name. 290 * The name is then written immediately following the 291 * archive header. 292 */ 293 if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) { 294 memcpy(&buff[AR_name_offset], filename, strlen(filename)); 295 buff[AR_name_offset + strlen(filename)] = ' '; 296 } 297 else { 298 memcpy(buff + AR_name_offset, "#1/", 3); 299 if (format_decimal(strlen(filename), 300 buff + AR_name_offset + 3, 301 AR_name_size - 3)) { 302 archive_set_error(&a->archive, ERANGE, 303 "File name too long"); 304 return (ARCHIVE_WARN); 305 } 306 append_fn = 1; 307 size += strlen(filename); 308 } 309 } 310 311 stat: 312 if (format_decimal(archive_entry_mtime(entry), buff + AR_date_offset, AR_date_size)) { 313 archive_set_error(&a->archive, ERANGE, 314 "File modification time too large"); 315 return (ARCHIVE_WARN); 316 } 317 if (format_decimal(archive_entry_uid(entry), buff + AR_uid_offset, AR_uid_size)) { 318 archive_set_error(&a->archive, ERANGE, 319 "Numeric user ID too large"); 320 return (ARCHIVE_WARN); 321 } 322 if (format_decimal(archive_entry_gid(entry), buff + AR_gid_offset, AR_gid_size)) { 323 archive_set_error(&a->archive, ERANGE, 324 "Numeric group ID too large"); 325 return (ARCHIVE_WARN); 326 } 327 if (format_octal(archive_entry_mode(entry), buff + AR_mode_offset, AR_mode_size)) { 328 archive_set_error(&a->archive, ERANGE, 329 "Numeric mode too large"); 330 return (ARCHIVE_WARN); 331 } 332 /* 333 * Sanity Check: A non-pseudo archive member should always be 334 * a regular file. 335 */ 336 if (filename != NULL && archive_entry_filetype(entry) != AE_IFREG) { 337 archive_set_error(&a->archive, EINVAL, 338 "Regular file required for non-pseudo member"); 339 return (ARCHIVE_WARN); 340 } 341 342 size: 343 if (format_decimal(size, buff + AR_size_offset, AR_size_size)) { 344 archive_set_error(&a->archive, ERANGE, 345 "File size out of range"); 346 return (ARCHIVE_WARN); 347 } 348 349 ret = __archive_write_output(a, buff, 60); 350 if (ret != ARCHIVE_OK) 351 return (ret); 352 353 ar->entry_bytes_remaining = size; 354 ar->entry_padding = ar->entry_bytes_remaining % 2; 355 356 if (append_fn > 0) { 357 ret = __archive_write_output(a, filename, strlen(filename)); 358 if (ret != ARCHIVE_OK) 359 return (ret); 360 ar->entry_bytes_remaining -= strlen(filename); 361 } 362 363 return (ARCHIVE_OK); 364 } 365 366 static ssize_t 367 archive_write_ar_data(struct archive_write *a, const void *buff, size_t s) 368 { 369 struct ar_w *ar; 370 int ret; 371 372 ar = (struct ar_w *)a->format_data; 373 if (s > ar->entry_bytes_remaining) 374 s = (size_t)ar->entry_bytes_remaining; 375 376 if (ar->is_strtab > 0) { 377 if (ar->has_strtab > 0) { 378 archive_set_error(&a->archive, EINVAL, 379 "More than one string tables exist"); 380 return (ARCHIVE_WARN); 381 } 382 383 ar->strtab = (char *)malloc(s + 1); 384 if (ar->strtab == NULL) { 385 archive_set_error(&a->archive, ENOMEM, 386 "Can't allocate strtab buffer"); 387 return (ARCHIVE_FATAL); 388 } 389 memcpy(ar->strtab, buff, s); 390 ar->strtab[s] = '\0'; 391 ar->has_strtab = 1; 392 } 393 394 ret = __archive_write_output(a, buff, s); 395 if (ret != ARCHIVE_OK) 396 return (ret); 397 398 ar->entry_bytes_remaining -= s; 399 return (s); 400 } 401 402 static int 403 archive_write_ar_free(struct archive_write *a) 404 { 405 struct ar_w *ar; 406 407 ar = (struct ar_w *)a->format_data; 408 409 if (ar == NULL) 410 return (ARCHIVE_OK); 411 412 if (ar->has_strtab > 0) { 413 free(ar->strtab); 414 ar->strtab = NULL; 415 } 416 417 free(ar); 418 a->format_data = NULL; 419 return (ARCHIVE_OK); 420 } 421 422 static int 423 archive_write_ar_close(struct archive_write *a) 424 { 425 struct ar_w *ar; 426 int ret; 427 428 /* 429 * If we haven't written anything yet, we need to write 430 * the ar global header now to make it a valid ar archive. 431 */ 432 ar = (struct ar_w *)a->format_data; 433 if (!ar->wrote_global_header) { 434 ar->wrote_global_header = 1; 435 ret = __archive_write_output(a, "!<arch>\n", 8); 436 return (ret); 437 } 438 439 return (ARCHIVE_OK); 440 } 441 442 static int 443 archive_write_ar_finish_entry(struct archive_write *a) 444 { 445 struct ar_w *ar; 446 int ret; 447 448 ar = (struct ar_w *)a->format_data; 449 450 if (ar->entry_bytes_remaining != 0) { 451 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 452 "Entry remaining bytes larger than 0"); 453 return (ARCHIVE_WARN); 454 } 455 456 if (ar->entry_padding == 0) { 457 return (ARCHIVE_OK); 458 } 459 460 if (ar->entry_padding != 1) { 461 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 462 "Padding wrong size: %ju should be 1 or 0", 463 (uintmax_t)ar->entry_padding); 464 return (ARCHIVE_WARN); 465 } 466 467 ret = __archive_write_output(a, "\n", 1); 468 return (ret); 469 } 470 471 /* 472 * Format a number into the specified field using base-8. 473 * NB: This version is slightly different from the one in 474 * _ustar.c 475 */ 476 static int 477 format_octal(int64_t v, char *p, int s) 478 { 479 int len; 480 char *h; 481 482 len = s; 483 h = p; 484 485 /* Octal values can't be negative, so use 0. */ 486 if (v < 0) { 487 while (len-- > 0) 488 *p++ = '0'; 489 return (-1); 490 } 491 492 p += s; /* Start at the end and work backwards. */ 493 do { 494 *--p = (char)('0' + (v & 7)); 495 v >>= 3; 496 } while (--s > 0 && v > 0); 497 498 if (v == 0) { 499 memmove(h, p, len - s); 500 p = h + len - s; 501 while (s-- > 0) 502 *p++ = ' '; 503 return (0); 504 } 505 /* If it overflowed, fill field with max value. */ 506 while (len-- > 0) 507 *p++ = '7'; 508 509 return (-1); 510 } 511 512 /* 513 * Format a number into the specified field using base-10. 514 */ 515 static int 516 format_decimal(int64_t v, char *p, int s) 517 { 518 int len; 519 char *h; 520 521 len = s; 522 h = p; 523 524 /* Negative values in ar header are meaningless, so use 0. */ 525 if (v < 0) { 526 while (len-- > 0) 527 *p++ = '0'; 528 return (-1); 529 } 530 531 p += s; 532 do { 533 *--p = (char)('0' + (v % 10)); 534 v /= 10; 535 } while (--s > 0 && v > 0); 536 537 if (v == 0) { 538 memmove(h, p, len - s); 539 p = h + len - s; 540 while (s-- > 0) 541 *p++ = ' '; 542 return (0); 543 } 544 /* If it overflowed, fill field with max value. */ 545 while (len-- > 0) 546 *p++ = '9'; 547 548 return (-1); 549 } 550 551 static const char * 552 ar_basename(const char *path) 553 { 554 const char *endp, *startp; 555 556 endp = path + strlen(path) - 1; 557 /* 558 * For filename with trailing slash(es), we return 559 * NULL indicating an error. 560 */ 561 if (*endp == '/') 562 return (NULL); 563 564 /* Find the start of the base */ 565 startp = endp; 566 while (startp > path && *(startp - 1) != '/') 567 startp--; 568 569 return (startp); 570 } 571