2005-12-29 19:40:48 +01:00
|
|
|
/*
|
|
|
|
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
|
|
|
*
|
|
|
|
* This file is part of Jam - see jam.c for Copyright information.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
|
|
|
|
* 04/03/01 (seiwald) - AIX uses SARMAG
|
|
|
|
* 07/16/02 (seiwald) - Support BSD style long filename in archives.
|
|
|
|
* 11/04/02 (seiwald) - const-ing for string literals
|
|
|
|
* 12/27/02 (seiwald) - support for AIX big archives
|
|
|
|
* 12/30/02 (seiwald) - terminate ar_hdr for solaris sscanf()
|
|
|
|
* 12/30/02 (seiwald) - skip solaris' empty archive member names (/, //xxx)
|
|
|
|
*/
|
|
|
|
|
|
|
|
# include "jam.h"
|
|
|
|
# include "filesys.h"
|
|
|
|
# include "pathsys.h"
|
|
|
|
|
|
|
|
# ifdef USE_FILEUNIX
|
|
|
|
|
|
|
|
# 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 )
|
|
|
|
/* 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
|
|
|
|
|
2021-08-27 22:02:33 +02:00
|
|
|
# if defined(__CYGWIN__) || defined(unix)
|
2009-06-26 18:26:50 +02:00
|
|
|
# include <unistd.h>
|
|
|
|
# endif
|
|
|
|
|
2005-12-29 19:40:48 +01:00
|
|
|
# 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 ) || \
|
2008-03-28 15:14:44 +01:00
|
|
|
defined( OS_HAIKU ) || \
|
2005-12-29 19:40:48 +01:00
|
|
|
defined( OS_MPEIX )
|
|
|
|
# define NO_AR
|
|
|
|
# define HAVE_AR
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# ifndef HAVE_AR
|
|
|
|
# ifdef _AIX43
|
|
|
|
/* AIX 43 ar SUPPORTs only __AR_BIG__ */
|
|
|
|
# define __AR_BIG__
|
|
|
|
# endif
|
|
|
|
# include <ar.h>
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# ifdef OPT_STAT_CACHE_SERVER_EXT
|
|
|
|
# include "beos_stat_cache.h"
|
|
|
|
# define opendir beos_stat_cache_opendir
|
|
|
|
# define readdir beos_stat_cache_readdir
|
|
|
|
# define closedir beos_stat_cache_closedir
|
|
|
|
# endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* file_dirscan() - scan a directory for files
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
file_dirscan(
|
|
|
|
const char *dir,
|
|
|
|
scanback func,
|
|
|
|
void *closure )
|
|
|
|
{
|
|
|
|
PATHNAME f;
|
|
|
|
DIR *d;
|
|
|
|
STRUCT_DIRENT *dirent;
|
|
|
|
char filename[ MAXJPATH ];
|
|
|
|
|
|
|
|
/* First enter directory itself */
|
|
|
|
|
|
|
|
memset( (char *)&f, '\0', sizeof( f ) );
|
|
|
|
|
|
|
|
f.f_dir.ptr = dir;
|
|
|
|
f.f_dir.len = strlen(dir);
|
|
|
|
|
|
|
|
dir = *dir ? dir : ".";
|
|
|
|
|
|
|
|
/* Special case / : enter it */
|
|
|
|
|
|
|
|
if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '/' )
|
|
|
|
(*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
|
|
|
|
|
|
|
|
/* Now enter contents of directory */
|
|
|
|
|
|
|
|
if( !( d = opendir( dir ) ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( DEBUG_BINDSCAN )
|
|
|
|
printf( "scan directory %s\n", dir );
|
|
|
|
|
|
|
|
while( dirent = readdir( d ) )
|
|
|
|
{
|
|
|
|
# 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 );
|
|
|
|
|
|
|
|
path_build( &f, filename, 0 );
|
|
|
|
|
|
|
|
(*func)( closure, filename, 0 /* not stat()'ed */, (time_t)0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir( d );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* file_time() - get timestamp of file, if not done by file_dirscan()
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
file_time(
|
|
|
|
const char *filename,
|
|
|
|
time_t *time )
|
|
|
|
{
|
|
|
|
struct stat statbuf;
|
|
|
|
|
|
|
|
# ifdef OPT_STAT_CACHE_SERVER_EXT
|
|
|
|
if( beos_stat_cache_stat( filename, &statbuf ) < 0 )
|
|
|
|
return -1;
|
|
|
|
# else
|
|
|
|
if( stat( filename, &statbuf ) < 0 )
|
|
|
|
return -1;
|
|
|
|
# endif
|
|
|
|
|
|
|
|
*time = statbuf.st_mtime;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* file_archscan() - scan an archive for files
|
|
|
|
*/
|
|
|
|
|
|
|
|
# ifndef AIAMAG /* God-fearing UNIX */
|
|
|
|
|
|
|
|
# define SARFMAG 2
|
|
|
|
# define SARHDR sizeof( struct ar_hdr )
|
|
|
|
|
|
|
|
void
|
|
|
|
file_archscan(
|
|
|
|
const 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 ) )
|
|
|
|
{
|
|
|
|
long lar_date;
|
|
|
|
long lar_size;
|
|
|
|
char lar_name[256];
|
|
|
|
char *dst = lar_name;
|
|
|
|
|
|
|
|
/* solaris sscanf() does strlen first, so terminate somewhere */
|
|
|
|
|
|
|
|
ar_hdr.ar_fmag[0] = 0;
|
|
|
|
|
|
|
|
/* Get date & size */
|
|
|
|
|
|
|
|
sscanf( ar_hdr.ar_date, "%ld", &lar_date );
|
|
|
|
sscanf( ar_hdr.ar_size, "%ld", &lar_size );
|
|
|
|
|
|
|
|
/* Handle solaris string table.
|
|
|
|
** The entry under the name // is the table,
|
|
|
|
** and entries with the name /nnnn refer to the table.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if( ar_hdr.ar_name[0] != '/' )
|
|
|
|
{
|
|
|
|
/* traditional archive entry names:
|
|
|
|
** ends at the first space, /, or null.
|
|
|
|
*/
|
|
|
|
|
|
|
|
char *src = ar_hdr.ar_name;
|
|
|
|
const char *e = src + sizeof( ar_hdr.ar_name );
|
|
|
|
|
|
|
|
while( src < e && *src && *src != ' ' && *src != '/' )
|
|
|
|
*dst++ = *src++;
|
|
|
|
}
|
|
|
|
else 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 *)malloc(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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
char *src = string_table + atoi( ar_hdr.ar_name + 1 );
|
|
|
|
|
|
|
|
while( *src != '/' )
|
|
|
|
*dst++ = *src++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Terminate lar_name */
|
|
|
|
|
|
|
|
*dst = 0;
|
|
|
|
|
|
|
|
/* Modern (BSD4.4) long names: if the name is "#1/nnnn",
|
|
|
|
** then the actual name is the nnnn bytes after the header.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if( !strcmp( lar_name, "#1" ) )
|
|
|
|
{
|
|
|
|
int len = atoi( ar_hdr.ar_name + 3 );
|
|
|
|
if( read( fd, lar_name, len ) != len )
|
|
|
|
printf("error reading archive entry\n");
|
|
|
|
lar_name[len] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build name and pass it on. */
|
|
|
|
|
|
|
|
if( lar_name[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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Position at next member */
|
|
|
|
|
|
|
|
offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
|
|
|
|
lseek( fd, offset, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (string_table)
|
|
|
|
free(string_table);
|
|
|
|
|
|
|
|
close( fd );
|
|
|
|
|
|
|
|
# endif /* NO_AR */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# else /* AIAMAG - RS6000 AIX */
|
|
|
|
|
|
|
|
void
|
|
|
|
file_archscan(
|
|
|
|
const char *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;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
# ifdef __AR_BIG__
|
|
|
|
|
|
|
|
if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ ||
|
|
|
|
strncmp( AIAMAGBIG, fl_hdr.fl_magic, SAIAMAG ) )
|
|
|
|
{
|
|
|
|
if( strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) )
|
|
|
|
printf( "Can't read new archive %s before AIX 4.3.\n" );
|
|
|
|
|
|
|
|
close( fd );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# else
|
|
|
|
|
|
|
|
if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ ||
|
|
|
|
strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) )
|
|
|
|
{
|
|
|
|
close( fd );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
close( fd );
|
|
|
|
}
|
|
|
|
|
|
|
|
# endif /* AIAMAG - RS6000 AIX */
|
|
|
|
|
|
|
|
# endif /* USE_FILEUNIX */
|
|
|
|
|