1 /* *** This file was borrowed from jam 2.5. The copyright statement from
2 * *** jam.c appears below.
3 */
4 /*
5 * /+\
6 * +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
7 * \+/
8 *
9 * This file is part of jam.
10 *
11 * License is hereby granted to use this software and distribute it
12 * freely, as long as this copyright notice is retained and modifications
13 * are clearly marked.
14 *
15 * ALL WARRANTIES ARE HEREBY DISCLAIMED.
16 */
17
18 /*
19 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
20 *
21 * This file is part of Jam - see jam.c for Copyright information.
22 */
23
24 /*
25 * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
26 *
27 * External routines:
28 *
29 * file_dirscan() - scan a directory for files
30 * file_time() - get timestamp of file, if not done by file_dirscan()
31 * file_archscan() - scan an archive for files
32 *
33 * File_dirscan() and file_archscan() call back a caller provided function
34 * for each file found. A flag to this callback function lets file_dirscan()
35 * and file_archscan() indicate that a timestamp is being provided with the
36 * file. If file_dirscan() or file_archscan() do not provide the file's
37 * timestamp, interested parties may later call file_time().
38 *
39 * 04/08/94 (seiwald) - Coherent/386 support added.
40 * 12/19/94 (mikem) - solaris string table insanity support
41 * 02/14/95 (seiwald) - parse and build /xxx properly
42 * 05/03/96 (seiwald) - split into pathunix.c
43 * 11/21/96 (peterk) - BEOS does not have Unix-style archives
44 * 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
45 * 04/03/01 (seiwald) - AIX uses SARMAG
46 * 07/16/02 (seiwald) - Support BSD style long filename in archives.
47 * 11/04/02 (seiwald) - const-ing for string literals
48 * 12/27/02 (seiwald) - support for AIX big archives
49 * 12/30/02 (seiwald) - terminate ar_hdr for solaris sscanf()
50 * 12/30/02 (seiwald) - skip solaris' empty archive member names (/, //xxx)
51 */
52
53 # include "jam.h"
54 # include "filesys.h"
55 # include "pathsys.h"
56
57 # ifdef USE_FILEUNIX
58
59 #if defined(OS_CYGWIN) /* TNB */
60 #include <sys/unistd.h>
61 # include <sys/stat.h>
62 #endif
63
64 # if defined( OS_SEQUENT ) || \
65 defined( OS_DGUX ) || \
66 defined( OS_SCO ) || \
67 defined( OS_ISC )
68 # define PORTAR 1
69 # endif
70
71 # if defined( OS_RHAPSODY ) || \
72 defined( OS_MACOSX ) || \
73 defined( OS_NEXT )
74 /* need unistd for rhapsody's proper lseek */
75 # include <sys/dir.h>
76 # include <unistd.h>
77 # define STRUCT_DIRENT struct direct
78 # else
79 # include <dirent.h>
80 # define STRUCT_DIRENT struct dirent
81 # endif
82
83 /* needed under SuSE 9.2 at least */
84 #include <sys/stat.h>
85 #include <unistd.h>
86
87 # ifdef OS_COHERENT
88 # include <arcoff.h>
89 # define HAVE_AR
90 # endif
91
92 # if defined( OS_MVS ) || \
93 defined( OS_INTERIX )
94
95 #define ARMAG "!<arch>\n"
96 #define SARMAG 8
97 #define ARFMAG "`\n"
98
99 struct ar_hdr /* archive file member header - printable ascii */
100 {
101 char ar_name[16]; /* file member name - `/' terminated */
102 char ar_date[12]; /* file member date - decimal */
103 char ar_uid[6]; /* file member user id - decimal */
104 char ar_gid[6]; /* file member group id - decimal */
105 char ar_mode[8]; /* file member mode - octal */
106 char ar_size[10]; /* file member size - decimal */
107 char ar_fmag[2]; /* ARFMAG - string to end header */
108 };
109
110 # define HAVE_AR
111 # endif
112
113 # if defined( OS_QNX ) || \
114 defined( OS_BEOS ) || \
115 defined( OS_MPEIX )
116 # define NO_AR
117 # define HAVE_AR
118 # endif
119
120 # ifndef HAVE_AR
121 # ifdef _AIX43
122 /* AIX 43 ar SUPPORTs only __AR_BIG__ */
123 # define __AR_BIG__
124 # endif
125 # include <ar.h>
126 # endif
127
128 /*
129 * file_dirscan() - scan a directory for files
130 */
131
132 void
file_dirscan(const char * dir,scanback func,void * closure)133 file_dirscan(
134 const char *dir,
135 scanback func,
136 void *closure )
137 {
138 PATHNAME f;
139 DIR *d;
140 STRUCT_DIRENT *dirent;
141 char filename[ MAXJPATH ];
142
143 /* First enter directory itself */
144
145 memset( (char *)&f, '\0', sizeof( f ) );
146
147 f.f_dir.ptr = dir;
148 f.f_dir.len = strlen(dir);
149
150 dir = *dir ? dir : ".";
151
152 /* Special case / : enter it */
153
154 if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '/' )
155 (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
156
157 /* Now enter contents of directory */
158
159 if( !( d = opendir( dir ) ) )
160 return;
161
162 if( DEBUG_BINDSCAN )
163 printf( "scan directory %s\n", dir );
164
165 while( (dirent = readdir( d )) )
166 {
167 # ifdef old_sinix
168 /* Broken structure definition on sinix. */
169 f.f_base.ptr = dirent->d_name - 2;
170 # else
171 f.f_base.ptr = dirent->d_name;
172 # endif
173 f.f_base.len = strlen( f.f_base.ptr );
174
175 path_build( &f, filename, 0 );
176
177 (*func)( closure, filename, 0 /* not stat()'ed */, (time_t)0 );
178 }
179
180 closedir( d );
181 }
182
183 /*
184 * file_time() - get timestamp of file, if not done by file_dirscan()
185 */
186
187 int
file_time(const char * filename,time_t * time)188 file_time(
189 const char *filename,
190 time_t *time )
191 {
192 struct stat statbuf;
193
194 if( stat( filename, &statbuf ) < 0 )
195 return -1;
196
197 *time = statbuf.st_mtime;
198 return 0;
199 }
200
201 /*
202 * file_archscan() - scan an archive for files
203 */
204
205 # ifndef AIAMAG /* God-fearing UNIX */
206
207 # define SARFMAG 2
208 # define SARHDR sizeof( struct ar_hdr )
209
210 void
file_archscan(const char * archive,scanback func,void * closure)211 file_archscan(
212 const char *archive,
213 scanback func,
214 void *closure )
215 {
216 # ifndef NO_AR
217 struct ar_hdr ar_hdr;
218 char buf[ MAXJPATH ];
219 long offset;
220 char *string_table = 0;
221 int fd;
222
223 if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
224 return;
225
226 if( read( fd, buf, SARMAG ) != SARMAG ||
227 strncmp( ARMAG, buf, SARMAG ) )
228 {
229 close( fd );
230 return;
231 }
232
233 offset = SARMAG;
234
235 if( DEBUG_BINDSCAN )
236 printf( "scan archive %s\n", archive );
237
238 while( read( fd, &ar_hdr, SARHDR ) == SARHDR &&
239 !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
240 {
241 long lar_date;
242 long lar_size;
243 char lar_name[256];
244 char *dst = lar_name;
245
246 /* solaris sscanf() does strlen first, so terminate somewhere */
247
248 ar_hdr.ar_fmag[0] = 0;
249
250 /* Get date & size */
251
252 sscanf( ar_hdr.ar_date, "%ld", &lar_date );
253 sscanf( ar_hdr.ar_size, "%ld", &lar_size );
254
255 /* Handle solaris string table.
256 ** The entry under the name // is the table,
257 ** and entries with the name /nnnn refer to the table.
258 */
259
260 if( ar_hdr.ar_name[0] != '/' )
261 {
262 /* traditional archive entry names:
263 ** ends at the first space, /, or null.
264 */
265
266 char *src = ar_hdr.ar_name;
267 const char *e = src + sizeof( ar_hdr.ar_name );
268
269 while( src < e && *src && *src != ' ' && *src != '/' )
270 *dst++ = *src++;
271 }
272 else if( ar_hdr.ar_name[1] == '/' )
273 {
274 /* this is the "string table" entry of the symbol table,
275 ** which holds strings of filenames that are longer than
276 ** 15 characters (ie. don't fit into a ar_name)
277 */
278
279 string_table = (char *)malloc(lar_size);
280
281 lseek(fd, offset + SARHDR, 0);
282 if( read(fd, string_table, lar_size) != lar_size )
283 printf( "error reading string table\n" );
284 }
285 else if( string_table && ar_hdr.ar_name[1] != ' ' )
286 {
287 /* Long filenames are recognized by "/nnnn" where nnnn is
288 ** the offset of the string in the string table represented
289 ** in ASCII decimals.
290 */
291
292 char *src = string_table + atoi( ar_hdr.ar_name + 1 );
293
294 while( *src != '/' )
295 *dst++ = *src++;
296 }
297
298 /* Terminate lar_name */
299
300 *dst = 0;
301
302 /* Modern (BSD4.4) long names: if the name is "#1/nnnn",
303 ** then the actual name is the nnnn bytes after the header.
304 */
305
306 if( !strcmp( lar_name, "#1" ) )
307 {
308 int len = atoi( ar_hdr.ar_name + 3 );
309 if( read( fd, lar_name, len ) != len )
310 printf("error reading archive entry\n");
311 lar_name[len] = 0;
312 }
313
314 /* Build name and pass it on. */
315
316 if( lar_name[0] )
317 {
318 if( DEBUG_BINDSCAN )
319 printf( "archive name %s found\n", lar_name );
320
321 sprintf( buf, "%s(%s)", archive, lar_name );
322
323 (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
324 }
325
326 /* Position at next member */
327
328 offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
329 lseek( fd, offset, 0 );
330 }
331
332 if (string_table)
333 free(string_table);
334
335 close( fd );
336
337 # endif /* NO_AR */
338
339 }
340
341 # else /* AIAMAG - RS6000 AIX */
342
343 void
file_archscan(const char * archive,scanback func,void * closure)344 file_archscan(
345 const char *archive,
346 scanback func,
347 void *closure )
348 {
349 struct fl_hdr fl_hdr;
350
351 struct {
352 struct ar_hdr hdr;
353 char pad[ 256 ];
354 } ar_hdr ;
355
356 char buf[ MAXJPATH ];
357 long offset;
358 int fd;
359
360 if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
361 return;
362
363 # ifdef __AR_BIG__
364
365 if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ ||
366 strncmp( AIAMAGBIG, fl_hdr.fl_magic, SAIAMAG ) )
367 {
368 if( strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) )
369 printf( "Can't read new archive %s before AIX 4.3.\n" );
370
371 close( fd );
372 return;
373 }
374
375 # else
376
377 if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ ||
378 strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) )
379 {
380 close( fd );
381 return;
382 }
383
384 # endif
385
386 sscanf( fl_hdr.fl_fstmoff, "%ld", &offset );
387
388 if( DEBUG_BINDSCAN )
389 printf( "scan archive %s\n", archive );
390
391 while( offset > 0 &&
392 lseek( fd, offset, 0 ) >= 0 &&
393 read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) )
394 {
395 long lar_date;
396 int lar_namlen;
397
398 sscanf( ar_hdr.hdr.ar_namlen, "%d", &lar_namlen );
399 sscanf( ar_hdr.hdr.ar_date, "%ld", &lar_date );
400 sscanf( ar_hdr.hdr.ar_nxtmem, "%ld", &offset );
401
402 if( !lar_namlen )
403 continue;
404
405 ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0';
406
407 sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
408
409 (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
410 }
411
412 close( fd );
413 }
414
415 # endif /* AIAMAG - RS6000 AIX */
416
417 # endif /* USE_FILEUNIX */
418
419