Imported Upstream version 201104
[platform/upstream/boost-jam.git] / fileunix.c
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 /*  This file is ALSO:
8  *  Copyright 2001-2004 David Abrahams.
9  *  Copyright 2005 Rene Rivera.
10  *  Distributed under the Boost Software License, Version 1.0.
11  *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
12  */
13
14 # include "jam.h"
15 # include "filesys.h"
16 # include "strings.h"
17 # include "pathsys.h"
18 # include "newstr.h"
19 # include <stdio.h>
20 # include <sys/stat.h>
21
22 #if defined(sun) || defined(__sun) || defined(linux)
23 # include <unistd.h> /* needed for read and close prototype */
24 #endif
25
26 # ifdef USE_FILEUNIX
27
28 #if defined(sun) || defined(__sun)
29 # include <unistd.h> /* needed for read and close prototype */
30 #endif
31
32 # if defined( OS_SEQUENT ) || \
33      defined( OS_DGUX ) || \
34      defined( OS_SCO ) || \
35      defined( OS_ISC )
36 # define PORTAR 1
37 # endif
38
39 # ifdef __EMX__
40 # include <sys/types.h>
41 # include <sys/stat.h>
42 # endif
43
44 # if defined( OS_RHAPSODY ) || \
45      defined( OS_MACOSX ) || \
46      defined( OS_NEXT )
47 /* need unistd for rhapsody's proper lseek */
48 # include <sys/dir.h>
49 # include <unistd.h>
50 # define STRUCT_DIRENT struct direct
51 # else
52 # include <dirent.h>
53 # define STRUCT_DIRENT struct dirent
54 # endif
55
56 # ifdef OS_COHERENT
57 # include <arcoff.h>
58 # define HAVE_AR
59 # endif
60
61 # if defined( OS_MVS ) || \
62          defined( OS_INTERIX )
63
64 #define ARMAG   "!<arch>\n"
65 #define SARMAG  8
66 #define ARFMAG  "`\n"
67
68 struct ar_hdr       /* archive file member header - printable ascii */
69 {
70     char    ar_name[16];    /* file member name - `/' terminated */
71     char    ar_date[12];    /* file member date - decimal */
72     char    ar_uid[6];  /* file member user id - decimal */
73     char    ar_gid[6];  /* file member group id - decimal */
74     char    ar_mode[8]; /* file member mode - octal */
75     char    ar_size[10];    /* file member size - decimal */
76     char    ar_fmag[2]; /* ARFMAG - string to end header */
77 };
78
79 # define HAVE_AR
80 # endif
81
82 # if defined( OS_QNX ) || \
83      defined( OS_BEOS ) || \
84      defined( OS_MPEIX )
85 # define NO_AR
86 # define HAVE_AR
87 # endif
88
89 # ifndef HAVE_AR
90
91 # ifdef OS_AIX
92 /* Define those for AIX to get the definitions for both the small and the
93  * big variant of the archive file format. */
94 #    define __AR_SMALL__
95 #    define __AR_BIG__
96 # endif
97
98 # include <ar.h>
99 # endif
100
101 /*
102  * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
103  *
104  * External routines:
105  *
106  *  file_dirscan() - scan a directory for files
107  *  file_time() - get timestamp of file, if not done by file_dirscan()
108  *  file_archscan() - scan an archive for files
109  *
110  * File_dirscan() and file_archscan() call back a caller provided function
111  * for each file found.  A flag to this callback function lets file_dirscan()
112  * and file_archscan() indicate that a timestamp is being provided with the
113  * file.   If file_dirscan() or file_archscan() do not provide the file's
114  * timestamp, interested parties may later call file_time().
115  *
116  * 04/08/94 (seiwald) - Coherent/386 support added.
117  * 12/19/94 (mikem) - solaris string table insanity support
118  * 02/14/95 (seiwald) - parse and build /xxx properly
119  * 05/03/96 (seiwald) - split into pathunix.c
120  * 11/21/96 (peterk) - BEOS does not have Unix-style archives
121  */
122
123
124 /*
125  * file_dirscan() - scan a directory for files.
126  */
127
128 void file_dirscan( char * dir, scanback func, void * closure )
129 {
130     PROFILE_ENTER( FILE_DIRSCAN );
131
132     file_info_t * d = 0;
133
134     d = file_query( dir );
135
136     if ( !d || !d->is_dir )
137     {
138         PROFILE_EXIT( FILE_DIRSCAN );
139         return;
140     }
141
142     if ( ! d->files )
143     {
144         LIST* files = L0;
145         PATHNAME f;
146         DIR *dd;
147         STRUCT_DIRENT *dirent;
148         string filename[1];
149
150         /* First enter directory itself */
151
152         memset( (char *)&f, '\0', sizeof( f ) );
153
154         f.f_dir.ptr = dir;
155         f.f_dir.len = strlen(dir);
156
157         dir = *dir ? dir : ".";
158
159         /* Now enter contents of directory. */
160
161         if ( !( dd = opendir( dir ) ) )
162         {
163             PROFILE_EXIT( FILE_DIRSCAN );
164             return;
165         }
166
167         if ( DEBUG_BINDSCAN )
168             printf( "scan directory %s\n", dir );
169
170         string_new( filename );
171         while ( ( dirent = readdir( dd ) ) )
172         {
173             # ifdef old_sinix
174             /* Broken structure definition on sinix. */
175             f.f_base.ptr = dirent->d_name - 2;
176             # else
177             f.f_base.ptr = dirent->d_name;
178             # endif
179             f.f_base.len = strlen( f.f_base.ptr );
180
181             string_truncate( filename, 0 );
182             path_build( &f, filename, 0 );
183
184             files = list_new( files, newstr(filename->value) );
185             file_query( filename->value );
186         }
187         string_free( filename );
188
189         closedir( dd );
190
191         d->files = files;
192     }
193
194     /* Special case / : enter it */
195     {
196         unsigned long len = strlen(d->name);
197         if ( ( len == 1 ) && ( d->name[0] == '/' ) )
198             (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
199     }
200
201     /* Now enter contents of directory */
202     if ( d->files )
203     {
204         LIST * files = d->files;
205         while ( files )
206         {
207             file_info_t * ff = file_info( files->string );
208             (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
209             files = list_next( files );
210         }
211     }
212
213     PROFILE_EXIT( FILE_DIRSCAN );
214 }
215
216
217 file_info_t * file_query( char * filename )
218 {
219     file_info_t * ff = file_info( filename );
220     if ( ! ff->time )
221     {
222         struct stat statbuf;
223
224         if ( stat( *filename ? filename : ".", &statbuf ) < 0 )
225             return 0;
226
227         ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
228         ff->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0;
229         ff->size = statbuf.st_size;
230         ff->time = statbuf.st_mtime ? statbuf.st_mtime : 1;
231     }
232     return ff;
233 }
234
235 /*
236  * file_time() - get timestamp of file, if not done by file_dirscan()
237  */
238
239 int
240 file_time(
241     char    *filename,
242     time_t  *time )
243 {
244     file_info_t * ff = file_query( filename );
245     if ( !ff ) return -1;
246     *time = ff->time;
247     return 0;
248 }
249
250 int file_is_file(char* filename)
251 {
252     file_info_t * ff = file_query( filename );
253     if ( !ff ) return -1;
254     return ff->is_file;
255 }
256
257 int file_mkdir(char* pathname)
258 {
259     return mkdir(pathname, 0766);
260 }
261
262 /*
263  * file_archscan() - scan an archive for files
264  */
265
266 # ifndef AIAMAG /* God-fearing UNIX */
267
268 # define SARFMAG 2
269 # define SARHDR sizeof( struct ar_hdr )
270
271 void
272 file_archscan(
273     char *archive,
274     scanback func,
275     void *closure )
276 {
277 # ifndef NO_AR
278     struct ar_hdr ar_hdr;
279     char buf[ MAXJPATH ];
280     long offset;
281     char    *string_table = 0;
282     int fd;
283
284     if ( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
285         return;
286
287     if ( read( fd, buf, SARMAG ) != SARMAG ||
288         strncmp( ARMAG, buf, SARMAG ) )
289     {
290         close( fd );
291         return;
292     }
293
294     offset = SARMAG;
295
296     if ( DEBUG_BINDSCAN )
297         printf( "scan archive %s\n", archive );
298
299     while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR )
300            && !( memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG )
301 #ifdef ARFZMAG
302               /* OSF also has a compressed format */
303               && memcmp( ar_hdr.ar_fmag, ARFZMAG, SARFMAG )
304 #endif
305           ) )
306     {
307         char   lar_name_[257];
308         char * lar_name = lar_name_ + 1;
309         long   lar_date;
310         long   lar_size;
311         long   lar_offset;
312         char * c;
313         char * src;
314         char * dest;
315
316         strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );
317
318         sscanf( ar_hdr.ar_date, "%ld", &lar_date );
319         sscanf( ar_hdr.ar_size, "%ld", &lar_size );
320
321         if (ar_hdr.ar_name[0] == '/')
322         {
323         if (ar_hdr.ar_name[1] == '/')
324         {
325             /* this is the "string table" entry of the symbol table,
326             ** which holds strings of filenames that are longer than
327             ** 15 characters (ie. don't fit into a ar_name
328             */
329
330             string_table = (char *)BJAM_MALLOC_ATOMIC(lar_size);
331             lseek(fd, offset + SARHDR, 0);
332             if (read(fd, string_table, lar_size) != lar_size)
333             printf("error reading string table\n");
334         }
335         else if (string_table && ar_hdr.ar_name[1] != ' ')
336         {
337             /* Long filenames are recognized by "/nnnn" where nnnn is
338             ** the offset of the string in the string table represented
339             ** in ASCII decimals.
340             */
341             dest = lar_name;
342             lar_offset = atoi(lar_name + 1);
343             src = &string_table[lar_offset];
344             while (*src != '/')
345             *dest++ = *src++;
346             *dest = '/';
347         }
348         }
349
350         c = lar_name - 1;
351         while ( ( *++c != ' ' ) && ( *c != '/' ) ) ;
352         *c = '\0';
353
354         if ( DEBUG_BINDSCAN )
355         printf( "archive name %s found\n", lar_name );
356
357         sprintf( buf, "%s(%s)", archive, lar_name );
358
359         (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
360
361         offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
362         lseek( fd, offset, 0 );
363     }
364
365     if (string_table)
366         BJAM_FREE(string_table);
367
368     close( fd );
369
370 # endif /* NO_AR */
371
372 }
373
374 # else /* AIAMAG - RS6000 AIX */
375
376 static void file_archscan_small(
377     int fd, char const *archive, scanback func, void *closure)
378 {
379     struct fl_hdr fl_hdr;
380
381     struct {
382         struct ar_hdr hdr;
383         char pad[ 256 ];
384     } ar_hdr ;
385
386     char buf[ MAXJPATH ];
387     long offset;
388
389     if ( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ)
390         return;
391
392     sscanf( fl_hdr.fl_fstmoff, "%ld", &offset );
393
394     if ( DEBUG_BINDSCAN )
395         printf( "scan archive %s\n", archive );
396
397     while ( ( offset > 0 )
398            && ( lseek( fd, offset, 0 ) >= 0 )
399            && ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) ) )
400     {
401         long lar_date;
402         int  lar_namlen;
403
404         sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
405         sscanf( ar_hdr.hdr.ar_date  , "%ld", &lar_date   );
406         sscanf( ar_hdr.hdr.ar_nxtmem, "%ld", &offset     );
407
408         if ( !lar_namlen )
409             continue;
410
411         ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0';
412
413         sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
414
415         (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
416     }
417 }
418
419 /* Check for OS version which supports the big variant. */
420 #ifdef AR_HSZ_BIG
421
422 static void file_archscan_big(
423     int fd, char const *archive, scanback func, void *closure)
424 {
425     struct fl_hdr_big fl_hdr;
426
427     struct {
428         struct ar_hdr_big hdr;
429         char pad[ 256 ];
430     } ar_hdr ;
431
432     char buf[ MAXJPATH ];
433     long long offset;
434
435     if ( read( fd, (char *)&fl_hdr, FL_HSZ_BIG) != FL_HSZ_BIG)
436         return;
437
438     sscanf( fl_hdr.fl_fstmoff, "%lld", &offset );
439
440     if ( DEBUG_BINDSCAN )
441         printf( "scan archive %s\n", archive );
442
443     while ( ( offset > 0 )
444            && ( lseek( fd, offset, 0 ) >= 0 )
445            && ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) ) )
446     {
447         long lar_date;
448         int  lar_namlen;
449
450         sscanf( ar_hdr.hdr.ar_namlen, "%d"  , &lar_namlen );
451         sscanf( ar_hdr.hdr.ar_date  , "%ld" , &lar_date   );
452         sscanf( ar_hdr.hdr.ar_nxtmem, "%lld", &offset     );
453
454         if ( !lar_namlen )
455             continue;
456
457         ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0';
458
459         sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
460
461         (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
462     }
463
464 }
465
466 #endif /* AR_HSZ_BIG */
467
468 void file_archscan(char *archive, scanback func, void *closure)
469 {
470     int fd;
471     char fl_magic[SAIAMAG];
472
473     if (( fd = open(archive, O_RDONLY, 0)) < 0)
474         return;
475
476     if (read( fd, fl_magic, SAIAMAG) != SAIAMAG
477        || lseek(fd, 0, SEEK_SET) == -1)
478     {
479         close(fd);
480         return;
481     }
482
483     if (strncmp(AIAMAG, fl_magic, SAIAMAG) == 0)
484     {
485         /* read small variant */
486         file_archscan_small(fd, archive, func, closure);
487     }
488 #ifdef AR_HSZ_BIG
489     else if (strncmp(AIAMAGBIG, fl_magic, SAIAMAG) == 0)
490     {
491         /* read big variant */
492         file_archscan_big(fd, archive, func, closure);
493     }
494 #endif
495
496     close( fd );
497 }
498
499 # endif /* AIAMAG - RS6000 AIX */
500
501 # endif /* USE_FILEUNIX */