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 * filent.c - scan directories and archives on NT 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 * 07/10/95 (taylor) Findfirst() returns the first file on NT. 23 * 05/03/96 (seiwald) split apart into pathnt.c 24 * 01/20/00 (seiwald) - Upgraded from K&R to ANSI C 25 * 10/03/00 (anton) - Porting for Borland C++ 5.5 26 * 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan 27 * 11/04/02 (seiwald) - const-ing for string literals 28 * 01/23/03 (seiwald) - long long handles for NT IA64 29 */ 30 31# include "jam.h" 32# include "filesys.h" 33# include "pathsys.h" 34 35# ifdef OS_NT 36 37# ifdef __BORLANDC__ 38# if __BORLANDC__ < 0x550 39# include <dir.h> 40# include <dos.h> 41# endif 42# undef PATHNAME /* cpp namespace collision */ 43# define _finddata_t ffblk 44# endif 45 46# include <io.h> 47# include <sys/stat.h> 48 49/* 50 * file_dirscan() - scan a directory for files 51 */ 52 53# ifdef _M_IA64 54# define FINDTYPE long long 55# else 56# define FINDTYPE long 57# endif 58 59void 60file_dirscan( 61 const char *dir, 62 scanback func, 63 void *closure ) 64{ 65 PATHNAME f; 66 char filespec[ MAXJPATH ]; 67 char filename[ MAXJPATH ]; 68 FINDTYPE handle; 69 int ret; 70 struct _finddata_t finfo[1]; 71 72 /* First enter directory itself */ 73 74 memset( (char *)&f, '\0', sizeof( f ) ); 75 76 f.f_dir.ptr = dir; 77 f.f_dir.len = strlen(dir); 78 79 dir = *dir ? dir : "."; 80 81 /* Special case \ or d:\ : enter it */ 82 83 if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' ) 84 (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); 85 else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' ) 86 (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); 87 88 /* Now enter contents of directory */ 89 90 sprintf( filespec, "%s/*", dir ); 91 92 if( DEBUG_BINDSCAN ) 93 printf( "scan directory %s\n", dir ); 94 95# if defined(__BORLANDC__) && __BORLANDC__ < 0x550 96 if ( ret = findfirst( filespec, finfo, FA_NORMAL | FA_DIREC ) ) 97 return; 98 99 while( !ret ) 100 { 101 time_t time_write = finfo->ff_fdate; 102 103 time_write = (time_write << 16) | finfo->ff_ftime; 104 f.f_base.ptr = finfo->ff_name; 105 f.f_base.len = strlen( finfo->ff_name ); 106 107 path_build( &f, filename ); 108 109 (*func)( closure, filename, 1 /* stat()'ed */, time_write ); 110 111 ret = findnext( finfo ); 112 } 113# else 114 handle = _findfirst( filespec, finfo ); 115 116 if( ret = ( handle == (FINDTYPE)(-1) ) ) 117 return; 118 119 while( !ret ) 120 { 121 f.f_base.ptr = finfo->name; 122 f.f_base.len = strlen( finfo->name ); 123 124 path_build( &f, filename, 0 ); 125 126 (*func)( closure, filename, 1 /* stat()'ed */, finfo->time_write ); 127 128 ret = _findnext( handle, finfo ); 129 } 130 131 _findclose( handle ); 132# endif 133 134} 135 136/* 137 * file_time() - get timestamp of file, if not done by file_dirscan() 138 */ 139 140int 141file_time( 142 const char *filename, 143 time_t *time ) 144{ 145 /* On NT this is called only for C:/ */ 146 147 struct stat statbuf; 148 149 if( stat( filename, &statbuf ) < 0 ) 150 return -1; 151 152 *time = statbuf.st_mtime; 153 154 return 0; 155} 156 157/* 158 * file_archscan() - scan an archive for files 159 */ 160 161/* Straight from SunOS */ 162 163#define ARMAG "!<arch>\n" 164#define SARMAG 8 165 166#define ARFMAG "`\n" 167 168struct ar_hdr { 169 char ar_name[16]; 170 char ar_date[12]; 171 char ar_uid[6]; 172 char ar_gid[6]; 173 char ar_mode[8]; 174 char ar_size[10]; 175 char ar_fmag[2]; 176}; 177 178# define SARFMAG 2 179# define SARHDR sizeof( struct ar_hdr ) 180 181void 182file_archscan( 183 const char *archive, 184 scanback func, 185 void *closure ) 186{ 187 struct ar_hdr ar_hdr; 188 char *string_table = 0; 189 char buf[ MAXJPATH ]; 190 long offset; 191 int fd; 192 193 if( ( fd = open( archive, O_RDONLY | O_BINARY, 0 ) ) < 0 ) 194 return; 195 196 if( read( fd, buf, SARMAG ) != SARMAG || 197 strncmp( ARMAG, buf, SARMAG ) ) 198 { 199 close( fd ); 200 return; 201 } 202 203 offset = SARMAG; 204 205 if( DEBUG_BINDSCAN ) 206 printf( "scan archive %s\n", archive ); 207 208 while( read( fd, &ar_hdr, SARHDR ) == SARHDR && 209 !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) ) 210 { 211 long lar_date; 212 long lar_size; 213 char *name = 0; 214 char *endname; 215 char *c; 216 217 sscanf( ar_hdr.ar_date, "%ld", &lar_date ); 218 sscanf( ar_hdr.ar_size, "%ld", &lar_size ); 219 220 lar_size = ( lar_size + 1 ) & ~1; 221 222 if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] == '/' ) 223 { 224 /* this is the "string table" entry of the symbol table, 225 ** which holds strings of filenames that are longer than 226 ** 15 characters (ie. don't fit into a ar_name 227 */ 228 229 string_table = malloc(lar_size); 230 if (read(fd, string_table, lar_size) != lar_size) 231 printf("error reading string table\n"); 232 offset += SARHDR + lar_size; 233 continue; 234 } 235 else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ') 236 { 237 /* Long filenames are recognized by "/nnnn" where nnnn is 238 ** the offset of the string in the string table represented 239 ** in ASCII decimals. 240 */ 241 242 name = string_table + atoi( ar_hdr.ar_name + 1 ); 243 endname = name + strlen( name ); 244 } 245 else 246 { 247 /* normal name */ 248 name = ar_hdr.ar_name; 249 endname = name + sizeof( ar_hdr.ar_name ); 250 } 251 252 /* strip trailing space, slashes, and backslashes */ 253 254 while( endname-- > name ) 255 if( *endname != ' ' && *endname != '\\' && *endname != '/' ) 256 break; 257 *++endname = 0; 258 259 /* strip leading directory names, an NT specialty */ 260 261 if( c = strrchr( name, '/' ) ) 262 name = c + 1; 263 if( c = strrchr( name, '\\' ) ) 264 name = c + 1; 265 266 sprintf( buf, "%s(%.*s)", archive, endname - name, name ); 267 (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date ); 268 269 offset += SARHDR + lar_size; 270 lseek( fd, offset, 0 ); 271 } 272 273 close( fd ); 274} 275 276# endif /* NT */ 277