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/* 8 * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS 9 * 10 * External routines: 11 * 12 * file_dirscan() - scan a directory for files 13 * file_time() - get timestamp of file, if not done by file_dirscan() 14 * file_archscan() - scan an archive for files 15 * 16 * File_dirscan() and file_archscan() call back a caller provided function 17 * for each file found. A flag to this callback function lets file_dirscan() 18 * and file_archscan() indicate that a timestamp is being provided with the 19 * file. If file_dirscan() or file_archscan() do not provide the file's 20 * timestamp, interested parties may later call file_time(). 21 * 22 * 04/08/94 (seiwald) - Coherent/386 support added. 23 * 12/19/94 (mikem) - solaris string table insanity support 24 * 02/14/95 (seiwald) - parse and build /xxx properly 25 * 05/03/96 (seiwald) - split into pathunix.c 26 * 11/21/96 (peterk) - BEOS does not have Unix-style archives 27 * 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan 28 * 04/03/01 (seiwald) - AIX uses SARMAG 29 * 07/16/02 (seiwald) - Support BSD style long filename in archives. 30 * 11/04/02 (seiwald) - const-ing for string literals 31 * 12/27/02 (seiwald) - support for AIX big archives 32 * 12/30/02 (seiwald) - terminate ar_hdr for solaris sscanf() 33 * 12/30/02 (seiwald) - skip solaris' empty archive member names (/, //xxx) 34 */ 35 36# include "jam.h" 37# include "filesys.h" 38# include "pathsys.h" 39 40# ifdef USE_FILEUNIX 41 42# if defined( OS_SEQUENT ) || \ 43 defined( OS_DGUX ) || \ 44 defined( OS_SCO ) || \ 45 defined( OS_ISC ) 46# define PORTAR 1 47# endif 48 49# if defined( OS_RHAPSODY ) || \ 50 defined( OS_MACOSX ) || \ 51 defined( OS_NEXT ) 52/* need unistd for rhapsody's proper lseek */ 53# include <sys/dir.h> 54# include <unistd.h> 55# define STRUCT_DIRENT struct direct 56# else 57# include <dirent.h> 58# define STRUCT_DIRENT struct dirent 59# endif 60 61# ifdef __CYGWIN__ 62# include <unistd.h> 63# endif 64 65# ifdef OS_COHERENT 66# include <arcoff.h> 67# define HAVE_AR 68# endif 69 70# if defined( OS_MVS ) || \ 71 defined( OS_INTERIX ) 72 73#define ARMAG "!<arch>\n" 74#define SARMAG 8 75#define ARFMAG "`\n" 76 77struct ar_hdr /* archive file member header - printable ascii */ 78{ 79 char ar_name[16]; /* file member name - `/' terminated */ 80 char ar_date[12]; /* file member date - decimal */ 81 char ar_uid[6]; /* file member user id - decimal */ 82 char ar_gid[6]; /* file member group id - decimal */ 83 char ar_mode[8]; /* file member mode - octal */ 84 char ar_size[10]; /* file member size - decimal */ 85 char ar_fmag[2]; /* ARFMAG - string to end header */ 86}; 87 88# define HAVE_AR 89# endif 90 91# if defined( OS_QNX ) || \ 92 defined( OS_BEOS ) || \ 93 defined( OS_HAIKU ) || \ 94 defined( OS_MPEIX ) 95# define NO_AR 96# define HAVE_AR 97# endif 98 99# ifndef HAVE_AR 100# ifdef _AIX43 101/* AIX 43 ar SUPPORTs only __AR_BIG__ */ 102# define __AR_BIG__ 103# endif 104# include <ar.h> 105# endif 106 107# ifdef OPT_STAT_CACHE_SERVER_EXT 108# include "beos_stat_cache.h" 109# define opendir beos_stat_cache_opendir 110# define readdir beos_stat_cache_readdir 111# define closedir beos_stat_cache_closedir 112# endif 113 114/* 115 * file_dirscan() - scan a directory for files 116 */ 117 118void 119file_dirscan( 120 const char *dir, 121 scanback func, 122 void *closure ) 123{ 124 PATHNAME f; 125 DIR *d; 126 STRUCT_DIRENT *dirent; 127 char filename[ MAXJPATH ]; 128 129 /* First enter directory itself */ 130 131 memset( (char *)&f, '\0', sizeof( f ) ); 132 133 f.f_dir.ptr = dir; 134 f.f_dir.len = strlen(dir); 135 136 dir = *dir ? dir : "."; 137 138 /* Special case / : enter it */ 139 140 if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '/' ) 141 (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); 142 143 /* Now enter contents of directory */ 144 145 if( !( d = opendir( dir ) ) ) 146 return; 147 148 if( DEBUG_BINDSCAN ) 149 printf( "scan directory %s\n", dir ); 150 151 while( dirent = readdir( d ) ) 152 { 153# ifdef old_sinix 154 /* Broken structure definition on sinix. */ 155 f.f_base.ptr = dirent->d_name - 2; 156# else 157 f.f_base.ptr = dirent->d_name; 158# endif 159 f.f_base.len = strlen( f.f_base.ptr ); 160 161 path_build( &f, filename, 0 ); 162 163 (*func)( closure, filename, 0 /* not stat()'ed */, (time_t)0 ); 164 } 165 166 closedir( d ); 167} 168 169/* 170 * file_time() - get timestamp of file, if not done by file_dirscan() 171 */ 172 173int 174file_time( 175 const char *filename, 176 time_t *time ) 177{ 178 struct stat statbuf; 179 180# ifdef OPT_STAT_CACHE_SERVER_EXT 181 if( beos_stat_cache_stat( filename, &statbuf ) < 0 ) 182 return -1; 183# else 184 if( stat( filename, &statbuf ) < 0 ) 185 return -1; 186# endif 187 188 *time = statbuf.st_mtime; 189 return 0; 190} 191 192/* 193 * file_archscan() - scan an archive for files 194 */ 195 196# ifndef AIAMAG /* God-fearing UNIX */ 197 198# define SARFMAG 2 199# define SARHDR sizeof( struct ar_hdr ) 200 201void 202file_archscan( 203 const char *archive, 204 scanback func, 205 void *closure ) 206{ 207# ifndef NO_AR 208 struct ar_hdr ar_hdr; 209 char buf[ MAXJPATH ]; 210 long offset; 211 char *string_table = 0; 212 int fd; 213 214 if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 ) 215 return; 216 217 if( read( fd, buf, SARMAG ) != SARMAG || 218 strncmp( ARMAG, buf, SARMAG ) ) 219 { 220 close( fd ); 221 return; 222 } 223 224 offset = SARMAG; 225 226 if( DEBUG_BINDSCAN ) 227 printf( "scan archive %s\n", archive ); 228 229 while( read( fd, &ar_hdr, SARHDR ) == SARHDR && 230 !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) ) 231 { 232 long lar_date; 233 long lar_size; 234 char lar_name[256]; 235 char *dst = lar_name; 236 237 /* solaris sscanf() does strlen first, so terminate somewhere */ 238 239 ar_hdr.ar_fmag[0] = 0; 240 241 /* Get date & size */ 242 243 sscanf( ar_hdr.ar_date, "%ld", &lar_date ); 244 sscanf( ar_hdr.ar_size, "%ld", &lar_size ); 245 246 /* Handle solaris string table. 247 ** The entry under the name // is the table, 248 ** and entries with the name /nnnn refer to the table. 249 */ 250 251 if( ar_hdr.ar_name[0] != '/' ) 252 { 253 /* traditional archive entry names: 254 ** ends at the first space, /, or null. 255 */ 256 257 char *src = ar_hdr.ar_name; 258 const char *e = src + sizeof( ar_hdr.ar_name ); 259 260 while( src < e && *src && *src != ' ' && *src != '/' ) 261 *dst++ = *src++; 262 } 263 else if( ar_hdr.ar_name[1] == '/' ) 264 { 265 /* this is the "string table" entry of the symbol table, 266 ** which holds strings of filenames that are longer than 267 ** 15 characters (ie. don't fit into a ar_name) 268 */ 269 270 string_table = (char *)malloc(lar_size); 271 272 lseek(fd, offset + SARHDR, 0); 273 if( read(fd, string_table, lar_size) != lar_size ) 274 printf( "error reading string table\n" ); 275 } 276 else if( string_table && ar_hdr.ar_name[1] != ' ' ) 277 { 278 /* Long filenames are recognized by "/nnnn" where nnnn is 279 ** the offset of the string in the string table represented 280 ** in ASCII decimals. 281 */ 282 283 char *src = string_table + atoi( ar_hdr.ar_name + 1 ); 284 285 while( *src != '/' ) 286 *dst++ = *src++; 287 } 288 289 /* Terminate lar_name */ 290 291 *dst = 0; 292 293 /* Modern (BSD4.4) long names: if the name is "#1/nnnn", 294 ** then the actual name is the nnnn bytes after the header. 295 */ 296 297 if( !strcmp( lar_name, "#1" ) ) 298 { 299 int len = atoi( ar_hdr.ar_name + 3 ); 300 if( read( fd, lar_name, len ) != len ) 301 printf("error reading archive entry\n"); 302 lar_name[len] = 0; 303 } 304 305 /* Build name and pass it on. */ 306 307 if( lar_name[0] ) 308 { 309 if( DEBUG_BINDSCAN ) 310 printf( "archive name %s found\n", lar_name ); 311 312 sprintf( buf, "%s(%s)", archive, lar_name ); 313 314 (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date ); 315 } 316 317 /* Position at next member */ 318 319 offset += SARHDR + ( ( lar_size + 1 ) & ~1 ); 320 lseek( fd, offset, 0 ); 321 } 322 323 if (string_table) 324 free(string_table); 325 326 close( fd ); 327 328# endif /* NO_AR */ 329 330} 331 332# else /* AIAMAG - RS6000 AIX */ 333 334void 335file_archscan( 336 const char *archive, 337 scanback func, 338 void *closure ) 339{ 340 struct fl_hdr fl_hdr; 341 342 struct { 343 struct ar_hdr hdr; 344 char pad[ 256 ]; 345 } ar_hdr ; 346 347 char buf[ MAXJPATH ]; 348 long offset; 349 int fd; 350 351 if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 ) 352 return; 353 354# ifdef __AR_BIG__ 355 356 if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ || 357 strncmp( AIAMAGBIG, fl_hdr.fl_magic, SAIAMAG ) ) 358 { 359 if( strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) ) 360 printf( "Can't read new archive %s before AIX 4.3.\n" ); 361 362 close( fd ); 363 return; 364 } 365 366# else 367 368 if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ || 369 strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) ) 370 { 371 close( fd ); 372 return; 373 } 374 375# endif 376 377 sscanf( fl_hdr.fl_fstmoff, "%ld", &offset ); 378 379 if( DEBUG_BINDSCAN ) 380 printf( "scan archive %s\n", archive ); 381 382 while( offset > 0 && 383 lseek( fd, offset, 0 ) >= 0 && 384 read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) ) 385 { 386 long lar_date; 387 int lar_namlen; 388 389 sscanf( ar_hdr.hdr.ar_namlen, "%d", &lar_namlen ); 390 sscanf( ar_hdr.hdr.ar_date, "%ld", &lar_date ); 391 sscanf( ar_hdr.hdr.ar_nxtmem, "%ld", &offset ); 392 393 if( !lar_namlen ) 394 continue; 395 396 ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0'; 397 398 sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name ); 399 400 (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date ); 401 } 402 403 close( fd ); 404} 405 406# endif /* AIAMAG - RS6000 AIX */ 407 408# endif /* USE_FILEUNIX */ 409 410