summaryrefslogtreecommitdiff
path: root/jam-files/engine/fileunix.c
diff options
context:
space:
mode:
authorKenneth Heafield <github@kheafield.com>2012-05-12 14:01:52 -0400
committerKenneth Heafield <github@kheafield.com>2012-05-12 14:01:52 -0400
commit3faecf9a00512dcbc8712c4bca9adae72fb64410 (patch)
tree9761b50d12f81a675fb7cbc663ceebad15079f78 /jam-files/engine/fileunix.c
parentc806a8fff63043f63773874986301f2822a2b552 (diff)
Give in and copy bjam into cdec source code
Diffstat (limited to 'jam-files/engine/fileunix.c')
-rw-r--r--jam-files/engine/fileunix.c501
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 */