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