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