diff options
Diffstat (limited to 'jam-files/engine/fileunix.c')
-rw-r--r-- | jam-files/engine/fileunix.c | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/jam-files/engine/fileunix.c b/jam-files/engine/fileunix.c new file mode 100644 index 00000000..680c3f53 --- /dev/null +++ b/jam-files/engine/fileunix.c @@ -0,0 +1,501 @@ +/* + * 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_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + */ + +# include "jam.h" +# include "filesys.h" +# include "strings.h" +# include "pathsys.h" +# include "newstr.h" +# include <stdio.h> +# include <sys/stat.h> + +#if defined(sun) || defined(__sun) || defined(linux) +# include <unistd.h> /* needed for read and close prototype */ +#endif + +# ifdef USE_FILEUNIX + +#if defined(sun) || defined(__sun) +# 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 + +# ifdef __EMX__ +# include <sys/types.h> +# include <sys/stat.h> +# endif + +# if defined( OS_RHAPSODY ) || \ + defined( OS_MACOSX ) || \ + defined( OS_NEXT ) +/* need unistd for rhapsody's proper lseek */ +# include <sys/dir.h> +# include <unistd.h> +# 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" + +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 */ +}; + +# define HAVE_AR +# endif + +# if defined( OS_QNX ) || \ + defined( OS_BEOS ) || \ + defined( OS_MPEIX ) +# define NO_AR +# define HAVE_AR +# endif + +# ifndef HAVE_AR + +# ifdef OS_AIX +/* Define those for AIX to get the definitions for both the small and the + * big variant of the archive file format. */ +# define __AR_SMALL__ +# define __AR_BIG__ +# endif + +# include <ar.h> +# endif + +/* + * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS + * + * External routines: + * + * file_dirscan() - scan a directory for files + * file_time() - get timestamp of file, if not done by file_dirscan() + * file_archscan() - scan an archive for files + * + * File_dirscan() and file_archscan() call back a caller provided function + * for each file found. A flag to this callback function lets file_dirscan() + * and file_archscan() indicate that a timestamp is being provided with the + * file. If file_dirscan() or file_archscan() do not provide the file's + * timestamp, interested parties may later call file_time(). + * + * 04/08/94 (seiwald) - Coherent/386 support added. + * 12/19/94 (mikem) - solaris string table insanity support + * 02/14/95 (seiwald) - parse and build /xxx properly + * 05/03/96 (seiwald) - split into pathunix.c + * 11/21/96 (peterk) - BEOS does not have Unix-style archives + */ + + +/* + * file_dirscan() - scan a directory for files. + */ + +void file_dirscan( char * dir, scanback func, void * closure ) +{ + PROFILE_ENTER( FILE_DIRSCAN ); + + file_info_t * d = 0; + + d = file_query( dir ); + + if ( !d || !d->is_dir ) + { + PROFILE_EXIT( FILE_DIRSCAN ); + return; + } + + if ( ! d->files ) + { + LIST* files = L0; + PATHNAME f; + DIR *dd; + STRUCT_DIRENT *dirent; + string filename[1]; + + /* First enter directory itself */ + + memset( (char *)&f, '\0', sizeof( f ) ); + + f.f_dir.ptr = dir; + f.f_dir.len = strlen(dir); + + dir = *dir ? dir : "."; + + /* Now enter contents of directory. */ + + if ( !( dd = opendir( dir ) ) ) + { + PROFILE_EXIT( FILE_DIRSCAN ); + return; + } + + if ( DEBUG_BINDSCAN ) + printf( "scan directory %s\n", dir ); + + string_new( filename ); + while ( ( dirent = readdir( dd ) ) ) + { + # ifdef old_sinix + /* Broken structure definition on sinix. */ + f.f_base.ptr = dirent->d_name - 2; + # else + f.f_base.ptr = dirent->d_name; + # endif + f.f_base.len = strlen( f.f_base.ptr ); + + string_truncate( filename, 0 ); + path_build( &f, filename, 0 ); + + files = list_new( files, newstr(filename->value) ); + file_query( filename->value ); + } + string_free( filename ); + + closedir( dd ); + + d->files = files; + } + + /* Special case / : enter it */ + { + unsigned long len = strlen(d->name); + if ( ( len == 1 ) && ( d->name[0] == '/' ) ) + (*func)( closure, d->name, 1 /* stat()'ed */, d->time ); + } + + /* Now enter contents of directory */ + if ( d->files ) + { + LIST * files = d->files; + while ( files ) + { + file_info_t * ff = file_info( files->string ); + (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time ); + files = list_next( files ); + } + } + + PROFILE_EXIT( FILE_DIRSCAN ); +} + + +file_info_t * file_query( char * filename ) +{ + file_info_t * ff = file_info( filename ); + if ( ! ff->time ) + { + struct stat statbuf; + + if ( stat( *filename ? filename : ".", &statbuf ) < 0 ) + return 0; + + ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0; + ff->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0; + ff->size = statbuf.st_size; + ff->time = statbuf.st_mtime ? statbuf.st_mtime : 1; + } + return ff; +} + +/* + * file_time() - get timestamp of file, if not done by file_dirscan() + */ + +int +file_time( + char *filename, + time_t *time ) +{ + file_info_t * ff = file_query( filename ); + if ( !ff ) return -1; + *time = ff->time; + return 0; +} + +int file_is_file(char* filename) +{ + file_info_t * ff = file_query( filename ); + if ( !ff ) return -1; + return ff->is_file; +} + +int file_mkdir(char* pathname) +{ + return mkdir(pathname, 0766); +} + +/* + * file_archscan() - scan an archive for files + */ + +# ifndef AIAMAG /* God-fearing UNIX */ + +# define SARFMAG 2 +# define SARHDR sizeof( struct ar_hdr ) + +void +file_archscan( + char *archive, + scanback func, + void *closure ) +{ +# ifndef NO_AR + struct ar_hdr ar_hdr; + char buf[ MAXJPATH ]; + long offset; + char *string_table = 0; + int fd; + + if ( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 ) + return; + + if ( read( fd, buf, SARMAG ) != SARMAG || + strncmp( ARMAG, buf, SARMAG ) ) + { + close( fd ); + return; + } + + offset = SARMAG; + + if ( DEBUG_BINDSCAN ) + printf( "scan archive %s\n", archive ); + + 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; + + strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) ); + + 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, + ** which holds strings of filenames that are longer than + ** 15 characters (ie. don't fit into a ar_name + */ + + string_table = (char *)BJAM_MALLOC_ATOMIC(lar_size); + lseek(fd, offset + SARHDR, 0); + if (read(fd, string_table, lar_size) != lar_size) + 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 ) + printf( "archive name %s found\n", lar_name ); + + sprintf( buf, "%s(%s)", archive, lar_name ); + + (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date ); + + offset += SARHDR + ( ( lar_size + 1 ) & ~1 ); + lseek( fd, offset, 0 ); + } + + if (string_table) + BJAM_FREE(string_table); + + close( fd ); + +# endif /* NO_AR */ + +} + +# else /* AIAMAG - RS6000 AIX */ + +static void file_archscan_small( + int fd, char const *archive, scanback func, void *closure) +{ + struct fl_hdr fl_hdr; + + struct { + struct ar_hdr hdr; + char pad[ 256 ]; + } ar_hdr ; + + char buf[ MAXJPATH ]; + long offset; + + if ( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ) + return; + + sscanf( fl_hdr.fl_fstmoff, "%ld", &offset ); + + if ( DEBUG_BINDSCAN ) + printf( "scan archive %s\n", archive ); + + 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, "%ld", &offset ); + + if ( !lar_namlen ) + continue; + + ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0'; + + sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name ); + + (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date ); + } +} + +/* Check for OS version which supports the big variant. */ +#ifdef AR_HSZ_BIG + +static void file_archscan_big( + int fd, char const *archive, scanback func, void *closure) +{ + struct fl_hdr_big fl_hdr; + + struct { + struct ar_hdr_big hdr; + char pad[ 256 ]; + } ar_hdr ; + + char buf[ MAXJPATH ]; + long long offset; + + if ( read( fd, (char *)&fl_hdr, FL_HSZ_BIG) != FL_HSZ_BIG) + return; + + sscanf( fl_hdr.fl_fstmoff, "%lld", &offset ); + + if ( DEBUG_BINDSCAN ) + printf( "scan archive %s\n", archive ); + + 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(%s)", archive, ar_hdr.hdr._ar_name.ar_name ); + + (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date ); + } + +} + +#endif /* AR_HSZ_BIG */ + +void file_archscan(char *archive, scanback func, void *closure) +{ + int fd; + char fl_magic[SAIAMAG]; + + if (( fd = open(archive, O_RDONLY, 0)) < 0) + return; + + if (read( fd, fl_magic, SAIAMAG) != SAIAMAG + || lseek(fd, 0, SEEK_SET) == -1) + { + close(fd); + return; + } + + if (strncmp(AIAMAG, fl_magic, SAIAMAG) == 0) + { + /* read small variant */ + file_archscan_small(fd, archive, func, closure); + } +#ifdef AR_HSZ_BIG + else if (strncmp(AIAMAGBIG, fl_magic, SAIAMAG) == 0) + { + /* read big variant */ + file_archscan_big(fd, archive, func, closure); + } +#endif + + close( fd ); +} + +# endif /* AIAMAG - RS6000 AIX */ + +# endif /* USE_FILEUNIX */ |