2 * Copyright 1993, 1995 Christopher Seiwald.
4 * This file is part of Jam - see jam.c for Copyright information.
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)
24 # if __BORLANDC__ < 0x550
28 # undef FILENAME /* cpp namespace collision */
29 # define _finddata_t ffblk
33 # include <sys/stat.h>
38 * filent.c - scan directories and archives on NT
42 * file_dirscan() - scan a directory for files
43 * file_time() - get timestamp of file, if not done by file_dirscan()
44 * file_archscan() - scan an archive for files
46 * File_dirscan() and file_archscan() call back a caller provided function
47 * for each file found. A flag to this callback function lets file_dirscan()
48 * and file_archscan() indicate that a timestamp is being provided with the
49 * file. If file_dirscan() or file_archscan() do not provide the file's
50 * timestamp, interested parties may later call file_time().
52 * 07/10/95 (taylor) Findfirst() returns the first file on NT.
53 * 05/03/96 (seiwald) split apart into pathnt.c
57 * file_dirscan() - scan a directory for files
60 void file_dirscan( char * dir, scanback func, void * closure )
62 PROFILE_ENTER( FILE_DIRSCAN );
66 dir = short_path_to_long_path( dir );
68 /* First enter directory itself */
70 d = file_query( dir );
72 if ( !d || !d->is_dir )
74 PROFILE_EXIT( FILE_DIRSCAN );
85 struct _finddata_t finfo[ 1 ];
87 int d_length = strlen( d->name );
89 memset( (char *)&f, '\0', sizeof( f ) );
91 f.f_dir.ptr = d->name;
92 f.f_dir.len = d_length;
94 /* Now enter contents of directory */
96 /* Prepare file search specification for the findfirst() API. */
98 string_copy( filespec, ".\\*" );
102 * We can not simply assume the given folder name will never include
103 * its trailing path separator or otherwise we would not support the
104 * Windows root folder specified without its drive letter, i.e. '\'.
106 char trailingChar = d->name[ d_length - 1 ] ;
107 string_copy( filespec, d->name );
108 if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
109 string_append( filespec, "\\" );
110 string_append( filespec, "*" );
113 if ( DEBUG_BINDSCAN )
114 printf( "scan directory %s\n", dir );
116 #if defined(__BORLANDC__) && __BORLANDC__ < 0x550
117 if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
119 string_free( filespec );
120 PROFILE_EXIT( FILE_DIRSCAN );
124 string_new ( filename );
127 file_info_t * ff = 0;
129 f.f_base.ptr = finfo->ff_name;
130 f.f_base.len = strlen( finfo->ff_name );
132 string_truncate( filename, 0 );
133 path_build( &f, filename );
135 files = list_new( files, newstr(filename->value) );
136 ff = file_info( filename->value );
137 ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1;
138 ff->is_dir = finfo->ff_attrib & FA_DIREC ? 1 : 0;
139 ff->size = finfo->ff_fsize;
140 ff->time = (finfo->ff_ftime << 16) | finfo->ff_ftime;
142 ret = findnext( finfo );
145 handle = _findfirst( filespec->value, finfo );
147 if ( ret = ( handle < 0L ) )
149 string_free( filespec );
150 PROFILE_EXIT( FILE_DIRSCAN );
154 string_new( filename );
157 file_info_t * ff = 0;
159 f.f_base.ptr = finfo->name;
160 f.f_base.len = strlen( finfo->name );
162 string_truncate( filename, 0 );
163 path_build( &f, filename, 0 );
165 files = list_new( files, newstr( filename->value ) );
166 ff = file_info( filename->value );
167 ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1;
168 ff->is_dir = finfo->attrib & _A_SUBDIR ? 1 : 0;
169 ff->size = finfo->size;
170 ff->time = finfo->time_write;
172 ret = _findnext( handle, finfo );
175 _findclose( handle );
177 string_free( filename );
178 string_free( filespec );
183 /* Special case \ or d:\ : enter it */
185 unsigned long len = strlen(d->name);
186 if ( len == 1 && d->name[0] == '\\' )
187 (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
188 else if ( len == 3 && d->name[1] == ':' ) {
189 (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
190 /* We've just entered 3-letter drive name spelling (with trailing
191 slash), into the hash table. Now enter two-letter variant,
192 without trailing slash, so that if we try to check whether
193 "c:" exists, we hit it.
195 Jam core has workarounds for that. Given:
196 x = c:\whatever\foo ;
199 There will be no trailing slash in $(p), but there will be one
200 in $(p2). But, that seems rather fragile.
203 (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
207 /* Now enter contents of directory */
210 LIST * files = d->files;
213 file_info_t * ff = file_info( files->string );
214 (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
215 files = list_next( files );
219 PROFILE_EXIT( FILE_DIRSCAN );
222 file_info_t * file_query( char * filename )
224 file_info_t * ff = file_info( filename );
229 if ( stat( *filename ? filename : ".", &statbuf ) < 0 )
232 ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
233 ff->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0;
234 ff->size = statbuf.st_size;
235 ff->time = statbuf.st_mtime ? statbuf.st_mtime : 1;
241 * file_time() - get timestamp of file, if not done by file_dirscan()
249 file_info_t * ff = file_query( filename );
250 if ( !ff ) return -1;
255 int file_is_file(char* filename)
257 file_info_t * ff = file_query( filename );
258 if ( !ff ) return -1;
262 int file_mkdir(char *pathname)
264 return _mkdir(pathname);
268 * file_archscan() - scan an archive for files
271 /* Straight from SunOS */
273 #define ARMAG "!<arch>\n"
289 # define SARHDR sizeof( struct ar_hdr )
297 struct ar_hdr ar_hdr;
298 char *string_table = 0;
299 char buf[ MAXJPATH ];
303 if ( ( fd = open( archive, O_RDONLY | O_BINARY, 0 ) ) < 0 )
306 if ( read( fd, buf, SARMAG ) != SARMAG ||
307 strncmp( ARMAG, buf, SARMAG ) )
315 if ( DEBUG_BINDSCAN )
316 printf( "scan archive %s\n", archive );
318 while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) &&
319 !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
327 sscanf( ar_hdr.ar_date, "%ld", &lar_date );
328 sscanf( ar_hdr.ar_size, "%ld", &lar_size );
330 lar_size = ( lar_size + 1 ) & ~1;
332 if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] == '/' )
334 /* this is the "string table" entry of the symbol table,
335 ** which holds strings of filenames that are longer than
336 ** 15 characters (ie. don't fit into a ar_name
339 string_table = BJAM_MALLOC_ATOMIC(lar_size+1);
340 if (read(fd, string_table, lar_size) != lar_size)
341 printf("error reading string table\n");
342 string_table[lar_size] = '\0';
343 offset += SARHDR + lar_size;
346 else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ')
348 /* Long filenames are recognized by "/nnnn" where nnnn is
349 ** the offset of the string in the string table represented
350 ** in ASCII decimals.
353 name = string_table + atoi( ar_hdr.ar_name + 1 );
354 for ( endname = name; *endname && *endname != '\n'; ++endname) {}
359 name = ar_hdr.ar_name;
360 endname = name + sizeof( ar_hdr.ar_name );
363 /* strip trailing white-space, slashes, and backslashes */
365 while ( endname-- > name )
366 if ( !isspace(*endname) && ( *endname != '\\' ) && ( *endname != '/' ) )
370 /* strip leading directory names, an NT specialty */
372 if ( c = strrchr( name, '/' ) )
374 if ( c = strrchr( name, '\\' ) )
377 sprintf( buf, "%s(%.*s)", archive, endname - name, name );
378 (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
380 offset += SARHDR + lar_size;
381 lseek( fd, offset, 0 );