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