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