1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright (c) 1988 AT&T 28 * All Rights Reserved 29 * 30 */ 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 #include "gelf.h" 35 #include "inc.h" 36 #include "extern.h" 37 38 static char *str_base; /* start of string table for names */ 39 static char *str_top; /* pointer to next available location */ 40 static char *str_base1, *str_top1; 41 static int pad_symtab; /* # of bytes by which to pad symbol table */ 42 43 44 /* 45 * The ar file format requires objects to be padded to an even size. 46 * We do that, but it turns out to be beneficial to go farther. 47 * 48 * ld(1) accesses archives by mmapping them into memory. If the mapped 49 * objects have the proper alignment, we can access them directly. If the 50 * alignment is wrong, elflib "slides" them so that they are also accessible. 51 * This is expensive in time (to copy memory) and space (it causes swap 52 * to be allocated by the system to back the now-modified pages). Hence, we 53 * really want to ensure that the alignment is right. 54 * 55 * We used to align 32-bit objects at 4-byte boundaries, and 64-bit objects 56 * at 8-byte. More recently, an elf section type has appeared that has 57 * 8-byte alignment requirements (SUNW_move) even in 32-bit objects. So, 58 * the current strategy is to align all objects to 8-bytes. 59 * 60 * There are two important things to consider when setting this value: 61 * 1) If a new elf section that ld(1) accesses in memory appears 62 * with a greater than 8-byte alignment requirement, this value 63 * will need to be raised. Or, alternatively, the entire approach may 64 * need reconsideration. 65 * 2) The size of this padding must be smaller than the size of the 66 * smallest possible ELF section. Otherwise, the logic contained 67 * in recover_padding() can be tricked. 68 */ 69 #define PADSZ 8 70 71 /* 72 * Function Prototypes 73 */ 74 static long mklong_tab(int *); 75 static char *trimslash(char *s); 76 77 static long mksymtab(ARFILEP **, Cmd_info *, int *); 78 static int writesymtab(char *, long, ARFILEP *); 79 static void savename(char *); 80 static void savelongname(ARFILE *, char *); 81 static void sputl(long, char *); 82 83 static char *writelargefile(Cmd_info *cmd_info, long long_tab_size, 84 int longnames, ARFILEP *symlist, long nsyms, int found_obj, 85 int new_archive); 86 87 static int sizeofmembers(); 88 static int sizeofnewarchive(int, int); 89 90 static int search_sym_tab(ARFILE *, Elf *, Elf_Scn *, 91 long *, ARFILEP **, int *); 92 93 #ifdef BROWSER 94 static void sbrowser_search_stab(Elf *, int, int, char *); 95 #endif 96 97 98 int 99 getaf(Cmd_info *cmd_info) 100 { 101 Elf_Cmd cmd; 102 int fd; 103 char *arnam = cmd_info->arnam; 104 105 if (elf_version(EV_CURRENT) == EV_NONE) { 106 error_message(ELF_VERSION_ERROR, 107 LIBELF_ERROR, elf_errmsg(-1)); 108 exit(1); 109 } 110 111 if ((cmd_info->afd = fd = open(arnam, O_RDONLY)) == -1) { 112 if (errno == ENOENT) { 113 /* archive does not exist yet, may have to create one */ 114 return (fd); 115 } else { 116 /* problem other than "does not exist" */ 117 error_message(SYS_OPEN_ERROR, 118 SYSTEM_ERROR, strerror(errno), arnam); 119 exit(1); 120 } 121 } 122 123 cmd = ELF_C_READ; 124 cmd_info->arf = elf_begin(fd, cmd, (Elf *)0); 125 126 if (elf_kind(cmd_info->arf) != ELF_K_AR) { 127 error_message(NOT_ARCHIVE_ERROR, 128 PLAIN_ERROR, (char *)0, arnam); 129 if (opt_FLAG(cmd_info, a_FLAG) || opt_FLAG(cmd_info, b_FLAG)) 130 error_message(USAGE_06_ERROR, 131 PLAIN_ERROR, (char *)0, cmd_info->ponam); 132 exit(1); 133 } 134 return (fd); 135 } 136 137 /* 138 * Given a size, return the number of bytes required to round it 139 * up to the next PADSZ boundary. 140 */ 141 static int 142 pad(int n) 143 { 144 int r; 145 146 r = n % PADSZ; 147 if (r) 148 r = PADSZ - r; 149 150 return (r); 151 } 152 153 /* 154 * If the current archive item is an object, then ar(1) may have added 155 * newline padding at the end in order to bring the following object 156 * into PADSZ alignment within the file. This padding cannot be 157 * distinguished from data using the information kept in the ar headers. 158 * This routine examines the objects, using knowledge of 159 * ELF and how our tools lay out objects to determine whether padding was 160 * added to an archive item. If so, it adjusts the st_size and 161 * st_padding fields of the file argument to reflect it. 162 */ 163 static void 164 recover_padding(Elf *elf, ARFILE *file) 165 { 166 long extent; 167 long padding; 168 GElf_Ehdr ehdr; 169 170 171 /* ar(1) only pads objects, so bail if not looking at one */ 172 if (gelf_getclass(elf) == ELFCLASSNONE) 173 return; 174 175 /* 176 * elflib always puts the section header array at the end 177 * of the object, and all of our compilers and other tools 178 * use elflib or follow this convention. So, it is extremely 179 * likely that the section header array is at the end of this 180 * object: Find the address at the end of the array and compare 181 * it to the archive ar_size. If they are within PADSZ bytes, then 182 * we've found the end, and the difference is padding (We assume 183 * that no ELF section can fit into PADSZ bytes). 184 */ 185 extent = gelf_getehdr(elf, &ehdr) 186 ? (ehdr.e_shoff + (ehdr.e_shnum * ehdr.e_shentsize)) : 0; 187 padding = file->ar_size - extent; 188 189 if ((padding < 0) || (padding >= PADSZ)) { 190 /* 191 * The section header array is not at the end of the object. 192 * Traverse the section headers and look for the one with 193 * the highest used address. If this address is within 194 * PADSZ bytes of ar_size, then this is the end of the object. 195 */ 196 Elf_Scn *scn = 0; 197 198 do { 199 scn = elf_nextscn(elf, scn); 200 if (scn) { 201 GElf_Shdr shdr; 202 203 if (gelf_getshdr(scn, &shdr)) { 204 long t = shdr.sh_offset + shdr.sh_size; 205 if (t > extent) 206 extent = t; 207 } 208 } 209 } while (scn); 210 } 211 212 /* 213 * Now, test the padding. We only act on padding in the range 214 * (0 < pad < PADSZ) (ar(1) will never add more than this). A pad 215 * of 0 requires no action, and any other size above (PADSZ-1) means 216 * that we don't understand the layout of this object, and as such, 217 * cannot do anything. 218 * 219 * If the padding is in range, and the raw data for the 220 * object is available, then we perform one additional sanity 221 * check before moving forward: ar(1) always pads with newline 222 * characters. If anything else is seen, it is not padding so 223 * leave it alone. 224 */ 225 if ((padding > 0) && (padding < PADSZ)) { 226 if (file->ar_contents) { 227 long cnt = padding; 228 char *p = file->ar_contents + extent; 229 230 while (cnt--) { 231 if (*p++ != '\n') { /* No padding */ 232 padding = 0; 233 break; 234 } 235 } 236 } 237 238 /* Remove the padding from the size */ 239 file->ar_size -= padding; 240 file->ar_padding = padding; 241 } 242 } 243 244 ARFILE * 245 getfile(Cmd_info *cmd_info) 246 { 247 Elf_Arhdr *mem_header; 248 ARFILE *file; 249 char *tmp_rawname, *file_rawname; 250 Elf *elf; 251 char *arnam = cmd_info->arnam; 252 int fd = cmd_info->afd; 253 Elf *arf = cmd_info->arf; 254 255 if (fd == -1) 256 return (NULL); /* the archive doesn't exist */ 257 258 if ((elf = elf_begin(fd, ELF_C_READ, arf)) == 0) 259 return (NULL); /* the archive is empty or have hit the end */ 260 261 if ((mem_header = elf_getarhdr(elf)) == NULL) { 262 error_message(ELF_MALARCHIVE_ERROR, 263 LIBELF_ERROR, elf_errmsg(-1), 264 arnam, elf_getbase(elf)); 265 exit(1); 266 } 267 268 /* zip past special members like the symbol and string table members */ 269 270 while (strncmp(mem_header->ar_name, "/", 1) == 0 || 271 strncmp(mem_header->ar_name, "//", 2) == 0) { 272 (void) elf_next(elf); 273 (void) elf_end(elf); 274 if ((elf = elf_begin(fd, ELF_C_READ, arf)) == 0) 275 return (NULL); 276 /* the archive is empty or have hit the end */ 277 if ((mem_header = elf_getarhdr(elf)) == NULL) { 278 error_message(ELF_MALARCHIVE_ERROR, 279 LIBELF_ERROR, elf_errmsg(-1), 280 arnam, elf_getbase(elf)); 281 exit(0); 282 } 283 } 284 285 /* 286 * NOTE: 287 * The mem_header->ar_name[] is set to a NULL string 288 * if the archive member header has some error. 289 * (See elf_getarhdr() man page.) 290 * It is set to NULL for example, the ar command reads 291 * the archive files created by SunOS 4.1 system. 292 * See c block comment in cmd.c, "Incompatible Archive Header". 293 */ 294 file = newfile(); 295 (void) strncpy(file->ar_name, mem_header->ar_name, SNAME); 296 297 if ((file->ar_longname 298 = malloc(strlen(mem_header->ar_name) + 1)) 299 == NULL) { 300 error_message(MALLOC_ERROR, 301 PLAIN_ERROR, (char *)0); 302 exit(1); 303 } 304 (void) strcpy(file->ar_longname, mem_header->ar_name); 305 if ((file->ar_rawname 306 = malloc(strlen(mem_header->ar_rawname) + 1)) 307 == NULL) { 308 error_message(MALLOC_ERROR, 309 PLAIN_ERROR, (char *)0); 310 exit(1); 311 } 312 tmp_rawname = mem_header->ar_rawname; 313 file_rawname = file->ar_rawname; 314 while (!isspace(*tmp_rawname) && 315 ((*file_rawname = *tmp_rawname) != '\0')) { 316 file_rawname++; 317 tmp_rawname++; 318 } 319 if (!(*tmp_rawname == '\0')) 320 *file_rawname = '\0'; 321 322 file->ar_date = mem_header->ar_date; 323 file->ar_uid = mem_header->ar_uid; 324 file->ar_gid = mem_header->ar_gid; 325 file->ar_mode = (unsigned long) mem_header->ar_mode; 326 file->ar_size = mem_header->ar_size; 327 328 /* reverse logic */ 329 if (!(opt_FLAG(cmd_info, t_FLAG) && !opt_FLAG(cmd_info, s_FLAG))) { 330 size_t ptr; 331 file->ar_flag = F_ELFRAW; 332 if ((file->ar_contents = elf_rawfile(elf, &ptr)) 333 == NULL) { 334 if (ptr != 0) { 335 error_message(ELF_RAWFILE_ERROR, 336 LIBELF_ERROR, elf_errmsg(-1)); 337 exit(1); 338 } 339 } 340 file->ar_elf = elf; 341 } 342 343 recover_padding(elf, file); 344 345 (void) elf_next(elf); 346 return (file); 347 } 348 349 ARFILE * 350 newfile(void) 351 { 352 static ARFILE *buffer = NULL; 353 static int count = 0; 354 ARFILE *fileptr; 355 356 if (count == 0) { 357 if ((buffer = (ARFILE *) calloc(CHUNK, sizeof (ARFILE))) 358 == NULL) { 359 error_message(MALLOC_ERROR, 360 PLAIN_ERROR, (char *)0); 361 exit(1); 362 } 363 count = CHUNK; 364 } 365 count--; 366 fileptr = buffer++; 367 368 if (listhead) 369 listend->ar_next = fileptr; 370 else 371 listhead = fileptr; 372 listend = fileptr; 373 return (fileptr); 374 } 375 376 static char * 377 trimslash(char *s) 378 { 379 static char buf[SNAME]; 380 381 (void) strncpy(buf, trim(s), SNAME - 2); 382 buf[SNAME - 2] = '\0'; 383 return (strcat(buf, "/")); 384 } 385 386 char * 387 trim(char *s) 388 { 389 char *p1, *p2; 390 391 for (p1 = s; *p1; p1++) 392 ; 393 while (p1 > s) { 394 if (*--p1 != '/') 395 break; 396 *p1 = 0; 397 } 398 p2 = s; 399 for (p1 = s; *p1; p1++) 400 if (*p1 == '/') 401 p2 = p1 + 1; 402 return (p2); 403 } 404 405 406 static long 407 mksymtab(ARFILEP **symlist, Cmd_info *cmd_info, int *found_obj) 408 { 409 ARFILE *fptr; 410 long mem_offset = 0; 411 Elf *elf; 412 Elf_Scn *scn; 413 GElf_Ehdr ehdr; 414 int newfd; 415 long nsyms = 0; 416 int class = 0; 417 Elf_Data *data; 418 char *sbshstr; 419 char *sbshstrtp; 420 int sbstabsect = -1; 421 int sbstabstrsect = -1; 422 int num_errs = 0; 423 424 newfd = 0; 425 for (fptr = listhead; fptr; fptr = fptr->ar_next) { 426 /* determine if file is coming from the archive or not */ 427 if ((fptr->ar_elf != 0) && (fptr->ar_pathname == NULL)) { 428 /* 429 * I can use the saved elf descriptor. 430 */ 431 elf = fptr->ar_elf; 432 } else if ((fptr->ar_elf == 0) && 433 (fptr->ar_pathname != NULL)) { 434 if ((newfd = 435 open(fptr->ar_pathname, O_RDONLY)) == -1) { 436 error_message(SYS_OPEN_ERROR, 437 SYSTEM_ERROR, strerror(errno), 438 fptr->ar_pathname); 439 num_errs++; 440 continue; 441 } 442 443 if ((elf = elf_begin(newfd, 444 ELF_C_READ, 445 (Elf *)0)) == 0) { 446 if (fptr->ar_pathname != NULL) 447 error_message(ELF_BEGIN_02_ERROR, 448 LIBELF_ERROR, elf_errmsg(-1), 449 fptr->ar_pathname); 450 else 451 error_message(ELF_BEGIN_03_ERROR, 452 LIBELF_ERROR, elf_errmsg(-1)); 453 (void) close(newfd); 454 newfd = 0; 455 num_errs++; 456 continue; 457 } 458 if (elf_kind(elf) == ELF_K_AR) { 459 if (fptr->ar_pathname != NULL) 460 error_message(ARCHIVE_IN_ARCHIVE_ERROR, 461 PLAIN_ERROR, (char *)0, 462 fptr->ar_pathname); 463 else 464 error_message(ARCHIVE_USAGE_ERROR, 465 PLAIN_ERROR, (char *)0); 466 if (newfd) { 467 (void) close(newfd); 468 newfd = 0; 469 } 470 (void) elf_end(elf); 471 continue; 472 } 473 } else { 474 error_message(INTERNAL_01_ERROR, 475 PLAIN_ERROR, (char *)0); 476 exit(1); 477 } 478 if (gelf_getehdr(elf, &ehdr) != 0) { 479 if ((class = gelf_getclass(elf)) == ELFCLASS64) { 480 fptr->ar_flag |= F_CLASS64; 481 } else if (class == ELFCLASS32) 482 fptr->ar_flag |= F_CLASS32; 483 scn = elf_getscn(elf, ehdr.e_shstrndx); 484 if (scn == NULL) { 485 if (fptr->ar_pathname != NULL) 486 error_message(ELF_GETSCN_01_ERROR, 487 LIBELF_ERROR, elf_errmsg(-1), 488 fptr->ar_pathname); 489 else 490 error_message(ELF_GETSCN_02_ERROR, 491 LIBELF_ERROR, elf_errmsg(-1)); 492 num_errs++; 493 if (newfd) { 494 (void) close(newfd); 495 newfd = 0; 496 } 497 (void) elf_end(elf); 498 continue; 499 } 500 501 data = 0; 502 data = elf_getdata(scn, data); 503 if (data == NULL) { 504 if (fptr->ar_pathname != NULL) 505 error_message(ELF_GETDATA_01_ERROR, 506 LIBELF_ERROR, elf_errmsg(-1), 507 fptr->ar_pathname); 508 else 509 error_message(ELF_GETDATA_02_ERROR, 510 LIBELF_ERROR, elf_errmsg(-1)); 511 num_errs++; 512 if (newfd) { 513 (void) close(newfd); 514 newfd = 0; 515 } 516 (void) elf_end(elf); 517 continue; 518 } 519 if (data->d_size == 0) { 520 if (fptr->ar_pathname != NULL) 521 error_message(W_ELF_NO_DATA_01_ERROR, 522 PLAIN_ERROR, (char *)0, 523 fptr->ar_pathname); 524 else 525 error_message(W_ELF_NO_DATA_02_ERROR, 526 PLAIN_ERROR, (char *)0); 527 if (newfd) { 528 (void) close(newfd); 529 newfd = 0; 530 } 531 (void) elf_end(elf); 532 num_errs++; 533 continue; 534 } 535 sbshstr = (char *)data->d_buf; 536 537 /* loop through sections to find symbol table */ 538 scn = 0; 539 while ((scn = elf_nextscn(elf, scn)) != 0) { 540 GElf_Shdr shdr; 541 if (gelf_getshdr(scn, &shdr) == NULL) { 542 if (fptr->ar_pathname != NULL) 543 error_message( 544 ELF_GETDATA_01_ERROR, 545 LIBELF_ERROR, elf_errmsg(-1), 546 fptr->ar_pathname); 547 else 548 error_message( 549 ELF_GETDATA_02_ERROR, 550 LIBELF_ERROR, elf_errmsg(-1)); 551 if (newfd) { 552 (void) close(newfd); 553 newfd = 0; 554 } 555 num_errs++; 556 (void) elf_end(elf); 557 continue; 558 } 559 *found_obj = 1; 560 if (shdr.sh_type == SHT_SYMTAB) 561 if (search_sym_tab(fptr, elf, 562 scn, 563 &nsyms, 564 symlist, 565 &num_errs) == -1) { 566 if (newfd) { 567 (void) close(newfd); 568 newfd = 0; 569 } 570 continue; 571 } 572 #ifdef BROWSER 573 /* 574 * XX64: sbrowser_search_stab() currently gets 575 * confused by sb-tabs in v9. at this 576 * point, no one knows what v9 sb-tabs are 577 * supposed to look like. 578 */ 579 /* if (shdr.sh_name != 0) { */ 580 if ((class == ELFCLASS32) && 581 (shdr.sh_name != 0)) { 582 sbshstrtp = (char *) 583 ((long)sbshstr + shdr.sh_name); 584 if (strcmp(sbshstrtp, ".stab") == 0) { 585 sbstabsect = elf_ndxscn(scn); 586 } else if (strcmp(sbshstrtp, 587 ".stabstr") == 0) { 588 sbstabstrsect = elf_ndxscn(scn); 589 } 590 } 591 #endif 592 } 593 #ifdef BROWSER 594 if (sbstabsect != -1 || sbstabstrsect != -1) { 595 sbrowser_search_stab( 596 elf, 597 sbstabsect, 598 sbstabstrsect, 599 cmd_info->arnam); 600 sbstabsect = -1; 601 sbstabstrsect = -1; 602 } 603 #endif 604 } 605 mem_offset += sizeof (struct ar_hdr) + fptr->ar_size; 606 if (fptr->ar_size & 01) 607 mem_offset++; 608 (void) elf_end(elf); 609 if (newfd) { 610 (void) close(newfd); 611 newfd = 0; 612 } 613 } /* for */ 614 if (num_errs) 615 exit(1); 616 return (nsyms); 617 } 618 619 /* 620 * This routine writes an archive symbol table for the 621 * output archive file. The symbol table is built if 622 * there was at least one object file specified. 623 * In rare case, there could be no symbol. 624 * In this case, str_top and str_base can not be used to 625 * make the string table. So the routine adjust the size 626 * and make a dummy string table. String table is needed 627 * by elf_getarsym(). 628 */ 629 static int 630 writesymtab(char *dst, long nsyms, ARFILEP *symlist) 631 { 632 char buf1[sizeof (struct ar_hdr) + 1]; 633 char *buf2, *bptr; 634 int i, j; 635 ARFILEP *ptr; 636 long sym_tab_size = 0; 637 int sum = 0; 638 639 /* 640 * patch up archive pointers and write the symbol entries 641 */ 642 while ((str_top - str_base) & 03) /* round up string table */ 643 *str_top++ = '\0'; 644 sym_tab_size = (nsyms +1) * 4 + sizeof (char) * (str_top - str_base); 645 if (nsyms == 0) 646 sym_tab_size += 4; 647 sym_tab_size += pad_symtab; 648 649 (void) sprintf(buf1, FORMAT, SYMDIRNAME, time(0), (unsigned)0, 650 (unsigned)0, (unsigned)0, (long)sym_tab_size, ARFMAG); 651 652 if (strlen(buf1) != sizeof (struct ar_hdr)) { 653 error_message(INTERNAL_02_ERROR); 654 exit(1); 655 } 656 657 if ((buf2 = malloc(4 * (nsyms + 1))) == NULL) { 658 error_message(MALLOC_ERROR); 659 error_message(DIAG_01_ERROR, errno); 660 exit(1); 661 } 662 sputl(nsyms, buf2); 663 bptr = buf2 + 4; 664 665 for (i = 0, j = SYMCHUNK, ptr = symlist; i < nsyms; i++, j--, ptr++) { 666 if (!j) { 667 j = SYMCHUNK; 668 ptr = (ARFILEP *)*ptr; 669 } 670 sputl((*ptr)->ar_offset, bptr); 671 bptr += 4; 672 } 673 (void) memcpy(dst, buf1, sizeof (struct ar_hdr)); 674 dst += sizeof (struct ar_hdr); 675 sum += sizeof (struct ar_hdr); 676 677 (void) memcpy(dst, buf2, (nsyms + 1) * 4); 678 dst += (nsyms + 1)*4; 679 sum += (nsyms + 1)*4; 680 681 if (nsyms != 0) { 682 (void) memcpy(dst, str_base, (str_top - str_base)); 683 dst += str_top - str_base; 684 sum += str_top - str_base; 685 } else { 686 /* 687 * Writing a dummy string table. 688 */ 689 int i; 690 for (i = 0; i < 4; i++) 691 *dst++ = 0; 692 sum += 4; 693 } 694 695 /* 696 * The first member file is an ELF object. We need to make 697 * sure it will be placed at the PADSZ byte boundary. 698 */ 699 if (pad_symtab) { 700 int i; 701 for (i = 0; i < pad_symtab; i++) 702 *dst++ = 0; 703 sum += pad_symtab; 704 } 705 706 free(buf2); 707 return (sum); 708 } 709 710 static void 711 savename(char *symbol) 712 { 713 static int str_length = BUFSIZ * 5; 714 char *p, *s; 715 unsigned int i; 716 int diff; 717 718 diff = 0; 719 if (str_base == (char *)0) { 720 /* no space allocated yet */ 721 if ((str_base = malloc((unsigned)str_length)) 722 == NULL) { 723 error_message(MALLOC_ERROR, 724 PLAIN_ERROR, (char *)0); 725 exit(1); 726 } 727 str_top = str_base; 728 } 729 730 p = str_top; 731 str_top += strlen(symbol) + 1; 732 733 if (str_top > str_base + str_length) { 734 char *old_base = str_base; 735 736 do 737 str_length += BUFSIZ * 2; 738 while (str_top > str_base + str_length); 739 if ((str_base = (char *)realloc(str_base, str_length)) == 740 NULL) { 741 error_message(MALLOC_ERROR, 742 PLAIN_ERROR, (char *)0); 743 exit(1); 744 } 745 /* 746 * Re-adjust other pointers 747 */ 748 diff = str_base - old_base; 749 p += diff; 750 } 751 for (i = 0, s = symbol; 752 i < strlen(symbol) && *s != '\0'; i++) { 753 *p++ = *s++; 754 } 755 *p++ = '\0'; 756 str_top = p; 757 } 758 759 static void 760 savelongname(ARFILE *fptr, char *ptr_index) 761 { 762 static int str_length = BUFSIZ * 5; 763 char *p, *s; 764 unsigned int i; 765 int diff; 766 static int bytes_used; 767 int index; 768 char ptr_index1[SNAME-1]; 769 770 diff = 0; 771 if (str_base1 == (char *)0) { 772 /* no space allocated yet */ 773 if ((str_base1 = malloc((unsigned)str_length)) 774 == NULL) { 775 error_message(MALLOC_ERROR, 776 PLAIN_ERROR, (char *)0); 777 exit(1); 778 } 779 str_top1 = str_base1; 780 } 781 782 p = str_top1; 783 str_top1 += strlen(fptr->ar_longname) + 2; 784 785 index = bytes_used; 786 (void) sprintf(ptr_index1, "%d", index); /* holds digits */ 787 (void) sprintf(ptr_index, FNFORMAT, SYMDIRNAME); 788 ptr_index[1] = '\0'; 789 (void) strcat(ptr_index, ptr_index1); 790 (void) strcpy(fptr->ar_name, ptr_index); 791 bytes_used += strlen(fptr->ar_longname) + 2; 792 793 if (str_top1 > str_base1 + str_length) { 794 char *old_base = str_base1; 795 796 do 797 str_length += BUFSIZ * 2; 798 while (str_top1 > str_base1 + str_length); 799 if ((str_base1 = (char *)realloc(str_base1, str_length)) 800 == NULL) { 801 error_message(MALLOC_ERROR, 802 PLAIN_ERROR, (char *)0); 803 exit(1); 804 } 805 /* 806 * Re-adjust other pointers 807 */ 808 diff = str_base1 - old_base; 809 p += diff; 810 } 811 for (i = 0, s = fptr->ar_longname; 812 i < strlen(fptr->ar_longname) && *s != '\0'; 813 i++) { 814 *p++ = *s++; 815 } 816 *p++ = '/'; 817 *p++ = '\n'; 818 str_top1 = p; 819 } 820 821 char * 822 writefile(Cmd_info *cmd_info) 823 { 824 ARFILE * fptr; 825 ARFILEP *symlist = 0; 826 int i; 827 int longnames = 0; 828 long long_tab_size = 0; 829 long nsyms; 830 int new_archive = 0; 831 char *name = cmd_info->arnam; 832 int arsize; 833 char *dst; 834 char *tmp_dst; 835 int nfd; 836 int found_obj = 0; 837 838 long_tab_size = mklong_tab(&longnames); 839 nsyms = mksymtab(&symlist, cmd_info, &found_obj); 840 841 for (i = 0; signum[i]; i++) 842 /* started writing, cannot interrupt */ 843 (void) signal(signum[i], SIG_IGN); 844 845 846 /* Is this a new archive? */ 847 if ((access(cmd_info->arnam, 0) < 0) && (errno == ENOENT)) { 848 new_archive = 1; 849 if (!opt_FLAG(cmd_info, c_FLAG)) { 850 error_message(BER_MES_CREATE_ERROR, 851 PLAIN_ERROR, (char *)0, cmd_info->arnam); 852 } 853 } 854 else 855 new_archive = 0; 856 857 /* 858 * Calculate the size of the new archive 859 */ 860 arsize = sizeofnewarchive(nsyms, longnames); 861 862 /* 863 * Dummy symtab ? 864 */ 865 if (nsyms == 0 && found_obj != 0) 866 /* 867 * 4 + 4 = First 4 bytes to keep the number of symbols. 868 * The second 4 bytes for string table. 869 */ 870 arsize += sizeof (struct ar_hdr) + 4 + 4; 871 872 if (arsize > AR_MAX_BYTES_IN_MEM) { 873 tmp_dst = dst = NULL; 874 } else { 875 tmp_dst = dst = malloc(arsize); 876 } 877 if (dst == NULL) { 878 return writelargefile(cmd_info, long_tab_size, 879 longnames, symlist, nsyms, found_obj, new_archive); 880 } 881 882 (void) memcpy(tmp_dst, ARMAG, SARMAG); 883 tmp_dst += SARMAG; 884 885 if (nsyms || found_obj != 0) { 886 int diff; 887 diff = writesymtab(tmp_dst, nsyms, symlist); 888 tmp_dst += diff; 889 } 890 891 if (longnames) { 892 (void) sprintf(tmp_dst, FORMAT, LONGDIRNAME, time(0), 893 (unsigned)0, (unsigned)0, (unsigned)0, 894 (long)long_tab_size, ARFMAG); 895 tmp_dst += sizeof (struct ar_hdr); 896 (void) memcpy(tmp_dst, str_base1, str_top1 - str_base1); 897 tmp_dst += str_top1 - str_base1; 898 } 899 for (fptr = listhead; fptr; fptr = fptr->ar_next) { 900 901 /* 902 * NOTE: 903 * The mem_header->ar_name[] is set to a NULL string 904 * if the archive member header has some error. 905 * (See elf_getarhdr() man page.) 906 * It is set to NULL for example, the ar command reads 907 * the archive files created by SunOS 4.1 system. 908 * See c block comment in cmd.c, "Incompatible Archive Header". 909 */ 910 if (fptr->ar_name[0] == 0) { 911 fptr->ar_longname = fptr->ar_rawname; 912 (void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME); 913 } 914 if (strlen(fptr->ar_longname) <= (unsigned)SNAME-2) 915 (void) sprintf(tmp_dst, FNFORMAT, 916 trimslash(fptr->ar_longname)); 917 else 918 (void) sprintf(tmp_dst, FNFORMAT, fptr->ar_name); 919 (void) sprintf(tmp_dst+16, TLFORMAT, fptr->ar_date, 920 (unsigned)fptr->ar_uid, (unsigned)fptr->ar_gid, 921 (unsigned)fptr->ar_mode, fptr->ar_size + fptr->ar_padding, 922 ARFMAG); 923 924 tmp_dst += sizeof (struct ar_hdr); 925 926 if (!(fptr->ar_flag & F_MALLOCED) && 927 !(fptr->ar_flag & F_MMAPED) && 928 !(fptr->ar_flag & F_ELFRAW)) { 929 /* file was not read in fptr->ar_contents during 'cmd' */ 930 /* do it now */ 931 FILE *f; 932 f = fopen(fptr->ar_pathname, "r"); 933 if (f == NULL) { 934 error_message(SYS_OPEN_ERROR, 935 SYSTEM_ERROR, strerror(errno), 936 fptr->ar_longname); 937 exit(1); 938 } else { 939 if (fread(tmp_dst, 940 sizeof (char), 941 fptr->ar_size, f) != fptr->ar_size) { 942 error_message(SYS_READ_ERROR, 943 SYSTEM_ERROR, strerror(errno), 944 fptr->ar_longname); 945 exit(1); 946 } 947 } 948 (void) fclose(f); 949 } else { 950 (void) memcpy(tmp_dst, fptr->ar_contents, 951 fptr->ar_size); 952 if (fptr->ar_flag & F_MALLOCED) { 953 (void) free(fptr->ar_contents); 954 fptr->ar_flag &= ~(F_MALLOCED); 955 } 956 } 957 tmp_dst += fptr->ar_size; 958 959 if (fptr->ar_size & 0x1) { 960 (void) memcpy(tmp_dst, "\n", 1); 961 tmp_dst++; 962 } 963 964 if (fptr->ar_padding) { 965 int i = fptr->ar_padding; 966 while (i) { 967 *tmp_dst++ = '\n'; 968 --i; 969 } 970 } 971 } 972 973 /* 974 * All preparation for writing is done. 975 */ 976 (void) elf_end(cmd_info->arf); 977 (void) close(cmd_info->afd); 978 979 /* 980 * Write out to the file 981 */ 982 if (new_archive) { 983 /* 984 * create a new file 985 */ 986 nfd = creat(name, 0666); 987 if (nfd == -1) { 988 error_message(SYS_CREATE_01_ERROR, 989 SYSTEM_ERROR, strerror(errno), name); 990 exit(1); 991 } 992 } else { 993 /* 994 * Open the new file 995 */ 996 nfd = open(name, O_RDWR|O_TRUNC); 997 if (nfd == -1) { 998 error_message(SYS_WRITE_02_ERROR, 999 SYSTEM_ERROR, strerror(errno), name); 1000 exit(1); 1001 } 1002 } 1003 #ifndef XPG4 1004 if (opt_FLAG(cmd_info, v_FLAG)) { 1005 error_message(BER_MES_WRITE_ERROR, 1006 PLAIN_ERROR, (char *)0, 1007 cmd_info->arnam); 1008 } 1009 #endif 1010 if (write(nfd, dst, arsize) != arsize) { 1011 error_message(SYS_WRITE_04_ERROR, 1012 SYSTEM_ERROR, strerror(errno), name); 1013 if (!new_archive) 1014 error_message(WARN_USER_ERROR, 1015 PLAIN_ERROR, (char *)0); 1016 exit(2); 1017 } 1018 return (dst); 1019 } 1020 1021 static long 1022 mklong_tab(int *longnames) 1023 { 1024 ARFILE *fptr; 1025 char ptr_index[SNAME+1]; 1026 long ret = 0; 1027 1028 for (fptr = listhead; fptr; fptr = fptr->ar_next) { 1029 if (strlen(fptr->ar_longname) >= (unsigned)SNAME-1) { 1030 (*longnames)++; 1031 savelongname(fptr, ptr_index); 1032 (void) strcpy(fptr->ar_name, ptr_index); 1033 } 1034 } 1035 if (*longnames) { 1036 /* round up table that keeps the long filenames */ 1037 while ((str_top1 - str_base1) & 03) 1038 *str_top1++ = '\n'; 1039 ret = sizeof (char) * (str_top1 - str_base1); 1040 } 1041 return (ret); 1042 } 1043 1044 /* Put bytes in archive header in machine independent order. */ 1045 1046 static void 1047 sputl(long n, char *cp) 1048 { 1049 *cp++ = n >> 24; 1050 *cp++ = n >> 16; 1051 *cp++ = n >> 8; 1052 1053 *cp++ = n & 255; 1054 } 1055 1056 #ifdef BROWSER 1057 1058 static void 1059 sbrowser_search_stab(Elf *elf, int stabid, int stabstrid, char *arnam) 1060 { 1061 Elf_Scn *stab_scn; 1062 Elf_Scn *stabstr_scn; 1063 Elf_Data *data; 1064 struct nlist *np; 1065 struct nlist *stabtab; 1066 char *stabstrtab; 1067 char *stabstroff; 1068 char *symname; 1069 int prevstabstrsz; 1070 GElf_Xword nstab; 1071 GElf_Shdr shdr; 1072 1073 /* use the .stab and stabstr section index to find the data buffer */ 1074 if (stabid == -1) { 1075 error_message(SBROW_01_ERROR, 1076 PLAIN_ERROR, (char *)0); 1077 return; 1078 } 1079 stab_scn = elf_getscn(elf, (size_t)stabid); 1080 if (stab_scn == NULL) { 1081 error_message(ELF_GETDATA_02_ERROR, 1082 LIBELF_ERROR, elf_errmsg(-1)); 1083 return; 1084 } 1085 1086 (void) gelf_getshdr(stab_scn, &shdr); 1087 /* 1088 * Zero length .stab sections have been produced by some compilers so 1089 * ignore the section if this is the case. 1090 */ 1091 if ((nstab = shdr.sh_size / shdr.sh_entsize) == 0) 1092 return; 1093 1094 if (stabstrid == -1) { 1095 error_message(SBROW_02_ERROR, 1096 PLAIN_ERROR, (char *)0); 1097 return; 1098 } 1099 stabstr_scn = elf_getscn(elf, (size_t)stabstrid); 1100 if (stabstr_scn == NULL) { 1101 error_message(ELF_GETDATA_02_ERROR, 1102 LIBELF_ERROR, elf_errmsg(-1)); 1103 return; 1104 } 1105 if (gelf_getshdr(stabstr_scn, &shdr) == NULL) { 1106 error_message(ELF_GETDATA_02_ERROR, 1107 LIBELF_ERROR, elf_errmsg(-1)); 1108 return; 1109 } 1110 if (shdr.sh_size == 0) { 1111 error_message(SBROW_03_ERROR, 1112 PLAIN_ERROR, (char *)0); 1113 return; 1114 } 1115 1116 data = 0; 1117 data = elf_getdata(stabstr_scn, data); 1118 if (data == NULL) { 1119 error_message(ELF_GETDATA_02_ERROR, 1120 LIBELF_ERROR, elf_errmsg(-1)); 1121 return; 1122 } 1123 if (data->d_size == 0) { 1124 error_message(SBROW_02_ERROR, 1125 PLAIN_ERROR, (char *)0); 1126 return; 1127 } 1128 stabstrtab = (char *)data->d_buf; 1129 data = 0; 1130 data = elf_getdata(stab_scn, data); 1131 if (data == NULL) { 1132 error_message(ELF_GETDATA_02_ERROR, 1133 LIBELF_ERROR, elf_errmsg(-1)); 1134 return; 1135 } 1136 if (data->d_size == 0) { 1137 error_message(SBROW_03_ERROR, 1138 PLAIN_ERROR, (char *)0); 1139 return; 1140 } 1141 stabtab = (struct nlist *)data->d_buf; 1142 stabstroff = stabstrtab; 1143 prevstabstrsz = 0; 1144 for (np = stabtab; np < &stabtab[nstab]; np++) { 1145 if (np->n_type == 0) { 1146 stabstroff += prevstabstrsz; 1147 prevstabstrsz = np->n_value; 1148 } 1149 symname = stabstroff + np->n_un.n_strx; 1150 if (np->n_type == 0x48) { 1151 sbfocus_symbol(&sb_data, arnam, "-a", symname); 1152 } 1153 } 1154 } 1155 #endif 1156 1157 1158 1159 static int 1160 search_sym_tab(ARFILE *fptr, Elf *elf, Elf_Scn *scn, 1161 long *nsyms, ARFILEP **symlist, int *num_errs) 1162 { 1163 Elf_Data *str_data, *sym_data; /* string table, symbol table */ 1164 Elf_Scn *str_scn; 1165 GElf_Sxword no_of_symbols; 1166 GElf_Shdr shdr; 1167 int counter; 1168 int str_shtype; 1169 char *symname; 1170 static ARFILEP *sym_ptr = 0; 1171 static ARFILEP *nextsym = NULL; 1172 static int syms_left = 0; 1173 char *fname = fptr->ar_pathname; 1174 1175 (void) gelf_getshdr(scn, &shdr); 1176 str_scn = elf_getscn(elf, shdr.sh_link); /* index for string table */ 1177 if (str_scn == NULL) { 1178 if (fname != NULL) 1179 error_message(ELF_GETDATA_01_ERROR, 1180 LIBELF_ERROR, elf_errmsg(-1), 1181 fname); 1182 else 1183 error_message(ELF_GETDATA_02_ERROR, 1184 LIBELF_ERROR, elf_errmsg(-1)); 1185 (*num_errs)++; 1186 return (-1); 1187 } 1188 1189 no_of_symbols = shdr.sh_size / shdr.sh_entsize; 1190 if (no_of_symbols == -1) { 1191 error_message(SYMTAB_01_ERROR, 1192 PLAIN_ERROR, (char *)0); 1193 return (-1); 1194 } 1195 1196 (void) gelf_getshdr(str_scn, &shdr); 1197 str_shtype = shdr.sh_type; 1198 if (str_shtype == -1) { 1199 if (fname != NULL) 1200 error_message(ELF_GETDATA_01_ERROR, 1201 LIBELF_ERROR, elf_errmsg(-1), fname); 1202 else 1203 error_message(ELF_GETDATA_02_ERROR, 1204 LIBELF_ERROR, elf_errmsg(-1)); 1205 (*num_errs)++; 1206 return (-1); 1207 } 1208 1209 /* This test must happen before testing the string table. */ 1210 if (no_of_symbols == 1) 1211 return (0); /* no symbols; 0th symbol is the non-symbol */ 1212 1213 if (str_shtype != SHT_STRTAB) { 1214 if (fname != NULL) 1215 error_message(SYMTAB_02_ERROR, 1216 PLAIN_ERROR, (char *)0, 1217 fname); 1218 else 1219 error_message(SYMTAB_03_ERROR, 1220 PLAIN_ERROR, (char *)0); 1221 return (0); 1222 } 1223 str_data = 0; 1224 if ((str_data = elf_getdata(str_scn, str_data)) == 0) { 1225 if (fname != NULL) 1226 error_message(SYMTAB_04_ERROR, 1227 PLAIN_ERROR, (char *)0, 1228 fname); 1229 else 1230 error_message(SYMTAB_05_ERROR, 1231 PLAIN_ERROR, (char *)0); 1232 return (0); 1233 } 1234 if (str_data->d_size == 0) { 1235 if (fname != NULL) 1236 error_message(SYMTAB_06_ERROR, 1237 PLAIN_ERROR, (char *)0, 1238 fname); 1239 else 1240 error_message(SYMTAB_07_ERROR, 1241 PLAIN_ERROR, (char *)0); 1242 return (0); 1243 } 1244 sym_data = 0; 1245 if ((sym_data = elf_getdata(scn, sym_data)) == NULL) { 1246 if (fname != NULL) 1247 error_message(ELF_01_ERROR, 1248 LIBELF_ERROR, elf_errmsg(-1), 1249 fname, elf_errmsg(-1)); 1250 else 1251 error_message(ELF_02_ERROR, 1252 LIBELF_ERROR, elf_errmsg(-1), 1253 elf_errmsg(-1)); 1254 return (0); 1255 } 1256 1257 /* start at 1, first symbol entry is ignored */ 1258 for (counter = 1; counter < no_of_symbols; counter++) { 1259 GElf_Sym sym; 1260 (void) gelf_getsym(sym_data, counter, &sym); 1261 1262 symname = (char *)(str_data->d_buf) + sym.st_name; 1263 1264 if (((GELF_ST_BIND(sym.st_info) == STB_GLOBAL) || 1265 (GELF_ST_BIND(sym.st_info) == STB_WEAK)) && 1266 (sym.st_shndx != SHN_UNDEF)) { 1267 if (!syms_left) { 1268 sym_ptr = malloc((SYMCHUNK+1) 1269 * sizeof (ARFILEP)); 1270 if (sym_ptr == NULL) { 1271 error_message(MALLOC_ERROR, 1272 PLAIN_ERROR, (char *)0); 1273 exit(1); 1274 } 1275 syms_left = SYMCHUNK; 1276 if (nextsym) 1277 *nextsym = (ARFILEP)sym_ptr; 1278 else 1279 *symlist = sym_ptr; 1280 nextsym = sym_ptr; 1281 } 1282 sym_ptr = nextsym; 1283 nextsym++; 1284 syms_left--; 1285 (*nsyms)++; 1286 *sym_ptr = fptr; 1287 savename(symname); /* put name in the archiver's */ 1288 /* symbol table string table */ 1289 } 1290 } 1291 return (0); 1292 } 1293 1294 /* 1295 * Get the output file size 1296 */ 1297 static int 1298 sizeofmembers(int psum) 1299 { 1300 int sum = 0; 1301 ARFILE *fptr; 1302 int hdrsize = sizeof (struct ar_hdr); 1303 1304 for (fptr = listhead; fptr; fptr = fptr->ar_next) { 1305 fptr->ar_offset = psum + sum; 1306 sum += fptr->ar_size; 1307 if (fptr->ar_size & 01) 1308 sum++; 1309 sum += hdrsize; 1310 1311 if ((fptr->ar_flag & (F_CLASS32 | F_CLASS64)) && 1312 fptr->ar_next && 1313 (fptr->ar_next->ar_flag & (F_CLASS32 | F_CLASS64))) { 1314 fptr->ar_padding = pad(psum + sum + hdrsize); 1315 sum += fptr->ar_padding; 1316 } 1317 } 1318 return (sum); 1319 } 1320 1321 static int 1322 sizeofnewarchiveheader(int nsyms, int longnames) 1323 { 1324 int sum = 0; 1325 1326 sum += SARMAG; 1327 1328 if (nsyms) { 1329 char *top = (char *)str_top; 1330 char *base = (char *)str_base; 1331 1332 while ((top - base) & 03) 1333 top++; 1334 sum += sizeof (struct ar_hdr); 1335 sum += (nsyms + 1) * 4; 1336 sum += top - base; 1337 } 1338 1339 if (longnames) { 1340 sum += sizeof (struct ar_hdr); 1341 sum += str_top1 - str_base1; 1342 } 1343 1344 /* 1345 * If the first member file is an ELF object, 1346 * we have to ensure the member contents will align 1347 * on PADSZ byte boundary. 1348 */ 1349 if (listhead && (listhead->ar_flag & (F_CLASS32 | F_CLASS64))) { 1350 pad_symtab = pad(sum + sizeof (struct ar_hdr)); 1351 sum += pad_symtab; 1352 } 1353 1354 return (sum); 1355 } 1356 1357 static int 1358 sizeofnewarchive(int nsyms, int longnames) 1359 { 1360 int sum; 1361 1362 sum = sizeofnewarchiveheader(nsyms, longnames); 1363 sum += sizeofmembers(sum); 1364 return (sum); 1365 } 1366 1367 static void 1368 arwrite(char *name, int nfd, char *dst, int size) { 1369 if (write(nfd, dst, size) != size) { 1370 error_message(SYS_WRITE_04_ERROR, 1371 SYSTEM_ERROR, strerror(errno), name); 1372 exit(2); 1373 } 1374 } 1375 1376 static char * 1377 make_tmpname(char *filename) { 1378 static char template[] = "arXXXXXX"; 1379 char *tmpname; 1380 char *slash = strrchr(filename, '/'); 1381 1382 if (slash != (char *)NULL) { 1383 char c; 1384 1385 c = *slash; 1386 *slash = 0; 1387 tmpname = (char *)malloc(strlen(filename) + 1388 sizeof (template) + 2); 1389 (void) strcpy(tmpname, filename); 1390 (void) strcat(tmpname, "/"); 1391 (void) strcat(tmpname, template); 1392 (void) mktemp(tmpname); 1393 *slash = c; 1394 } else { 1395 tmpname = malloc(sizeof (template)); 1396 (void) strcpy(tmpname, template); 1397 (void) mktemp(tmpname); 1398 } 1399 return (tmpname); 1400 } 1401 1402 static int 1403 ar_copy(char *from, char *to) { 1404 int fromfd, tofd, nread; 1405 int saved; 1406 char buf[8192]; 1407 1408 fromfd = open(from, O_RDONLY); 1409 if (fromfd < 0) 1410 return (-1); 1411 tofd = open(to, O_CREAT | O_WRONLY | O_TRUNC, 0777); 1412 if (tofd < 0) { 1413 saved = errno; 1414 (void) close(fromfd); 1415 errno = saved; 1416 return (-1); 1417 } 1418 while ((nread = read(fromfd, buf, sizeof (buf))) > 0) { 1419 if (write(tofd, buf, nread) != nread) { 1420 saved = errno; 1421 (void) close(fromfd); 1422 (void) close(tofd); 1423 errno = saved; 1424 return (-1); 1425 } 1426 } 1427 saved = errno; 1428 (void) close(fromfd); 1429 (void) close(tofd); 1430 if (nread < 0) { 1431 errno = saved; 1432 return (-1); 1433 } 1434 return (0); 1435 } 1436 1437 static int 1438 ar_rename(char *from, char *to) 1439 { 1440 int exists; 1441 struct stat s; 1442 int ret = 0; 1443 1444 exists = lstat(to, &s) == 0; 1445 1446 if (! exists || (!S_ISLNK(s.st_mode) && s.st_nlink == 1)) { 1447 ret = rename(from, to); 1448 if (ret == 0) { 1449 if (exists) { 1450 (void) chmod(to, s.st_mode & 0777); 1451 if (chown(to, s.st_uid, s.st_gid) >= 0) 1452 (void) chmod(to, s.st_mode & 07777); 1453 } 1454 } else { 1455 (void) unlink(from); 1456 } 1457 } else { 1458 ret = ar_copy(from, to); 1459 (void) unlink(from); 1460 } 1461 return (ret); 1462 } 1463 1464 static char * 1465 writelargefile(Cmd_info *cmd_info, long long_tab_size, int longnames, 1466 ARFILEP *symlist, long nsyms, int found_obj, int new_archive) 1467 { 1468 ARFILE * fptr; 1469 char *name = cmd_info->arnam; 1470 int arsize; 1471 char *dst; 1472 char *tmp_dst; 1473 int nfd; 1474 char *new_name; 1475 FILE *f; 1476 struct stat stbuf; 1477 1478 new_name = make_tmpname(name); 1479 1480 if (new_archive) { 1481 nfd = open(name, O_RDWR|O_CREAT|O_LARGEFILE, 0666); 1482 if (nfd == -1) { 1483 error_message(SYS_CREATE_01_ERROR, 1484 SYSTEM_ERROR, strerror(errno), name); 1485 exit(1); 1486 } 1487 } else { 1488 nfd = open(new_name, O_RDWR|O_CREAT|O_LARGEFILE, 0666); 1489 if (nfd == -1) { 1490 error_message(SYS_WRITE_02_ERROR, 1491 SYSTEM_ERROR, strerror(errno), name); 1492 exit(1); 1493 } 1494 } 1495 1496 arsize = sizeofnewarchiveheader(nsyms, longnames); 1497 if (nsyms == 0 && found_obj != 0) 1498 arsize += sizeof (struct ar_hdr) + 4 + 4; 1499 if (arsize < 2048) { 1500 arsize = 2048; 1501 } 1502 dst = tmp_dst = (char *)malloc(arsize); 1503 (void) memcpy(tmp_dst, ARMAG, SARMAG); 1504 tmp_dst += SARMAG; 1505 1506 if (nsyms || found_obj != 0) { 1507 int diff; 1508 diff = writesymtab(tmp_dst, nsyms, symlist); 1509 tmp_dst += diff; 1510 } 1511 1512 if (longnames) { 1513 (void) sprintf(tmp_dst, FORMAT, LONGDIRNAME, time(0), 1514 (unsigned)0, (unsigned)0, (unsigned)0, 1515 (long)long_tab_size, ARFMAG); 1516 tmp_dst += sizeof (struct ar_hdr); 1517 (void) memcpy(tmp_dst, str_base1, str_top1 - str_base1); 1518 tmp_dst += str_top1 - str_base1; 1519 } 1520 #ifndef XPG4 1521 if (opt_FLAG(cmd_info, v_FLAG)) { 1522 error_message(BER_MES_WRITE_ERROR, 1523 PLAIN_ERROR, (char *)0, 1524 cmd_info->arnam); 1525 } 1526 #endif 1527 arwrite(name, nfd, dst, (int)(tmp_dst - dst)); 1528 1529 for (fptr = listhead; fptr; fptr = fptr->ar_next) { 1530 if (fptr->ar_name[0] == 0) { 1531 fptr->ar_longname = fptr->ar_rawname; 1532 (void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME); 1533 } 1534 if (strlen(fptr->ar_longname) <= (unsigned)SNAME-2) 1535 (void) sprintf(dst, FNFORMAT, 1536 trimslash(fptr->ar_longname)); 1537 else 1538 (void) sprintf(dst, FNFORMAT, fptr->ar_name); 1539 (void) sprintf(dst+16, TLFORMAT, fptr->ar_date, 1540 (unsigned)fptr->ar_uid, (unsigned)fptr->ar_gid, 1541 (unsigned)fptr->ar_mode, fptr->ar_size + fptr->ar_padding, 1542 ARFMAG); 1543 arwrite(name, nfd, dst, sizeof (struct ar_hdr)); 1544 1545 if (!(fptr->ar_flag & F_MALLOCED) && 1546 !(fptr->ar_flag & F_MMAPED) && 1547 !(fptr->ar_flag & F_ELFRAW)) { 1548 f = fopen(fptr->ar_pathname, "r"); 1549 if (stat(fptr->ar_pathname, &stbuf) < 0) { 1550 (void) fclose(f); 1551 f = NULL; 1552 } 1553 if (f == NULL) { 1554 error_message(SYS_OPEN_ERROR, 1555 SYSTEM_ERROR, strerror(errno), 1556 fptr->ar_longname); 1557 exit(1); 1558 } else { 1559 if ((fptr->ar_contents = (char *) 1560 malloc(ROUNDUP(stbuf.st_size))) == NULL) { 1561 error_message(MALLOC_ERROR, 1562 PLAIN_ERROR, (char *)0); 1563 exit(1); 1564 } 1565 if (fread(fptr->ar_contents, 1566 sizeof (char), 1567 stbuf.st_size, f) != stbuf.st_size) { 1568 error_message(SYS_READ_ERROR, 1569 SYSTEM_ERROR, strerror(errno), 1570 fptr->ar_longname); 1571 exit(1); 1572 } 1573 } 1574 arwrite(name, nfd, fptr->ar_contents, fptr->ar_size); 1575 (void) fclose(f); 1576 free(fptr->ar_contents); 1577 } else { 1578 arwrite(name, nfd, fptr->ar_contents, fptr->ar_size); 1579 if (fptr->ar_flag & F_MALLOCED) { 1580 (void) free(fptr->ar_contents); 1581 fptr->ar_flag &= ~(F_MALLOCED); 1582 } 1583 } 1584 1585 if (fptr->ar_size & 0x1) { 1586 arwrite(name, nfd, "\n", 1); 1587 } 1588 1589 if (fptr->ar_padding) { 1590 int i = fptr->ar_padding; 1591 while (i) { 1592 arwrite(name, nfd, "\n", 1); 1593 --i; 1594 } 1595 } 1596 } 1597 1598 /* 1599 * All preparation for writing is done. 1600 */ 1601 (void) elf_end(cmd_info->arf); 1602 (void) close(cmd_info->afd); 1603 1604 if (!new_archive) { 1605 (void) ar_rename(new_name, name); 1606 } 1607 1608 return (dst); 1609 } 1610