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 2004 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * @(#)ar.cc 1.28 06/12/12 27 */ 28 29 #pragma ident "@(#)ar.cc 1.28 06/12/12" 30 31 /* 32 * ar.c 33 * 34 * Deal with the lib.a(member.o) and lib.a((entry-point)) notations 35 * 36 * Look inside archives for notations a(b) and a((b)) 37 * a(b) is file member b in archive a 38 * a((b)) is entry point b in object archive a 39 * 40 * For 6.0, create a make which can understand all archive 41 * formats. This is kind of tricky, and <ar.h> isnt any help. 42 */ 43 44 /* 45 * Included files 46 */ 47 #include <avo/avo_alloca.h> /* alloca() */ 48 #include <ar.h> 49 #include <errno.h> /* errno */ 50 #include <fcntl.h> /* open() */ 51 #include <mk/defs.h> 52 #include <mksh/misc.h> /* retmem_mb() */ 53 54 #if defined(SUN5_0) || defined(HP_UX) || defined(linux) 55 struct ranlib { 56 union { 57 off_t ran_strx; /* string table index of */ 58 char *ran_name; /* symbol defined by */ 59 } ran_un; 60 off_t ran_off; /* library member at this offset */ 61 }; 62 #else 63 #include <ranlib.h> 64 #endif 65 66 #if defined(linux) 67 #include <ctype.h> /* isspace */ 68 #else 69 #include <unistd.h> /* close() */ 70 #endif 71 72 73 /* 74 * Defined macros 75 */ 76 #ifndef S5EMUL 77 #undef BITSPERBYTE 78 #define BITSPERBYTE 8 79 #endif 80 81 /* 82 * Defines for all the different archive formats. See next comment 83 * block for justification for not using <ar.h>s versions. 84 */ 85 #define AR_5_MAGIC "<ar>" /* 5.0 format magic string */ 86 #define AR_5_MAGIC_LENGTH 4 /* 5.0 format string length */ 87 88 #define AR_PORT_MAGIC "!<arch>\n" /* Port. (6.0) magic string */ 89 #define AR_PORT_MAGIC_LENGTH 8 /* Port. (6.0) string length */ 90 #define AR_PORT_END_MAGIC "`\n" /* Port. (6.0) end of header */ 91 #define AR_PORT_WORD 4 /* Port. (6.0) 'word' length */ 92 93 /* 94 * typedefs & structs 95 */ 96 /* 97 * These are the archive file headers for the formats. Note 98 * that it really doesnt matter if these structures are defined 99 * here. They are correct as of the respective archive format 100 * releases. If the archive format is changed, then since backwards 101 * compatability is the desired behavior, a new structure is added 102 * to the list. 103 */ 104 typedef struct { /* 5.0 ar header format: vax family; 3b family */ 105 char ar_magic[AR_5_MAGIC_LENGTH]; /* AR_5_MAGIC*/ 106 char ar_name[16]; /* Space terminated */ 107 char ar_date[AR_PORT_WORD]; /* sgetl() accessed */ 108 char ar_syms[AR_PORT_WORD]; /* sgetl() accessed */ 109 } Arh_5; 110 111 typedef struct { /* 5.0 ar symbol format: vax family; 3b family */ 112 char sym_name[8]; /* Space terminated */ 113 char sym_ptr[AR_PORT_WORD]; /* sgetl() accessed */ 114 } Ars_5; 115 116 typedef struct { /* 5.0 ar member format: vax family; 3b family */ 117 char arf_name[16]; /* Space terminated */ 118 char arf_date[AR_PORT_WORD]; /* sgetl() accessed */ 119 char arf_uid[AR_PORT_WORD]; /* sgetl() accessed */ 120 char arf_gid[AR_PORT_WORD]; /* sgetl() accessed */ 121 char arf_mode[AR_PORT_WORD]; /* sgetl() accessed */ 122 char arf_size[AR_PORT_WORD]; /* sgetl() accessed */ 123 } Arf_5; 124 125 typedef struct { /* Portable (6.0) ar format: vax family; 3b family */ 126 char ar_name[16]; /* Space terminated */ 127 /* left-adjusted fields; decimal ascii; blank filled */ 128 char ar_date[12]; 129 char ar_uid[6]; 130 char ar_gid[6]; 131 char ar_mode[8]; /* octal ascii */ 132 char ar_size[10]; 133 /* special end-of-header string (AR_PORT_END_MAGIC) */ 134 char ar_fmag[2]; 135 } Ar_port; 136 137 enum ar_type { 138 AR_5, 139 AR_PORT 140 }; 141 142 typedef unsigned int ar_port_word; // must be 4-bytes long 143 144 typedef struct { 145 FILE *fd; 146 /* to distiguish ar format */ 147 enum ar_type type; 148 /* where first ar member header is at */ 149 long first_ar_mem; 150 /* where the symbol lookup starts */ 151 long sym_begin; 152 /* the number of symbols available */ 153 long num_symbols; 154 /* length of symbol directory file */ 155 long sym_size; 156 Arh_5 arh_5; 157 Ars_5 ars_5; 158 Arf_5 arf_5; 159 Ar_port ar_port; 160 } Ar; 161 162 /* 163 * Static variables 164 */ 165 166 /* 167 * File table of contents 168 */ 169 extern timestruc_t& read_archive(register Name target); 170 static Boolean open_archive(char *filename, register Ar *arp); 171 static void close_archive(register Ar *arp); 172 static Boolean read_archive_dir(register Ar *arp, Name library, char **long_names_table); 173 static void translate_entry(register Ar *arp, Name target, register Property member, char **long_names_table); 174 static long sgetl(char *); 175 176 /* 177 * read_archive(target) 178 * 179 * Read the contents of an ar file. 180 * 181 * Return value: 182 * The time the member was created 183 * 184 * Parameters: 185 * target The member to find time for 186 * 187 * Global variables used: 188 * empty_name The Name "" 189 */ 190 191 int read_member_header (Ar_port *header, FILE *fd, char* filename); 192 int process_long_names_member (register Ar *arp, char **long_names_table, char *filename); 193 194 timestruc_t& 195 read_archive(register Name target) 196 { 197 register Property member; 198 wchar_t *slash; 199 String_rec true_member_name; 200 wchar_t buffer[STRING_BUFFER_LENGTH]; 201 register Name true_member = NULL; 202 Ar ar; 203 char *long_names_table = NULL; /* Table of long 204 member names */ 205 206 member = get_prop(target->prop, member_prop); 207 /* 208 * Check if the member has directory component. 209 * If so, remove the dir and see if we know the date. 210 */ 211 if (member->body.member.member != NULL) { 212 Wstring member_string(member->body.member.member); 213 wchar_t * wcb = member_string.get_string(); 214 if((slash = (wchar_t *) wsrchr(wcb, (int) slash_char)) != NULL) { 215 INIT_STRING_FROM_STACK(true_member_name, buffer); 216 append_string(member->body.member.library->string_mb, 217 &true_member_name, 218 FIND_LENGTH); 219 append_char((int) parenleft_char, &true_member_name); 220 append_string(slash + 1, &true_member_name, FIND_LENGTH); 221 append_char((int) parenright_char, &true_member_name); 222 true_member = GETNAME(true_member_name.buffer.start, 223 FIND_LENGTH); 224 if (true_member->stat.time != file_no_time) { 225 target->stat.time = true_member->stat.time; 226 return target->stat.time; 227 } 228 } 229 } 230 if (open_archive(member->body.member.library->string_mb, &ar) == failed) { 231 if (errno == ENOENT) { 232 target->stat.stat_errno = ENOENT; 233 close_archive(&ar); 234 if (member->body.member.member == NULL) { 235 member->body.member.member = empty_name; 236 } 237 return target->stat.time = file_doesnt_exist; 238 } else { 239 fatal(catgets(catd, 1, 1, "Can't access archive `%s': %s"), 240 member->body.member.library->string_mb, 241 errmsg(errno)); 242 } 243 } 244 if (target->stat.time == file_no_time) { 245 if (read_archive_dir(&ar, member->body.member.library, 246 &long_names_table) 247 == failed){ 248 fatal(catgets(catd, 1, 2, "Can't access archive `%s': %s"), 249 member->body.member.library->string_mb, 250 errmsg(errno)); 251 } 252 } 253 if (member->body.member.entry != NULL) { 254 translate_entry(&ar, target, member,&long_names_table); 255 } 256 close_archive(&ar); 257 if (long_names_table) { 258 retmem_mb(long_names_table); 259 } 260 if (true_member != NULL) { 261 target->stat.time = true_member->stat.time; 262 } 263 if (target->stat.time == file_no_time) { 264 target->stat.time = file_doesnt_exist; 265 } 266 return target->stat.time; 267 } 268 269 /* 270 * open_archive(filename, arp) 271 * 272 * Return value: 273 * Indicates if open failed or not 274 * 275 * Parameters: 276 * filename The name of the archive we need to read 277 * arp Pointer to ar file description block 278 * 279 * Global variables used: 280 */ 281 static Boolean 282 open_archive(char *filename, register Ar *arp) 283 { 284 int fd; 285 char mag_5[AR_5_MAGIC_LENGTH]; 286 char mag_port[AR_PORT_MAGIC_LENGTH]; 287 char buffer[4]; 288 289 arp->fd = NULL; 290 fd = open_vroot(filename, O_RDONLY, 0, NULL, VROOT_DEFAULT); 291 if ((fd < 0) || ((arp->fd = fdopen(fd, "r")) == NULL)) { 292 return failed; 293 } 294 (void) fcntl(fileno(arp->fd), F_SETFD, 1); 295 296 #if !defined(SUN5_0) && !defined(linux) //XXX 297 /* Read enough of the archive to distinguish between the formats */ 298 if (fread(mag_5, AR_5_MAGIC_LENGTH, 1, arp->fd) != 1) { 299 return failed; 300 } 301 if (IS_EQUALN(mag_5, AR_5_MAGIC, AR_5_MAGIC_LENGTH)) { 302 arp->type = AR_5; 303 /* Must read in header to set necessary info */ 304 if (fseek(arp->fd, 0L, 0) != 0 || 305 fread((char *) &arp->arh_5, sizeof (Arh_5), 1, arp->fd) != 306 1) { 307 return failed; 308 } 309 arp->sym_begin = ftell(arp->fd); 310 arp->num_symbols = sgetl(arp->arh_5.ar_syms); 311 arp->first_ar_mem = arp->sym_begin + 312 sizeof (Ars_5) * arp->num_symbols; 313 arp->sym_size = 0L; 314 return succeeded; 315 } 316 if (fseek(arp->fd, 0L, 0) != 0) { 317 return failed; 318 } 319 #endif 320 if (fread(mag_port, AR_PORT_MAGIC_LENGTH, 1, arp->fd) != 1) { 321 return failed; 322 } 323 if (IS_EQUALN(mag_port, AR_PORT_MAGIC, AR_PORT_MAGIC_LENGTH)) { 324 arp->type = AR_PORT; 325 /* 326 * Read in first member header to find out if there is 327 * a symbol definition table. 328 */ 329 330 int ret = read_member_header(&arp->ar_port, arp->fd, filename); 331 if (ret == failed) { 332 return failed; 333 } else if(ret == -1) { 334 /* There is no member header - empty archive */ 335 arp->sym_size = arp->num_symbols = arp->sym_begin = 0L; 336 arp->first_ar_mem = ftell(arp->fd); 337 return succeeded; 338 } 339 /* 340 * The following values are the default if there is 341 * no symbol directory and long member names. 342 */ 343 arp->sym_size = arp->num_symbols = arp->sym_begin = 0L; 344 arp->first_ar_mem = ftell(arp->fd) - (long) sizeof (Ar_port); 345 346 /* 347 * Do we have a symbol table? A symbol table is always 348 * the first member in an archive. In 4.1.x it has the 349 * name __.SYMDEF, in SVr4, it has the name "/ " 350 */ 351 /* 352 #ifdef SUN5_0 353 MBSTOWCS(wcs_buffer, NOCATGETS("/ ")); 354 if (IS_WEQUALN(arp->ar_port.ar_name, wcs_buffer, 16)) { 355 #else 356 MBSTOWCS(wcs_buffer, NOCATGETS("__.SYMDEF ")); 357 if (IS_WEQUALN(arp->ar_port.ar_name, wcs_buffer, 16)) { 358 #endif 359 */ 360 #if defined(SUN5_0) || defined(HP_UX) || defined(linux) 361 if (IS_EQUALN(arp->ar_port.ar_name, 362 NOCATGETS("/ "), 363 16)) { 364 #else 365 if (IS_EQUALN(arp->ar_port.ar_name, 366 NOCATGETS("__.SYMDEF "), 367 16)) { 368 #endif 369 if (sscanf(arp->ar_port.ar_size, 370 "%ld", 371 &arp->sym_size) != 1) { 372 return failed; 373 } 374 arp->sym_size += (arp->sym_size & 1); /* round up */ 375 if (fread(buffer, sizeof buffer, 1, arp->fd) != 1) { 376 return failed; 377 } 378 arp->num_symbols = sgetl(buffer); 379 arp->sym_begin = ftell(arp->fd); 380 arp->first_ar_mem = arp->sym_begin + 381 arp->sym_size - sizeof buffer; 382 } 383 return succeeded; 384 } 385 fatal(catgets(catd, 1, 3, "`%s' is not an archive"), filename); 386 /* NOTREACHED */ 387 return failed; 388 } 389 390 391 /* 392 * close_archive(arp) 393 * 394 * Parameters: 395 * arp Pointer to ar file description block 396 * 397 * Global variables used: 398 */ 399 static void 400 close_archive(register Ar *arp) 401 { 402 if (arp->fd != NULL) { 403 (void) fclose(arp->fd); 404 } 405 } 406 407 /* 408 * read_archive_dir(arp, library, long_names_table) 409 * 410 * Reads the directory of an archive and enters all 411 * the members into the make symboltable in lib(member) format 412 * with their dates. 413 * 414 * Parameters: 415 * arp Pointer to ar file description block 416 * library Name of lib to enter members for. 417 * Used to form "lib(member)" string. 418 * long_names_table table that contains list of members 419 * with names > 15 characters long 420 * 421 * Global variables used: 422 */ 423 static Boolean 424 #if defined(SUN5_0) || defined(linux) //XXX 425 read_archive_dir(register Ar *arp, Name library, char **long_names_table) 426 #else 427 read_archive_dir(register Ar *arp, Name library, char **) 428 #endif 429 { 430 wchar_t *name_string; 431 wchar_t *member_string; 432 register long len; 433 register wchar_t *p; 434 register char *q; 435 register Name name; 436 Property member; 437 long ptr; 438 long date; 439 440 #if defined(SUN5_0) || defined(linux) //XXX 441 int offset; 442 443 /* 444 * If any of the members has a name > 15 chars, 445 * it will be found here. 446 */ 447 if (process_long_names_member(arp, long_names_table, library->string_mb) == failed) { 448 return failed; 449 } 450 #endif 451 name_string = ALLOC_WC((int) (library->hash.length + 452 (int) ar_member_name_len * 2)); 453 (void) mbstowcs(name_string, library->string_mb, (int) library->hash.length); 454 member_string = name_string + library->hash.length; 455 *member_string++ = (int) parenleft_char; 456 457 if (fseek(arp->fd, arp->first_ar_mem, 0) != 0) { 458 goto read_error; 459 } 460 /* Read the directory using the appropriate format */ 461 switch (arp->type) { 462 case AR_5: 463 for (;;) { 464 if (fread((char *) &arp->arf_5, sizeof arp->arf_5, 1, arp->fd) 465 != 1) { 466 if (feof(arp->fd)) { 467 return succeeded; 468 } 469 break; 470 } 471 len = sizeof arp->arf_5.arf_name; 472 for (p = member_string, q = arp->arf_5.arf_name; 473 (len > 0) && (*q != (int) nul_char) && !isspace(*q); 474 ) { 475 MBTOWC(p, q); 476 p++; 477 q++; 478 } 479 *p++ = (int) parenright_char; 480 *p = (int) nul_char; 481 name = GETNAME(name_string, FIND_LENGTH); 482 /* 483 * [tolik] Fix for dmake bug 1234018. 484 * If name->stat.time is already set, then it should not 485 * be changed. (D)make propogates time stamp for one 486 * member, and when it calls exists() for another member, 487 * the first one may be changed. 488 */ 489 if(name->stat.time == file_no_time) { 490 name->stat.time.tv_sec = sgetl(arp->arf_5.arf_date); 491 name->stat.time.tv_nsec = LONG_MAX; 492 } 493 name->is_member = library->is_member; 494 member = maybe_append_prop(name, member_prop); 495 member->body.member.library = library; 496 *--p = (int) nul_char; 497 if (member->body.member.member == NULL) { 498 member->body.member.member = 499 GETNAME(member_string, FIND_LENGTH); 500 } 501 ptr = sgetl(arp->arf_5.arf_size); 502 ptr += (ptr & 1); 503 if (fseek(arp->fd, ptr, 1) != 0) { 504 goto read_error; 505 } 506 } 507 break; 508 case AR_PORT: 509 for (;;) { 510 if ((fread((char *) &arp->ar_port, 511 sizeof arp->ar_port, 512 1, 513 arp->fd) != 1) || 514 !IS_EQUALN(arp->ar_port.ar_fmag, 515 AR_PORT_END_MAGIC, 516 sizeof arp->ar_port.ar_fmag)) { 517 if (feof(arp->fd)) { 518 return succeeded; 519 } 520 fatal( 521 catgets(catd, 1, 28, "Read error in archive `%s': invalid archive file member header at 0x%x"), 522 library->string_mb, 523 ftell(arp->fd) 524 ); 525 } 526 #if defined(SUN5_0) || defined(linux) //XXX 527 /* If it's a long name, retrieve it from long name table */ 528 if (arp->ar_port.ar_name[0] == '/') { 529 /* 530 * "len" is used for hashing the string. 531 * We're using "ar_member_name_len" instead of 532 * the actual name length since it's the longest 533 * string the "ar" command can handle at this 534 * point. 535 */ 536 len = ar_member_name_len; 537 sscanf(arp->ar_port.ar_name + 1, 538 "%ld", 539 &offset); 540 q = *long_names_table + offset; 541 } else { 542 q = arp->ar_port.ar_name; 543 len = sizeof arp->ar_port.ar_name; 544 } 545 #else 546 q = arp->ar_port.ar_name; 547 len = sizeof arp->ar_port.ar_name; 548 #endif 549 550 for (p = member_string; 551 (len > 0) && 552 (*q != (int) nul_char) && 553 !isspace(*q) && 554 (*q != (int) slash_char); 555 ) { 556 MBTOWC(p, q); 557 p++; 558 q++; 559 } 560 *p++ = (int) parenright_char; 561 *p = (int) nul_char; 562 name = GETNAME(name_string, FIND_LENGTH); 563 name->is_member = library->is_member; 564 member = maybe_append_prop(name, member_prop); 565 member->body.member.library = library; 566 *--p = (int) nul_char; 567 if (member->body.member.member == NULL) { 568 member->body.member.member = 569 GETNAME(member_string, FIND_LENGTH); 570 } 571 if (sscanf(arp->ar_port.ar_date, "%ld", &date) != 1) { 572 WCSTOMBS(mbs_buffer, name_string); 573 fatal(catgets(catd, 1, 4, "Bad date field for member `%s' in archive `%s'"), 574 mbs_buffer, 575 library->string_mb); 576 } 577 /* 578 * [tolik] Fix for dmake bug 1234018. 579 */ 580 if(name->stat.time == file_no_time) { 581 name->stat.time.tv_sec = date; 582 name->stat.time.tv_nsec = LONG_MAX; 583 } 584 if (sscanf(arp->ar_port.ar_size, "%ld", &ptr) != 1) { 585 WCSTOMBS(mbs_buffer, name_string); 586 fatal(catgets(catd, 1, 5, "Bad size field for member `%s' in archive `%s'"), 587 mbs_buffer, 588 library->string_mb); 589 } 590 ptr += (ptr & 1); 591 if (fseek(arp->fd, ptr, 1) != 0) { 592 goto read_error; 593 } 594 } 595 break; 596 } 597 598 /* Only here if fread() [or IS_EQUALN()] failed and not at EOF */ 599 read_error: 600 fatal(catgets(catd, 1, 6, "Read error in archive `%s': %s"), 601 library->string_mb, 602 errmsg(errno)); 603 /* NOTREACHED */ 604 } 605 606 607 /* 608 * process_long_names_member(arp) 609 * 610 * If the archive contains members with names longer 611 * than 15 characters, then it has a special member 612 * with the name "// " that contains a table 613 * of null-terminated long names. This member 614 * is always the first member, after the symbol table 615 * if it exists. 616 * 617 * Parameters: 618 * arp Pointer to ar file description block 619 * 620 * Global variables used: 621 */ 622 int 623 process_long_names_member(register Ar *arp, char **long_names_table, char *filename) 624 { 625 Ar_port *ar_member_header; 626 int table_size; 627 628 if (fseek(arp->fd, arp->first_ar_mem, 0) != 0) { 629 return failed; 630 } 631 if ((ar_member_header = 632 (Ar_port *) alloca((int) sizeof(Ar_port))) == NULL){ 633 perror(catgets(catd, 1, 7, "memory allocation failure")); 634 return failed; 635 } 636 int ret = read_member_header(ar_member_header, arp->fd, filename); 637 if (ret == failed) { 638 return failed; 639 } else if(ret == -1) { 640 /* There is no member header - empty archive */ 641 return succeeded; 642 } 643 /* Do we have special member containing long names? */ 644 if (IS_EQUALN(ar_member_header->ar_name, 645 NOCATGETS("// "), 646 16)){ 647 if (sscanf(ar_member_header->ar_size, 648 "%ld", 649 &table_size) != 1) { 650 return failed; 651 } 652 *long_names_table = (char *) malloc(table_size); 653 /* Read the list of long member names into the table */ 654 if (fread(*long_names_table, table_size, 1, arp->fd) != 1) { 655 return failed; 656 } 657 arp->first_ar_mem = ftell(arp->fd); 658 } 659 return succeeded; 660 } 661 662 /* 663 * translate_entry(arp, target, member) 664 * 665 * Finds the member for one lib.a((entry)) 666 * 667 * Parameters: 668 * arp Pointer to ar file description block 669 * target Target to find member name for 670 * member Property to fill in with info 671 * 672 * Global variables used: 673 */ 674 static void 675 translate_entry(register Ar *arp, Name target, register Property member, char **long_names_table) 676 { 677 register int len; 678 register int i; 679 wchar_t *member_string; 680 ar_port_word *offs; 681 int strtablen; 682 char *syms; /* string table */ 683 char *csym; /* string table */ 684 ar_port_word *offend; /* end of offsets table */ 685 int date; 686 register wchar_t *ap; 687 register char *hp; 688 int maxs; 689 int offset; 690 char buffer[4]; 691 692 if (arp->sym_begin == 0L || arp->num_symbols == 0L) { 693 fatal(catgets(catd, 1, 8, "Cannot find symbol `%s' in archive `%s'"), 694 member->body.member.entry->string_mb, 695 member->body.member.library->string_mb); 696 } 697 698 if (fseek(arp->fd, arp->sym_begin, 0) != 0) { 699 goto read_error; 700 } 701 member_string = ALLOC_WC((int) ((int) ar_member_name_len * 2)); 702 703 switch (arp->type) { 704 case AR_5: 705 if ((len = member->body.member.entry->hash.length) > 8) { 706 len = 8; 707 } 708 for (i = 0; i < arp->num_symbols; i++) { 709 if (fread((char *) &arp->ars_5, 710 sizeof arp->ars_5, 711 1, 712 arp->fd) != 1) { 713 goto read_error; 714 } 715 if (IS_EQUALN(arp->ars_5.sym_name, 716 member->body.member.entry->string_mb, 717 len)) { 718 if ((fseek(arp->fd, 719 sgetl(arp->ars_5.sym_ptr), 720 0) != 0) || 721 (fread((char *) &arp->arf_5, 722 sizeof arp->arf_5, 723 1, 724 arp->fd) != 1)) { 725 goto read_error; 726 } 727 MBSTOWCS(wcs_buffer, arp->arf_5.arf_name); 728 (void) wsncpy(member_string, 729 wcs_buffer, 730 wslen(wcs_buffer)); 731 member_string[sizeof(arp->arf_5.arf_name)] = 732 (int) nul_char; 733 member->body.member.member = 734 GETNAME(member_string, FIND_LENGTH); 735 target->stat.time.tv_sec = sgetl(arp->arf_5.arf_date); 736 target->stat.time.tv_nsec = LONG_MAX; 737 return; 738 } 739 } 740 break; 741 case AR_PORT: 742 offs = (ar_port_word *) alloca((int) (arp->num_symbols * AR_PORT_WORD)); 743 if (fread((char *) offs, 744 AR_PORT_WORD, 745 (int) arp->num_symbols, 746 arp->fd) != arp->num_symbols) { 747 goto read_error; 748 } 749 750 for(i=0;i<arp->num_symbols;i++) { 751 *((int*)buffer)=offs[i]; 752 offs[i]=(ar_port_word)sgetl(buffer); 753 } 754 755 strtablen=arp->sym_size-4-(int) (arp->num_symbols * AR_PORT_WORD); 756 syms = (char *) alloca(strtablen); 757 if (fread(syms, 758 sizeof (char), 759 strtablen, 760 arp->fd) != strtablen) { 761 goto read_error; 762 } 763 offend = &offs[arp->num_symbols]; 764 while (offs < offend) { 765 maxs = strlen(member->body.member.entry->string_mb); 766 if(strlen(syms) > maxs) 767 maxs = strlen(syms); 768 if (IS_EQUALN(syms, 769 member->body.member.entry->string_mb, 770 maxs)) { 771 if (fseek(arp->fd, 772 (long) *offs, 773 0) != 0) { 774 goto read_error; 775 } 776 if ((fread((char *) &arp->ar_port, 777 sizeof arp->ar_port, 778 1, 779 arp->fd) != 1) || 780 !IS_EQUALN(arp->ar_port.ar_fmag, 781 AR_PORT_END_MAGIC, 782 sizeof arp->ar_port.ar_fmag)) { 783 goto read_error; 784 } 785 if (sscanf(arp->ar_port.ar_date, 786 "%ld", 787 &date) != 1) { 788 fatal(catgets(catd, 1, 9, "Bad date field for member `%s' in archive `%s'"), 789 arp->ar_port.ar_name, 790 target->string_mb); 791 } 792 #if defined(SUN5_0) || defined(linux) //XXX 793 /* If it's a long name, retrieve it from long name table */ 794 if (arp->ar_port.ar_name[0] == '/') { 795 sscanf(arp->ar_port.ar_name + 1, 796 "%ld", 797 &offset); 798 len = ar_member_name_len; 799 hp = *long_names_table + offset; 800 } else { 801 len = sizeof arp->ar_port.ar_name; 802 hp = arp->ar_port.ar_name; 803 } 804 #else 805 hp = arp->ar_port.ar_name; 806 #endif 807 ap = member_string; 808 while (*hp && 809 (*hp != (int) slash_char) && 810 (ap < &member_string[len])) { 811 MBTOWC(ap, hp); 812 ap++; 813 hp++; 814 } 815 *ap = (int) nul_char; 816 member->body.member.member = 817 GETNAME(member_string, FIND_LENGTH); 818 target->stat.time.tv_sec = date; 819 target->stat.time.tv_nsec = LONG_MAX; 820 return; 821 } 822 offs++; 823 while(*syms!='\0') syms++; 824 syms++; 825 } 826 } 827 fatal(catgets(catd, 1, 10, "Cannot find symbol `%s' in archive `%s'"), 828 member->body.member.entry->string_mb, 829 member->body.member.library->string_mb); 830 /*NOTREACHED*/ 831 832 read_error: 833 if (ferror(arp->fd)) { 834 fatal(catgets(catd, 1, 11, "Read error in archive `%s': %s"), 835 member->body.member.library->string_mb, 836 errmsg(errno)); 837 } else { 838 fatal(catgets(catd, 1, 12, "Read error in archive `%s': Premature EOF"), 839 member->body.member.library->string_mb); 840 } 841 } 842 843 /* 844 * sgetl(buffer) 845 * 846 * The intent here is to provide a means to make the value of 847 * bytes in an io-buffer correspond to the value of a long 848 * in the memory while doing the io a long at a time. 849 * Files written and read in this way are machine-independent. 850 * 851 * Return value: 852 * Long int read from buffer 853 * Parameters: 854 * buffer buffer we need to read long int from 855 * 856 * Global variables used: 857 */ 858 static long 859 sgetl(register char *buffer) 860 { 861 register long w = 0; 862 register int i = BITSPERBYTE * AR_PORT_WORD; 863 864 while ((i -= BITSPERBYTE) >= 0) { 865 w |= (long) ((unsigned char) *buffer++) << i; 866 } 867 return w; 868 } 869 870 871 /* 872 * read_member_header(header, fd, filename) 873 * 874 * reads the member header for the 4.1.x and SVr4 archives. 875 * 876 * Return value: 877 * fails if read error or member 878 * header is not the right format 879 * Parameters: 880 * header There's one before each archive member 881 * fd file descriptor for the archive file. 882 * 883 * Global variables used: 884 */ 885 int 886 read_member_header(Ar_port *header, FILE *fd, char* filename) 887 { 888 int num = fread((char *) header, sizeof (Ar_port), 1, fd); 889 if (num != 1 && feof(fd)) { 890 /* There is no member header - empty archive */ 891 return -1; 892 } 893 if ((num != 1) || 894 !IS_EQUALN( 895 AR_PORT_END_MAGIC, 896 header->ar_fmag, 897 sizeof (header->ar_fmag) 898 ) 899 ) { 900 fatal( 901 catgets(catd, 1, 28, "Read error in archive `%s': invalid archive file member header at 0x%x"), 902 filename, 903 ftell(fd) 904 ); 905 } 906 return succeeded; 907 } 908