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