]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | /* This file is ALSO: | |
8 | * Copyright 2001-2004 David Abrahams. | |
9 | * Copyright 2005 Rene Rivera. | |
10 | * Copyright 2015 Artur Shepilko. | |
11 | * Distributed under the Boost Software License, Version 1.0. | |
12 | * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) | |
13 | */ | |
14 | ||
15 | ||
16 | #include "jam.h" | |
17 | #include "filesys.h" | |
18 | ||
19 | #include "object.h" | |
20 | #include "pathsys.h" | |
21 | #include "strings.h" | |
22 | ||
23 | ||
24 | #ifdef OS_VMS | |
25 | ||
26 | /* | |
27 | * filevms.c - manipulate file names and scan directories on VMS. | |
28 | * | |
29 | * This implementation is based on POSIX-style path manipulation. | |
30 | * | |
31 | * VMS CTRL directly supports both POSIX- and native VMS-style path expressions, | |
32 | * with the POSIX-to-VMS path translation performed internally by the same | |
33 | * set of functions. For the most part such processing is transparent, with | |
34 | * few differences mainly related to file versions (in POSIX mode only the recent | |
35 | * version is visible). | |
36 | * | |
37 | * This should allow us to re-use fileunix.c implementation, | |
38 | * excluding archive/library member processing. | |
39 | * | |
40 | * Thus in jam-files the path references can also remain POSIX/UNIX-style on all | |
41 | * levels EXCEPT in actions scope, where these must be translated to the native | |
42 | * VMS-style. This approach is somewhat similar to jam CYGWIN handling. | |
43 | * | |
44 | * | |
45 | * External routines: | |
46 | * file_archscan() - scan an archive for files | |
47 | * file_mkdir() - create a directory | |
48 | * file_supported_fmt_resolution() - file modification timestamp resolution | |
49 | * | |
50 | * External routines called only via routines in filesys.c: | |
51 | * file_collect_dir_content_() - collects directory content information | |
52 | * file_dirscan_() - OS specific file_dirscan() implementation | |
53 | * file_query_() - query information about a path from the OS | |
54 | * file_collect_archive_content_() - collects information about archive members | |
55 | * file_archivescan_() - OS specific file_archivescan() implementation | |
56 | */ | |
57 | ||
58 | #include <assert.h> | |
59 | #include <stdio.h> | |
60 | ||
61 | #include <sys/stat.h> /* needed for mkdir() */ | |
62 | #include <unistd.h> /* needed for read and close prototype */ | |
63 | ||
64 | #include <dirent.h> | |
65 | #define STRUCT_DIRENT struct dirent | |
66 | ||
67 | ||
68 | void path_translate_to_os_( char const * f, string * file ); | |
69 | ||
70 | /* | |
71 | * file_collect_dir_content_() - collects directory content information | |
72 | */ | |
73 | ||
74 | int file_collect_dir_content_( file_info_t * const d ) | |
75 | { | |
76 | LIST * files = L0; | |
77 | PATHNAME f; | |
78 | DIR * dd; | |
79 | STRUCT_DIRENT * dirent; | |
80 | string path[ 1 ]; | |
81 | char const * dirstr; | |
82 | ||
83 | assert( d ); | |
84 | assert( d->is_dir ); | |
85 | assert( list_empty( d->files ) ); | |
86 | ||
87 | dirstr = object_str( d->name ); | |
88 | ||
89 | memset( (char *)&f, '\0', sizeof( f ) ); | |
90 | f.f_dir.ptr = dirstr; | |
91 | f.f_dir.len = strlen( dirstr ); | |
92 | ||
93 | if ( !*dirstr ) dirstr = "."; | |
94 | ||
95 | if ( !( dd = opendir( dirstr ) ) ) | |
96 | return -1; | |
97 | ||
98 | string_new( path ); | |
99 | while ( ( dirent = readdir( dd ) ) ) | |
100 | { | |
101 | OBJECT * name; | |
102 | f.f_base.ptr = dirent->d_name | |
103 | #ifdef old_sinix | |
104 | - 2 /* Broken structure definition on sinix. */ | |
105 | #endif | |
106 | ; | |
107 | f.f_base.len = strlen( f.f_base.ptr ); | |
108 | ||
109 | string_truncate( path, 0 ); | |
110 | path_build( &f, path ); | |
111 | name = object_new( path->value ); | |
112 | /* Immediately stat the file to preserve invariants. */ | |
113 | if ( file_query( name ) ) | |
114 | files = list_push_back( files, name ); | |
115 | else | |
116 | object_free( name ); | |
117 | } | |
118 | string_free( path ); | |
119 | ||
120 | closedir( dd ); | |
121 | ||
122 | d->files = files; | |
123 | return 0; | |
124 | } | |
125 | ||
126 | ||
127 | /* | |
128 | * file_dirscan_() - OS specific file_dirscan() implementation | |
129 | */ | |
130 | ||
131 | void file_dirscan_( file_info_t * const d, scanback func, void * closure ) | |
132 | { | |
133 | assert( d ); | |
134 | assert( d->is_dir ); | |
135 | ||
136 | /* Special case / : enter it */ | |
137 | if ( !strcmp( object_str( d->name ), "/" ) ) | |
138 | (*func)( closure, d->name, 1 /* stat()'ed */, &d->time ); | |
139 | } | |
140 | ||
141 | ||
142 | /* | |
143 | * file_mkdir() - create a directory | |
144 | */ | |
145 | ||
146 | int file_mkdir( char const * const path ) | |
147 | { | |
148 | /* Explicit cast to remove const modifiers and avoid related compiler | |
149 | * warnings displayed when using the intel compiler. | |
150 | */ | |
151 | return mkdir( (char *)path, 0777 ); | |
152 | } | |
153 | ||
154 | ||
155 | /* | |
156 | * file_query_() - query information about a path from the OS | |
157 | */ | |
158 | ||
159 | void file_query_( file_info_t * const info ) | |
160 | { | |
161 | file_query_posix_( info ); | |
162 | } | |
163 | ||
164 | ||
7c673cae FG |
165 | /*------------------------------------------------------------------------------ |
166 | * VMS-specific processing: | |
167 | * | |
168 | */ | |
169 | ||
170 | #include <descrip.h> | |
171 | #include <lbrdef.h> | |
172 | #include <credef.h> | |
173 | #include <mhddef.h> | |
174 | #include <lhidef.h> | |
175 | #include <lib$routines.h> | |
176 | #include <starlet.h> | |
177 | ||
178 | /* Supply missing prototypes for lbr$-routines*/ | |
179 | ||
180 | #ifdef __cplusplus | |
181 | extern "C" { | |
182 | #endif /* __cplusplus */ | |
183 | ||
184 | int lbr$set_module( | |
185 | void **, | |
186 | unsigned long *, | |
187 | struct dsc$descriptor_s *, | |
188 | unsigned short *, | |
189 | void * ); | |
190 | ||
191 | int lbr$open( void **, | |
192 | struct dsc$descriptor_s *, | |
193 | void *, | |
194 | void *, | |
195 | void *, | |
196 | void *, | |
197 | void * ); | |
198 | ||
199 | int lbr$ini_control( | |
200 | void **, | |
201 | unsigned long *, | |
202 | unsigned long *, | |
203 | void * ); | |
204 | ||
205 | int lbr$get_index( | |
206 | void **, | |
207 | unsigned long * const, | |
208 | int (*func)( struct dsc$descriptor_s *, unsigned long *), | |
209 | void * ); | |
210 | ||
211 | int lbr$search( | |
212 | void **, | |
213 | unsigned long * const, | |
214 | unsigned short *, | |
215 | int (*func)( struct dsc$descriptor_s *, unsigned long *), | |
216 | unsigned long *); | |
217 | ||
218 | int lbr$close( | |
219 | void ** ); | |
220 | ||
221 | #ifdef __cplusplus | |
222 | } | |
223 | #endif /* __cplusplus */ | |
224 | ||
225 | ||
226 | ||
227 | static void | |
228 | file_cvttime( | |
229 | unsigned int *curtime, | |
230 | time_t *unixtime ) | |
231 | { | |
232 | static const size_t divisor = 10000000; | |
233 | static unsigned int bastim[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */ | |
234 | int delta[2], remainder; | |
235 | ||
236 | lib$subx( curtime, bastim, delta ); | |
237 | lib$ediv( &divisor, delta, unixtime, &remainder ); | |
238 | } | |
239 | ||
240 | ||
241 | static void downcase_inplace( char * p ) | |
242 | { | |
243 | for ( ; *p; ++p ) | |
244 | *p = tolower( *p ); | |
245 | } | |
246 | ||
247 | ||
248 | static file_archive_info_t * m_archive = NULL; | |
249 | static file_info_t * m_member_found = NULL; | |
250 | static void * m_lbr_context = NULL; | |
251 | static unsigned short * m_rfa_found = NULL; | |
252 | static const unsigned long LBR_MODINDEX_NUM = 1, | |
253 | LBR_SYMINDEX_NUM = 2; /* GST:global symbol table */ | |
254 | ||
255 | ||
256 | static unsigned int set_archive_symbol( struct dsc$descriptor_s *symbol, | |
257 | unsigned long *rfa ) | |
258 | { | |
259 | file_info_t * member = m_member_found; | |
260 | char buf[ MAXJPATH ] = { 0 }; | |
261 | ||
262 | strncpy(buf, symbol->dsc$a_pointer, symbol->dsc$w_length); | |
263 | buf[ symbol->dsc$w_length ] = 0; | |
264 | ||
265 | member->files = list_push_back( member->files, object_new( buf ) ); | |
266 | ||
267 | return ( 1 ); /* continue */ | |
268 | } | |
269 | ||
270 | ||
271 | static unsigned int set_archive_member( struct dsc$descriptor_s *module, | |
272 | unsigned long *rfa ) | |
273 | { | |
274 | file_archive_info_t * archive = m_archive; | |
275 | ||
276 | static struct dsc$descriptor_s bufdsc = | |
277 | {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL}; | |
278 | ||
279 | struct mhddef *mhd; | |
280 | char filename[128] = { 0 }; | |
281 | char buf[ MAXJPATH ] = { 0 }; | |
282 | ||
283 | int status; | |
284 | time_t library_date; | |
285 | ||
286 | register int i; | |
287 | register char *p; | |
288 | ||
289 | bufdsc.dsc$a_pointer = filename; | |
290 | bufdsc.dsc$w_length = sizeof( filename ); | |
291 | status = lbr$set_module( &m_lbr_context, rfa, &bufdsc, | |
292 | &bufdsc.dsc$w_length, NULL ); | |
293 | ||
294 | if ( !(status & 1) ) | |
295 | return ( 1 ); /* continue */ | |
296 | ||
297 | mhd = (struct mhddef *)filename; | |
298 | ||
299 | file_cvttime( &mhd->mhd$l_datim, &library_date ); | |
300 | ||
301 | /* strncpy( filename, module->dsc$a_pointer, module->dsc$w_length ); | |
302 | */ | |
303 | for ( i = 0, p = module->dsc$a_pointer; i < module->dsc$w_length; ++i, ++p ) | |
304 | filename[ i ] = *p; | |
305 | ||
306 | filename[ i ] = '\0'; | |
307 | ||
308 | if ( strcmp( filename, "" ) != 0 ) | |
309 | { | |
310 | file_info_t * member = 0; | |
311 | ||
312 | /* Construct member's filename as lowercase "module.obj" */ | |
313 | sprintf( buf, "%s.obj", filename ); | |
314 | downcase_inplace( buf ); | |
315 | archive->members = filelist_push_back( archive->members, object_new( buf ) ); | |
316 | ||
317 | member = filelist_back( archive->members ); | |
318 | member->is_file = 1; | |
319 | member->is_dir = 0; | |
320 | member->exists = 0; | |
321 | timestamp_init( &member->time, (time_t)library_date, 0 ); | |
322 | ||
323 | m_member_found = member; | |
324 | m_rfa_found = rfa; | |
325 | status = lbr$search(&m_lbr_context, &LBR_SYMINDEX_NUM, m_rfa_found, set_archive_symbol, NULL); | |
326 | } | |
327 | ||
328 | return ( 1 ); /* continue */ | |
329 | } | |
330 | ||
331 | ||
332 | ||
333 | void file_archscan( char const * arch, scanback func, void * closure ) | |
334 | { | |
335 | OBJECT * path = object_new( arch ); | |
336 | file_archive_info_t * archive = file_archive_query( path ); | |
337 | ||
338 | object_free( path ); | |
339 | ||
340 | if ( filelist_empty( archive->members ) ) | |
341 | { | |
342 | if ( DEBUG_BINDSCAN ) | |
343 | out_printf( "scan archive %s\n", object_str( archive->file->name ) ); | |
344 | ||
345 | if ( file_collect_archive_content_( archive ) < 0 ) | |
346 | return; | |
347 | } | |
348 | ||
349 | /* Report the collected archive content. */ | |
350 | { | |
351 | FILELISTITER iter = filelist_begin( archive->members ); | |
352 | FILELISTITER const end = filelist_end( archive->members ); | |
353 | char buf[ MAXJPATH ]; | |
354 | ||
355 | for ( ; iter != end ; iter = filelist_next( iter ) ) | |
356 | { | |
357 | file_info_t * member_file = filelist_item( iter ); | |
358 | LIST * symbols = member_file->files; | |
359 | ||
360 | /* Construct member path: 'archive-path(member-name)' | |
361 | */ | |
362 | sprintf( buf, "%s(%s)", | |
363 | object_str( archive->file->name ), | |
364 | object_str( member_file->name ) ); | |
365 | { | |
366 | OBJECT * const member = object_new( buf ); | |
367 | (*func)( closure, member, 1 /* time valid */, &member_file->time ); | |
368 | object_free( member ); | |
369 | } | |
370 | } | |
371 | } | |
372 | } | |
373 | ||
374 | ||
375 | /* | |
376 | * file_archivescan_() - OS specific file_archivescan() implementation | |
377 | */ | |
378 | void file_archivescan_( file_archive_info_t * const archive, archive_scanback func, | |
379 | void * closure ) | |
380 | { | |
381 | } | |
382 | ||
383 | ||
384 | /* | |
385 | * file_collect_archive_content_() - collects information about archive members | |
386 | */ | |
387 | ||
388 | int file_collect_archive_content_( file_archive_info_t * const archive ) | |
389 | { | |
390 | unsigned short rfa[3]; | |
391 | ||
392 | static struct dsc$descriptor_s library = | |
393 | {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL}; | |
394 | ||
395 | unsigned long lfunc = LBR$C_READ; | |
396 | unsigned long typ = LBR$C_TYP_UNK; | |
397 | ||
398 | register int status; | |
399 | string buf[ 1 ]; | |
400 | char vmspath[ MAXJPATH ] = { 0 }; | |
401 | ||
402 | m_archive = archive; | |
403 | ||
404 | if ( ! filelist_empty( archive->members ) ) filelist_free( archive->members ); | |
405 | ||
406 | /* Translate path to VMS | |
407 | */ | |
408 | string_new( buf ); | |
409 | path_translate_to_os_( object_str( archive->file->name ), buf ); | |
410 | strcpy( vmspath, buf->value ); | |
411 | string_free( buf ); | |
412 | ||
413 | ||
414 | status = lbr$ini_control( &m_lbr_context, &lfunc, &typ, NULL ); | |
415 | if ( !( status & 1 ) ) | |
416 | return -1; | |
417 | ||
418 | library.dsc$a_pointer = vmspath; | |
419 | library.dsc$w_length = strlen( vmspath ); | |
420 | ||
421 | status = lbr$open( &m_lbr_context, &library, NULL, NULL, NULL, NULL, NULL ); | |
422 | if ( !( status & 1 ) ) | |
423 | return -1; | |
424 | ||
425 | /* Scan main index for modules. | |
426 | * For each module search symbol-index to collect module's symbols. | |
427 | */ | |
428 | status = lbr$get_index( &m_lbr_context, &LBR_MODINDEX_NUM, set_archive_member, NULL ); | |
429 | ||
430 | if ( !( status & 1 ) ) | |
431 | return -1; | |
432 | ||
433 | ||
434 | (void) lbr$close( &m_lbr_context ); | |
435 | ||
436 | return 0; | |
437 | } | |
438 | ||
439 | #endif /* OS_VMS */ | |
440 |