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