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