summaryrefslogtreecommitdiff
path: root/usr/src/make_src/Make/bin/make/common/ar.cc
diff options
context:
space:
mode:
authorIgor Pashev <igor.pashev@nexenta.com>2012-06-29 14:36:07 +0400
committerIgor Pashev <igor.pashev@nexenta.com>2012-06-29 14:36:07 +0400
commite0463df9c3d2ee6155221cc443c571d5da47098a (patch)
tree5c6b99e64c1b65d986e2722728c74f202a578be6 /usr/src/make_src/Make/bin/make/common/ar.cc
downloadsunmake-orig.tar.gz
Initial import of DevPro make sourcesorig
Downloaded from http://dlc.sun.com/osol/devpro/downloads/current/ Licensed under CDDL http://www.opensource.org/licenses/CDDL-1.0
Diffstat (limited to 'usr/src/make_src/Make/bin/make/common/ar.cc')
-rw-r--r--usr/src/make_src/Make/bin/make/common/ar.cc908
1 files changed, 908 insertions, 0 deletions
diff --git a/usr/src/make_src/Make/bin/make/common/ar.cc b/usr/src/make_src/Make/bin/make/common/ar.cc
new file mode 100644
index 0000000..dfd0362
--- /dev/null
+++ b/usr/src/make_src/Make/bin/make/common/ar.cc
@@ -0,0 +1,908 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * @(#)ar.cc 1.28 06/12/12
+ */
+
+#pragma ident "@(#)ar.cc 1.28 06/12/12"
+
+/*
+ * ar.c
+ *
+ * Deal with the lib.a(member.o) and lib.a((entry-point)) notations
+ *
+ * Look inside archives for notations a(b) and a((b))
+ * a(b) is file member b in archive a
+ * a((b)) is entry point b in object archive a
+ *
+ * For 6.0, create a make which can understand all archive
+ * formats. This is kind of tricky, and <ar.h> isnt any help.
+ */
+
+/*
+ * Included files
+ */
+#include <avo/avo_alloca.h> /* alloca() */
+#include <ar.h>
+#include <errno.h> /* errno */
+#include <fcntl.h> /* open() */
+#include <mk/defs.h>
+#include <mksh/misc.h> /* retmem_mb() */
+
+#if defined(SUN5_0) || defined(HP_UX) || defined(linux)
+struct ranlib {
+ union {
+ off_t ran_strx; /* string table index of */
+ char *ran_name; /* symbol defined by */
+ } ran_un;
+ off_t ran_off; /* library member at this offset */
+};
+#else
+#include <ranlib.h>
+#endif
+
+#if defined(linux)
+#include <ctype.h> /* isspace */
+#else
+#include <unistd.h> /* close() */
+#endif
+
+
+/*
+ * Defined macros
+ */
+#ifndef S5EMUL
+#undef BITSPERBYTE
+#define BITSPERBYTE 8
+#endif
+
+/*
+ * Defines for all the different archive formats. See next comment
+ * block for justification for not using <ar.h>s versions.
+ */
+#define AR_5_MAGIC "<ar>" /* 5.0 format magic string */
+#define AR_5_MAGIC_LENGTH 4 /* 5.0 format string length */
+
+#define AR_PORT_MAGIC "!<arch>\n" /* Port. (6.0) magic string */
+#define AR_PORT_MAGIC_LENGTH 8 /* Port. (6.0) string length */
+#define AR_PORT_END_MAGIC "`\n" /* Port. (6.0) end of header */
+#define AR_PORT_WORD 4 /* Port. (6.0) 'word' length */
+
+/*
+ * typedefs & structs
+ */
+/*
+ * These are the archive file headers for the formats. Note
+ * that it really doesnt matter if these structures are defined
+ * here. They are correct as of the respective archive format
+ * releases. If the archive format is changed, then since backwards
+ * compatability is the desired behavior, a new structure is added
+ * to the list.
+ */
+typedef struct { /* 5.0 ar header format: vax family; 3b family */
+ char ar_magic[AR_5_MAGIC_LENGTH]; /* AR_5_MAGIC*/
+ char ar_name[16]; /* Space terminated */
+ char ar_date[AR_PORT_WORD]; /* sgetl() accessed */
+ char ar_syms[AR_PORT_WORD]; /* sgetl() accessed */
+} Arh_5;
+
+typedef struct { /* 5.0 ar symbol format: vax family; 3b family */
+ char sym_name[8]; /* Space terminated */
+ char sym_ptr[AR_PORT_WORD]; /* sgetl() accessed */
+} Ars_5;
+
+typedef struct { /* 5.0 ar member format: vax family; 3b family */
+ char arf_name[16]; /* Space terminated */
+ char arf_date[AR_PORT_WORD]; /* sgetl() accessed */
+ char arf_uid[AR_PORT_WORD]; /* sgetl() accessed */
+ char arf_gid[AR_PORT_WORD]; /* sgetl() accessed */
+ char arf_mode[AR_PORT_WORD]; /* sgetl() accessed */
+ char arf_size[AR_PORT_WORD]; /* sgetl() accessed */
+} Arf_5;
+
+typedef struct { /* Portable (6.0) ar format: vax family; 3b family */
+ char ar_name[16]; /* Space terminated */
+ /* left-adjusted fields; decimal ascii; blank filled */
+ char ar_date[12];
+ char ar_uid[6];
+ char ar_gid[6];
+ char ar_mode[8]; /* octal ascii */
+ char ar_size[10];
+ /* special end-of-header string (AR_PORT_END_MAGIC) */
+ char ar_fmag[2];
+} Ar_port;
+
+enum ar_type {
+ AR_5,
+ AR_PORT
+};
+
+typedef unsigned int ar_port_word; // must be 4-bytes long
+
+typedef struct {
+ FILE *fd;
+ /* to distiguish ar format */
+ enum ar_type type;
+ /* where first ar member header is at */
+ long first_ar_mem;
+ /* where the symbol lookup starts */
+ long sym_begin;
+ /* the number of symbols available */
+ long num_symbols;
+ /* length of symbol directory file */
+ long sym_size;
+ Arh_5 arh_5;
+ Ars_5 ars_5;
+ Arf_5 arf_5;
+ Ar_port ar_port;
+} Ar;
+
+/*
+ * Static variables
+ */
+
+/*
+ * File table of contents
+ */
+extern timestruc_t& read_archive(register Name target);
+static Boolean open_archive(char *filename, register Ar *arp);
+static void close_archive(register Ar *arp);
+static Boolean read_archive_dir(register Ar *arp, Name library, char **long_names_table);
+static void translate_entry(register Ar *arp, Name target, register Property member, char **long_names_table);
+static long sgetl(char *);
+
+/*
+ * read_archive(target)
+ *
+ * Read the contents of an ar file.
+ *
+ * Return value:
+ * The time the member was created
+ *
+ * Parameters:
+ * target The member to find time for
+ *
+ * Global variables used:
+ * empty_name The Name ""
+ */
+
+int read_member_header (Ar_port *header, FILE *fd, char* filename);
+int process_long_names_member (register Ar *arp, char **long_names_table, char *filename);
+
+timestruc_t&
+read_archive(register Name target)
+{
+ register Property member;
+ wchar_t *slash;
+ String_rec true_member_name;
+ wchar_t buffer[STRING_BUFFER_LENGTH];
+ register Name true_member = NULL;
+ Ar ar;
+ char *long_names_table = NULL; /* Table of long
+ member names */
+
+ member = get_prop(target->prop, member_prop);
+ /*
+ * Check if the member has directory component.
+ * If so, remove the dir and see if we know the date.
+ */
+ if (member->body.member.member != NULL) {
+ Wstring member_string(member->body.member.member);
+ wchar_t * wcb = member_string.get_string();
+ if((slash = (wchar_t *) wsrchr(wcb, (int) slash_char)) != NULL) {
+ INIT_STRING_FROM_STACK(true_member_name, buffer);
+ append_string(member->body.member.library->string_mb,
+ &true_member_name,
+ FIND_LENGTH);
+ append_char((int) parenleft_char, &true_member_name);
+ append_string(slash + 1, &true_member_name, FIND_LENGTH);
+ append_char((int) parenright_char, &true_member_name);
+ true_member = GETNAME(true_member_name.buffer.start,
+ FIND_LENGTH);
+ if (true_member->stat.time != file_no_time) {
+ target->stat.time = true_member->stat.time;
+ return target->stat.time;
+ }
+ }
+ }
+ if (open_archive(member->body.member.library->string_mb, &ar) == failed) {
+ if (errno == ENOENT) {
+ target->stat.stat_errno = ENOENT;
+ close_archive(&ar);
+ if (member->body.member.member == NULL) {
+ member->body.member.member = empty_name;
+ }
+ return target->stat.time = file_doesnt_exist;
+ } else {
+ fatal(catgets(catd, 1, 1, "Can't access archive `%s': %s"),
+ member->body.member.library->string_mb,
+ errmsg(errno));
+ }
+ }
+ if (target->stat.time == file_no_time) {
+ if (read_archive_dir(&ar, member->body.member.library,
+ &long_names_table)
+ == failed){
+ fatal(catgets(catd, 1, 2, "Can't access archive `%s': %s"),
+ member->body.member.library->string_mb,
+ errmsg(errno));
+ }
+ }
+ if (member->body.member.entry != NULL) {
+ translate_entry(&ar, target, member,&long_names_table);
+ }
+ close_archive(&ar);
+ if (long_names_table) {
+ retmem_mb(long_names_table);
+ }
+ if (true_member != NULL) {
+ target->stat.time = true_member->stat.time;
+ }
+ if (target->stat.time == file_no_time) {
+ target->stat.time = file_doesnt_exist;
+ }
+ return target->stat.time;
+}
+
+/*
+ * open_archive(filename, arp)
+ *
+ * Return value:
+ * Indicates if open failed or not
+ *
+ * Parameters:
+ * filename The name of the archive we need to read
+ * arp Pointer to ar file description block
+ *
+ * Global variables used:
+ */
+static Boolean
+open_archive(char *filename, register Ar *arp)
+{
+ int fd;
+ char mag_5[AR_5_MAGIC_LENGTH];
+ char mag_port[AR_PORT_MAGIC_LENGTH];
+ char buffer[4];
+
+ arp->fd = NULL;
+ fd = open_vroot(filename, O_RDONLY, 0, NULL, VROOT_DEFAULT);
+ if ((fd < 0) || ((arp->fd = fdopen(fd, "r")) == NULL)) {
+ return failed;
+ }
+ (void) fcntl(fileno(arp->fd), F_SETFD, 1);
+
+#if !defined(SUN5_0) && !defined(linux) //XXX
+ /* Read enough of the archive to distinguish between the formats */
+ if (fread(mag_5, AR_5_MAGIC_LENGTH, 1, arp->fd) != 1) {
+ return failed;
+ }
+ if (IS_EQUALN(mag_5, AR_5_MAGIC, AR_5_MAGIC_LENGTH)) {
+ arp->type = AR_5;
+ /* Must read in header to set necessary info */
+ if (fseek(arp->fd, 0L, 0) != 0 ||
+ fread((char *) &arp->arh_5, sizeof (Arh_5), 1, arp->fd) !=
+ 1) {
+ return failed;
+ }
+ arp->sym_begin = ftell(arp->fd);
+ arp->num_symbols = sgetl(arp->arh_5.ar_syms);
+ arp->first_ar_mem = arp->sym_begin +
+ sizeof (Ars_5) * arp->num_symbols;
+ arp->sym_size = 0L;
+ return succeeded;
+ }
+ if (fseek(arp->fd, 0L, 0) != 0) {
+ return failed;
+ }
+#endif
+ if (fread(mag_port, AR_PORT_MAGIC_LENGTH, 1, arp->fd) != 1) {
+ return failed;
+ }
+ if (IS_EQUALN(mag_port, AR_PORT_MAGIC, AR_PORT_MAGIC_LENGTH)) {
+ arp->type = AR_PORT;
+ /*
+ * Read in first member header to find out if there is
+ * a symbol definition table.
+ */
+
+ int ret = read_member_header(&arp->ar_port, arp->fd, filename);
+ if (ret == failed) {
+ return failed;
+ } else if(ret == -1) {
+ /* There is no member header - empty archive */
+ arp->sym_size = arp->num_symbols = arp->sym_begin = 0L;
+ arp->first_ar_mem = ftell(arp->fd);
+ return succeeded;
+ }
+ /*
+ * The following values are the default if there is
+ * no symbol directory and long member names.
+ */
+ arp->sym_size = arp->num_symbols = arp->sym_begin = 0L;
+ arp->first_ar_mem = ftell(arp->fd) - (long) sizeof (Ar_port);
+
+ /*
+ * Do we have a symbol table? A symbol table is always
+ * the first member in an archive. In 4.1.x it has the
+ * name __.SYMDEF, in SVr4, it has the name "/ "
+ */
+/*
+#ifdef SUN5_0
+ MBSTOWCS(wcs_buffer, NOCATGETS("/ "));
+ if (IS_WEQUALN(arp->ar_port.ar_name, wcs_buffer, 16)) {
+#else
+ MBSTOWCS(wcs_buffer, NOCATGETS("__.SYMDEF "));
+ if (IS_WEQUALN(arp->ar_port.ar_name, wcs_buffer, 16)) {
+#endif
+ */
+#if defined(SUN5_0) || defined(HP_UX) || defined(linux)
+ if (IS_EQUALN(arp->ar_port.ar_name,
+ NOCATGETS("/ "),
+ 16)) {
+#else
+ if (IS_EQUALN(arp->ar_port.ar_name,
+ NOCATGETS("__.SYMDEF "),
+ 16)) {
+#endif
+ if (sscanf(arp->ar_port.ar_size,
+ "%ld",
+ &arp->sym_size) != 1) {
+ return failed;
+ }
+ arp->sym_size += (arp->sym_size & 1); /* round up */
+ if (fread(buffer, sizeof buffer, 1, arp->fd) != 1) {
+ return failed;
+ }
+ arp->num_symbols = sgetl(buffer);
+ arp->sym_begin = ftell(arp->fd);
+ arp->first_ar_mem = arp->sym_begin +
+ arp->sym_size - sizeof buffer;
+ }
+ return succeeded;
+ }
+ fatal(catgets(catd, 1, 3, "`%s' is not an archive"), filename);
+ /* NOTREACHED */
+ return failed;
+}
+
+
+/*
+ * close_archive(arp)
+ *
+ * Parameters:
+ * arp Pointer to ar file description block
+ *
+ * Global variables used:
+ */
+static void
+close_archive(register Ar *arp)
+{
+ if (arp->fd != NULL) {
+ (void) fclose(arp->fd);
+ }
+}
+
+/*
+ * read_archive_dir(arp, library, long_names_table)
+ *
+ * Reads the directory of an archive and enters all
+ * the members into the make symboltable in lib(member) format
+ * with their dates.
+ *
+ * Parameters:
+ * arp Pointer to ar file description block
+ * library Name of lib to enter members for.
+ * Used to form "lib(member)" string.
+ * long_names_table table that contains list of members
+ * with names > 15 characters long
+ *
+ * Global variables used:
+ */
+static Boolean
+#if defined(SUN5_0) || defined(linux) //XXX
+read_archive_dir(register Ar *arp, Name library, char **long_names_table)
+#else
+read_archive_dir(register Ar *arp, Name library, char **)
+#endif
+{
+ wchar_t *name_string;
+ wchar_t *member_string;
+ register long len;
+ register wchar_t *p;
+ register char *q;
+ register Name name;
+ Property member;
+ long ptr;
+ long date;
+
+#if defined(SUN5_0) || defined(linux) //XXX
+ int offset;
+
+ /*
+ * If any of the members has a name > 15 chars,
+ * it will be found here.
+ */
+ if (process_long_names_member(arp, long_names_table, library->string_mb) == failed) {
+ return failed;
+ }
+#endif
+ name_string = ALLOC_WC((int) (library->hash.length +
+ (int) ar_member_name_len * 2));
+ (void) mbstowcs(name_string, library->string_mb, (int) library->hash.length);
+ member_string = name_string + library->hash.length;
+ *member_string++ = (int) parenleft_char;
+
+ if (fseek(arp->fd, arp->first_ar_mem, 0) != 0) {
+ goto read_error;
+ }
+ /* Read the directory using the appropriate format */
+ switch (arp->type) {
+ case AR_5:
+ for (;;) {
+ if (fread((char *) &arp->arf_5, sizeof arp->arf_5, 1, arp->fd)
+ != 1) {
+ if (feof(arp->fd)) {
+ return succeeded;
+ }
+ break;
+ }
+ len = sizeof arp->arf_5.arf_name;
+ for (p = member_string, q = arp->arf_5.arf_name;
+ (len > 0) && (*q != (int) nul_char) && !isspace(*q);
+ ) {
+ MBTOWC(p, q);
+ p++;
+ q++;
+ }
+ *p++ = (int) parenright_char;
+ *p = (int) nul_char;
+ name = GETNAME(name_string, FIND_LENGTH);
+ /*
+ * [tolik] Fix for dmake bug 1234018.
+ * If name->stat.time is already set, then it should not
+ * be changed. (D)make propogates time stamp for one
+ * member, and when it calls exists() for another member,
+ * the first one may be changed.
+ */
+ if(name->stat.time == file_no_time) {
+ name->stat.time.tv_sec = sgetl(arp->arf_5.arf_date);
+ name->stat.time.tv_nsec = LONG_MAX;
+ }
+ name->is_member = library->is_member;
+ member = maybe_append_prop(name, member_prop);
+ member->body.member.library = library;
+ *--p = (int) nul_char;
+ if (member->body.member.member == NULL) {
+ member->body.member.member =
+ GETNAME(member_string, FIND_LENGTH);
+ }
+ ptr = sgetl(arp->arf_5.arf_size);
+ ptr += (ptr & 1);
+ if (fseek(arp->fd, ptr, 1) != 0) {
+ goto read_error;
+ }
+ }
+ break;
+ case AR_PORT:
+ for (;;) {
+ if ((fread((char *) &arp->ar_port,
+ sizeof arp->ar_port,
+ 1,
+ arp->fd) != 1) ||
+ !IS_EQUALN(arp->ar_port.ar_fmag,
+ AR_PORT_END_MAGIC,
+ sizeof arp->ar_port.ar_fmag)) {
+ if (feof(arp->fd)) {
+ return succeeded;
+ }
+ fatal(
+ catgets(catd, 1, 28, "Read error in archive `%s': invalid archive file member header at 0x%x"),
+ library->string_mb,
+ ftell(arp->fd)
+ );
+ }
+#if defined(SUN5_0) || defined(linux) //XXX
+ /* If it's a long name, retrieve it from long name table */
+ if (arp->ar_port.ar_name[0] == '/') {
+ /*
+ * "len" is used for hashing the string.
+ * We're using "ar_member_name_len" instead of
+ * the actual name length since it's the longest
+ * string the "ar" command can handle at this
+ * point.
+ */
+ len = ar_member_name_len;
+ sscanf(arp->ar_port.ar_name + 1,
+ "%ld",
+ &offset);
+ q = *long_names_table + offset;
+ } else {
+ q = arp->ar_port.ar_name;
+ len = sizeof arp->ar_port.ar_name;
+ }
+#else
+ q = arp->ar_port.ar_name;
+ len = sizeof arp->ar_port.ar_name;
+#endif
+
+ for (p = member_string;
+ (len > 0) &&
+ (*q != (int) nul_char) &&
+ !isspace(*q) &&
+ (*q != (int) slash_char);
+ ) {
+ MBTOWC(p, q);
+ p++;
+ q++;
+ }
+ *p++ = (int) parenright_char;
+ *p = (int) nul_char;
+ name = GETNAME(name_string, FIND_LENGTH);
+ name->is_member = library->is_member;
+ member = maybe_append_prop(name, member_prop);
+ member->body.member.library = library;
+ *--p = (int) nul_char;
+ if (member->body.member.member == NULL) {
+ member->body.member.member =
+ GETNAME(member_string, FIND_LENGTH);
+ }
+ if (sscanf(arp->ar_port.ar_date, "%ld", &date) != 1) {
+ WCSTOMBS(mbs_buffer, name_string);
+ fatal(catgets(catd, 1, 4, "Bad date field for member `%s' in archive `%s'"),
+ mbs_buffer,
+ library->string_mb);
+ }
+ /*
+ * [tolik] Fix for dmake bug 1234018.
+ */
+ if(name->stat.time == file_no_time) {
+ name->stat.time.tv_sec = date;
+ name->stat.time.tv_nsec = LONG_MAX;
+ }
+ if (sscanf(arp->ar_port.ar_size, "%ld", &ptr) != 1) {
+ WCSTOMBS(mbs_buffer, name_string);
+ fatal(catgets(catd, 1, 5, "Bad size field for member `%s' in archive `%s'"),
+ mbs_buffer,
+ library->string_mb);
+ }
+ ptr += (ptr & 1);
+ if (fseek(arp->fd, ptr, 1) != 0) {
+ goto read_error;
+ }
+ }
+ break;
+ }
+
+ /* Only here if fread() [or IS_EQUALN()] failed and not at EOF */
+read_error:
+ fatal(catgets(catd, 1, 6, "Read error in archive `%s': %s"),
+ library->string_mb,
+ errmsg(errno));
+ /* NOTREACHED */
+}
+
+
+/*
+ * process_long_names_member(arp)
+ *
+ * If the archive contains members with names longer
+ * than 15 characters, then it has a special member
+ * with the name "// " that contains a table
+ * of null-terminated long names. This member
+ * is always the first member, after the symbol table
+ * if it exists.
+ *
+ * Parameters:
+ * arp Pointer to ar file description block
+ *
+ * Global variables used:
+ */
+int
+process_long_names_member(register Ar *arp, char **long_names_table, char *filename)
+{
+ Ar_port *ar_member_header;
+ int table_size;
+
+ if (fseek(arp->fd, arp->first_ar_mem, 0) != 0) {
+ return failed;
+ }
+ if ((ar_member_header =
+ (Ar_port *) alloca((int) sizeof(Ar_port))) == NULL){
+ perror(catgets(catd, 1, 7, "memory allocation failure"));
+ return failed;
+ }
+ int ret = read_member_header(ar_member_header, arp->fd, filename);
+ if (ret == failed) {
+ return failed;
+ } else if(ret == -1) {
+ /* There is no member header - empty archive */
+ return succeeded;
+ }
+ /* Do we have special member containing long names? */
+ if (IS_EQUALN(ar_member_header->ar_name,
+ NOCATGETS("// "),
+ 16)){
+ if (sscanf(ar_member_header->ar_size,
+ "%ld",
+ &table_size) != 1) {
+ return failed;
+ }
+ *long_names_table = (char *) malloc(table_size);
+ /* Read the list of long member names into the table */
+ if (fread(*long_names_table, table_size, 1, arp->fd) != 1) {
+ return failed;
+ }
+ arp->first_ar_mem = ftell(arp->fd);
+ }
+ return succeeded;
+}
+
+/*
+ * translate_entry(arp, target, member)
+ *
+ * Finds the member for one lib.a((entry))
+ *
+ * Parameters:
+ * arp Pointer to ar file description block
+ * target Target to find member name for
+ * member Property to fill in with info
+ *
+ * Global variables used:
+ */
+static void
+translate_entry(register Ar *arp, Name target, register Property member, char **long_names_table)
+{
+ register int len;
+ register int i;
+ wchar_t *member_string;
+ ar_port_word *offs;
+ int strtablen;
+ char *syms; /* string table */
+ char *csym; /* string table */
+ ar_port_word *offend; /* end of offsets table */
+ int date;
+ register wchar_t *ap;
+ register char *hp;
+ int maxs;
+ int offset;
+ char buffer[4];
+
+ if (arp->sym_begin == 0L || arp->num_symbols == 0L) {
+ fatal(catgets(catd, 1, 8, "Cannot find symbol `%s' in archive `%s'"),
+ member->body.member.entry->string_mb,
+ member->body.member.library->string_mb);
+ }
+
+ if (fseek(arp->fd, arp->sym_begin, 0) != 0) {
+ goto read_error;
+ }
+ member_string = ALLOC_WC((int) ((int) ar_member_name_len * 2));
+
+ switch (arp->type) {
+ case AR_5:
+ if ((len = member->body.member.entry->hash.length) > 8) {
+ len = 8;
+ }
+ for (i = 0; i < arp->num_symbols; i++) {
+ if (fread((char *) &arp->ars_5,
+ sizeof arp->ars_5,
+ 1,
+ arp->fd) != 1) {
+ goto read_error;
+ }
+ if (IS_EQUALN(arp->ars_5.sym_name,
+ member->body.member.entry->string_mb,
+ len)) {
+ if ((fseek(arp->fd,
+ sgetl(arp->ars_5.sym_ptr),
+ 0) != 0) ||
+ (fread((char *) &arp->arf_5,
+ sizeof arp->arf_5,
+ 1,
+ arp->fd) != 1)) {
+ goto read_error;
+ }
+ MBSTOWCS(wcs_buffer, arp->arf_5.arf_name);
+ (void) wsncpy(member_string,
+ wcs_buffer,
+ wslen(wcs_buffer));
+ member_string[sizeof(arp->arf_5.arf_name)] =
+ (int) nul_char;
+ member->body.member.member =
+ GETNAME(member_string, FIND_LENGTH);
+ target->stat.time.tv_sec = sgetl(arp->arf_5.arf_date);
+ target->stat.time.tv_nsec = LONG_MAX;
+ return;
+ }
+ }
+ break;
+ case AR_PORT:
+ offs = (ar_port_word *) alloca((int) (arp->num_symbols * AR_PORT_WORD));
+ if (fread((char *) offs,
+ AR_PORT_WORD,
+ (int) arp->num_symbols,
+ arp->fd) != arp->num_symbols) {
+ goto read_error;
+ }
+
+ for(i=0;i<arp->num_symbols;i++) {
+ *((int*)buffer)=offs[i];
+ offs[i]=(ar_port_word)sgetl(buffer);
+ }
+
+ strtablen=arp->sym_size-4-(int) (arp->num_symbols * AR_PORT_WORD);
+ syms = (char *) alloca(strtablen);
+ if (fread(syms,
+ sizeof (char),
+ strtablen,
+ arp->fd) != strtablen) {
+ goto read_error;
+ }
+ offend = &offs[arp->num_symbols];
+ while (offs < offend) {
+ maxs = strlen(member->body.member.entry->string_mb);
+ if(strlen(syms) > maxs)
+ maxs = strlen(syms);
+ if (IS_EQUALN(syms,
+ member->body.member.entry->string_mb,
+ maxs)) {
+ if (fseek(arp->fd,
+ (long) *offs,
+ 0) != 0) {
+ goto read_error;
+ }
+ if ((fread((char *) &arp->ar_port,
+ sizeof arp->ar_port,
+ 1,
+ arp->fd) != 1) ||
+ !IS_EQUALN(arp->ar_port.ar_fmag,
+ AR_PORT_END_MAGIC,
+ sizeof arp->ar_port.ar_fmag)) {
+ goto read_error;
+ }
+ if (sscanf(arp->ar_port.ar_date,
+ "%ld",
+ &date) != 1) {
+ fatal(catgets(catd, 1, 9, "Bad date field for member `%s' in archive `%s'"),
+ arp->ar_port.ar_name,
+ target->string_mb);
+ }
+#if defined(SUN5_0) || defined(linux) //XXX
+ /* If it's a long name, retrieve it from long name table */
+ if (arp->ar_port.ar_name[0] == '/') {
+ sscanf(arp->ar_port.ar_name + 1,
+ "%ld",
+ &offset);
+ len = ar_member_name_len;
+ hp = *long_names_table + offset;
+ } else {
+ len = sizeof arp->ar_port.ar_name;
+ hp = arp->ar_port.ar_name;
+ }
+#else
+ hp = arp->ar_port.ar_name;
+#endif
+ ap = member_string;
+ while (*hp &&
+ (*hp != (int) slash_char) &&
+ (ap < &member_string[len])) {
+ MBTOWC(ap, hp);
+ ap++;
+ hp++;
+ }
+ *ap = (int) nul_char;
+ member->body.member.member =
+ GETNAME(member_string, FIND_LENGTH);
+ target->stat.time.tv_sec = date;
+ target->stat.time.tv_nsec = LONG_MAX;
+ return;
+ }
+ offs++;
+ while(*syms!='\0') syms++;
+ syms++;
+ }
+ }
+ fatal(catgets(catd, 1, 10, "Cannot find symbol `%s' in archive `%s'"),
+ member->body.member.entry->string_mb,
+ member->body.member.library->string_mb);
+ /*NOTREACHED*/
+
+read_error:
+ if (ferror(arp->fd)) {
+ fatal(catgets(catd, 1, 11, "Read error in archive `%s': %s"),
+ member->body.member.library->string_mb,
+ errmsg(errno));
+ } else {
+ fatal(catgets(catd, 1, 12, "Read error in archive `%s': Premature EOF"),
+ member->body.member.library->string_mb);
+ }
+}
+
+/*
+ * sgetl(buffer)
+ *
+ * The intent here is to provide a means to make the value of
+ * bytes in an io-buffer correspond to the value of a long
+ * in the memory while doing the io a long at a time.
+ * Files written and read in this way are machine-independent.
+ *
+ * Return value:
+ * Long int read from buffer
+ * Parameters:
+ * buffer buffer we need to read long int from
+ *
+ * Global variables used:
+ */
+static long
+sgetl(register char *buffer)
+{
+ register long w = 0;
+ register int i = BITSPERBYTE * AR_PORT_WORD;
+
+ while ((i -= BITSPERBYTE) >= 0) {
+ w |= (long) ((unsigned char) *buffer++) << i;
+ }
+ return w;
+}
+
+
+/*
+ * read_member_header(header, fd, filename)
+ *
+ * reads the member header for the 4.1.x and SVr4 archives.
+ *
+ * Return value:
+ * fails if read error or member
+ * header is not the right format
+ * Parameters:
+ * header There's one before each archive member
+ * fd file descriptor for the archive file.
+ *
+ * Global variables used:
+ */
+int
+read_member_header(Ar_port *header, FILE *fd, char* filename)
+{
+ int num = fread((char *) header, sizeof (Ar_port), 1, fd);
+ if (num != 1 && feof(fd)) {
+ /* There is no member header - empty archive */
+ return -1;
+ }
+ if ((num != 1) ||
+ !IS_EQUALN(
+ AR_PORT_END_MAGIC,
+ header->ar_fmag,
+ sizeof (header->ar_fmag)
+ )
+ ) {
+ fatal(
+ catgets(catd, 1, 28, "Read error in archive `%s': invalid archive file member header at 0x%x"),
+ filename,
+ ftell(fd)
+ );
+ }
+ return succeeded;
+}
+