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