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