]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/engine/filent.c
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / build / src / engine / filent.c
1 /*
2 * Copyright 1993, 1995 Christopher Seiwald.
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 copy at
12 * http://www.boost.org/LICENSE_1_0.txt)
13 */
14
15 /*
16 * filent.c - scan directories and archives on NT
17 *
18 * External routines:
19 * file_archscan() - scan an archive for files
20 * file_mkdir() - create a directory
21 * file_supported_fmt_resolution() - file modification timestamp resolution
22 *
23 * External routines called only via routines in filesys.c:
24 * file_collect_dir_content_() - collects directory content information
25 * file_dirscan_() - OS specific file_dirscan() implementation
26 * file_query_() - query information about a path from the OS
27 * file_collect_archive_content_() - collects information about archive members
28 * file_archivescan_() - OS specific file_archivescan() implementation
29 */
30
31 #include "jam.h"
32 #ifdef OS_NT
33 #include "filesys.h"
34
35 #include "object.h"
36 #include "pathsys.h"
37 #include "strings.h"
38 #include "output.h"
39
40 #ifdef __BORLANDC__
41 # undef FILENAME /* cpp namespace collision */
42 #endif
43
44 #define WIN32_LEAN_AND_MEAN
45 #include <windows.h>
46
47 #include <assert.h>
48 #include <ctype.h>
49 #include <direct.h>
50 #include <io.h>
51
52
53 int file_collect_archive_content_( file_archive_info_t * const archive );
54
55 /*
56 * file_collect_dir_content_() - collects directory content information
57 */
58
59 int file_collect_dir_content_( file_info_t * const d )
60 {
61 PATHNAME f;
62 string pathspec[ 1 ];
63 string pathname[ 1 ];
64 LIST * files = L0;
65 int d_length;
66
67 assert( d );
68 assert( d->is_dir );
69 assert( list_empty( d->files ) );
70
71 d_length = strlen( object_str( d->name ) );
72
73 memset( (char *)&f, '\0', sizeof( f ) );
74 f.f_dir.ptr = object_str( d->name );
75 f.f_dir.len = d_length;
76
77 /* Prepare file search specification for the FindXXX() Windows API. */
78 if ( !d_length )
79 string_copy( pathspec, ".\\*" );
80 else
81 {
82 /* We can not simply assume the given folder name will never include its
83 * trailing path separator or otherwise we would not support the Windows
84 * root folder specified without its drive letter, i.e. '\'.
85 */
86 char const trailingChar = object_str( d->name )[ d_length - 1 ] ;
87 string_copy( pathspec, object_str( d->name ) );
88 if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
89 string_append( pathspec, "\\" );
90 string_append( pathspec, "*" );
91 }
92
93 /* The following code for collecting information about all files in a folder
94 * needs to be kept synchronized with how the file_query() operation is
95 * implemented (collects information about a single file).
96 */
97 {
98 /* FIXME: Avoid duplicate FindXXX Windows API calls here and in the code
99 * determining a normalized path.
100 */
101 WIN32_FIND_DATA finfo;
102 HANDLE const findHandle = FindFirstFileA( pathspec->value, &finfo );
103 if ( findHandle == INVALID_HANDLE_VALUE )
104 {
105 string_free( pathspec );
106 return -1;
107 }
108
109 string_new( pathname );
110 do
111 {
112 OBJECT * pathname_obj;
113
114 f.f_base.ptr = finfo.cFileName;
115 f.f_base.len = strlen( finfo.cFileName );
116
117 string_truncate( pathname, 0 );
118 path_build( &f, pathname );
119
120 pathname_obj = object_new( pathname->value );
121 path_register_key( pathname_obj );
122 files = list_push_back( files, pathname_obj );
123 {
124 int found;
125 file_info_t * const ff = file_info( pathname_obj, &found );
126 ff->is_dir = finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
127 ff->is_file = !ff->is_dir;
128 ff->exists = 1;
129 timestamp_from_filetime( &ff->time, &finfo.ftLastWriteTime );
130 // Use the timestamp of the link target, not the link itself
131 // (i.e. stat instead of lstat)
132 if ( finfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
133 {
134 HANDLE hLink = CreateFileA( pathname->value, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
135 BY_HANDLE_FILE_INFORMATION target_finfo[ 1 ];
136 if ( hLink != INVALID_HANDLE_VALUE && GetFileInformationByHandle( hLink, target_finfo ) )
137 {
138 ff->is_file = target_finfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? 0 : 1;
139 ff->is_dir = target_finfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0;
140 timestamp_from_filetime( &ff->time, &target_finfo->ftLastWriteTime );
141 }
142 }
143 }
144 }
145 while ( FindNextFile( findHandle, &finfo ) );
146
147 FindClose( findHandle );
148 }
149
150 string_free( pathname );
151 string_free( pathspec );
152
153 d->files = files;
154 return 0;
155 }
156
157
158 /*
159 * file_dirscan_() - OS specific file_dirscan() implementation
160 */
161
162 void file_dirscan_( file_info_t * const d, scanback func, void * closure )
163 {
164 assert( d );
165 assert( d->is_dir );
166
167 /* Special case \ or d:\ : enter it */
168 {
169 char const * const name = object_str( d->name );
170 if ( name[ 0 ] == '\\' && !name[ 1 ] )
171 {
172 (*func)( closure, d->name, 1 /* stat()'ed */, &d->time );
173 }
174 else if ( name[ 0 ] && name[ 1 ] == ':' && name[ 2 ] && !name[ 3 ] )
175 {
176 /* We have just entered a 3-letter drive name spelling (with a
177 * trailing slash), into the hash table. Now enter its two-letter
178 * variant, without the trailing slash, so that if we try to check
179 * whether "c:" exists, we hit it.
180 *
181 * Jam core has workarounds for that. Given:
182 * x = c:\whatever\foo ;
183 * p = $(x:D) ;
184 * p2 = $(p:D) ;
185 * There will be no trailing slash in $(p), but there will be one in
186 * $(p2). But, that seems rather fragile.
187 */
188 OBJECT * const dir_no_slash = object_new_range( name, 2 );
189 (*func)( closure, d->name, 1 /* stat()'ed */, &d->time );
190 (*func)( closure, dir_no_slash, 1 /* stat()'ed */, &d->time );
191 object_free( dir_no_slash );
192 }
193 }
194 }
195
196
197 /*
198 * file_mkdir() - create a directory
199 */
200
201 int file_mkdir( char const * const path )
202 {
203 return _mkdir( path );
204 }
205
206
207 /*
208 * file_query_() - query information about a path from the OS
209 *
210 * The following code for collecting information about a single file needs to be
211 * kept synchronized with how the file_collect_dir_content_() operation is
212 * implemented (collects information about all files in a folder).
213 */
214
215 int try_file_query_root( file_info_t * const info )
216 {
217 WIN32_FILE_ATTRIBUTE_DATA fileData;
218 char buf[ 4 ];
219 char const * const pathstr = object_str( info->name );
220 if ( !pathstr[ 0 ] )
221 {
222 buf[ 0 ] = '.';
223 buf[ 1 ] = 0;
224 }
225 else if ( pathstr[ 0 ] == '\\' && ! pathstr[ 1 ] )
226 {
227 buf[ 0 ] = '\\';
228 buf[ 1 ] = '\0';
229 }
230 else if ( pathstr[ 1 ] == ':' )
231 {
232 if ( !pathstr[ 2 ] || ( pathstr[ 2 ] == '\\' && !pathstr[ 3 ] ) )
233 {
234 buf[ 0 ] = pathstr[ 0 ];
235 buf[ 1 ] = ':';
236 buf[ 2 ] = '\\';
237 buf[ 3 ] = '\0';
238 }
239 else
240 {
241 return 0;
242 }
243 }
244 else
245 {
246 return 0;
247 }
248
249 /* We have a root path */
250 if ( !GetFileAttributesExA( buf, GetFileExInfoStandard, &fileData ) )
251 {
252 info->is_dir = 0;
253 info->is_file = 0;
254 info->exists = 0;
255 timestamp_clear( &info->time );
256 }
257 else
258 {
259 info->is_dir = fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
260 info->is_file = !info->is_dir;
261 info->exists = 1;
262 timestamp_from_filetime( &info->time, &fileData.ftLastWriteTime );
263 }
264 return 1;
265 }
266
267 void file_query_( file_info_t * const info )
268 {
269 char const * const pathstr = object_str( info->name );
270 const char * dir;
271 OBJECT * parent;
272 file_info_t * parent_info;
273
274 if ( try_file_query_root( info ) )
275 return;
276
277 if ( ( dir = strrchr( pathstr, '\\' ) ) )
278 {
279 parent = object_new_range( pathstr, dir - pathstr );
280 }
281 else
282 {
283 parent = object_copy( constant_empty );
284 }
285 parent_info = file_query( parent );
286 object_free( parent );
287 if ( !parent_info || !parent_info->is_dir )
288 {
289 info->is_dir = 0;
290 info->is_file = 0;
291 info->exists = 0;
292 timestamp_clear( &info->time );
293 }
294 else
295 {
296 info->is_dir = 0;
297 info->is_file = 0;
298 info->exists = 0;
299 timestamp_clear( &info->time );
300 if ( list_empty( parent_info->files ) )
301 file_collect_dir_content_( parent_info );
302 }
303 }
304
305
306 /*
307 * file_supported_fmt_resolution() - file modification timestamp resolution
308 *
309 * Returns the minimum file modification timestamp resolution supported by this
310 * Boost Jam implementation. File modification timestamp changes of less than
311 * the returned value might not be recognized.
312 *
313 * Does not take into consideration any OS or file system related restrictions.
314 *
315 * Return value 0 indicates that any value supported by the OS is also supported
316 * here.
317 */
318
319 void file_supported_fmt_resolution( timestamp * const t )
320 {
321 /* On Windows we support nano-second file modification timestamp resolution,
322 * just the same as the Windows OS itself.
323 */
324 timestamp_init( t, 0, 0 );
325 }
326
327
328 /*
329 * file_archscan() - scan an archive for files
330 */
331
332 /* Straight from SunOS */
333
334 #define ARMAG "!<arch>\n"
335 #define SARMAG 8
336
337 #define ARFMAG "`\n"
338
339 struct ar_hdr
340 {
341 char ar_name[ 16 ];
342 char ar_date[ 12 ];
343 char ar_uid[ 6 ];
344 char ar_gid[ 6 ];
345 char ar_mode[ 8 ];
346 char ar_size[ 10 ];
347 char ar_fmag[ 2 ];
348 };
349
350 #define SARFMAG 2
351 #define SARHDR sizeof( struct ar_hdr )
352
353 void file_archscan( char const * arch, scanback func, void * closure )
354 {
355 OBJECT * path = object_new( arch );
356 file_archive_info_t * archive = file_archive_query( path );
357
358 object_free( path );
359
360 if ( filelist_empty( archive->members ) )
361 {
362 if ( file_collect_archive_content_( archive ) < 0 )
363 return;
364 }
365
366 /* Report the collected archive content. */
367 {
368 FILELISTITER iter = filelist_begin( archive->members );
369 FILELISTITER const end = filelist_end( archive->members );
370 char buf[ MAXJPATH ];
371
372 for ( ; iter != end ; iter = filelist_next( iter ) )
373 {
374 file_info_t * member_file = filelist_item( iter );
375 LIST * symbols = member_file->files;
376
377 /* Construct member path: 'archive-path(member-name)'
378 */
379 sprintf( buf, "%s(%s)",
380 object_str( archive->file->name ),
381 object_str( member_file->name ) );
382 {
383 OBJECT * const member = object_new( buf );
384 (*func)( closure, member, 1 /* time valid */, &member_file->time );
385 object_free( member );
386 }
387 }
388 }
389 }
390
391
392 /*
393 * file_archivescan_() - OS specific file_archivescan() implementation
394 */
395
396 void file_archivescan_( file_archive_info_t * const archive, archive_scanback func,
397 void * closure )
398 {
399 }
400
401
402 /*
403 * file_collect_archive_content_() - collects information about archive members
404 */
405
406 int file_collect_archive_content_( file_archive_info_t * const archive )
407 {
408 struct ar_hdr ar_hdr;
409 char * string_table = 0;
410 char buf[ MAXJPATH ];
411 long offset;
412 const char * path = object_str( archive->file->name );
413 int const fd = open( path , O_RDONLY | O_BINARY, 0 );
414
415 if ( ! filelist_empty( archive->members ) ) filelist_free( archive->members );
416
417 if ( fd < 0 )
418 return -1;
419
420 if ( read( fd, buf, SARMAG ) != SARMAG || strncmp( ARMAG, buf, SARMAG ) )
421 {
422 close( fd );
423 return -1;
424 }
425
426 offset = SARMAG;
427
428 if ( DEBUG_BINDSCAN )
429 out_printf( "scan archive %s\n", path );
430
431 while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) &&
432 !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
433 {
434 long lar_date;
435 long lar_size;
436 char * name = 0;
437 char * endname;
438
439 sscanf( ar_hdr.ar_date, "%ld", &lar_date );
440 sscanf( ar_hdr.ar_size, "%ld", &lar_size );
441
442 lar_size = ( lar_size + 1 ) & ~1;
443
444 if ( ar_hdr.ar_name[ 0 ] == '/' && ar_hdr.ar_name[ 1 ] == '/' )
445 {
446 /* This is the "string table" entry of the symbol table, holding
447 * filename strings longer than 15 characters, i.e. those that do
448 * not fit into ar_name.
449 */
450 string_table = BJAM_MALLOC_ATOMIC( lar_size + 1 );
451 if ( read( fd, string_table, lar_size ) != lar_size )
452 out_printf( "error reading string table\n" );
453 string_table[ lar_size ] = '\0';
454 offset += SARHDR + lar_size;
455 continue;
456 }
457 else if ( ar_hdr.ar_name[ 0 ] == '/' && ar_hdr.ar_name[ 1 ] != ' ' )
458 {
459 /* Long filenames are recognized by "/nnnn" where nnnn is the
460 * string's offset in the string table represented in ASCII
461 * decimals.
462 */
463 name = string_table + atoi( ar_hdr.ar_name + 1 );
464 for ( endname = name; *endname && *endname != '\n'; ++endname );
465 }
466 else
467 {
468 /* normal name */
469 name = ar_hdr.ar_name;
470 endname = name + sizeof( ar_hdr.ar_name );
471 }
472
473 /* strip trailing white-space, slashes, and backslashes */
474
475 while ( endname-- > name )
476 if ( !isspace( *endname ) && ( *endname != '\\' ) && ( *endname !=
477 '/' ) )
478 break;
479 *++endname = 0;
480
481 /* strip leading directory names, an NT specialty */
482 {
483 char * c;
484 if ( c = strrchr( name, '/' ) )
485 name = c + 1;
486 if ( c = strrchr( name, '\\' ) )
487 name = c + 1;
488 }
489
490 sprintf( buf, "%.*s", endname - name, name );
491
492 if ( strcmp( buf, "") != 0 )
493 {
494 file_info_t * member = 0;
495
496 /* NT static libraries appear to store the objects in a sequence
497 * reverse to the order in which they were inserted.
498 * Here we reverse the stored sequence by pushing members to front of
499 * member file list to get the intended members order.
500 */
501 archive->members = filelist_push_front( archive->members, object_new( buf ) );
502 member = filelist_front( archive->members );
503 member->is_file = 1;
504 member->is_dir = 0;
505 member->exists = 0;
506 timestamp_init( &member->time, (time_t)lar_date, 0 );
507 }
508
509 offset += SARHDR + lar_size;
510 lseek( fd, offset, 0 );
511 }
512
513 close( fd );
514
515 return 0;
516 }
517
518 #endif /* OS_NT */