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