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