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 /* 1312 * If the current item, and the next item are both ELF 1313 * objects, then add padding to current item so that the 1314 * next item will have PADSZ alignment. 1315 * 1316 * In any other case, set the padding to 0. If the 1317 * item comes from another archive, it may be carrying 1318 * a non-zero padding value from that archive that does 1319 * not apply to the one we are about to build. 1320 */ 1321 if ((fptr->ar_flag & (F_CLASS32 | F_CLASS64)) && 1322 fptr->ar_next && 1323 (fptr->ar_next->ar_flag & (F_CLASS32 | F_CLASS64))) { 1324 fptr->ar_padding = pad(psum + sum + hdrsize); 1325 sum += fptr->ar_padding; 1326 } else { 1327 fptr->ar_padding = 0; 1328 } 1329 } 1330 return (sum); 1331 } 1332 1333 static int 1334 sizeofnewarchiveheader(int nsyms, int longnames) 1335 { 1336 int sum = 0; 1337 1338 sum += SARMAG; 1339 1340 if (nsyms) { 1341 char *top = (char *)str_top; 1342 char *base = (char *)str_base; 1343 1344 while ((top - base) & 03) 1345 top++; 1346 sum += sizeof (struct ar_hdr); 1347 sum += (nsyms + 1) * 4; 1348 sum += top - base; 1349 } 1350 1351 if (longnames) { 1352 sum += sizeof (struct ar_hdr); 1353 sum += str_top1 - str_base1; 1354 } 1355 1356 /* 1357 * If the first member file is an ELF object, 1358 * we have to ensure the member contents will align 1359 * on PADSZ byte boundary. 1360 */ 1361 if (listhead && (listhead->ar_flag & (F_CLASS32 | F_CLASS64))) { 1362 pad_symtab = pad(sum + sizeof (struct ar_hdr)); 1363 sum += pad_symtab; 1364 } 1365 1366 return (sum); 1367 } 1368 1369 static int 1370 sizeofnewarchive(int nsyms, int longnames) 1371 { 1372 int sum; 1373 1374 sum = sizeofnewarchiveheader(nsyms, longnames); 1375 sum += sizeofmembers(sum); 1376 return (sum); 1377 } 1378 1379 static void 1380 arwrite(char *name, int nfd, char *dst, int size) { 1381 if (write(nfd, dst, size) != size) { 1382 error_message(SYS_WRITE_04_ERROR, 1383 SYSTEM_ERROR, strerror(errno), name); 1384 exit(2); 1385 } 1386 } 1387 1388 static char * 1389 make_tmpname(char *filename) { 1390 static char template[] = "arXXXXXX"; 1391 char *tmpname; 1392 char *slash = strrchr(filename, '/'); 1393 1394 if (slash != (char *)NULL) { 1395 char c; 1396 1397 c = *slash; 1398 *slash = 0; 1399 tmpname = (char *)malloc(strlen(filename) + 1400 sizeof (template) + 2); 1401 (void) strcpy(tmpname, filename); 1402 (void) strcat(tmpname, "/"); 1403 (void) strcat(tmpname, template); 1404 (void) mktemp(tmpname); 1405 *slash = c; 1406 } else { 1407 tmpname = malloc(sizeof (template)); 1408 (void) strcpy(tmpname, template); 1409 (void) mktemp(tmpname); 1410 } 1411 return (tmpname); 1412 } 1413 1414 static int 1415 ar_copy(char *from, char *to) { 1416 int fromfd, tofd, nread; 1417 int saved; 1418 char buf[8192]; 1419 1420 fromfd = open(from, O_RDONLY); 1421 if (fromfd < 0) 1422 return (-1); 1423 tofd = open(to, O_CREAT | O_WRONLY | O_TRUNC, 0777); 1424 if (tofd < 0) { 1425 saved = errno; 1426 (void) close(fromfd); 1427 errno = saved; 1428 return (-1); 1429 } 1430 while ((nread = read(fromfd, buf, sizeof (buf))) > 0) { 1431 if (write(tofd, buf, nread) != nread) { 1432 saved = errno; 1433 (void) close(fromfd); 1434 (void) close(tofd); 1435 errno = saved; 1436 return (-1); 1437 } 1438 } 1439 saved = errno; 1440 (void) close(fromfd); 1441 (void) close(tofd); 1442 if (nread < 0) { 1443 errno = saved; 1444 return (-1); 1445 } 1446 return (0); 1447 } 1448 1449 static int 1450 ar_rename(char *from, char *to) 1451 { 1452 int exists; 1453 struct stat s; 1454 int ret = 0; 1455 1456 exists = lstat(to, &s) == 0; 1457 1458 if (! exists || (!S_ISLNK(s.st_mode) && s.st_nlink == 1)) { 1459 ret = rename(from, to); 1460 if (ret == 0) { 1461 if (exists) { 1462 (void) chmod(to, s.st_mode & 0777); 1463 if (chown(to, s.st_uid, s.st_gid) >= 0) 1464 (void) chmod(to, s.st_mode & 07777); 1465 } 1466 } else { 1467 (void) unlink(from); 1468 } 1469 } else { 1470 ret = ar_copy(from, to); 1471 (void) unlink(from); 1472 } 1473 return (ret); 1474 } 1475 1476 static char * 1477 writelargefile(Cmd_info *cmd_info, long long_tab_size, int longnames, 1478 ARFILEP *symlist, long nsyms, int found_obj, int new_archive) 1479 { 1480 ARFILE * fptr; 1481 char *name = cmd_info->arnam; 1482 int arsize; 1483 char *dst; 1484 char *tmp_dst; 1485 int nfd; 1486 char *new_name; 1487 FILE *f; 1488 struct stat stbuf; 1489 1490 new_name = make_tmpname(name); 1491 1492 if (new_archive) { 1493 nfd = open(name, O_RDWR|O_CREAT|O_LARGEFILE, 0666); 1494 if (nfd == -1) { 1495 error_message(SYS_CREATE_01_ERROR, 1496 SYSTEM_ERROR, strerror(errno), name); 1497 exit(1); 1498 } 1499 } else { 1500 nfd = open(new_name, O_RDWR|O_CREAT|O_LARGEFILE, 0666); 1501 if (nfd == -1) { 1502 error_message(SYS_WRITE_02_ERROR, 1503 SYSTEM_ERROR, strerror(errno), name); 1504 exit(1); 1505 } 1506 } 1507 1508 arsize = sizeofnewarchiveheader(nsyms, longnames); 1509 if (nsyms == 0 && found_obj != 0) 1510 arsize += sizeof (struct ar_hdr) + 4 + 4; 1511 if (arsize < 2048) { 1512 arsize = 2048; 1513 } 1514 dst = tmp_dst = (char *)malloc(arsize); 1515 (void) memcpy(tmp_dst, ARMAG, SARMAG); 1516 tmp_dst += SARMAG; 1517 1518 if (nsyms || found_obj != 0) { 1519 int diff; 1520 diff = writesymtab(tmp_dst, nsyms, symlist); 1521 tmp_dst += diff; 1522 } 1523 1524 if (longnames) { 1525 (void) sprintf(tmp_dst, FORMAT, LONGDIRNAME, time(0), 1526 (unsigned)0, (unsigned)0, (unsigned)0, 1527 (long)long_tab_size, ARFMAG); 1528 tmp_dst += sizeof (struct ar_hdr); 1529 (void) memcpy(tmp_dst, str_base1, str_top1 - str_base1); 1530 tmp_dst += str_top1 - str_base1; 1531 } 1532 #ifndef XPG4 1533 if (opt_FLAG(cmd_info, v_FLAG)) { 1534 error_message(BER_MES_WRITE_ERROR, 1535 PLAIN_ERROR, (char *)0, 1536 cmd_info->arnam); 1537 } 1538 #endif 1539 arwrite(name, nfd, dst, (int)(tmp_dst - dst)); 1540 1541 for (fptr = listhead; fptr; fptr = fptr->ar_next) { 1542 if (fptr->ar_name[0] == 0) { 1543 fptr->ar_longname = fptr->ar_rawname; 1544 (void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME); 1545 } 1546 if (strlen(fptr->ar_longname) <= (unsigned)SNAME-2) 1547 (void) sprintf(dst, FNFORMAT, 1548 trimslash(fptr->ar_longname)); 1549 else 1550 (void) sprintf(dst, FNFORMAT, fptr->ar_name); 1551 (void) sprintf(dst+16, TLFORMAT, fptr->ar_date, 1552 (unsigned)fptr->ar_uid, (unsigned)fptr->ar_gid, 1553 (unsigned)fptr->ar_mode, fptr->ar_size + fptr->ar_padding, 1554 ARFMAG); 1555 arwrite(name, nfd, dst, sizeof (struct ar_hdr)); 1556 1557 if (!(fptr->ar_flag & F_MALLOCED) && 1558 !(fptr->ar_flag & F_MMAPED) && 1559 !(fptr->ar_flag & F_ELFRAW)) { 1560 f = fopen(fptr->ar_pathname, "r"); 1561 if (stat(fptr->ar_pathname, &stbuf) < 0) { 1562 (void) fclose(f); 1563 f = NULL; 1564 } 1565 if (f == NULL) { 1566 error_message(SYS_OPEN_ERROR, 1567 SYSTEM_ERROR, strerror(errno), 1568 fptr->ar_longname); 1569 exit(1); 1570 } else { 1571 if ((fptr->ar_contents = (char *) 1572 malloc(ROUNDUP(stbuf.st_size))) == NULL) { 1573 error_message(MALLOC_ERROR, 1574 PLAIN_ERROR, (char *)0); 1575 exit(1); 1576 } 1577 if (fread(fptr->ar_contents, 1578 sizeof (char), 1579 stbuf.st_size, f) != stbuf.st_size) { 1580 error_message(SYS_READ_ERROR, 1581 SYSTEM_ERROR, strerror(errno), 1582 fptr->ar_longname); 1583 exit(1); 1584 } 1585 } 1586 arwrite(name, nfd, fptr->ar_contents, fptr->ar_size); 1587 (void) fclose(f); 1588 free(fptr->ar_contents); 1589 } else { 1590 arwrite(name, nfd, fptr->ar_contents, fptr->ar_size); 1591 if (fptr->ar_flag & F_MALLOCED) { 1592 (void) free(fptr->ar_contents); 1593 fptr->ar_flag &= ~(F_MALLOCED); 1594 } 1595 } 1596 1597 if (fptr->ar_size & 0x1) { 1598 arwrite(name, nfd, "\n", 1); 1599 } 1600 1601 if (fptr->ar_padding) { 1602 int i = fptr->ar_padding; 1603 while (i) { 1604 arwrite(name, nfd, "\n", 1); 1605 --i; 1606 } 1607 } 1608 } 1609 1610 /* 1611 * All preparation for writing is done. 1612 */ 1613 (void) elf_end(cmd_info->arf); 1614 (void) close(cmd_info->afd); 1615 1616 if (!new_archive) { 1617 (void) ar_rename(new_name, name); 1618 } 1619 1620 return (dst); 1621 } 1622