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