]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/engine/fileunix.c
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / build / src / engine / 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 /*
15 * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
16 *
17 * External routines:
18 * file_archscan() - scan an archive for files
19 * file_mkdir() - create a directory
20 * file_supported_fmt_resolution() - file modification timestamp resolution
21 *
22 * External routines called only via routines in filesys.c:
23 * file_collect_dir_content_() - collects directory content information
24 * file_dirscan_() - OS specific file_dirscan() implementation
25 * file_query_() - query information about a path from the OS
26 * file_collect_archive_content_() - collects information about archive members
27 * file_archivescan_() - OS specific file_archivescan() implementation
28 */
29
30 #include "jam.h"
31 #ifdef USE_FILEUNIX
32 #include "filesys.h"
33
34 #include "object.h"
35 #include "pathsys.h"
36 #include "strings.h"
37 #include "output.h"
38
39 #include <assert.h>
40 #include <stdio.h>
41 #include <sys/stat.h> /* needed for mkdir() */
42
43 #if defined( sun ) || defined( __sun ) || defined( linux )
44 # include <unistd.h> /* needed for read and close prototype */
45 #endif
46
47 #if defined( OS_SEQUENT ) || \
48 defined( OS_DGUX ) || \
49 defined( OS_SCO ) || \
50 defined( OS_ISC )
51 # define PORTAR 1
52 #endif
53
54 #if defined( OS_RHAPSODY ) || defined( OS_MACOSX ) || defined( OS_NEXT )
55 # include <sys/dir.h>
56 # include <unistd.h> /* need unistd for rhapsody's proper lseek */
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 ) || defined( OS_INTERIX )
69 #define ARMAG "!<arch>\n"
70 #define SARMAG 8
71 #define ARFMAG "`\n"
72 #define HAVE_AR
73
74 struct ar_hdr /* archive file member header - printable ascii */
75 {
76 char ar_name[ 16 ]; /* file member name - `/' terminated */
77 char ar_date[ 12 ]; /* file member date - decimal */
78 char ar_uid[ 6 ]; /* file member user id - decimal */
79 char ar_gid[ 6 ]; /* file member group id - decimal */
80 char ar_mode[ 8 ]; /* file member mode - octal */
81 char ar_size[ 10 ]; /* file member size - decimal */
82 char ar_fmag[ 2 ]; /* ARFMAG - string to end header */
83 };
84 #endif
85
86 #if defined( OS_QNX ) || \
87 defined( OS_BEOS ) || \
88 defined( OS_HAIKU ) || \
89 defined( OS_MPEIX )
90 # define NO_AR
91 # define HAVE_AR
92 #endif
93
94 #ifndef HAVE_AR
95 # ifdef OS_AIX
96 /* Define these for AIX to get the definitions for both small and big archive
97 * file format variants.
98 */
99 # define __AR_SMALL__
100 # define __AR_BIG__
101 # endif
102 # include <ar.h>
103 #endif
104
105
106 /*
107 * file_collect_dir_content_() - collects directory content information
108 */
109
110 int file_collect_dir_content_( file_info_t * const d )
111 {
112 LIST * files = L0;
113 PATHNAME f;
114 int n;
115 STRUCT_DIRENT ** namelist;
116 STRUCT_DIRENT * dirent;
117 string path[ 1 ];
118 char const * dirstr;
119
120 assert( d );
121 assert( d->is_dir );
122 assert( list_empty( d->files ) );
123
124 dirstr = object_str( d->name );
125
126 memset( (char *)&f, '\0', sizeof( f ) );
127 f.f_dir.ptr = dirstr;
128 f.f_dir.len = strlen( dirstr );
129
130 if ( !*dirstr ) dirstr = ".";
131
132 if ( -1 == ( n = scandir( dirstr, &namelist, NULL, alphasort ) ) )
133 return -1;
134
135 string_new( path );
136 while ( n-- )
137 {
138 OBJECT * name;
139 dirent = namelist[ n ];
140 f.f_base.ptr = dirent->d_name
141 #ifdef old_sinix
142 - 2 /* Broken structure definition on sinix. */
143 #endif
144 ;
145 f.f_base.len = strlen( f.f_base.ptr );
146
147 string_truncate( path, 0 );
148 path_build( &f, path );
149 name = object_new( path->value );
150 /* Immediately stat the file to preserve invariants. */
151 if ( file_query( name ) )
152 files = list_push_back( files, name );
153 else
154 object_free( name );
155 free( dirent );
156 }
157 string_free( path );
158
159 free( namelist );
160
161 d->files = files;
162 return 0;
163 }
164
165
166 /*
167 * file_dirscan_() - OS specific file_dirscan() implementation
168 */
169
170 void file_dirscan_( file_info_t * const d, scanback func, void * closure )
171 {
172 assert( d );
173 assert( d->is_dir );
174
175 /* Special case / : enter it */
176 if ( !strcmp( object_str( d->name ), "/" ) )
177 (*func)( closure, d->name, 1 /* stat()'ed */, &d->time );
178 }
179
180
181 /*
182 * file_mkdir() - create a directory
183 */
184
185 int file_mkdir( char const * const path )
186 {
187 /* Explicit cast to remove const modifiers and avoid related compiler
188 * warnings displayed when using the intel compiler.
189 */
190 return mkdir( (char *)path, 0777 );
191 }
192
193
194 /*
195 * file_query_() - query information about a path from the OS
196 */
197
198 void file_query_( file_info_t * const info )
199 {
200 file_query_posix_( info );
201 }
202
203
204 /*
205 * file_supported_fmt_resolution() - file modification timestamp resolution
206 *
207 * Returns the minimum file modification timestamp resolution supported by this
208 * Boost Jam implementation. File modification timestamp changes of less than
209 * the returned value might not be recognized.
210 *
211 * Does not take into consideration any OS or file system related restrictions.
212 *
213 * Return value 0 indicates that any value supported by the OS is also supported
214 * here.
215 */
216
217 void file_supported_fmt_resolution( timestamp * const t )
218 {
219 /* The current implementation does not support file modification timestamp
220 * resolution of less than one second.
221 */
222 timestamp_init( t, 1, 0 );
223 }
224
225 int file_collect_archive_content_( file_archive_info_t * const archive );
226
227 /*
228 * file_archscan() - scan an archive for files
229 */
230 void file_archscan( char const * arch, scanback func, void * closure )
231 {
232 OBJECT * path = object_new( arch );
233 file_archive_info_t * archive = file_archive_query( path );
234
235 object_free( path );
236
237 if ( filelist_empty( archive->members ) )
238 {
239 if ( file_collect_archive_content_( archive ) < 0 )
240 return;
241 }
242
243 /* Report the collected archive content. */
244 {
245 FILELISTITER iter = filelist_begin( archive->members );
246 FILELISTITER const end = filelist_end( archive->members );
247 char buf[ MAXJPATH ];
248
249 for ( ; iter != end ; iter = filelist_next( iter ) )
250 {
251 file_info_t * member_file = filelist_item( iter );
252 LIST * symbols = member_file->files;
253
254 /* Construct member path: 'archive-path(member-name)'
255 */
256 sprintf( buf, "%s(%s)",
257 object_str( archive->file->name ),
258 object_str( member_file->name ) );
259 {
260 OBJECT * const member = object_new( buf );
261 (*func)( closure, member, 1 /* time valid */, &member_file->time );
262 object_free( member );
263 }
264 }
265 }
266 }
267
268
269 /*
270 * file_archivescan_() - OS specific file_archivescan() implementation
271 */
272
273 void file_archivescan_( file_archive_info_t * const archive, archive_scanback func,
274 void * closure )
275 {
276 }
277
278
279 /*
280 * file_collect_archive_content_() - collects information about archive members
281 */
282
283 #ifndef AIAMAG /* God-fearing UNIX */
284
285 #define SARFMAG 2
286 #define SARHDR sizeof( struct ar_hdr )
287
288 int file_collect_archive_content_( file_archive_info_t * const archive )
289 {
290 #ifndef NO_AR
291 struct ar_hdr ar_hdr;
292 char * string_table = 0;
293 char buf[ MAXJPATH ];
294 long offset;
295 int fd;
296 const char * path = object_str( archive->file->name );
297
298 if ( ! filelist_empty( archive->members ) ) filelist_free( archive->members );
299
300 if ( ( fd = open( path, O_RDONLY, 0 ) ) < 0 )
301 return -1;
302
303 if ( read( fd, buf, SARMAG ) != SARMAG ||
304 strncmp( ARMAG, buf, SARMAG ) )
305 {
306 close( fd );
307 return -1;
308 }
309
310 offset = SARMAG;
311
312 if ( DEBUG_BINDSCAN )
313 out_printf( "scan archive %s\n", path );
314
315 while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) &&
316 !( memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG )
317 #ifdef ARFZMAG
318 /* OSF also has a compressed format */
319 && memcmp( ar_hdr.ar_fmag, ARFZMAG, SARFMAG )
320 #endif
321 ) )
322 {
323 char lar_name_[ 257 ];
324 char * lar_name = lar_name_ + 1;
325 long lar_date;
326 long lar_size;
327 long lar_offset;
328 char * c;
329 char * src;
330 char * dest;
331
332 strncpy( lar_name, ar_hdr.ar_name, sizeof( ar_hdr.ar_name ) );
333
334 sscanf( ar_hdr.ar_date, "%ld", &lar_date );
335 sscanf( ar_hdr.ar_size, "%ld", &lar_size );
336
337 if ( ar_hdr.ar_name[ 0 ] == '/' )
338 {
339 if ( ar_hdr.ar_name[ 1 ] == '/' )
340 {
341 /* This is the "string table" entry of the symbol table, holding
342 * filename strings longer than 15 characters, i.e. those that
343 * do not fit into ar_name.
344 */
345 string_table = (char *)BJAM_MALLOC_ATOMIC( lar_size );
346 lseek( fd, offset + SARHDR, 0 );
347 if ( read( fd, string_table, lar_size ) != lar_size )
348 out_printf("error reading string table\n");
349 }
350 else if ( string_table && ar_hdr.ar_name[ 1 ] != ' ' )
351 {
352 /* Long filenames are recognized by "/nnnn" where nnnn is the
353 * offset of the string in the string table represented in ASCII
354 * decimals.
355 */
356 dest = lar_name;
357 lar_offset = atoi( lar_name + 1 );
358 src = &string_table[ lar_offset ];
359 while ( *src != '/' )
360 *dest++ = *src++;
361 *dest = '/';
362 }
363 }
364
365 c = lar_name - 1;
366 while ( ( *++c != ' ' ) && ( *c != '/' ) );
367 *c = '\0';
368
369 if ( DEBUG_BINDSCAN )
370 out_printf( "archive name %s found\n", lar_name );
371
372 sprintf( buf, "%s", lar_name );
373
374 if ( strcmp( buf, "") != 0 )
375 {
376 file_info_t * member = 0;
377
378 archive->members = filelist_push_back( archive->members, object_new( buf ) );
379 member = filelist_back( archive->members );
380 member->is_file = 1;
381 member->is_dir = 0;
382 member->exists = 0;
383 timestamp_init( &member->time, (time_t)lar_date, 0 );
384 }
385
386 offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
387 lseek( fd, offset, 0 );
388 }
389
390 if ( string_table )
391 BJAM_FREE( string_table );
392
393 close( fd );
394 #endif /* NO_AR */
395
396 return 0;
397 }
398
399 #else /* AIAMAG - RS6000 AIX */
400
401 static void collect_archive_content_small( int fd, file_archive_info_t * const archive )
402 {
403 struct fl_hdr fl_hdr;
404
405 struct {
406 struct ar_hdr hdr;
407 char pad[ 256 ];
408 } ar_hdr ;
409
410 char buf[ MAXJPATH ];
411 long offset;
412 const char * path = object_str( archive->file->name );
413
414 if ( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ )
415 return;
416
417 sscanf( fl_hdr.fl_fstmoff, "%ld", &offset );
418
419 if ( DEBUG_BINDSCAN )
420 out_printf( "scan archive %s\n", path );
421
422 while ( offset > 0 && lseek( fd, offset, 0 ) >= 0 &&
423 read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= (int)sizeof( ar_hdr.hdr ) )
424 {
425 long lar_date;
426 int lar_namlen;
427
428 sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
429 sscanf( ar_hdr.hdr.ar_date , "%ld", &lar_date );
430 sscanf( ar_hdr.hdr.ar_nxtmem, "%ld", &offset );
431
432 if ( !lar_namlen )
433 continue;
434
435 ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0';
436
437 sprintf( buf, "%s", ar_hdr.hdr._ar_name.ar_name );
438
439 if ( strcmp( buf, "") != 0 )
440 {
441 file_info_t * member = 0;
442
443 archive->members = filelist_push_back( archive->members, object_new( buf ) );
444 member = filelist_back( archive->members );
445 member->is_file = 1;
446 member->is_dir = 0;
447 member->exists = 0;
448 timestamp_init( &member->time, (time_t)lar_date, 0 );
449 }
450 }
451 }
452
453 /* Check for OS versions supporting the big variant. */
454 #ifdef AR_HSZ_BIG
455
456 static void collect_archive_content_big( int fd, file_archive_info_t * const archive )
457 {
458 struct fl_hdr_big fl_hdr;
459
460 struct {
461 struct ar_hdr_big hdr;
462 char pad[ 256 ];
463 } ar_hdr ;
464
465 char buf[ MAXJPATH ];
466 long long offset;
467 const char * path = object_str( archive->file->name );
468
469 if ( read( fd, (char *)&fl_hdr, FL_HSZ_BIG ) != FL_HSZ_BIG )
470 return;
471
472 sscanf( fl_hdr.fl_fstmoff, "%lld", &offset );
473
474 if ( DEBUG_BINDSCAN )
475 out_printf( "scan archive %s\n", path );
476
477 while ( offset > 0 && lseek( fd, offset, 0 ) >= 0 &&
478 read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) )
479 {
480 long lar_date;
481 int lar_namlen;
482
483 sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
484 sscanf( ar_hdr.hdr.ar_date , "%ld" , &lar_date );
485 sscanf( ar_hdr.hdr.ar_nxtmem, "%lld", &offset );
486
487 if ( !lar_namlen )
488 continue;
489
490 ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0';
491
492 sprintf( buf, "%s", ar_hdr.hdr._ar_name.ar_name );
493
494 if ( strcmp( buf, "") != 0 )
495 {
496 file_info_t * member = 0;
497
498 archive->members = filelist_push_back( archive->members, object_new( buf ) );
499 member = filelist_back( archive->members );
500 member->is_file = 1;
501 member->is_dir = 0;
502 member->exists = 0;
503 timestamp_init( &member->time, (time_t)lar_date, 0 );
504 }
505 }
506 }
507
508 #endif /* AR_HSZ_BIG */
509
510 int file_collect_archive_content_( file_archive_info_t * const archive )
511 {
512 int fd;
513 char fl_magic[ SAIAMAG ];
514 const char * path = object_str( archive->file->name );
515
516 if ( ! filelist_empty( archive->members ) ) filelist_free( archive->members );
517
518 if ( ( fd = open( path, O_RDONLY, 0 ) ) < 0 )
519 return -1;
520
521 if ( read( fd, fl_magic, SAIAMAG ) != SAIAMAG ||
522 lseek( fd, 0, SEEK_SET ) == -1 )
523 {
524 close( fd );
525 return -1;
526 }
527
528 if ( !strncmp( AIAMAG, fl_magic, SAIAMAG ) )
529 {
530 /* read small variant */
531 collect_archive_content_small( fd, archive );
532 }
533 #ifdef AR_HSZ_BIG
534 else if ( !strncmp( AIAMAGBIG, fl_magic, SAIAMAG ) )
535 {
536 /* read big variant */
537 collect_archive_content_big( fd, archive );
538 }
539 #endif
540
541 close( fd );
542
543 return 0;
544 }
545
546 #endif /* AIAMAG - RS6000 AIX */
547
548 #endif /* USE_FILEUNIX */