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