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