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