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 * filevms.c - scan directories and libaries on VMS 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 * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length! 23 * 05/03/96 (seiwald) - split into pathvms.c 24 * 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan 25 * 03/23/01 (seiwald) - VMS C++ changes. 26 * 11/04/02 (seiwald) - const-ing for string literals 27 */ 28 29# include "jam.h" 30# include "filesys.h" 31# include "pathsys.h" 32 33# ifdef OS_VMS 34 35# include <rms.h> 36# include <iodef.h> 37# include <ssdef.h> 38# include <string.h> 39# include <stdlib.h> 40# include <stdio.h> 41# include <descrip.h> 42 43#include <lbrdef.h> 44#include <credef.h> 45#include <mhddef.h> 46#include <lhidef.h> 47#include <lib$routines.h> 48#include <starlet.h> 49 50/* Supply missing prototypes for lbr$-routines*/ 51 52extern "C" { 53 54int lbr$set_module( 55 void **, 56 unsigned long *, 57 struct dsc$descriptor_s *, 58 unsigned short *, 59 void * ); 60 61int lbr$open( void **, 62 struct dsc$descriptor_s *, 63 void *, 64 void *, 65 void *, 66 void *, 67 void * ); 68 69int lbr$ini_control( 70 void **, 71 unsigned long *, 72 unsigned long *, 73 void * ); 74 75int lbr$get_index( 76 void **, 77 unsigned long *, 78 int (*func)( struct dsc$descriptor_s *, unsigned long *), 79 void * ); 80 81int lbr$close( 82 void ** ); 83 84} 85 86static void 87file_cvttime( 88 unsigned int *curtime, 89 time_t *unixtime ) 90{ 91 static const size_t divisor = 10000000; 92 static unsigned int bastim[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */ 93 int delta[2], remainder; 94 95 lib$subx( curtime, bastim, delta ); 96 lib$ediv( &divisor, delta, unixtime, &remainder ); 97} 98 99# define DEFAULT_FILE_SPECIFICATION "[]*.*;0" 100 101# define min( a,b ) ((a)<(b)?(a):(b)) 102 103void 104file_dirscan( 105 const char *dir, 106 scanback func, 107 void *closure ) 108{ 109 110 struct FAB xfab; 111 struct NAM xnam; 112 struct XABDAT xab; 113 char esa[256]; 114 char filename[256]; 115 char filename2[256]; 116 char dirname[256]; 117 register int status; 118 PATHNAME f; 119 120 memset( (char *)&f, '\0', sizeof( f ) ); 121 122 f.f_root.ptr = dir; 123 f.f_root.len = strlen( dir ); 124 125 /* get the input file specification 126 */ 127 xnam = cc$rms_nam; 128 xnam.nam$l_esa = esa; 129 xnam.nam$b_ess = sizeof( esa ) - 1; 130 xnam.nam$l_rsa = filename; 131 xnam.nam$b_rss = min( sizeof( filename ) - 1, NAM$C_MAXRSS ); 132 133 xab = cc$rms_xabdat; /* initialize extended attributes */ 134 xab.xab$b_cod = XAB$C_DAT; /* ask for date */ 135 xab.xab$l_nxt = NULL; /* terminate XAB chain */ 136 137 xfab = cc$rms_fab; 138 xfab.fab$l_dna = DEFAULT_FILE_SPECIFICATION; 139 xfab.fab$b_dns = sizeof( DEFAULT_FILE_SPECIFICATION ) - 1; 140 xfab.fab$l_fop = FAB$M_NAM; 141 xfab.fab$l_fna = (char *)dir; /* address of file name */ 142 xfab.fab$b_fns = strlen( dir ); /* length of file name */ 143 xfab.fab$l_nam = &xnam; /* address of NAB block */ 144 xfab.fab$l_xab = (char *)&xab; /* address of XAB block */ 145 146 147 status = sys$parse( &xfab ); 148 149 if( DEBUG_BINDSCAN ) 150 printf( "scan directory %s\n", dir ); 151 152 if ( !( status & 1 ) ) 153 return; 154 155 156 157 /* Add bogus directory for [000000] */ 158 159 if( !strcmp( dir, "[000000]" ) ) 160 { 161 (*func)( closure, "[000000]", 1 /* time valid */, 1 /* old but true */ ); 162 } 163 164 /* Add bogus directory for [] */ 165 166 if( !strcmp( dir, "[]" ) ) 167 { 168 (*func)( closure, "[]", 1 /* time valid */, 1 /* old but true */ ); 169 (*func)( closure, "[-]", 1 /* time valid */, 1 /* old but true */ ); 170 } 171 172 while ( (status = sys$search( &xfab )) & 1 ) 173 { 174 char *s; 175 time_t time; 176 177 /* "I think that might work" - eml */ 178 179 sys$open( &xfab ); 180 sys$close( &xfab ); 181 182 file_cvttime( (unsigned int *)&xab.xab$q_rdt, &time ); 183 184 filename[xnam.nam$b_rsl] = '\0'; 185 186 /* What we do with the name depends on the suffix: */ 187 /* .dir is a directory */ 188 /* .xxx is a file with a suffix */ 189 /* . is no suffix at all */ 190 191 if( xnam.nam$b_type == 4 && !strncmp( xnam.nam$l_type, ".DIR", 4 ) ) 192 { 193 /* directory */ 194 sprintf( dirname, "[.%.*s]", xnam.nam$b_name, xnam.nam$l_name ); 195 f.f_dir.ptr = dirname; 196 f.f_dir.len = strlen( dirname ); 197 f.f_base.ptr = 0; 198 f.f_base.len = 0; 199 f.f_suffix.ptr = 0; 200 f.f_suffix.len = 0; 201 } 202 else 203 { 204 /* normal file with a suffix */ 205 f.f_dir.ptr = 0; 206 f.f_dir.len = 0; 207 f.f_base.ptr = xnam.nam$l_name; 208 f.f_base.len = xnam.nam$b_name; 209 f.f_suffix.ptr = xnam.nam$l_type; 210 f.f_suffix.len = xnam.nam$b_type; 211 } 212 213 path_build( &f, filename2, 0 ); 214 215 /* 216 if( DEBUG_SEARCH ) 217 printf("root '%s' base %.*s suf %.*s = %s\n", 218 dir, 219 xnam.nam$b_name, xnam.nam$l_name, 220 xnam.nam$b_type, xnam.nam$l_type, 221 filename2); 222 */ 223 224 (*func)( closure, filename2, 1 /* time valid */, time ); 225 } 226} 227 228int 229file_time( 230 const char *filename, 231 time_t *time ) 232{ 233 /* This should never be called, as all files are */ 234 /* timestampped in file_dirscan() and file_archscan() */ 235 return -1; 236} 237 238static char *VMS_archive = 0; 239static scanback VMS_func; 240static void *VMS_closure; 241static void *context; 242 243static int 244file_archmember( 245 struct dsc$descriptor_s *module, 246 unsigned long *rfa ) 247{ 248 static struct dsc$descriptor_s bufdsc = 249 {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL}; 250 251 struct mhddef *mhd; 252 char filename[128]; 253 char buf[ MAXJPATH ]; 254 255 int status; 256 time_t library_date; 257 258 register int i; 259 register char *p; 260 261 bufdsc.dsc$a_pointer = filename; 262 bufdsc.dsc$w_length = sizeof( filename ); 263 status = lbr$set_module( &context, rfa, &bufdsc, 264 &bufdsc.dsc$w_length, NULL ); 265 266 if ( !(status & 1) ) 267 return ( 1 ); 268 269 mhd = (struct mhddef *)filename; 270 271 file_cvttime( &mhd->mhd$l_datim, &library_date ); 272 273 for ( i = 0, p = module->dsc$a_pointer; i < module->dsc$w_length; i++, p++ ) 274 filename[i] = *p; 275 276 filename[i] = '\0'; 277 278 sprintf( buf, "%s(%s.obj)", VMS_archive, filename ); 279 280 (*VMS_func)( VMS_closure, buf, 1 /* time valid */, (time_t)library_date ); 281 282 return ( 1 ); 283} 284 285void 286file_archscan( 287 const char *archive, 288 scanback func, 289 void *closure ) 290{ 291 static struct dsc$descriptor_s library = 292 {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL}; 293 294 unsigned long lfunc = LBR$C_READ; 295 unsigned long typ = LBR$C_TYP_UNK; 296 unsigned long index = 1; 297 298 register int status; 299 300 VMS_archive = (char *)archive; 301 VMS_func = func; 302 VMS_closure = closure; 303 304 status = lbr$ini_control( &context, &lfunc, &typ, NULL ); 305 if ( !( status & 1 ) ) 306 return; 307 308 library.dsc$a_pointer = (char *)archive; 309 library.dsc$w_length = strlen( archive ); 310 311 status = lbr$open( &context, &library, NULL, NULL, NULL, NULL, NULL ); 312 if ( !( status & 1 ) ) 313 return; 314 315 (void) lbr$get_index( &context, &index, file_archmember, NULL ); 316 317 (void) lbr$close( &context ); 318} 319 320# endif /* VMS */ 321 322