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