diff options
Diffstat (limited to '')
-rw-r--r-- | src/boost/tools/build/src/engine/fileunix.cpp | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/src/boost/tools/build/src/engine/fileunix.cpp b/src/boost/tools/build/src/engine/fileunix.cpp new file mode 100644 index 000000000..4982c9bb8 --- /dev/null +++ b/src/boost/tools/build/src/engine/fileunix.cpp @@ -0,0 +1,533 @@ +/* + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. + * + * This file is part of Jam - see jam.c for Copyright information. + */ + +/* This file is ALSO: + * Copyright 2001-2004 David Abrahams. + * Copyright 2005 Rene Rivera. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt) + */ + +/* + * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS + * + * External routines: + * file_archscan() - scan an archive for files + * file_mkdir() - create a directory + * file_supported_fmt_resolution() - file modification timestamp resolution + * + * External routines called only via routines in filesys.c: + * file_collect_dir_content_() - collects directory content information + * file_dirscan_() - OS specific file_dirscan() implementation + * file_query_() - query information about a path from the OS + * file_collect_archive_content_() - collects information about archive members + * file_archivescan_() - OS specific file_archivescan() implementation + */ + +#include "jam.h" +#ifdef USE_FILEUNIX +#include "filesys.h" + +#include "object.h" +#include "pathsys.h" +#include "jam_strings.h" +#include "output.h" + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <sys/stat.h> /* needed for mkdir() */ + +#if defined( sun ) || defined( __sun ) || defined( linux ) +# include <unistd.h> /* needed for read and close prototype */ +#endif + +#if defined( OS_SEQUENT ) || \ + defined( OS_DGUX ) || \ + defined( OS_SCO ) || \ + defined( OS_ISC ) +# define PORTAR 1 +#endif + +#if defined( OS_RHAPSODY ) || defined( OS_MACOSX ) || defined( OS_NEXT ) +# include <sys/dir.h> +# include <unistd.h> /* need unistd for rhapsody's proper lseek */ +# define STRUCT_DIRENT struct direct +#else +# include <dirent.h> +# define STRUCT_DIRENT struct dirent +#endif + +#ifdef OS_COHERENT +# include <arcoff.h> +# define HAVE_AR +#endif + +#if defined( OS_MVS ) || defined( OS_INTERIX ) +#define ARMAG "!<arch>\n" +#define SARMAG 8 +#define ARFMAG "`\n" +#define HAVE_AR + +struct ar_hdr /* archive file member header - printable ascii */ +{ + char ar_name[ 16 ]; /* file member name - `/' terminated */ + char ar_date[ 12 ]; /* file member date - decimal */ + char ar_uid[ 6 ]; /* file member user id - decimal */ + char ar_gid[ 6 ]; /* file member group id - decimal */ + char ar_mode[ 8 ]; /* file member mode - octal */ + char ar_size[ 10 ]; /* file member size - decimal */ + char ar_fmag[ 2 ]; /* ARFMAG - string to end header */ +}; +#endif + +#if defined( OS_QNX ) || \ + defined( OS_BEOS ) || \ + defined( OS_HAIKU ) || \ + defined( OS_MPEIX ) +# define NO_AR +# define HAVE_AR +#endif + +#ifndef HAVE_AR +# ifdef OS_AIX +/* Define these for AIX to get the definitions for both small and big archive + * file format variants. + */ +# define __AR_SMALL__ +# define __AR_BIG__ +# endif +# include <ar.h> +#endif + + +/* + * file_collect_dir_content_() - collects directory content information + */ + +int file_collect_dir_content_( file_info_t * const d ) +{ + LIST * files = L0; + PATHNAME f; + int n; + STRUCT_DIRENT ** namelist; + STRUCT_DIRENT * dirent; + string path[ 1 ]; + char const * dirstr; + + assert( d ); + assert( d->is_dir ); + assert( list_empty( d->files ) ); + + dirstr = object_str( d->name ); + + memset( (char *)&f, '\0', sizeof( f ) ); + f.f_dir.ptr = dirstr; + f.f_dir.len = strlen( dirstr ); + + if ( !*dirstr ) dirstr = "."; + + if ( -1 == ( n = scandir( dirstr, &namelist, NULL, alphasort ) ) ) + { + if (n != ENOENT && n != ENOTDIR) + err_printf( "[errno %d] scandir '%s' failed: %s\n", + errno, dirstr, strerror(errno) ); + return -1; + } + + string_new( path ); + while ( n-- ) + { + OBJECT * name; + dirent = namelist[ n ]; + f.f_base.ptr = dirent->d_name + #ifdef old_sinix + - 2 /* Broken structure definition on sinix. */ + #endif + ; + f.f_base.len = strlen( f.f_base.ptr ); + + string_truncate( path, 0 ); + path_build( &f, path ); + name = object_new( path->value ); + /* Immediately stat the file to preserve invariants. */ + if ( file_query( name ) ) + files = list_push_back( files, name ); + else + object_free( name ); + free( dirent ); + } + string_free( path ); + + free( namelist ); + + d->files = files; + return 0; +} + + +/* + * file_dirscan_() - OS specific file_dirscan() implementation + */ + +void file_dirscan_( file_info_t * const d, scanback func, void * closure ) +{ + assert( d ); + assert( d->is_dir ); + + /* Special case / : enter it */ + if ( !strcmp( object_str( d->name ), "/" ) ) + (*func)( closure, d->name, 1 /* stat()'ed */, &d->time ); +} + + +/* + * file_mkdir() - create a directory + */ + +int file_mkdir( char const * const path ) +{ + /* Explicit cast to remove const modifiers and avoid related compiler + * warnings displayed when using the intel compiler. + */ + return mkdir( (char *)path, 0777 ); +} + + +/* + * file_query_() - query information about a path from the OS + */ + +void file_query_( file_info_t * const info ) +{ + file_query_posix_( info ); +} + + +int file_collect_archive_content_( file_archive_info_t * const archive ); + +/* + * file_archscan() - scan an archive for files + */ +void file_archscan( char const * arch, scanback func, void * closure ) +{ + OBJECT * path = object_new( arch ); + file_archive_info_t * archive = file_archive_query( path ); + + object_free( path ); + + if ( filelist_empty( archive->members ) ) + { + if ( file_collect_archive_content_( archive ) < 0 ) + return; + } + + /* Report the collected archive content. */ + { + FILELISTITER iter = filelist_begin( archive->members ); + FILELISTITER const end = filelist_end( archive->members ); + char buf[ MAXJPATH ]; + + for ( ; iter != end ; iter = filelist_next( iter ) ) + { + file_info_t * member_file = filelist_item( iter ); + + /* Construct member path: 'archive-path(member-name)' + */ + sprintf( buf, "%s(%s)", + object_str( archive->file->name ), + object_str( member_file->name ) ); + { + OBJECT * const member = object_new( buf ); + (*func)( closure, member, 1 /* time valid */, &member_file->time ); + object_free( member ); + } + } + } +} + + +/* + * file_archivescan_() - OS specific file_archivescan() implementation + */ + +void file_archivescan_( file_archive_info_t * const archive, archive_scanback func, + void * closure ) +{ +} + + +/* + * file_collect_archive_content_() - collects information about archive members + */ + +#ifndef AIAMAG /* God-fearing UNIX */ + +#define SARFMAG 2 +#define SARHDR sizeof( struct ar_hdr ) + +int file_collect_archive_content_( file_archive_info_t * const archive ) +{ +#ifndef NO_AR + struct ar_hdr ar_hdr; + char * string_table = 0; + char buf[ MAXJPATH ]; + long offset; + int fd; + const char * path = object_str( archive->file->name ); + + if ( ! filelist_empty( archive->members ) ) filelist_free( archive->members ); + + if ( ( fd = open( path, O_RDONLY, 0 ) ) < 0 ) + return -1; + + if ( read( fd, buf, SARMAG ) != SARMAG || + strncmp( ARMAG, buf, SARMAG ) ) + { + close( fd ); + return -1; + } + + offset = SARMAG; + + if ( DEBUG_BINDSCAN ) + out_printf( "scan archive %s\n", path ); + + while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) && + !( memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) +#ifdef ARFZMAG + /* OSF also has a compressed format */ + && memcmp( ar_hdr.ar_fmag, ARFZMAG, SARFMAG ) +#endif + ) ) + { + char lar_name_[ 257 ]; + char * lar_name = lar_name_ + 1; + long lar_date; + long lar_size; + long lar_offset; + char * c; + char * src; + char * dest; + + int32_t ar_hdr_name_size = sizeof( ar_hdr.ar_name ); // Workaround for sizeof strncpy warning. + strncpy( lar_name, ar_hdr.ar_name, ar_hdr_name_size ); + + sscanf( ar_hdr.ar_date, "%ld", &lar_date ); + sscanf( ar_hdr.ar_size, "%ld", &lar_size ); + + if ( ar_hdr.ar_name[ 0 ] == '/' ) + { + if ( ar_hdr.ar_name[ 1 ] == '/' ) + { + /* This is the "string table" entry of the symbol table, holding + * filename strings longer than 15 characters, i.e. those that + * do not fit into ar_name. + */ + string_table = (char *)BJAM_MALLOC_ATOMIC( lar_size ); + lseek( fd, offset + SARHDR, 0 ); + if ( read( fd, string_table, lar_size ) != lar_size ) + out_printf("error reading string table\n"); + } + else if ( string_table && ar_hdr.ar_name[ 1 ] != ' ' ) + { + /* Long filenames are recognized by "/nnnn" where nnnn is the + * offset of the string in the string table represented in ASCII + * decimals. + */ + dest = lar_name; + lar_offset = atoi( lar_name + 1 ); + src = &string_table[ lar_offset ]; + while ( *src != '/' ) + *dest++ = *src++; + *dest = '/'; + } + } + + c = lar_name - 1; + while ( ( *++c != ' ' ) && ( *c != '/' ) ); + *c = '\0'; + + if ( DEBUG_BINDSCAN ) + out_printf( "archive name %s found\n", lar_name ); + + sprintf( buf, "%s", lar_name ); + + if ( strcmp( buf, "") != 0 ) + { + file_info_t * member = 0; + + archive->members = filelist_push_back( archive->members, object_new( buf ) ); + member = filelist_back( archive->members ); + member->is_file = 1; + member->is_dir = 0; + member->exists = 0; + timestamp_init( &member->time, (time_t)lar_date, 0 ); + } + + offset += SARHDR + ( ( lar_size + 1 ) & ~1 ); + lseek( fd, offset, 0 ); + } + + if ( string_table ) + BJAM_FREE( string_table ); + + close( fd ); +#endif /* NO_AR */ + + return 0; +} + +#else /* AIAMAG - RS6000 AIX */ + +static void collect_archive_content_small( int fd, file_archive_info_t * const archive ) +{ + struct fl_hdr fl_hdr; + + struct { + struct ar_hdr hdr; + char pad[ 256 ]; + } ar_hdr ; + + char buf[ MAXJPATH ]; + long offset; + const char * path = object_str( archive->file->name ); + + if ( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ ) + return; + + sscanf( fl_hdr.fl_fstmoff, "%ld", &offset ); + + if ( DEBUG_BINDSCAN ) + out_printf( "scan archive %s\n", path ); + + while ( offset > 0 && lseek( fd, offset, 0 ) >= 0 && + read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= (int)sizeof( ar_hdr.hdr ) ) + { + long lar_date; + int lar_namlen; + + sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen ); + sscanf( ar_hdr.hdr.ar_date , "%ld", &lar_date ); + sscanf( ar_hdr.hdr.ar_nxtmem, "%ld", &offset ); + + if ( !lar_namlen ) + continue; + + ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0'; + + sprintf( buf, "%s", ar_hdr.hdr._ar_name.ar_name ); + + if ( strcmp( buf, "") != 0 ) + { + file_info_t * member = 0; + + archive->members = filelist_push_back( archive->members, object_new( buf ) ); + member = filelist_back( archive->members ); + member->is_file = 1; + member->is_dir = 0; + member->exists = 0; + timestamp_init( &member->time, (time_t)lar_date, 0 ); + } + } +} + +/* Check for OS versions supporting the big variant. */ +#ifdef AR_HSZ_BIG + +static void collect_archive_content_big( int fd, file_archive_info_t * const archive ) +{ + struct fl_hdr_big fl_hdr; + + struct { + struct ar_hdr_big hdr; + char pad[ 256 ]; + } ar_hdr ; + + char buf[ MAXJPATH ]; + long long offset; + const char * path = object_str( archive->file->name ); + + if ( read( fd, (char *)&fl_hdr, FL_HSZ_BIG ) != FL_HSZ_BIG ) + return; + + sscanf( fl_hdr.fl_fstmoff, "%lld", &offset ); + + if ( DEBUG_BINDSCAN ) + out_printf( "scan archive %s\n", path ); + + while ( offset > 0 && lseek( fd, offset, 0 ) >= 0 && + read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) ) + { + long lar_date; + int lar_namlen; + + sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen ); + sscanf( ar_hdr.hdr.ar_date , "%ld" , &lar_date ); + sscanf( ar_hdr.hdr.ar_nxtmem, "%lld", &offset ); + + if ( !lar_namlen ) + continue; + + ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0'; + + sprintf( buf, "%s", ar_hdr.hdr._ar_name.ar_name ); + + if ( strcmp( buf, "") != 0 ) + { + file_info_t * member = 0; + + archive->members = filelist_push_back( archive->members, object_new( buf ) ); + member = filelist_back( archive->members ); + member->is_file = 1; + member->is_dir = 0; + member->exists = 0; + timestamp_init( &member->time, (time_t)lar_date, 0 ); + } + } +} + +#endif /* AR_HSZ_BIG */ + +int file_collect_archive_content_( file_archive_info_t * const archive ) +{ + int fd; + char fl_magic[ SAIAMAG ]; + const char * path = object_str( archive->file->name ); + + if ( ! filelist_empty( archive->members ) ) filelist_free( archive->members ); + + if ( ( fd = open( path, O_RDONLY, 0 ) ) < 0 ) + return -1; + + if ( read( fd, fl_magic, SAIAMAG ) != SAIAMAG || + lseek( fd, 0, SEEK_SET ) == -1 ) + { + close( fd ); + return -1; + } + + if ( !strncmp( AIAMAG, fl_magic, SAIAMAG ) ) + { + /* read small variant */ + collect_archive_content_small( fd, archive ); + } +#ifdef AR_HSZ_BIG + else if ( !strncmp( AIAMAGBIG, fl_magic, SAIAMAG ) ) + { + /* read big variant */ + collect_archive_content_big( fd, archive ); + } +#endif + + close( fd ); + + return 0; +} + +#endif /* AIAMAG - RS6000 AIX */ + +#endif /* USE_FILEUNIX */ |