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