1 /* $RCSfile: arlib.c,v $
3 -- last change: $Author: hr $ $Date: 2006-04-20 12:18:37 $
6 -- Unix archive manipulation code.
9 -- Originally this code was provided by Eric Gisin of MKS. I took
10 -- his code and completely rewrote it adding cacheing of lib members
11 -- and other various optimizations. I kept the overal functional
12 -- idea of the library routines as they are similar to those in GNU
13 -- make and felt it advantageous to maintain a similar interface.
16 -- Dennis Vadura, dvadura@dmake.wticorp.com
19 -- http://dmake.wticorp.com/
22 -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
24 -- This program is NOT free software; you can redistribute it and/or
25 -- modify it under the terms of the Software License Agreement Provided
26 -- in the file <distribution-root>/readme/license.txt.
29 -- Use cvs log to obtain detailed change logs.
32 /* Sun unix on 386i's has a broken ar.h that does not assume PORTAR format
33 * by default, so we fix it here. */
34 #if defined(i386) || defined(__DGUX__)
38 #if !defined (COHERENT) && !defined(__COHERENT__)
42 #endif /* COHERENT, __COHERENT__ */
46 /* By defining the defines below it is possible to configure the library
47 * code for library cacheing/non-cacheing, ASCII archive headers, and a full
48 * decode of the ar_hdr fields in the scan_ar function. */
51 #define ASCARCH 1 /* ASCII time stored in archive */
55 #define LC 1 /* Turn on library cacheing */
59 #define CHECKELF 1 /* Enable Elf long member names */
62 #ifndef DECODE_ALL_AR_FIELDS
63 #define DECODE_ALL_AR_FIELDS 0 /* decode only fields make needs*/
66 #ifndef AR_TRUNCATE_MEMBER_NAMES
67 #define AR_TRUNCATE_MEMBER_NAMES 0 /* truncate member names for */
68 #endif /* comparison. */
71 # define FOUND_MEMBER FALSE
73 # define FOUND_MEMBER TRUE
74 # define _cache_member(a, b, c)
75 # define _check_cache(a, b, c, d) FALSE
78 #define MAXFNAME 255 /* Max length of member name */
79 #define MAXMNAME 8 /* Max module name < MAXFNAME */
82 /* This struct is used to pass the library and member inrmation about the
83 * routines that perform the library seeking/cacheing */
92 char ar_name
[MAXFNAME
+1]; /* File name */
93 long ar_size
; /* Size in bytes */
94 time_t ar_time
; /* Modification time */
97 char ar_modname
[MAXMNAME
+1]; /* DOS module name */
100 #if DECODE_ALL_AR_FIELDS
101 uint16 ar_mode
; /* File mode */
102 uint16 ar_uid
; /* File owner */
103 uint16 ar_gid
; /* File group owner */
108 static int ar_scan
ANSI((FILE *,
109 int (*) ANSI((FILE *, struct AR
*,struct ar_args
*)),
111 static int ar_touch
ANSI(( FILE *, time_t ));
112 static int time_function
ANSI(( FILE *, struct AR
*, struct ar_args
* ));
113 static int touch_function
ANSI(( FILE *, struct AR
*, struct ar_args
* ));
114 static int ar_name_equal
ANSI((char *, char *));
117 static int _cache_member
ANSI((char *, char *, time_t));
118 static int _check_cache
ANSI((char *, char *, time_t *, int));
121 /* decoded archive header */
123 static off_t arhdroffset
; /* member seek offset */
127 seek_arch(name
, lib
)/*
128 ======================
129 Look for module 'name' inside 'lib'. If compiled with cacheing then first
130 check to see if the specified lib is cached. If so then return that time
131 stamp instead of looking into the library. */
140 /* Check the cache first (if there is a cache) */
141 if( _check_cache(name
, lib
, &mtime
, FALSE
) ) return( mtime
);
143 /* Open the lib file and perform the scan of the members, looking
144 * for our particular member. If cacheing is enabled it will be
145 * taken care of automatically during the scan. */
149 args
.time
= (time_t)0L;
151 if( (f
= fopen(lib
, "r")) == NIL(FILE) ) return( (time_t)0L );
152 rv
= ar_scan(f
, time_function
, &args
);
155 if( rv
< 0 ) Fatal("(%s): Invalid library format", lib
);
162 touch_arch(name
, lib
)/*
163 =======================
164 Look for module 'name' inside 'lib'. If compiled with cacheing then first
165 check to see if the specified lib is cached. If so then set that time
166 stamp and write it into the library. Returns 0 on success, non-zero
175 /* Open the lib file and perform the scan of the members, looking
176 * for our particular member. If cacheing is enabled it will be
177 * taken care of automatically during the scan. */
181 args
.time
= (time_t)0L;
183 if( (f
= fopen(lib
, "r+")) == NIL(FILE) ) return( (time_t)1L );
184 rv
= ar_scan(f
, touch_function
, &args
);
187 if( rv
< 0 ) Fatal("(%s): Invalid library format", lib
);
195 time_function(f
, arp
, argp
)/*
196 =============================
197 get library member's time, if it matches than return it in argp, if
198 cacheing is enabled than cache the library members also. */
199 FILE *f
; /* library file */
200 struct AR
*arp
; /* library member header */
201 struct ar_args
*argp
;
203 int rv
= _cache_member( arp
->ar_name
, argp
->lib
, arp
->ar_time
);
205 if( ar_name_equal (argp
->member
, arp
->ar_name
)) {
206 argp
->time
= arp
->ar_time
;
208 if( arp
->ar_time
== 0 && !(Glob_attr
& A_SILENT
) )
209 Warning( "(%s): Can't extract library member timestamp; using EPOCH",
212 return( rv
); /* 1 => no cacheing, 0 => cacheing */
215 return( FALSE
); /* continue scan */
221 touch_function(f
, arp
, argp
)/*
222 ==============================
223 Update library member's time stamp, and write new time value into cache
225 FILE *f
; /* library file */
226 struct AR
*arp
; /* library member header */
227 struct ar_args
*argp
;
229 extern time_t time
ANSI(( time_t * ));
230 time_t now
= time((time_t*) NULL
); /* Current time. */
232 if( ar_name_equal(argp
->member
, arp
->ar_name
) ) {
233 _check_cache( argp
->member
, argp
->lib
, &now
, TRUE
);
239 return( FALSE
); /* continue scan */
244 ar_name_equal (char * name1
, char * name2
)
248 #if AR_TRUNCATE_MEMBER_NAMES
251 equal
= !strncmp (name1
, name2
, sizeof (hdr
.ar_name
)-1);
253 equal
= !strcmp (name1
, name2
);
261 ar_scan(f
, function
, arg
)/*
262 ===========================
263 Scan the opened archive, and call the given function for each member found.
264 The function will be called with the file positioned at the beginning of
265 the member and it can read up to arp->ar_size bytes of the archive member.
266 If the function returns 1, we stop and return 1. We return 0 at the end
267 of the archive, or -1 if the archive has invalid format. This interface
268 is more general than required by "make", but it can be used by other
271 int (*function
) ANSI((FILE *, struct AR
*, struct ar_args
*));
276 struct ar_hdr arhdr
; /* archive member header */
277 long nsize
; /* size of member name */
278 long arind
=0; /* archive index offset */
281 struct fl_hdr flhdr
; /* archive file header */
282 char magic
[SAIAMAG
]; /* size of magic string */
291 fseek( f
, 0L, 0 ); /* Start at the beginning of the archive file */
295 fread( (char *)&flhdr
, sizeof(flhdr
), 1, f
);
296 if( strncmp(flhdr
.fl_magic
,AIAMAG
, SAIAMAG
) != 0 ) return(-1);
297 fseek(f
, atol(flhdr
.fl_fstmoff
), 0 ); /* postition to first member */
299 fread( magic
, sizeof(magic
), 1, f
);
300 if( strncmp(magic
, ARMAG
, SARMAG
) != 0 ) return( -1 );
303 fread( (char*)&word
, sizeof(word
), 1, f
);
304 if( word
!= ARMAG
) return( -1 );
307 /* scan the library, calling `function' for each member
310 arhdroffset
= ftell(f
);
312 if( fread((char*)&arhdr
,sizeof(arhdr
)-sizeof(arhdr
._ar_name
),1,f
)!=1)
314 nsize
= atoi(arhdr
.ar_namlen
);
315 fseek(f
, arhdroffset
+(unsigned long)(((struct ar_hdr
*)0)->_ar_name
.ar_name
), 0);
316 if( fread((char*)_ar
.ar_name
,nsize
,1,f
)!=1)
318 _ar
.ar_name
[nsize
]='\0';
320 if( fread((char*) &arhdr
, sizeof(arhdr
), 1, f
) != 1 ) break;
321 strncpy(_ar
.ar_name
, arhdr
.ar_name
, nsize
= sizeof(arhdr
.ar_name
));
324 for( p
= &_ar
.ar_name
[nsize
];
325 --p
>= _ar
.ar_name
&& *p
== ' ';);
328 if( *p
== '/' ) *p
= 0; /* SysV has trailing '/' */
330 /* check to see if this is an archive index using SsysV Index scheme.
331 * see ar(4) man page for more info */
333 if( _ar
.ar_name
[0] == '/' && _ar
.ar_name
[1] == '\0' ) {
334 arind
= arhdroffset
+sizeof(arhdr
);
343 if( strncmp(arhdr
.ar_fmag
, ARFMAG
, sizeof(arhdr
.ar_fmag
)) != 0 )
345 _ar
.ar_time
= atol(arhdr
.ar_date
);
346 _ar
.ar_size
= atol(arhdr
.ar_size
);
348 _ar
.ar_time
= arhdr
.ar_date
;
349 _ar
.ar_size
= arhdr
.ar_size
;
352 /* check for names of the form /xxxx where xxxx is an offset into the
353 * name table pointed at by arind. */
354 if(arind
&& _ar
.ar_name
[0] == '/') {
355 long offset
= atol(_ar
.ar_name
+1);
356 long here
= ftell(f
);
359 fseek(f
, arind
+offset
, 0);
361 while((c
=fgetc(f
)) != EOF
) {
369 if (c
==EOF
) return(-1); /* 'c' should never be EOF */
375 _ar
.ar_time
= atol(arhdr
.ar_date
);
376 _ar
.ar_size
= atol(arhdr
.ar_nxtmem
);
378 _ar
.ar_time
= arhdr
.ar_date
;
379 _ar
.ar_size
= arhdr
.ar_nxtmem
;
384 #if DECODE_ALL_AR_FIELDS
386 _ar
.ar_mode
= atoi(arhdr
.ar_mode
);
387 _ar
.ar_uid
= atoi(arhdr
.ar_uid
);
388 _ar
.ar_gid
= atoi(arhdr
.ar_gid
);
390 _ar
.ar_mode
= arhdr
.ar_mode
;
391 _ar
.ar_uid
= arhdr
.ar_uid
;
392 _ar
.ar_gid
= arhdr
.ar_gid
;
395 if( process
&& (*function
)(f
, &_ar
, arg
) ) return( 1 );
398 if( _ar
.ar_size
== 0L ) break;
399 fseek( f
, (long) _ar
.ar_size
, 0 );
401 fseek( f
, arhdroffset
+ sizeof(arhdr
) + ((_ar
.ar_size
+1) & ~1L), 0 );
406 if( !feof(f
) ) return( -1 );
416 touch module header timestamp. */
421 fseek(f
, arhdroffset
+ (unsigned long)(((struct ar_hdr
*)0)->ar_date
), 0);
424 fprintf(f
, "%lu", now
);
426 fwrite((char *)now
, sizeof(now
), 1, f
);
429 return( ferror(f
) ? 0 : 1 );
435 time_t m_time
; /* modify time of member*/
436 struct mem
*m_next
; /* next member in lib */
437 char m_valid
; /* valid cache entry */
438 char m_name
[1]; /* lib member name */
442 struct lib
*lb_next
; /* next library in list */
443 struct mem
*lb_members
; /* list of lib members */
444 char lb_valid
; /* valid cache entry */
445 char *lb_name
; /* library name */
448 static LIBPTR _cache
= NIL(LIB
);
449 static MEMPTR _find_member
ANSI(( LIBPTR
, char * ));
452 _check_cache( name
, lib
, pmtime
, touch
)/*
453 ==========================================
454 Check to see if we have cached member in lib, if so return time in pmtime
455 and return TRUE, otherwise return FALSE, if touch is TRUE then touch
456 the archive member instead. */
465 for( lp
=_cache
; lp
!= NIL(LIB
) && lp
->lb_name
!= lib
; lp
=lp
->lb_next
);
466 if( lp
== NIL(LIB
) ) return( FALSE
);
468 mp
= _find_member( lp
, name
);
469 if( mp
== NIL(MEM
) || !mp
->m_valid
) return( FALSE
);
473 mp
->m_time
= *pmtime
;
477 *pmtime
= mp
->m_time
;
488 _cache_member( name
, lib
, mtime
)/*
489 ===================================
490 Cache name in lib along with it's time */
499 lp
!= NIL(LIB
) && lp
->lb_name
!= NIL(char) && lp
->lb_name
!= lib
;
504 lp
= (LIBPTR
) malloc(sizeof(LIB
));
505 if( lp
== NIL(LIB
) ) No_ram();
508 lp
->lb_members
= NIL(MEM
);
509 lp
->lb_next
= _cache
;
514 /* On UNIX ar does not allow multiple copies of the same .o file to live
515 * in the same AR file. If this is not TRUE then use the commented out
516 * version to set the value of mp. */
518 /*mp = _find_member(lp, name);*/
523 mp
= (MEMPTR
) malloc(sizeof(char)*offsetof(MEM
,m_name
[strlen(name
)+1]));
524 if( mp
== NIL(MEM
) ) No_ram();
526 strcpy( mp
->m_name
, name
);
529 if( lp
->lb_members
== NIL(MEM
) ) {
534 mp
->m_next
= lp
->lb_members
->m_next
;
535 lp
->lb_members
->m_next
= mp
;
544 return( lp
->lb_valid
);
549 _find_member( lp
, name
)
553 register MEMPTR mp
= lp
->lb_members
;
555 if( mp
== NIL(MEM
) ) return(mp
);
558 if( !strcmp(mp
->m_name
, name
) ) return( mp
);
561 while( mp
!= lp
->lb_members
);
570 void_lcache( lib
, member
)/*
571 ============================
572 Void the library cache for lib. If member is NIL(char) then nuke all
573 of the members, if member is NOT NIL(char) then invalidate only that
583 for( lp
=_cache
; lp
!= NIL(LIB
) && lp
->lb_name
!= lib
; lp
=lp
->lb_next
);
584 if( lp
== NIL(LIB
) ) return;
586 if( member
== NIL(char) ) {
592 } while( mp
!= lp
->lb_members
);
595 lp
->lb_members
= NIL(MEM
);
596 lp
->lb_name
= NIL(char);
601 if( strcmp( member
, mp
->m_name
) == 0 ) {
602 lp
->lb_members
= mp
->m_next
;
607 } while( mp
!= lp
->lb_members
);