xref: /illumos-gate/usr/src/cmd/make/bin/ar.cc (revision e7afc443cb8c2e0a379fe48b15a0c7fb61a4b2fc)
110d63b7dSRichard Lowe /*
210d63b7dSRichard Lowe  * CDDL HEADER START
310d63b7dSRichard Lowe  *
410d63b7dSRichard Lowe  * The contents of this file are subject to the terms of the
510d63b7dSRichard Lowe  * Common Development and Distribution License (the "License").
610d63b7dSRichard Lowe  * You may not use this file except in compliance with the License.
710d63b7dSRichard Lowe  *
810d63b7dSRichard Lowe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910d63b7dSRichard Lowe  * or http://www.opensolaris.org/os/licensing.
1010d63b7dSRichard Lowe  * See the License for the specific language governing permissions
1110d63b7dSRichard Lowe  * and limitations under the License.
1210d63b7dSRichard Lowe  *
1310d63b7dSRichard Lowe  * When distributing Covered Code, include this CDDL HEADER in each
1410d63b7dSRichard Lowe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510d63b7dSRichard Lowe  * If applicable, add the following below this CDDL HEADER, with the
1610d63b7dSRichard Lowe  * fields enclosed by brackets "[]" replaced with your own identifying
1710d63b7dSRichard Lowe  * information: Portions Copyright [yyyy] [name of copyright owner]
1810d63b7dSRichard Lowe  *
1910d63b7dSRichard Lowe  * CDDL HEADER END
2010d63b7dSRichard Lowe  */
2110d63b7dSRichard Lowe /*
2210d63b7dSRichard Lowe  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
2310d63b7dSRichard Lowe  * Use is subject to license terms.
2410d63b7dSRichard Lowe  */
2510d63b7dSRichard Lowe 
2610d63b7dSRichard Lowe /*
2710d63b7dSRichard Lowe  *	ar.c
2810d63b7dSRichard Lowe  *
2910d63b7dSRichard Lowe  *	Deal with the lib.a(member.o) and lib.a((entry-point)) notations
3010d63b7dSRichard Lowe  *
3110d63b7dSRichard Lowe  * Look inside archives for notations a(b) and a((b))
3210d63b7dSRichard Lowe  *	a(b)	is file member   b  in archive a
3310d63b7dSRichard Lowe  *	a((b))	is entry point   b  in object archive a
3410d63b7dSRichard Lowe  *
3510d63b7dSRichard Lowe  * For 6.0, create a make which can understand all archive
3610d63b7dSRichard Lowe  * formats.  This is kind of tricky, and <ar.h> isnt any help.
3710d63b7dSRichard Lowe  */
3810d63b7dSRichard Lowe 
3910d63b7dSRichard Lowe /*
4010d63b7dSRichard Lowe  * Included files
4110d63b7dSRichard Lowe  */
4210d63b7dSRichard Lowe #include <alloca.h>		/* alloca() */
4310d63b7dSRichard Lowe #include <ar.h>
4410d63b7dSRichard Lowe #include <errno.h>		/* errno */
4510d63b7dSRichard Lowe #include <fcntl.h>		/* open() */
4610d63b7dSRichard Lowe #include <libintl.h>
4710d63b7dSRichard Lowe #include <mk/defs.h>
4810d63b7dSRichard Lowe #include <mksh/misc.h>		/* retmem_mb() */
4910d63b7dSRichard Lowe 
5010d63b7dSRichard Lowe struct ranlib {
5110d63b7dSRichard Lowe 	union {
5210d63b7dSRichard Lowe 		off_t	ran_strx;	/* string table index of */
5310d63b7dSRichard Lowe 		char	*ran_name;	/* symbol defined by */
5410d63b7dSRichard Lowe 	}	ran_un;
5510d63b7dSRichard Lowe 	off_t	ran_off;		/* library member at this offset */
5610d63b7dSRichard Lowe };
5710d63b7dSRichard Lowe 
5810d63b7dSRichard Lowe #include <unistd.h>		/* close() */
5910d63b7dSRichard Lowe 
6010d63b7dSRichard Lowe 
6110d63b7dSRichard Lowe /*
6210d63b7dSRichard Lowe  * Defined macros
6310d63b7dSRichard Lowe  */
6410d63b7dSRichard Lowe #ifndef S5EMUL
6510d63b7dSRichard Lowe #undef BITSPERBYTE
6610d63b7dSRichard Lowe #define BITSPERBYTE	8
6710d63b7dSRichard Lowe #endif
6810d63b7dSRichard Lowe 
6910d63b7dSRichard Lowe /*
7010d63b7dSRichard Lowe  * Defines for all the different archive formats.  See next comment
7110d63b7dSRichard Lowe  * block for justification for not using <ar.h>s versions.
7210d63b7dSRichard Lowe  */
7310d63b7dSRichard Lowe #define AR_5_MAGIC		"<ar>"		/* 5.0 format magic string */
7410d63b7dSRichard Lowe #define AR_5_MAGIC_LENGTH	4		/* 5.0 format string length */
7510d63b7dSRichard Lowe 
7610d63b7dSRichard Lowe #define AR_PORT_MAGIC		"!<arch>\n"	/* Port. (6.0) magic string */
7710d63b7dSRichard Lowe #define AR_PORT_MAGIC_LENGTH	8		/* Port. (6.0) string length */
7810d63b7dSRichard Lowe #define AR_PORT_END_MAGIC	"`\n"		/* Port. (6.0) end of header */
7910d63b7dSRichard Lowe #define AR_PORT_WORD		4		/* Port. (6.0) 'word' length */
8010d63b7dSRichard Lowe 
8110d63b7dSRichard Lowe /*
8210d63b7dSRichard Lowe  * typedefs & structs
8310d63b7dSRichard Lowe  */
8410d63b7dSRichard Lowe /*
8510d63b7dSRichard Lowe  * These are the archive file headers for the formats.  Note
8610d63b7dSRichard Lowe  * that it really doesnt matter if these structures are defined
8710d63b7dSRichard Lowe  * here.  They are correct as of the respective archive format
8810d63b7dSRichard Lowe  * releases.  If the archive format is changed, then since backwards
8910d63b7dSRichard Lowe  * compatability is the desired behavior, a new structure is added
9010d63b7dSRichard Lowe  * to the list.
9110d63b7dSRichard Lowe  */
9210d63b7dSRichard Lowe typedef struct {	/* 5.0 ar header format: vax family; 3b family */
9310d63b7dSRichard Lowe 	char			ar_magic[AR_5_MAGIC_LENGTH];	/* AR_5_MAGIC*/
9410d63b7dSRichard Lowe 	char			ar_name[16];	/* Space terminated */
9510d63b7dSRichard Lowe 	char			ar_date[AR_PORT_WORD];	/* sgetl() accessed */
9610d63b7dSRichard Lowe 	char			ar_syms[AR_PORT_WORD];	/* sgetl() accessed */
9710d63b7dSRichard Lowe }			Arh_5;
9810d63b7dSRichard Lowe 
9910d63b7dSRichard Lowe typedef struct {	/* 5.0 ar symbol format: vax family; 3b family */
10010d63b7dSRichard Lowe 	char			sym_name[8];	/* Space terminated */
10110d63b7dSRichard Lowe 	char			sym_ptr[AR_PORT_WORD];	/* sgetl() accessed */
10210d63b7dSRichard Lowe }			Ars_5;
10310d63b7dSRichard Lowe 
10410d63b7dSRichard Lowe typedef struct {	/* 5.0 ar member format: vax family; 3b family */
10510d63b7dSRichard Lowe 	char			arf_name[16];	/* Space terminated */
10610d63b7dSRichard Lowe 	char			arf_date[AR_PORT_WORD];	/* sgetl() accessed */
10710d63b7dSRichard Lowe 	char			arf_uid[AR_PORT_WORD];	/* sgetl() accessed */
10810d63b7dSRichard Lowe 	char			arf_gid[AR_PORT_WORD];	/* sgetl() accessed */
10910d63b7dSRichard Lowe 	char			arf_mode[AR_PORT_WORD];	/* sgetl() accessed */
11010d63b7dSRichard Lowe 	char			arf_size[AR_PORT_WORD];	/* sgetl() accessed */
11110d63b7dSRichard Lowe }			Arf_5;
11210d63b7dSRichard Lowe 
11310d63b7dSRichard Lowe typedef struct {	/* Portable (6.0) ar format: vax family; 3b family */
11410d63b7dSRichard Lowe 	char			ar_name[16];	/* Space terminated */
11510d63b7dSRichard Lowe 	/* left-adjusted fields; decimal ascii; blank filled */
11610d63b7dSRichard Lowe 	char			ar_date[12];
11710d63b7dSRichard Lowe 	char			ar_uid[6];
11810d63b7dSRichard Lowe 	char			ar_gid[6];
11910d63b7dSRichard Lowe 	char			ar_mode[8];	/* octal ascii */
12010d63b7dSRichard Lowe 	char			ar_size[10];
12110d63b7dSRichard Lowe 	/* special end-of-header string (AR_PORT_END_MAGIC) */
12210d63b7dSRichard Lowe 	char			ar_fmag[2];
12310d63b7dSRichard Lowe }			Ar_port;
12410d63b7dSRichard Lowe 
12510d63b7dSRichard Lowe enum ar_type {
12610d63b7dSRichard Lowe 		AR_5,
12710d63b7dSRichard Lowe 		AR_PORT
12810d63b7dSRichard Lowe };
12910d63b7dSRichard Lowe 
13010d63b7dSRichard Lowe typedef unsigned int ar_port_word; // must be 4-bytes long
13110d63b7dSRichard Lowe 
13210d63b7dSRichard Lowe typedef struct {
13310d63b7dSRichard Lowe 	FILE			*fd;
13410d63b7dSRichard Lowe 	/* to distiguish ar format */
13510d63b7dSRichard Lowe 	enum ar_type		type;
13610d63b7dSRichard Lowe 	/* where first ar member header is at */
13710d63b7dSRichard Lowe 	long			first_ar_mem;
13810d63b7dSRichard Lowe 	/* where the symbol lookup starts */
13910d63b7dSRichard Lowe 	long			sym_begin;
14010d63b7dSRichard Lowe 	/* the number of symbols available */
14110d63b7dSRichard Lowe 	long			num_symbols;
14210d63b7dSRichard Lowe 	/* length of symbol directory file */
14310d63b7dSRichard Lowe 	long			sym_size;
14410d63b7dSRichard Lowe 	Arh_5			arh_5;
14510d63b7dSRichard Lowe 	Ars_5			ars_5;
14610d63b7dSRichard Lowe 	Arf_5			arf_5;
14710d63b7dSRichard Lowe 	Ar_port			ar_port;
14810d63b7dSRichard Lowe }			Ar;
14910d63b7dSRichard Lowe 
15010d63b7dSRichard Lowe /*
15110d63b7dSRichard Lowe  * Static variables
15210d63b7dSRichard Lowe  */
15310d63b7dSRichard Lowe 
15410d63b7dSRichard Lowe /*
15510d63b7dSRichard Lowe  * File table of contents
15610d63b7dSRichard Lowe  */
157*e7afc443SToomas Soome extern	timestruc_t&	read_archive(Name target);
158*e7afc443SToomas Soome static	Boolean		open_archive(char *filename, Ar *arp);
159*e7afc443SToomas Soome static	void		close_archive(Ar *arp);
160*e7afc443SToomas Soome static	Boolean		read_archive_dir(Ar *arp, Name library, char **long_names_table);
161*e7afc443SToomas Soome static	void		translate_entry(Ar *arp, Name target, Property member, char **long_names_table);
16210d63b7dSRichard Lowe static	long		sgetl(char *);
16310d63b7dSRichard Lowe 
16410d63b7dSRichard Lowe /*
16510d63b7dSRichard Lowe  *	read_archive(target)
16610d63b7dSRichard Lowe  *
16710d63b7dSRichard Lowe  *	Read the contents of an ar file.
16810d63b7dSRichard Lowe  *
16910d63b7dSRichard Lowe  *	Return value:
17010d63b7dSRichard Lowe  *				The time the member was created
17110d63b7dSRichard Lowe  *
17210d63b7dSRichard Lowe  *	Parameters:
17310d63b7dSRichard Lowe  *		target		The member to find time for
17410d63b7dSRichard Lowe  *
17510d63b7dSRichard Lowe  *	Global variables used:
17610d63b7dSRichard Lowe  *		empty_name	The Name ""
17710d63b7dSRichard Lowe  */
17810d63b7dSRichard Lowe 
17910d63b7dSRichard Lowe int read_member_header (Ar_port *header, FILE *fd, char* filename);
180*e7afc443SToomas Soome int process_long_names_member (Ar *arp, char **long_names_table, char *filename);
18110d63b7dSRichard Lowe 
18210d63b7dSRichard Lowe timestruc_t&
read_archive(Name target)183*e7afc443SToomas Soome read_archive(Name target)
18410d63b7dSRichard Lowe {
185*e7afc443SToomas Soome 	Property       member;
18610d63b7dSRichard Lowe 	wchar_t			*slash;
18710d63b7dSRichard Lowe 	String_rec		true_member_name;
18810d63b7dSRichard Lowe 	wchar_t			buffer[STRING_BUFFER_LENGTH];
189*e7afc443SToomas Soome 	Name		true_member = NULL;
19010d63b7dSRichard Lowe 	Ar                      ar;
19110d63b7dSRichard Lowe 	char			*long_names_table = NULL; /* Table of long
19210d63b7dSRichard Lowe 							     member names */
19310d63b7dSRichard Lowe 
19410d63b7dSRichard Lowe 	member = get_prop(target->prop, member_prop);
19510d63b7dSRichard Lowe 	/*
19610d63b7dSRichard Lowe 	 * Check if the member has directory component.
19710d63b7dSRichard Lowe 	 * If so, remove the dir and see if we know the date.
19810d63b7dSRichard Lowe 	 */
19910d63b7dSRichard Lowe 	if (member->body.member.member != NULL) {
20010d63b7dSRichard Lowe 		Wstring member_string(member->body.member.member);
20110d63b7dSRichard Lowe 		wchar_t * wcb = member_string.get_string();
20210d63b7dSRichard Lowe 		if((slash = (wchar_t *) wcsrchr(wcb, (int) slash_char)) != NULL) {
20310d63b7dSRichard Lowe 			INIT_STRING_FROM_STACK(true_member_name, buffer);
20410d63b7dSRichard Lowe 			append_string(member->body.member.library->string_mb,
20510d63b7dSRichard Lowe 				      &true_member_name,
20610d63b7dSRichard Lowe 				      FIND_LENGTH);
20710d63b7dSRichard Lowe 			append_char((int) parenleft_char, &true_member_name);
20810d63b7dSRichard Lowe 			append_string(slash + 1, &true_member_name, FIND_LENGTH);
20910d63b7dSRichard Lowe 			append_char((int) parenright_char, &true_member_name);
21010d63b7dSRichard Lowe 			true_member = GETNAME(true_member_name.buffer.start,
21110d63b7dSRichard Lowe 					      FIND_LENGTH);
21210d63b7dSRichard Lowe 			if (true_member->stat.time != file_no_time) {
21310d63b7dSRichard Lowe 				target->stat.time = true_member->stat.time;
21410d63b7dSRichard Lowe 				return target->stat.time;
21510d63b7dSRichard Lowe 			}
21610d63b7dSRichard Lowe 		}
21710d63b7dSRichard Lowe 	}
21810d63b7dSRichard Lowe 	if (open_archive(member->body.member.library->string_mb, &ar) == failed) {
21910d63b7dSRichard Lowe 		if (errno == ENOENT) {
22010d63b7dSRichard Lowe 			target->stat.stat_errno = ENOENT;
22110d63b7dSRichard Lowe 			close_archive(&ar);
22210d63b7dSRichard Lowe 			if (member->body.member.member == NULL) {
22310d63b7dSRichard Lowe 				member->body.member.member = empty_name;
22410d63b7dSRichard Lowe 			}
22510d63b7dSRichard Lowe 			return target->stat.time = file_doesnt_exist;
22610d63b7dSRichard Lowe 		} else {
22710d63b7dSRichard Lowe 			fatal(gettext("Can't access archive `%s': %s"),
22810d63b7dSRichard Lowe 			      member->body.member.library->string_mb,
22910d63b7dSRichard Lowe 			      errmsg(errno));
23010d63b7dSRichard Lowe 		}
23110d63b7dSRichard Lowe 	}
23210d63b7dSRichard Lowe 	if (target->stat.time == file_no_time) {
23310d63b7dSRichard Lowe 		if (read_archive_dir(&ar, member->body.member.library,
23410d63b7dSRichard Lowe 				     &long_names_table)
23510d63b7dSRichard Lowe 		    == failed){
23610d63b7dSRichard Lowe 			fatal(gettext("Can't access archive `%s': %s"),
23710d63b7dSRichard Lowe 			      member->body.member.library->string_mb,
23810d63b7dSRichard Lowe 			      errmsg(errno));
23910d63b7dSRichard Lowe 		}
24010d63b7dSRichard Lowe 	}
24110d63b7dSRichard Lowe 	if (member->body.member.entry != NULL) {
24210d63b7dSRichard Lowe 		translate_entry(&ar, target, member,&long_names_table);
24310d63b7dSRichard Lowe 	}
24410d63b7dSRichard Lowe 	close_archive(&ar);
24510d63b7dSRichard Lowe 	if (long_names_table) {
24610d63b7dSRichard Lowe 		retmem_mb(long_names_table);
24710d63b7dSRichard Lowe 	}
24810d63b7dSRichard Lowe 	if (true_member != NULL) {
24910d63b7dSRichard Lowe 		target->stat.time = true_member->stat.time;
25010d63b7dSRichard Lowe 	}
25110d63b7dSRichard Lowe 	if (target->stat.time == file_no_time) {
25210d63b7dSRichard Lowe 		target->stat.time = file_doesnt_exist;
25310d63b7dSRichard Lowe 	}
25410d63b7dSRichard Lowe 	return target->stat.time;
25510d63b7dSRichard Lowe }
25610d63b7dSRichard Lowe 
25710d63b7dSRichard Lowe /*
25810d63b7dSRichard Lowe  *	open_archive(filename, arp)
25910d63b7dSRichard Lowe  *
26010d63b7dSRichard Lowe  *	Return value:
26110d63b7dSRichard Lowe  *				Indicates if open failed or not
26210d63b7dSRichard Lowe  *
26310d63b7dSRichard Lowe  *	Parameters:
26410d63b7dSRichard Lowe  *		filename	The name of the archive we need to read
26510d63b7dSRichard Lowe  *		arp		Pointer to ar file description block
26610d63b7dSRichard Lowe  *
26710d63b7dSRichard Lowe  *	Global variables used:
26810d63b7dSRichard Lowe  */
26910d63b7dSRichard Lowe static Boolean
open_archive(char * filename,Ar * arp)270*e7afc443SToomas Soome open_archive(char *filename, Ar *arp)
27110d63b7dSRichard Lowe {
27210d63b7dSRichard Lowe 	int			fd;
27310d63b7dSRichard Lowe 	char			mag_5[AR_5_MAGIC_LENGTH];
27410d63b7dSRichard Lowe 	char			mag_port[AR_PORT_MAGIC_LENGTH];
27510d63b7dSRichard Lowe 	char			buffer[4];
27610d63b7dSRichard Lowe 
27710d63b7dSRichard Lowe 	arp->fd = NULL;
27810d63b7dSRichard Lowe 	fd = open_vroot(filename, O_RDONLY, 0, NULL, VROOT_DEFAULT);
27910d63b7dSRichard Lowe 	if ((fd < 0) || ((arp->fd = fdopen(fd, "r")) == NULL)) {
28010d63b7dSRichard Lowe 		return failed;
28110d63b7dSRichard Lowe 	}
28210d63b7dSRichard Lowe 	(void) fcntl(fileno(arp->fd), F_SETFD, 1);
28310d63b7dSRichard Lowe 
28410d63b7dSRichard Lowe 	if (fread(mag_port, AR_PORT_MAGIC_LENGTH, 1, arp->fd) != 1) {
28510d63b7dSRichard Lowe 		return failed;
28610d63b7dSRichard Lowe 	}
28710d63b7dSRichard Lowe 	if (IS_EQUALN(mag_port, AR_PORT_MAGIC, AR_PORT_MAGIC_LENGTH)) {
28810d63b7dSRichard Lowe 		arp->type = AR_PORT;
28910d63b7dSRichard Lowe 		/*
29010d63b7dSRichard Lowe 		 * Read in first member header to find out if there is
29110d63b7dSRichard Lowe 		 * a symbol definition table.
29210d63b7dSRichard Lowe 		 */
29310d63b7dSRichard Lowe 
29410d63b7dSRichard Lowe 		int ret = read_member_header(&arp->ar_port, arp->fd, filename);
29510d63b7dSRichard Lowe 		if (ret == failed) {
29610d63b7dSRichard Lowe 			return failed;
29710d63b7dSRichard Lowe 		} else if(ret == -1) {
29810d63b7dSRichard Lowe 			/* There is no member header - empty archive */
29910d63b7dSRichard Lowe 			arp->sym_size = arp->num_symbols = arp->sym_begin = 0L;
30010d63b7dSRichard Lowe 			arp->first_ar_mem = ftell(arp->fd);
30110d63b7dSRichard Lowe 			return succeeded;
30210d63b7dSRichard Lowe 		}
30310d63b7dSRichard Lowe 		/*
30410d63b7dSRichard Lowe 		 * The following values are the default if there is
30510d63b7dSRichard Lowe 		 * no symbol directory and long member names.
30610d63b7dSRichard Lowe 		 */
30710d63b7dSRichard Lowe 		arp->sym_size = arp->num_symbols = arp->sym_begin = 0L;
30810d63b7dSRichard Lowe 		arp->first_ar_mem = ftell(arp->fd) - (long) sizeof (Ar_port);
30910d63b7dSRichard Lowe 
31010d63b7dSRichard Lowe 		/*
31110d63b7dSRichard Lowe 		 * Do we have a symbol table? A symbol table is always
31210d63b7dSRichard Lowe 		 * the first member in an archive. In 4.1.x it has the
31310d63b7dSRichard Lowe 		 * name __.SYMDEF, in SVr4, it has the name "/        "
31410d63b7dSRichard Lowe 		 */
31510d63b7dSRichard Lowe /*
31610d63b7dSRichard Lowe 		MBSTOWCS(wcs_buffer, "/               ");
31710d63b7dSRichard Lowe 		if (IS_WEQUALN(arp->ar_port.ar_name, wcs_buffer, 16)) {
31810d63b7dSRichard Lowe  */
31910d63b7dSRichard Lowe 		if (IS_EQUALN(arp->ar_port.ar_name,
32010d63b7dSRichard Lowe 			      "/               ",
32110d63b7dSRichard Lowe 			      16)) {
32210d63b7dSRichard Lowe 			if (sscanf(arp->ar_port.ar_size,
32310d63b7dSRichard Lowe 				   "%ld",
32410d63b7dSRichard Lowe 				   &arp->sym_size) != 1) {
32510d63b7dSRichard Lowe 				return failed;
32610d63b7dSRichard Lowe 			}
32710d63b7dSRichard Lowe 			arp->sym_size += (arp->sym_size & 1); /* round up */
32810d63b7dSRichard Lowe 			if (fread(buffer, sizeof buffer, 1, arp->fd) != 1) {
32910d63b7dSRichard Lowe 				return failed;
33010d63b7dSRichard Lowe 			}
33110d63b7dSRichard Lowe 			arp->num_symbols = sgetl(buffer);
33210d63b7dSRichard Lowe 			arp->sym_begin = ftell(arp->fd);
33310d63b7dSRichard Lowe 			arp->first_ar_mem = arp->sym_begin +
33410d63b7dSRichard Lowe 						arp->sym_size - sizeof buffer;
33510d63b7dSRichard Lowe 		}
33610d63b7dSRichard Lowe 		return succeeded;
33710d63b7dSRichard Lowe 	}
33810d63b7dSRichard Lowe 	fatal(gettext("`%s' is not an archive"), filename);
33910d63b7dSRichard Lowe 	/* NOTREACHED */
34010d63b7dSRichard Lowe 	return failed;
34110d63b7dSRichard Lowe }
34210d63b7dSRichard Lowe 
34310d63b7dSRichard Lowe 
34410d63b7dSRichard Lowe /*
34510d63b7dSRichard Lowe  *	close_archive(arp)
34610d63b7dSRichard Lowe  *
34710d63b7dSRichard Lowe  *	Parameters:
34810d63b7dSRichard Lowe  *		arp		Pointer to ar file description block
34910d63b7dSRichard Lowe  *
35010d63b7dSRichard Lowe  *	Global variables used:
35110d63b7dSRichard Lowe  */
35210d63b7dSRichard Lowe static void
close_archive(Ar * arp)353*e7afc443SToomas Soome close_archive(Ar *arp)
35410d63b7dSRichard Lowe {
35510d63b7dSRichard Lowe 	if (arp->fd != NULL) {
35610d63b7dSRichard Lowe 		(void) fclose(arp->fd);
35710d63b7dSRichard Lowe 	}
35810d63b7dSRichard Lowe }
35910d63b7dSRichard Lowe 
36010d63b7dSRichard Lowe /*
36110d63b7dSRichard Lowe  *	read_archive_dir(arp, library, long_names_table)
36210d63b7dSRichard Lowe  *
36310d63b7dSRichard Lowe  *	Reads the directory of an archive and enters all
36410d63b7dSRichard Lowe  *	the members into the make symboltable in lib(member) format
36510d63b7dSRichard Lowe  *	with their dates.
36610d63b7dSRichard Lowe  *
36710d63b7dSRichard Lowe  *	Parameters:
36810d63b7dSRichard Lowe  *		arp		Pointer to ar file description block
36910d63b7dSRichard Lowe  *		library		Name of lib to enter members for.
37010d63b7dSRichard Lowe  *				Used to form "lib(member)" string.
37110d63b7dSRichard Lowe  *		long_names_table table that contains list of members
37210d63b7dSRichard Lowe  *				with names > 15 characters long
37310d63b7dSRichard Lowe  *
37410d63b7dSRichard Lowe  *	Global variables used:
37510d63b7dSRichard Lowe  */
37610d63b7dSRichard Lowe static Boolean
read_archive_dir(Ar * arp,Name library,char ** long_names_table)377*e7afc443SToomas Soome read_archive_dir(Ar *arp, Name library, char **long_names_table)
37810d63b7dSRichard Lowe {
37910d63b7dSRichard Lowe 	wchar_t			*name_string;
38010d63b7dSRichard Lowe 	wchar_t			*member_string;
381*e7afc443SToomas Soome 	long		len;
382*e7afc443SToomas Soome 	wchar_t	*p;
383*e7afc443SToomas Soome 	char		*q;
384*e7afc443SToomas Soome 	Name		name;
38510d63b7dSRichard Lowe 	Property		member;
38610d63b7dSRichard Lowe 	long			ptr;
38710d63b7dSRichard Lowe 	long			date;
38810d63b7dSRichard Lowe 
38910d63b7dSRichard Lowe 	int			offset;
39010d63b7dSRichard Lowe 
39110d63b7dSRichard Lowe 	/*
39210d63b7dSRichard Lowe 	 * If any of the members has a name > 15 chars,
39310d63b7dSRichard Lowe 	 * it will be found here.
39410d63b7dSRichard Lowe 	 */
39510d63b7dSRichard Lowe 	if (process_long_names_member(arp, long_names_table, library->string_mb) == failed) {
39610d63b7dSRichard Lowe 		return failed;
39710d63b7dSRichard Lowe 	}
39810d63b7dSRichard Lowe 	name_string = ALLOC_WC((int) (library->hash.length +
39910d63b7dSRichard Lowe 				      (int) ar_member_name_len * 2));
40010d63b7dSRichard Lowe 	(void) mbstowcs(name_string, library->string_mb, (int) library->hash.length);
40110d63b7dSRichard Lowe 	member_string = name_string + library->hash.length;
40210d63b7dSRichard Lowe 	*member_string++ = (int) parenleft_char;
40310d63b7dSRichard Lowe 
40410d63b7dSRichard Lowe 	if (fseek(arp->fd, arp->first_ar_mem, 0) != 0) {
40510d63b7dSRichard Lowe 		goto read_error;
40610d63b7dSRichard Lowe 	}
40710d63b7dSRichard Lowe 	/* Read the directory using the appropriate format */
40810d63b7dSRichard Lowe 	switch (arp->type) {
40910d63b7dSRichard Lowe 	case AR_5:
41010d63b7dSRichard Lowe 	    for (;;) {
41110d63b7dSRichard Lowe 		if (fread((char *) &arp->arf_5, sizeof arp->arf_5, 1, arp->fd)
41210d63b7dSRichard Lowe 		    != 1) {
41310d63b7dSRichard Lowe 			if (feof(arp->fd)) {
41410d63b7dSRichard Lowe 				return succeeded;
41510d63b7dSRichard Lowe 			}
41610d63b7dSRichard Lowe 			break;
41710d63b7dSRichard Lowe 		}
41810d63b7dSRichard Lowe 		len = sizeof arp->arf_5.arf_name;
41910d63b7dSRichard Lowe 		for (p = member_string, q = arp->arf_5.arf_name;
42010d63b7dSRichard Lowe 		     (len > 0) && (*q != (int) nul_char) && !isspace(*q);
42110d63b7dSRichard Lowe 		     ) {
42210d63b7dSRichard Lowe 			MBTOWC(p, q);
42310d63b7dSRichard Lowe 			p++;
42410d63b7dSRichard Lowe 			q++;
42510d63b7dSRichard Lowe 		}
42610d63b7dSRichard Lowe 		*p++ = (int) parenright_char;
42710d63b7dSRichard Lowe 		*p = (int) nul_char;
42810d63b7dSRichard Lowe 		name = GETNAME(name_string, FIND_LENGTH);
42910d63b7dSRichard Lowe 		/*
43010d63b7dSRichard Lowe 		 * [tolik] Fix for dmake bug 1234018.
43110d63b7dSRichard Lowe 		 * If name->stat.time is already set, then it should not
43210d63b7dSRichard Lowe 		 * be changed. (D)make propogates time stamp for one
43310d63b7dSRichard Lowe 		 * member, and when it calls exists() for another member,
43410d63b7dSRichard Lowe 		 * the first one may be changed.
43510d63b7dSRichard Lowe 		 */
43610d63b7dSRichard Lowe 		if(name->stat.time == file_no_time) {
43710d63b7dSRichard Lowe 			name->stat.time.tv_sec = sgetl(arp->arf_5.arf_date);
43810d63b7dSRichard Lowe 			name->stat.time.tv_nsec = LONG_MAX;
43910d63b7dSRichard Lowe 		}
44010d63b7dSRichard Lowe 		name->is_member = library->is_member;
44110d63b7dSRichard Lowe 		member = maybe_append_prop(name, member_prop);
44210d63b7dSRichard Lowe 		member->body.member.library = library;
44310d63b7dSRichard Lowe 		*--p = (int) nul_char;
44410d63b7dSRichard Lowe 		if (member->body.member.member == NULL) {
44510d63b7dSRichard Lowe 			member->body.member.member =
44610d63b7dSRichard Lowe 			  GETNAME(member_string, FIND_LENGTH);
44710d63b7dSRichard Lowe 		}
44810d63b7dSRichard Lowe 		ptr = sgetl(arp->arf_5.arf_size);
44910d63b7dSRichard Lowe 		ptr += (ptr & 1);
45010d63b7dSRichard Lowe 		if (fseek(arp->fd, ptr, 1) != 0) {
45110d63b7dSRichard Lowe 			goto read_error;
45210d63b7dSRichard Lowe 		}
45310d63b7dSRichard Lowe 	    }
45410d63b7dSRichard Lowe 	    break;
45510d63b7dSRichard Lowe 	case AR_PORT:
45610d63b7dSRichard Lowe 	    for (;;) {
45710d63b7dSRichard Lowe 		    if ((fread((char *) &arp->ar_port,
45810d63b7dSRichard Lowe 			       sizeof arp->ar_port,
45910d63b7dSRichard Lowe 			       1,
46010d63b7dSRichard Lowe 			       arp->fd) != 1) ||
46110d63b7dSRichard Lowe 			!IS_EQUALN(arp->ar_port.ar_fmag,
46210d63b7dSRichard Lowe 				   AR_PORT_END_MAGIC,
46310d63b7dSRichard Lowe 				   sizeof arp->ar_port.ar_fmag)) {
46410d63b7dSRichard Lowe 			    if (feof(arp->fd)) {
46510d63b7dSRichard Lowe 				    return succeeded;
46610d63b7dSRichard Lowe 			    }
46710d63b7dSRichard Lowe 			    fatal(
46810d63b7dSRichard Lowe 				gettext("Read error in archive `%s': invalid archive file member header at 0x%x"),
46910d63b7dSRichard Lowe 				library->string_mb,
47010d63b7dSRichard Lowe 				ftell(arp->fd)
47110d63b7dSRichard Lowe 			    );
47210d63b7dSRichard Lowe 		    }
47310d63b7dSRichard Lowe 		    /* If it's a long name, retrieve it from long name table */
47410d63b7dSRichard Lowe 		    if (arp->ar_port.ar_name[0] == '/') {
47510d63b7dSRichard Lowe 			    /*
47610d63b7dSRichard Lowe 			     * "len" is used for hashing the string.
47710d63b7dSRichard Lowe 			     * We're using "ar_member_name_len" instead of
47810d63b7dSRichard Lowe 			     * the actual name length since it's the longest
47910d63b7dSRichard Lowe 			     * string the "ar" command can handle at this
48010d63b7dSRichard Lowe 			     * point.
48110d63b7dSRichard Lowe 			     */
48210d63b7dSRichard Lowe 			    len = ar_member_name_len;
48310d63b7dSRichard Lowe 			    sscanf(arp->ar_port.ar_name + 1,
48410d63b7dSRichard Lowe 				   "%ld",
48510d63b7dSRichard Lowe 				   &offset);
48610d63b7dSRichard Lowe 			    q = *long_names_table + offset;
48710d63b7dSRichard Lowe 		    } else {
48810d63b7dSRichard Lowe 			    q = arp->ar_port.ar_name;
48910d63b7dSRichard Lowe 			    len = sizeof arp->ar_port.ar_name;
49010d63b7dSRichard Lowe 		    }
49110d63b7dSRichard Lowe 
49210d63b7dSRichard Lowe 		    for (p = member_string;
49310d63b7dSRichard Lowe 			 (len > 0) &&
49410d63b7dSRichard Lowe 			 (*q != (int) nul_char) &&
49510d63b7dSRichard Lowe 			 !isspace(*q) &&
49610d63b7dSRichard Lowe 			 (*q != (int) slash_char);
49710d63b7dSRichard Lowe 			 ) {
49810d63b7dSRichard Lowe 			    MBTOWC(p, q);
49910d63b7dSRichard Lowe 			    p++;
50010d63b7dSRichard Lowe 			    q++;
50110d63b7dSRichard Lowe 		    }
50210d63b7dSRichard Lowe 		    *p++ = (int) parenright_char;
50310d63b7dSRichard Lowe 		    *p = (int) nul_char;
50410d63b7dSRichard Lowe 		    name = GETNAME(name_string, FIND_LENGTH);
50510d63b7dSRichard Lowe 		    name->is_member = library->is_member;
50610d63b7dSRichard Lowe 		    member = maybe_append_prop(name, member_prop);
50710d63b7dSRichard Lowe 		    member->body.member.library = library;
50810d63b7dSRichard Lowe 		    *--p = (int) nul_char;
50910d63b7dSRichard Lowe 		    if (member->body.member.member == NULL) {
51010d63b7dSRichard Lowe 			    member->body.member.member =
51110d63b7dSRichard Lowe 			      GETNAME(member_string, FIND_LENGTH);
51210d63b7dSRichard Lowe 		    }
51310d63b7dSRichard Lowe 		    if (sscanf(arp->ar_port.ar_date, "%ld", &date) != 1) {
51410d63b7dSRichard Lowe 			    WCSTOMBS(mbs_buffer, name_string);
51510d63b7dSRichard Lowe 			    fatal(gettext("Bad date field for member `%s' in archive `%s'"),
51610d63b7dSRichard Lowe 				  mbs_buffer,
51710d63b7dSRichard Lowe 				  library->string_mb);
51810d63b7dSRichard Lowe 		    }
51910d63b7dSRichard Lowe 		    /*
52010d63b7dSRichard Lowe 		     * [tolik] Fix for dmake bug 1234018.
52110d63b7dSRichard Lowe 		     */
52210d63b7dSRichard Lowe 		    if(name->stat.time == file_no_time) {
52310d63b7dSRichard Lowe 			name->stat.time.tv_sec = date;
52410d63b7dSRichard Lowe 			name->stat.time.tv_nsec = LONG_MAX;
52510d63b7dSRichard Lowe 		    }
52610d63b7dSRichard Lowe 		    if (sscanf(arp->ar_port.ar_size, "%ld", &ptr) != 1) {
52710d63b7dSRichard Lowe 			    WCSTOMBS(mbs_buffer, name_string);
52810d63b7dSRichard Lowe 			    fatal(gettext("Bad size field for member `%s' in archive `%s'"),
52910d63b7dSRichard Lowe 				  mbs_buffer,
53010d63b7dSRichard Lowe 				  library->string_mb);
53110d63b7dSRichard Lowe 		    }
53210d63b7dSRichard Lowe 		    ptr += (ptr & 1);
53310d63b7dSRichard Lowe 		    if (fseek(arp->fd, ptr, 1) != 0) {
53410d63b7dSRichard Lowe 			    goto read_error;
53510d63b7dSRichard Lowe 		    }
53610d63b7dSRichard Lowe 	    }
53710d63b7dSRichard Lowe 	    break;
53810d63b7dSRichard Lowe 	}
53910d63b7dSRichard Lowe 
54010d63b7dSRichard Lowe 	/* Only here if fread() [or IS_EQUALN()] failed and not at EOF */
54110d63b7dSRichard Lowe read_error:
54210d63b7dSRichard Lowe 	fatal(gettext("Read error in archive `%s': %s"),
54310d63b7dSRichard Lowe 	      library->string_mb,
54410d63b7dSRichard Lowe 	      errmsg(errno));
54510d63b7dSRichard Lowe 	    /* NOTREACHED */
54610d63b7dSRichard Lowe }
54710d63b7dSRichard Lowe 
54810d63b7dSRichard Lowe 
54910d63b7dSRichard Lowe /*
55010d63b7dSRichard Lowe  *	process_long_names_member(arp)
55110d63b7dSRichard Lowe  *
55210d63b7dSRichard Lowe  *	If the archive contains members with names longer
55310d63b7dSRichard Lowe  *	than 15 characters, then it has a special member
55410d63b7dSRichard Lowe  *	with the name "//        " that contains a table
55510d63b7dSRichard Lowe  *	of null-terminated long names. This member
55610d63b7dSRichard Lowe  *	is always the first member, after the symbol table
55710d63b7dSRichard Lowe  *	if it exists.
55810d63b7dSRichard Lowe  *
55910d63b7dSRichard Lowe  *	Parameters:
56010d63b7dSRichard Lowe  *		arp		Pointer to ar file description block
56110d63b7dSRichard Lowe  *
56210d63b7dSRichard Lowe  *	Global variables used:
56310d63b7dSRichard Lowe  */
56410d63b7dSRichard Lowe int
process_long_names_member(Ar * arp,char ** long_names_table,char * filename)565*e7afc443SToomas Soome process_long_names_member(Ar *arp, char **long_names_table, char *filename)
56610d63b7dSRichard Lowe {
56710d63b7dSRichard Lowe 	Ar_port			*ar_member_header;
56810d63b7dSRichard Lowe 	int			table_size;
56910d63b7dSRichard Lowe 
57010d63b7dSRichard Lowe 	if (fseek(arp->fd, arp->first_ar_mem, 0) != 0) {
57110d63b7dSRichard Lowe 		return failed;
57210d63b7dSRichard Lowe 	}
57310d63b7dSRichard Lowe 	if ((ar_member_header =
57410d63b7dSRichard Lowe 	     (Ar_port *) alloca((int) sizeof(Ar_port))) == NULL){
57510d63b7dSRichard Lowe 		perror(gettext("memory allocation failure"));
57610d63b7dSRichard Lowe 		return failed;
57710d63b7dSRichard Lowe 	}
57810d63b7dSRichard Lowe 	int ret = read_member_header(ar_member_header, arp->fd, filename);
57910d63b7dSRichard Lowe 	if (ret == failed) {
58010d63b7dSRichard Lowe 		return failed;
58110d63b7dSRichard Lowe 	} else if(ret == -1) {
58210d63b7dSRichard Lowe 		/* There is no member header - empty archive */
58310d63b7dSRichard Lowe 		return succeeded;
58410d63b7dSRichard Lowe 	}
58510d63b7dSRichard Lowe 	/* Do we have special member containing long names? */
58610d63b7dSRichard Lowe 	if (IS_EQUALN(ar_member_header->ar_name,
58710d63b7dSRichard Lowe 		      "//              ",
58810d63b7dSRichard Lowe 		      16)){
58910d63b7dSRichard Lowe 		if (sscanf(ar_member_header->ar_size,
59010d63b7dSRichard Lowe 			   "%ld",
59110d63b7dSRichard Lowe 			   &table_size) != 1) {
59210d63b7dSRichard Lowe 			return failed;
59310d63b7dSRichard Lowe 		}
59410d63b7dSRichard Lowe 		*long_names_table = (char *) malloc(table_size);
59510d63b7dSRichard Lowe 		/* Read the list of long member names into the table */
59610d63b7dSRichard Lowe 		if (fread(*long_names_table, table_size, 1, arp->fd) != 1) {
59710d63b7dSRichard Lowe 			return failed;
59810d63b7dSRichard Lowe 		}
59910d63b7dSRichard Lowe 		arp->first_ar_mem = ftell(arp->fd);
60010d63b7dSRichard Lowe 	}
60110d63b7dSRichard Lowe 	return succeeded;
60210d63b7dSRichard Lowe }
60310d63b7dSRichard Lowe 
60410d63b7dSRichard Lowe /*
60510d63b7dSRichard Lowe  *	translate_entry(arp, target, member)
60610d63b7dSRichard Lowe  *
60710d63b7dSRichard Lowe  *	Finds the member for one lib.a((entry))
60810d63b7dSRichard Lowe  *
60910d63b7dSRichard Lowe  *	Parameters:
61010d63b7dSRichard Lowe  *		arp		Pointer to ar file description block
61110d63b7dSRichard Lowe  *		target		Target to find member name for
61210d63b7dSRichard Lowe  *		member		Property to fill in with info
61310d63b7dSRichard Lowe  *
61410d63b7dSRichard Lowe  *	Global variables used:
61510d63b7dSRichard Lowe  */
61610d63b7dSRichard Lowe static void
translate_entry(Ar * arp,Name target,Property member,char ** long_names_table)617*e7afc443SToomas Soome translate_entry(Ar *arp, Name target, Property member, char **long_names_table)
61810d63b7dSRichard Lowe {
619*e7afc443SToomas Soome 	int		len;
620*e7afc443SToomas Soome 	int		i;
62110d63b7dSRichard Lowe 	wchar_t			*member_string;
62210d63b7dSRichard Lowe 	ar_port_word		*offs;
62310d63b7dSRichard Lowe 	int			strtablen;
62410d63b7dSRichard Lowe 	char			*syms;		 /* string table */
62510d63b7dSRichard Lowe 	char			*csym;		 /* string table */
62610d63b7dSRichard Lowe 	ar_port_word		*offend;	 /* end of offsets table */
62710d63b7dSRichard Lowe 	int			date;
628*e7afc443SToomas Soome 	wchar_t	*ap;
629*e7afc443SToomas Soome 	char		*hp;
63010d63b7dSRichard Lowe 	int			maxs;
63110d63b7dSRichard Lowe 	int			offset;
63210d63b7dSRichard Lowe 	char		buffer[4];
63310d63b7dSRichard Lowe 
63410d63b7dSRichard Lowe 	if (arp->sym_begin == 0L || arp->num_symbols == 0L) {
63510d63b7dSRichard Lowe 		fatal(gettext("Cannot find symbol `%s' in archive `%s'"),
63610d63b7dSRichard Lowe 		      member->body.member.entry->string_mb,
63710d63b7dSRichard Lowe 		      member->body.member.library->string_mb);
63810d63b7dSRichard Lowe 	}
63910d63b7dSRichard Lowe 
64010d63b7dSRichard Lowe 	if (fseek(arp->fd, arp->sym_begin, 0) != 0) {
64110d63b7dSRichard Lowe 		goto read_error;
64210d63b7dSRichard Lowe 	}
64310d63b7dSRichard Lowe 	member_string = ALLOC_WC((int) ((int) ar_member_name_len * 2));
64410d63b7dSRichard Lowe 
64510d63b7dSRichard Lowe 	switch (arp->type) {
64610d63b7dSRichard Lowe 	case AR_5:
64710d63b7dSRichard Lowe 		if ((len = member->body.member.entry->hash.length) > 8) {
64810d63b7dSRichard Lowe 			len = 8;
64910d63b7dSRichard Lowe 		}
65010d63b7dSRichard Lowe 		for (i = 0; i < arp->num_symbols; i++) {
65110d63b7dSRichard Lowe 			if (fread((char *) &arp->ars_5,
65210d63b7dSRichard Lowe 				  sizeof arp->ars_5,
65310d63b7dSRichard Lowe 				  1,
65410d63b7dSRichard Lowe 				  arp->fd) != 1) {
65510d63b7dSRichard Lowe 				goto read_error;
65610d63b7dSRichard Lowe 			}
65710d63b7dSRichard Lowe 			if (IS_EQUALN(arp->ars_5.sym_name,
65810d63b7dSRichard Lowe 				      member->body.member.entry->string_mb,
65910d63b7dSRichard Lowe 				      len)) {
66010d63b7dSRichard Lowe 				if ((fseek(arp->fd,
66110d63b7dSRichard Lowe 					   sgetl(arp->ars_5.sym_ptr),
66210d63b7dSRichard Lowe 					   0) != 0) ||
66310d63b7dSRichard Lowe 				    (fread((char *) &arp->arf_5,
66410d63b7dSRichard Lowe 					   sizeof arp->arf_5,
66510d63b7dSRichard Lowe 					   1,
66610d63b7dSRichard Lowe 					   arp->fd) != 1)) {
66710d63b7dSRichard Lowe 					goto read_error;
66810d63b7dSRichard Lowe 				}
66910d63b7dSRichard Lowe 				MBSTOWCS(wcs_buffer, arp->arf_5.arf_name);
67010d63b7dSRichard Lowe 				(void) wcsncpy(member_string,
67110d63b7dSRichard Lowe 					      wcs_buffer,
67210d63b7dSRichard Lowe 					      wcslen(wcs_buffer));
67310d63b7dSRichard Lowe 				member_string[sizeof(arp->arf_5.arf_name)] =
67410d63b7dSRichard Lowe 								(int) nul_char;
67510d63b7dSRichard Lowe 				member->body.member.member =
67610d63b7dSRichard Lowe 					GETNAME(member_string, FIND_LENGTH);
67710d63b7dSRichard Lowe 				target->stat.time.tv_sec = sgetl(arp->arf_5.arf_date);
67810d63b7dSRichard Lowe 				target->stat.time.tv_nsec = LONG_MAX;
67910d63b7dSRichard Lowe 				return;
68010d63b7dSRichard Lowe 			}
68110d63b7dSRichard Lowe 		}
68210d63b7dSRichard Lowe 		break;
68310d63b7dSRichard Lowe 	case AR_PORT:
68410d63b7dSRichard Lowe 		offs = (ar_port_word *) alloca((int) (arp->num_symbols * AR_PORT_WORD));
68510d63b7dSRichard Lowe 		if (fread((char *) offs,
68610d63b7dSRichard Lowe 			  AR_PORT_WORD,
68710d63b7dSRichard Lowe 			  (int) arp->num_symbols,
68810d63b7dSRichard Lowe 			  arp->fd) != arp->num_symbols) {
68910d63b7dSRichard Lowe 			goto read_error;
69010d63b7dSRichard Lowe 		}
69110d63b7dSRichard Lowe 
69210d63b7dSRichard Lowe 		for(i=0;i<arp->num_symbols;i++) {
69310d63b7dSRichard Lowe 			*((int*)buffer)=offs[i];
69410d63b7dSRichard Lowe 			offs[i]=(ar_port_word)sgetl(buffer);
69510d63b7dSRichard Lowe 		}
69610d63b7dSRichard Lowe 
69710d63b7dSRichard Lowe 		strtablen=arp->sym_size-4-(int) (arp->num_symbols * AR_PORT_WORD);
69810d63b7dSRichard Lowe 		syms = (char *) alloca(strtablen);
69910d63b7dSRichard Lowe 		if (fread(syms,
70010d63b7dSRichard Lowe 			  sizeof (char),
70110d63b7dSRichard Lowe 			  strtablen,
70210d63b7dSRichard Lowe 			  arp->fd) != strtablen) {
70310d63b7dSRichard Lowe 			goto read_error;
70410d63b7dSRichard Lowe 		}
70510d63b7dSRichard Lowe 		offend = &offs[arp->num_symbols];
70610d63b7dSRichard Lowe 		while (offs < offend) {
70710d63b7dSRichard Lowe 			maxs = strlen(member->body.member.entry->string_mb);
70810d63b7dSRichard Lowe 			if(strlen(syms) > maxs)
70910d63b7dSRichard Lowe 				maxs = strlen(syms);
71010d63b7dSRichard Lowe 			if (IS_EQUALN(syms,
71110d63b7dSRichard Lowe 				      member->body.member.entry->string_mb,
71210d63b7dSRichard Lowe 				      maxs)) {
71310d63b7dSRichard Lowe 				if (fseek(arp->fd,
71410d63b7dSRichard Lowe 					  (long) *offs,
71510d63b7dSRichard Lowe 					  0) != 0) {
71610d63b7dSRichard Lowe 					goto read_error;
71710d63b7dSRichard Lowe 				}
71810d63b7dSRichard Lowe 				if ((fread((char *) &arp->ar_port,
71910d63b7dSRichard Lowe 					   sizeof arp->ar_port,
72010d63b7dSRichard Lowe 					   1,
72110d63b7dSRichard Lowe 					   arp->fd) != 1) ||
72210d63b7dSRichard Lowe 				    !IS_EQUALN(arp->ar_port.ar_fmag,
72310d63b7dSRichard Lowe 					       AR_PORT_END_MAGIC,
72410d63b7dSRichard Lowe 					       sizeof arp->ar_port.ar_fmag)) {
72510d63b7dSRichard Lowe 					goto read_error;
72610d63b7dSRichard Lowe 				}
72710d63b7dSRichard Lowe 				if (sscanf(arp->ar_port.ar_date,
72810d63b7dSRichard Lowe 					   "%ld",
72910d63b7dSRichard Lowe 					   &date) != 1) {
73010d63b7dSRichard Lowe 					fatal(gettext("Bad date field for member `%s' in archive `%s'"),
73110d63b7dSRichard Lowe 					      arp->ar_port.ar_name,
73210d63b7dSRichard Lowe 					      target->string_mb);
73310d63b7dSRichard Lowe 				}
73410d63b7dSRichard Lowe 		    /* If it's a long name, retrieve it from long name table */
73510d63b7dSRichard Lowe 		    if (arp->ar_port.ar_name[0] == '/') {
73610d63b7dSRichard Lowe 			    sscanf(arp->ar_port.ar_name + 1,
73710d63b7dSRichard Lowe 				   "%ld",
73810d63b7dSRichard Lowe 				   &offset);
73910d63b7dSRichard Lowe 			    len = ar_member_name_len;
74010d63b7dSRichard Lowe 			    hp = *long_names_table + offset;
74110d63b7dSRichard Lowe 		    } else {
74210d63b7dSRichard Lowe 			    len = sizeof arp->ar_port.ar_name;
74310d63b7dSRichard Lowe 			    hp = arp->ar_port.ar_name;
74410d63b7dSRichard Lowe 		    }
74510d63b7dSRichard Lowe 				ap = member_string;
74610d63b7dSRichard Lowe 				while (*hp &&
74710d63b7dSRichard Lowe 				       (*hp != (int) slash_char) &&
74810d63b7dSRichard Lowe 				       (ap < &member_string[len])) {
74910d63b7dSRichard Lowe 					MBTOWC(ap, hp);
75010d63b7dSRichard Lowe 					ap++;
75110d63b7dSRichard Lowe 					hp++;
75210d63b7dSRichard Lowe 				}
75310d63b7dSRichard Lowe 				*ap = (int) nul_char;
75410d63b7dSRichard Lowe 				member->body.member.member =
75510d63b7dSRichard Lowe 					GETNAME(member_string, FIND_LENGTH);
75610d63b7dSRichard Lowe 				target->stat.time.tv_sec = date;
75710d63b7dSRichard Lowe 				target->stat.time.tv_nsec = LONG_MAX;
75810d63b7dSRichard Lowe 				return;
75910d63b7dSRichard Lowe 			}
76010d63b7dSRichard Lowe 			offs++;
76110d63b7dSRichard Lowe 			while(*syms!='\0') syms++;
76210d63b7dSRichard Lowe 			syms++;
76310d63b7dSRichard Lowe 		}
76410d63b7dSRichard Lowe 	}
76510d63b7dSRichard Lowe 	fatal(gettext("Cannot find symbol `%s' in archive `%s'"),
76610d63b7dSRichard Lowe 	      member->body.member.entry->string_mb,
76710d63b7dSRichard Lowe 	      member->body.member.library->string_mb);
76810d63b7dSRichard Lowe 	/*NOTREACHED*/
76910d63b7dSRichard Lowe 
77010d63b7dSRichard Lowe read_error:
77110d63b7dSRichard Lowe 	if (ferror(arp->fd)) {
77210d63b7dSRichard Lowe 		fatal(gettext("Read error in archive `%s': %s"),
77310d63b7dSRichard Lowe 		      member->body.member.library->string_mb,
77410d63b7dSRichard Lowe 		      errmsg(errno));
77510d63b7dSRichard Lowe 	} else {
77610d63b7dSRichard Lowe 		fatal(gettext("Read error in archive `%s': Premature EOF"),
77710d63b7dSRichard Lowe 		      member->body.member.library->string_mb);
77810d63b7dSRichard Lowe 	}
77910d63b7dSRichard Lowe }
78010d63b7dSRichard Lowe 
78110d63b7dSRichard Lowe /*
78210d63b7dSRichard Lowe  *	sgetl(buffer)
78310d63b7dSRichard Lowe  *
78410d63b7dSRichard Lowe  *	The intent here is to provide a means to make the value of
78510d63b7dSRichard Lowe  *	bytes in an io-buffer correspond to the value of a long
78610d63b7dSRichard Lowe  *	in the memory while doing the io a long at a time.
78710d63b7dSRichard Lowe  *	Files written and read in this way are machine-independent.
78810d63b7dSRichard Lowe  *
78910d63b7dSRichard Lowe  *	Return value:
79010d63b7dSRichard Lowe  *				Long int read from buffer
79110d63b7dSRichard Lowe  *	Parameters:
79210d63b7dSRichard Lowe  *		buffer		buffer we need to read long int from
79310d63b7dSRichard Lowe  *
79410d63b7dSRichard Lowe  *	Global variables used:
79510d63b7dSRichard Lowe  */
79610d63b7dSRichard Lowe static long
sgetl(char * buffer)797*e7afc443SToomas Soome sgetl(char *buffer)
79810d63b7dSRichard Lowe {
799*e7afc443SToomas Soome 	long		w = 0;
800*e7afc443SToomas Soome 	int		i = BITSPERBYTE * AR_PORT_WORD;
80110d63b7dSRichard Lowe 
80210d63b7dSRichard Lowe 	while ((i -= BITSPERBYTE) >= 0) {
80310d63b7dSRichard Lowe 		w |= (long) ((unsigned char) *buffer++) << i;
80410d63b7dSRichard Lowe 	}
80510d63b7dSRichard Lowe 	return w;
80610d63b7dSRichard Lowe }
80710d63b7dSRichard Lowe 
80810d63b7dSRichard Lowe 
80910d63b7dSRichard Lowe /*
81010d63b7dSRichard Lowe  *	read_member_header(header, fd, filename)
81110d63b7dSRichard Lowe  *
81210d63b7dSRichard Lowe  *	reads the member header for the 4.1.x and SVr4 archives.
81310d63b7dSRichard Lowe  *
81410d63b7dSRichard Lowe  *	Return value:
81510d63b7dSRichard Lowe  *				fails if read error or member
81610d63b7dSRichard Lowe  *				header is not the right format
81710d63b7dSRichard Lowe  *	Parameters:
81810d63b7dSRichard Lowe  *		header		There's one before each archive member
81910d63b7dSRichard Lowe  *		fd		file descriptor for the archive file.
82010d63b7dSRichard Lowe  *
82110d63b7dSRichard Lowe  *	Global variables used:
82210d63b7dSRichard Lowe  */
82310d63b7dSRichard Lowe int
read_member_header(Ar_port * header,FILE * fd,char * filename)82410d63b7dSRichard Lowe read_member_header(Ar_port *header, FILE *fd, char* filename)
82510d63b7dSRichard Lowe {
82610d63b7dSRichard Lowe 	int num = fread((char *) header, sizeof (Ar_port), 1, fd);
82710d63b7dSRichard Lowe 	if (num != 1 && feof(fd)) {
82810d63b7dSRichard Lowe 		/* There is no member header - empty archive */
82910d63b7dSRichard Lowe 		return -1;
83010d63b7dSRichard Lowe 	}
83110d63b7dSRichard Lowe 	if ((num != 1) ||
83210d63b7dSRichard Lowe 	    !IS_EQUALN(
83310d63b7dSRichard Lowe 		AR_PORT_END_MAGIC,
83410d63b7dSRichard Lowe 		header->ar_fmag,
83510d63b7dSRichard Lowe 		sizeof (header->ar_fmag)
83610d63b7dSRichard Lowe 	    )
83710d63b7dSRichard Lowe 	) {
83810d63b7dSRichard Lowe 		fatal(
83910d63b7dSRichard Lowe 			gettext("Read error in archive `%s': invalid archive file member header at 0x%x"),
84010d63b7dSRichard Lowe 			filename,
84110d63b7dSRichard Lowe 			ftell(fd)
84210d63b7dSRichard Lowe 		);
84310d63b7dSRichard Lowe 	}
84410d63b7dSRichard Lowe 	return succeeded;
84510d63b7dSRichard Lowe }
84610d63b7dSRichard Lowe 
847