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.
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.
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]
22 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 * Deal with the lib.a(member.o) and lib.a((entry-point)) notations
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
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.
42 #include <alloca.h> /* alloca() */
44 #include <errno.h> /* errno */
45 #include <fcntl.h> /* open() */
48 #include <mksh/misc.h> /* retmem_mb() */
52 off_t ran_strx
; /* string table index of */
53 char *ran_name
; /* symbol defined by */
55 off_t ran_off
; /* library member at this offset */
58 #include <unistd.h> /* close() */
70 * Defines for all the different archive formats. See next comment
71 * block for justification for not using <ar.h>s versions.
73 #define AR_5_MAGIC "<ar>" /* 5.0 format magic string */
74 #define AR_5_MAGIC_LENGTH 4 /* 5.0 format string length */
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 */
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
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 */
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 */
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 */
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 */
119 char ar_mode
[8]; /* octal ascii */
121 /* special end-of-header string (AR_PORT_END_MAGIC) */
130 typedef unsigned int ar_port_word
; // must be 4-bytes long
134 /* to distiguish ar format */
136 /* where first ar member header is at */
138 /* where the symbol lookup starts */
140 /* the number of symbols available */
142 /* length of symbol directory file */
155 * File table of contents
157 extern timestruc_t
& read_archive(register Name target
);
158 static Boolean
open_archive(char *filename
, register Ar
*arp
);
159 static void close_archive(register Ar
*arp
);
160 static Boolean
read_archive_dir(register Ar
*arp
, Name library
, char **long_names_table
);
161 static void translate_entry(register Ar
*arp
, Name target
, register Property member
, char **long_names_table
);
162 static long sgetl(char *);
165 * read_archive(target)
167 * Read the contents of an ar file.
170 * The time the member was created
173 * target The member to find time for
175 * Global variables used:
176 * empty_name The Name ""
179 int read_member_header (Ar_port
*header
, FILE *fd
, char* filename
);
180 int process_long_names_member (register Ar
*arp
, char **long_names_table
, char *filename
);
183 read_archive(register Name target
)
185 register Property member
;
187 String_rec true_member_name
;
188 wchar_t buffer
[STRING_BUFFER_LENGTH
];
189 register Name true_member
= NULL
;
191 char *long_names_table
= NULL
; /* Table of long
194 member
= get_prop(target
->prop
, member_prop
);
196 * Check if the member has directory component.
197 * If so, remove the dir and see if we know the date.
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
,
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
,
212 if (true_member
->stat
.time
!= file_no_time
) {
213 target
->stat
.time
= true_member
->stat
.time
;
214 return target
->stat
.time
;
218 if (open_archive(member
->body
.member
.library
->string_mb
, &ar
) == failed
) {
219 if (errno
== ENOENT
) {
220 target
->stat
.stat_errno
= ENOENT
;
222 if (member
->body
.member
.member
== NULL
) {
223 member
->body
.member
.member
= empty_name
;
225 return target
->stat
.time
= file_doesnt_exist
;
227 fatal(gettext("Can't access archive `%s': %s"),
228 member
->body
.member
.library
->string_mb
,
232 if (target
->stat
.time
== file_no_time
) {
233 if (read_archive_dir(&ar
, member
->body
.member
.library
,
236 fatal(gettext("Can't access archive `%s': %s"),
237 member
->body
.member
.library
->string_mb
,
241 if (member
->body
.member
.entry
!= NULL
) {
242 translate_entry(&ar
, target
, member
,&long_names_table
);
245 if (long_names_table
) {
246 retmem_mb(long_names_table
);
248 if (true_member
!= NULL
) {
249 target
->stat
.time
= true_member
->stat
.time
;
251 if (target
->stat
.time
== file_no_time
) {
252 target
->stat
.time
= file_doesnt_exist
;
254 return target
->stat
.time
;
258 * open_archive(filename, arp)
261 * Indicates if open failed or not
264 * filename The name of the archive we need to read
265 * arp Pointer to ar file description block
267 * Global variables used:
270 open_archive(char *filename
, register Ar
*arp
)
273 char mag_5
[AR_5_MAGIC_LENGTH
];
274 char mag_port
[AR_PORT_MAGIC_LENGTH
];
278 fd
= open_vroot(filename
, O_RDONLY
, 0, NULL
, VROOT_DEFAULT
);
279 if ((fd
< 0) || ((arp
->fd
= fdopen(fd
, "r")) == NULL
)) {
282 (void) fcntl(fileno(arp
->fd
), F_SETFD
, 1);
284 if (fread(mag_port
, AR_PORT_MAGIC_LENGTH
, 1, arp
->fd
) != 1) {
287 if (IS_EQUALN(mag_port
, AR_PORT_MAGIC
, AR_PORT_MAGIC_LENGTH
)) {
290 * Read in first member header to find out if there is
291 * a symbol definition table.
294 int ret
= read_member_header(&arp
->ar_port
, arp
->fd
, filename
);
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
);
304 * The following values are the default if there is
305 * no symbol directory and long member names.
307 arp
->sym_size
= arp
->num_symbols
= arp
->sym_begin
= 0L;
308 arp
->first_ar_mem
= ftell(arp
->fd
) - (long) sizeof (Ar_port
);
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 "/ "
316 MBSTOWCS(wcs_buffer, "/ ");
317 if (IS_WEQUALN(arp->ar_port.ar_name, wcs_buffer, 16)) {
319 if (IS_EQUALN(arp
->ar_port
.ar_name
,
322 if (sscanf(arp
->ar_port
.ar_size
,
324 &arp
->sym_size
) != 1) {
327 arp
->sym_size
+= (arp
->sym_size
& 1); /* round up */
328 if (fread(buffer
, sizeof buffer
, 1, arp
->fd
) != 1) {
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
;
338 fatal(gettext("`%s' is not an archive"), filename
);
348 * arp Pointer to ar file description block
350 * Global variables used:
353 close_archive(register Ar
*arp
)
355 if (arp
->fd
!= NULL
) {
356 (void) fclose(arp
->fd
);
361 * read_archive_dir(arp, library, long_names_table)
363 * Reads the directory of an archive and enters all
364 * the members into the make symboltable in lib(member) format
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
374 * Global variables used:
377 read_archive_dir(register Ar
*arp
, Name library
, char **long_names_table
)
379 wchar_t *name_string
;
380 wchar_t *member_string
;
392 * If any of the members has a name > 15 chars,
393 * it will be found here.
395 if (process_long_names_member(arp
, long_names_table
, library
->string_mb
) == failed
) {
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
;
404 if (fseek(arp
->fd
, arp
->first_ar_mem
, 0) != 0) {
407 /* Read the directory using the appropriate format */
411 if (fread((char *) &arp
->arf_5
, sizeof arp
->arf_5
, 1, arp
->fd
)
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
);
426 *p
++ = (int) parenright_char
;
428 name
= GETNAME(name_string
, FIND_LENGTH
);
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.
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
;
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
);
448 ptr
= sgetl(arp
->arf_5
.arf_size
);
450 if (fseek(arp
->fd
, ptr
, 1) != 0) {
457 if ((fread((char *) &arp
->ar_port
,
461 !IS_EQUALN(arp
->ar_port
.ar_fmag
,
463 sizeof arp
->ar_port
.ar_fmag
)) {
468 gettext("Read error in archive `%s': invalid archive file member header at 0x%x"),
473 /* If it's a long name, retrieve it from long name table */
474 if (arp
->ar_port
.ar_name
[0] == '/') {
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
482 len
= ar_member_name_len
;
483 sscanf(arp
->ar_port
.ar_name
+ 1,
486 q
= *long_names_table
+ offset
;
488 q
= arp
->ar_port
.ar_name
;
489 len
= sizeof arp
->ar_port
.ar_name
;
492 for (p
= member_string
;
494 (*q
!= (int) nul_char
) &&
496 (*q
!= (int) slash_char
);
502 *p
++ = (int) parenright_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
);
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'"),
520 * [tolik] Fix for dmake bug 1234018.
522 if(name
->stat
.time
== file_no_time
) {
523 name
->stat
.time
.tv_sec
= date
;
524 name
->stat
.time
.tv_nsec
= LONG_MAX
;
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'"),
533 if (fseek(arp
->fd
, ptr
, 1) != 0) {
540 /* Only here if fread() [or IS_EQUALN()] failed and not at EOF */
542 fatal(gettext("Read error in archive `%s': %s"),
550 * process_long_names_member(arp)
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
560 * arp Pointer to ar file description block
562 * Global variables used:
565 process_long_names_member(register Ar
*arp
, char **long_names_table
, char *filename
)
567 Ar_port
*ar_member_header
;
570 if (fseek(arp
->fd
, arp
->first_ar_mem
, 0) != 0) {
573 if ((ar_member_header
=
574 (Ar_port
*) alloca((int) sizeof(Ar_port
))) == NULL
){
575 perror(gettext("memory allocation failure"));
578 int ret
= read_member_header(ar_member_header
, arp
->fd
, filename
);
581 } else if(ret
== -1) {
582 /* There is no member header - empty archive */
585 /* Do we have special member containing long names? */
586 if (IS_EQUALN(ar_member_header
->ar_name
,
589 if (sscanf(ar_member_header
->ar_size
,
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) {
599 arp
->first_ar_mem
= ftell(arp
->fd
);
605 * translate_entry(arp, target, member)
607 * Finds the member for one lib.a((entry))
610 * arp Pointer to ar file description block
611 * target Target to find member name for
612 * member Property to fill in with info
614 * Global variables used:
617 translate_entry(register Ar
*arp
, Name target
, register Property member
, char **long_names_table
)
621 wchar_t *member_string
;
624 char *syms
; /* string table */
625 char *csym
; /* string table */
626 ar_port_word
*offend
; /* end of offsets table */
628 register wchar_t *ap
;
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
);
640 if (fseek(arp
->fd
, arp
->sym_begin
, 0) != 0) {
643 member_string
= ALLOC_WC((int) ((int) ar_member_name_len
* 2));
647 if ((len
= member
->body
.member
.entry
->hash
.length
) > 8) {
650 for (i
= 0; i
< arp
->num_symbols
; i
++) {
651 if (fread((char *) &arp
->ars_5
,
657 if (IS_EQUALN(arp
->ars_5
.sym_name
,
658 member
->body
.member
.entry
->string_mb
,
661 sgetl(arp
->ars_5
.sym_ptr
),
663 (fread((char *) &arp
->arf_5
,
669 MBSTOWCS(wcs_buffer
, arp
->arf_5
.arf_name
);
670 (void) wcsncpy(member_string
,
673 member_string
[sizeof(arp
->arf_5
.arf_name
)] =
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
;
684 offs
= (ar_port_word
*) alloca((int) (arp
->num_symbols
* AR_PORT_WORD
));
685 if (fread((char *) offs
,
687 (int) arp
->num_symbols
,
688 arp
->fd
) != arp
->num_symbols
) {
692 for(i
=0;i
<arp
->num_symbols
;i
++) {
693 *((int*)buffer
)=offs
[i
];
694 offs
[i
]=(ar_port_word
)sgetl(buffer
);
697 strtablen
=arp
->sym_size
-4-(int) (arp
->num_symbols
* AR_PORT_WORD
);
698 syms
= (char *) alloca(strtablen
);
702 arp
->fd
) != strtablen
) {
705 offend
= &offs
[arp
->num_symbols
];
706 while (offs
< offend
) {
707 maxs
= strlen(member
->body
.member
.entry
->string_mb
);
708 if(strlen(syms
) > maxs
)
711 member
->body
.member
.entry
->string_mb
,
718 if ((fread((char *) &arp
->ar_port
,
722 !IS_EQUALN(arp
->ar_port
.ar_fmag
,
724 sizeof arp
->ar_port
.ar_fmag
)) {
727 if (sscanf(arp
->ar_port
.ar_date
,
730 fatal(gettext("Bad date field for member `%s' in archive `%s'"),
731 arp
->ar_port
.ar_name
,
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,
739 len
= ar_member_name_len
;
740 hp
= *long_names_table
+ offset
;
742 len
= sizeof arp
->ar_port
.ar_name
;
743 hp
= arp
->ar_port
.ar_name
;
747 (*hp
!= (int) slash_char
) &&
748 (ap
< &member_string
[len
])) {
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
;
761 while(*syms
!='\0') syms
++;
765 fatal(gettext("Cannot find symbol `%s' in archive `%s'"),
766 member
->body
.member
.entry
->string_mb
,
767 member
->body
.member
.library
->string_mb
);
771 if (ferror(arp
->fd
)) {
772 fatal(gettext("Read error in archive `%s': %s"),
773 member
->body
.member
.library
->string_mb
,
776 fatal(gettext("Read error in archive `%s': Premature EOF"),
777 member
->body
.member
.library
->string_mb
);
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.
790 * Long int read from buffer
792 * buffer buffer we need to read long int from
794 * Global variables used:
797 sgetl(register char *buffer
)
800 register int i
= BITSPERBYTE
* AR_PORT_WORD
;
802 while ((i
-= BITSPERBYTE
) >= 0) {
803 w
|= (long) ((unsigned char) *buffer
++) << i
;
810 * read_member_header(header, fd, filename)
812 * reads the member header for the 4.1.x and SVr4 archives.
815 * fails if read error or member
816 * header is not the right format
818 * header There's one before each archive member
819 * fd file descriptor for the archive file.
821 * Global variables used:
824 read_member_header(Ar_port
*header
, FILE *fd
, char* filename
)
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 */
835 sizeof (header
->ar_fmag
)
839 gettext("Read error in archive `%s': invalid archive file member header at 0x%x"),