]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ada/adaint.c
2010-10-18 Vincent Celier <celier@adacore.com>
[thirdparty/gcc.git] / gcc / ada / adaint.c
CommitLineData
1fac938e 1/****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
1fac938e 7 * C Implementation File *
8 * *
44fef051 9 * Copyright (C) 1992-2010, Free Software Foundation, Inc. *
1fac938e 10 * *
11 * GNAT is free software; you can redistribute it and/or modify it under *
12 * terms of the GNU General Public License as published by the Free Soft- *
6bc9506f 13 * ware Foundation; either version 3, or (at your option) any later ver- *
1fac938e 14 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
15 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
6bc9506f 16 * or FITNESS FOR A PARTICULAR PURPOSE. *
17 * *
18 * As a special exception under Section 7 of GPL version 3, you are granted *
19 * additional permissions described in the GCC Runtime Library Exception, *
20 * version 3.1, as published by the Free Software Foundation. *
21 * *
22 * You should have received a copy of the GNU General Public License and *
23 * a copy of the GCC Runtime Library Exception along with this program; *
24 * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see *
25 * <http://www.gnu.org/licenses/>. *
1fac938e 26 * *
27 * GNAT was originally developed by the GNAT team at New York University. *
e78e8c8e 28 * Extensive contributions were provided by Ada Core Technologies Inc. *
1fac938e 29 * *
30 ****************************************************************************/
31
f15731c4 32/* This file contains those routines named by Import pragmas in
33 packages in the GNAT hierarchy (especially GNAT.OS_Lib) and in
34 package Osint. Many of the subprograms in OS_Lib import standard
35 library calls directly. This file contains all other routines. */
1fac938e 36
37#ifdef __vxworks
f15731c4 38
39/* No need to redefine exit here. */
1fac938e 40#undef exit
f15731c4 41
1fac938e 42/* We want to use the POSIX variants of include files. */
43#define POSIX
44#include "vxWorks.h"
45
46#if defined (__mips_vxworks)
47#include "cacheLib.h"
48#endif /* __mips_vxworks */
49
50#endif /* VxWorks */
51
90bc406c 52#if (defined (__mips) && defined (__sgi)) || defined (__APPLE__)
53#include <unistd.h>
54#endif
55
56#if defined (__hpux__)
57#include <sys/param.h>
58#include <sys/pstat.h>
59#endif
60
cafd02b3 61#ifdef VMS
62#define _POSIX_EXIT 1
ba706ed3 63#define HOST_EXECUTABLE_SUFFIX ".exe"
64#define HOST_OBJECT_SUFFIX ".obj"
cafd02b3 65#endif
66
1fac938e 67#ifdef IN_RTS
68#include "tconfig.h"
69#include "tsystem.h"
9dfe12ae 70
1fac938e 71#include <sys/stat.h>
72#include <fcntl.h>
73#include <time.h>
cafd02b3 74#ifdef VMS
75#include <unixio.h>
76#endif
1fac938e 77
f15731c4 78/* We don't have libiberty, so use malloc. */
1fac938e 79#define xmalloc(S) malloc (S)
f15731c4 80#define xrealloc(V,S) realloc (V,S)
1fac938e 81#else
82#include "config.h"
83#include "system.h"
e2c62f37 84#include "version.h"
1fac938e 85#endif
9dfe12ae 86
fa0b5df1 87#if defined (__MINGW32__)
88
e2a33c18 89#if defined (RTX)
90#include <windows.h>
91#include <Rtapi.h>
fa0b5df1 92#else
9dfe12ae 93#include "mingw32.h"
f60cc57d 94
95/* Current code page to use, set in initialize.c. */
96UINT CurrentCodePage;
fa0b5df1 97#endif
98
9dfe12ae 99#include <sys/utime.h>
a4f295eb 100
101/* For isalpha-like tests in the compiler, we're expected to resort to
102 safe-ctype.h/ISALPHA. This isn't available for the runtime library
103 build, so we fallback on ctype.h/isalpha there. */
104
105#ifdef IN_RTS
f0a28ccb 106#include <ctype.h>
a4f295eb 107#define ISALPHA isalpha
108#endif
2359306a 109
110#elif defined (__Lynx__)
111
112/* Lynx utime.h only defines the entities of interest to us if
113 defined (VMOS_DEV), so ... */
114#define VMOS_DEV
115#include <utime.h>
116#undef VMOS_DEV
117
118#elif !defined (VMS)
9dfe12ae 119#include <utime.h>
9dfe12ae 120#endif
121
5091bc2f 122/* wait.h processing */
9dfe12ae 123#ifdef __MINGW32__
124#if OLD_MINGW
1fac938e 125#include <sys/wait.h>
9dfe12ae 126#endif
8ffbc401 127#elif defined (__vxworks) && defined (__RTP__)
128#include <wait.h>
2359306a 129#elif defined (__Lynx__)
130/* ??? We really need wait.h and it includes resource.h on Lynx. GCC
131 has a resource.h header as well, included instead of the lynx
132 version in our setup, causing lots of errors. We don't really need
133 the lynx contents of this file, so just workaround the issue by
134 preventing the inclusion of the GCC header from doing anything. */
135#define GCC_RESOURCE_H
136#include <sys/wait.h>
5091bc2f 137#elif defined (__nucleus__)
138/* No wait() or waitpid() calls available */
9dfe12ae 139#else
5091bc2f 140/* Default case */
9dfe12ae 141#include <sys/wait.h>
142#endif
1fac938e 143
30592778 144#if defined (_WIN32)
d8dd2062 145#elif defined (VMS)
71a3e619 146
f15731c4 147/* Header files and definitions for __gnat_set_file_time_name. */
71a3e619 148
8620a406 149#define __NEW_STARLET 1
ba706ed3 150#include <vms/rms.h>
151#include <vms/atrdef.h>
152#include <vms/fibdef.h>
153#include <vms/stsdef.h>
154#include <vms/iodef.h>
d8dd2062 155#include <errno.h>
ba706ed3 156#include <vms/descrip.h>
d8dd2062 157#include <string.h>
158#include <unixlib.h>
159
f15731c4 160/* Use native 64-bit arithmetic. */
d8dd2062 161#define unix_time_to_vms(X,Y) \
162 { unsigned long long reftime, tmptime = (X); \
163 $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
164 SYS$BINTIM (&unixtime, &reftime); \
165 Y = tmptime * 10000000 + reftime; }
166
167/* descrip.h doesn't have everything ... */
8620a406 168typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
d8dd2062 169struct dsc$descriptor_fib
170{
8620a406 171 unsigned int fib$l_len;
172 __fibdef_ptr32 fib$l_addr;
d8dd2062 173};
174
71a3e619 175/* I/O Status Block. */
d8dd2062 176struct IOSB
9dfe12ae 177{
d8dd2062 178 unsigned short status, count;
8620a406 179 unsigned int devdep;
d8dd2062 180};
181
182static char *tryfile;
183
71a3e619 184/* Variable length string. */
d8dd2062 185struct vstring
186{
187 short length;
f15731c4 188 char string[NAM$C_MAXRSS+1];
d8dd2062 189};
190
d8dd2062 191#else
192#include <utime.h>
193#endif
194
30592778 195#if defined (_WIN32)
1fac938e 196#include <process.h>
197#endif
198
199#if defined (_WIN32)
4c4697b8 200
1fac938e 201#include <dir.h>
202#include <windows.h>
7db1ef17 203#include <accctrl.h>
204#include <aclapi.h>
fef772a5 205#undef DIR_SEPARATOR
206#define DIR_SEPARATOR '\\'
1fac938e 207#endif
208
209#include "adaint.h"
210
211/* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
212 defined in the current system. On DOS-like systems these flags control
213 whether the file is opened/created in text-translation mode (CR/LF in
214 external file mapped to LF in internal file), but in Unix-like systems,
215 no text translation is required, so these flags have no effect. */
216
1fac938e 217#ifndef O_BINARY
218#define O_BINARY 0
219#endif
220
221#ifndef O_TEXT
222#define O_TEXT 0
223#endif
224
225#ifndef HOST_EXECUTABLE_SUFFIX
226#define HOST_EXECUTABLE_SUFFIX ""
227#endif
228
229#ifndef HOST_OBJECT_SUFFIX
230#define HOST_OBJECT_SUFFIX ".o"
231#endif
232
233#ifndef PATH_SEPARATOR
234#define PATH_SEPARATOR ':'
235#endif
236
237#ifndef DIR_SEPARATOR
238#define DIR_SEPARATOR '/'
239#endif
240
a3b0f4f2 241/* Check for cross-compilation */
8c7d3bad 242#if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
243#define IS_CROSS 1
a3b0f4f2 244int __gnat_is_cross_compiler = 1;
245#else
8c7d3bad 246#undef IS_CROSS
a3b0f4f2 247int __gnat_is_cross_compiler = 0;
248#endif
249
1fac938e 250char __gnat_dir_separator = DIR_SEPARATOR;
251
252char __gnat_path_separator = PATH_SEPARATOR;
253
254/* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
255 the base filenames that libraries specified with -lsomelib options
256 may have. This is used by GNATMAKE to check whether an executable
257 is up-to-date or not. The syntax is
258
259 library_template ::= { pattern ; } pattern NUL
260 pattern ::= [ prefix ] * [ postfix ]
261
262 These should only specify names of static libraries as it makes
263 no sense to determine at link time if dynamic-link libraries are
264 up to date or not. Any libraries that are not found are supposed
265 to be up-to-date:
266
267 * if they are needed but not present, the link
268 will fail,
269
270 * otherwise they are libraries in the system paths and so
271 they are considered part of the system and not checked
272 for that reason.
273
274 ??? This should be part of a GNAT host-specific compiler
275 file instead of being included in all user applications
f15731c4 276 as well. This is only a temporary work-around for 3.11b. */
1fac938e 277
278#ifndef GNAT_LIBRARY_TEMPLATE
30592778 279#if defined (VMS)
1fac938e 280#define GNAT_LIBRARY_TEMPLATE "*.olb"
281#else
282#define GNAT_LIBRARY_TEMPLATE "lib*.a"
283#endif
284#endif
285
286const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
287
f15731c4 288/* This variable is used in hostparm.ads to say whether the host is a VMS
289 system. */
290#ifdef VMS
291const int __gnat_vmsp = 1;
292#else
293const int __gnat_vmsp = 0;
294#endif
295
30592778 296#if defined (VMS)
9dfe12ae 297#define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
e633acdc 298
5091bc2f 299#elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
9dfe12ae 300#define GNAT_MAX_PATH_LEN PATH_MAX
301
302#else
303
304#if defined (__MINGW32__)
305#include "mingw32.h"
306
307#if OLD_MINGW
308#include <sys/param.h>
309#endif
e633acdc 310
311#else
312#include <sys/param.h>
9dfe12ae 313#endif
314
8ae72cac 315#ifdef MAXPATHLEN
9dfe12ae 316#define GNAT_MAX_PATH_LEN MAXPATHLEN
8ae72cac 317#else
318#define GNAT_MAX_PATH_LEN 256
319#endif
e633acdc 320
321#endif
322
5f93bcbf 323/* Used for Ada bindings */
d2697a05 324const int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
5f93bcbf 325
326/* Reset the file attributes as if no system call had been performed */
327void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
328
9dfe12ae 329/* The __gnat_max_path_len variable is used to export the maximum
330 length of a path name to Ada code. max_path_len is also provided
331 for compatibility with older GNAT versions, please do not use
332 it. */
333
334int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
335int max_path_len = GNAT_MAX_PATH_LEN;
336
2726b813 337/* Control whether we can use ACL on Windows. */
338
339int __gnat_use_acl = 1;
340
1fac938e 341/* The following macro HAVE_READDIR_R should be defined if the
f15731c4 342 system provides the routine readdir_r. */
1fac938e 343#undef HAVE_READDIR_R
344\f
6d9c3443 345#if defined(VMS) && defined (__LONG_POINTERS)
346
347/* Return a 32 bit pointer to an array of 32 bit pointers
348 given a 64 bit pointer to an array of 64 bit pointers */
349
350typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
351
352static __char_ptr_char_ptr32
353to_ptr32 (char **ptr64)
354{
355 int argc;
356 __char_ptr_char_ptr32 short_argv;
357
358 for (argc=0; ptr64[argc]; argc++);
359
360 /* Reallocate argv with 32 bit pointers. */
361 short_argv = (__char_ptr_char_ptr32) decc$malloc
362 (sizeof (__char_ptr32) * (argc + 1));
363
364 for (argc=0; ptr64[argc]; argc++)
365 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
366
367 short_argv[argc] = (__char_ptr32) 0;
368 return short_argv;
369
370}
371#define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
372#else
373#define MAYBE_TO_PTR32(argv) argv
374#endif
375
44fef051 376static const char ATTR_UNSET = 127;
bce992c9 377
5f93bcbf 378void
d2697a05 379__gnat_reset_attributes
5f93bcbf 380 (struct file_attributes* attr)
381{
bce992c9 382 attr->exists = ATTR_UNSET;
5f93bcbf 383
bce992c9 384 attr->writable = ATTR_UNSET;
385 attr->readable = ATTR_UNSET;
386 attr->executable = ATTR_UNSET;
5f93bcbf 387
bce992c9 388 attr->regular = ATTR_UNSET;
389 attr->symbolic_link = ATTR_UNSET;
390 attr->directory = ATTR_UNSET;
5f93bcbf 391
392 attr->timestamp = (OS_Time)-2;
393 attr->file_length = -1;
394}
395
1e622f0e 396OS_Time
397__gnat_current_time
398 (void)
399{
400 time_t res = time (NULL);
401 return (OS_Time) res;
402}
403
a17c817e 404/* Return the current local time as a string in the ISO 8601 format of
405 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
406 long. */
407
408void
409__gnat_current_time_string
410 (char *result)
411{
412 const char *format = "%Y-%m-%d %H:%M:%S";
413 /* Format string necessary to describe the ISO 8601 format */
414
415 const time_t t_val = time (NULL);
416
417 strftime (result, 22, format, localtime (&t_val));
418 /* Convert the local time into a string following the ISO format, copying
419 at most 22 characters into the result string. */
420
421 result [19] = '.';
422 result [20] = '0';
423 result [21] = '0';
424 /* The sub-seconds are manually set to zero since type time_t lacks the
425 precision necessary for nanoseconds. */
426}
427
1fac938e 428void
9dfe12ae 429__gnat_to_gm_time
430 (OS_Time *p_time,
431 int *p_year,
432 int *p_month,
433 int *p_day,
434 int *p_hours,
435 int *p_mins,
436 int *p_secs)
1fac938e 437{
438 struct tm *res;
9dfe12ae 439 time_t time = (time_t) *p_time;
1fac938e 440
441#ifdef _WIN32
442 /* On Windows systems, the time is sometimes rounded up to the nearest
443 even second, so if the number of seconds is odd, increment it. */
444 if (time & 1)
445 time++;
446#endif
447
9dfe12ae 448#ifdef VMS
449 res = localtime (&time);
450#else
1fac938e 451 res = gmtime (&time);
9dfe12ae 452#endif
1fac938e 453
454 if (res)
455 {
456 *p_year = res->tm_year;
457 *p_month = res->tm_mon;
458 *p_day = res->tm_mday;
459 *p_hours = res->tm_hour;
460 *p_mins = res->tm_min;
461 *p_secs = res->tm_sec;
f15731c4 462 }
1fac938e 463 else
464 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
465}
466
467/* Place the contents of the symbolic link named PATH in the buffer BUF,
468 which has size BUFSIZ. If PATH is a symbolic link, then return the number
5091bc2f 469 of characters of its content in BUF. Otherwise, return -1.
470 For systems not supporting symbolic links, always return -1. */
1fac938e 471
9dfe12ae 472int
f0a28ccb 473__gnat_readlink (char *path ATTRIBUTE_UNUSED,
474 char *buf ATTRIBUTE_UNUSED,
475 size_t bufsiz ATTRIBUTE_UNUSED)
1fac938e 476{
30592778 477#if defined (_WIN32) || defined (VMS) \
478 || defined(__vxworks) || defined (__nucleus__)
1fac938e 479 return -1;
480#else
481 return readlink (path, buf, bufsiz);
482#endif
483}
484
5091bc2f 485/* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
486 If NEWPATH exists it will NOT be overwritten.
487 For systems not supporting symbolic links, always return -1. */
1fac938e 488
489int
f0a28ccb 490__gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
491 char *newpath ATTRIBUTE_UNUSED)
1fac938e 492{
30592778 493#if defined (_WIN32) || defined (VMS) \
494 || defined(__vxworks) || defined (__nucleus__)
1fac938e 495 return -1;
496#else
497 return symlink (oldpath, newpath);
498#endif
499}
500
f15731c4 501/* Try to lock a file, return 1 if success. */
1fac938e 502
30592778 503#if defined (__vxworks) || defined (__nucleus__) \
504 || defined (_WIN32) || defined (VMS)
1fac938e 505
506/* Version that does not use link. */
507
508int
9dfe12ae 509__gnat_try_lock (char *dir, char *file)
1fac938e 510{
1fac938e 511 int fd;
3b18b370 512#ifdef __MINGW32__
513 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
514 TCHAR wfile[GNAT_MAX_PATH_LEN];
515 TCHAR wdir[GNAT_MAX_PATH_LEN];
516
f60cc57d 517 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
518 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
3b18b370 519
520 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
521 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
522#else
523 char full_path[256];
1fac938e 524
525 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
526 fd = open (full_path, O_CREAT | O_EXCL, 0600);
3b18b370 527#endif
528
f15731c4 529 if (fd < 0)
1fac938e 530 return 0;
f15731c4 531
1fac938e 532 close (fd);
533 return 1;
534}
535
1fac938e 536#else
f15731c4 537
1fac938e 538/* Version using link(), more secure over NFS. */
9dfe12ae 539/* See TN 6913-016 for discussion ??? */
1fac938e 540
541int
9dfe12ae 542__gnat_try_lock (char *dir, char *file)
1fac938e 543{
f15731c4 544 char full_path[256];
545 char temp_file[256];
8cb516d7 546 GNAT_STRUCT_STAT stat_result;
1fac938e 547 int fd;
548
549 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
4a3f445c 550 sprintf (temp_file, "%s%cTMP-%ld-%ld",
551 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
1fac938e 552
f15731c4 553 /* Create the temporary file and write the process number. */
1fac938e 554 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
555 if (fd < 0)
556 return 0;
557
558 close (fd);
559
f15731c4 560 /* Link it with the new file. */
1fac938e 561 link (temp_file, full_path);
562
563 /* Count the references on the old one. If we have a count of two, then
f15731c4 564 the link did succeed. Remove the temporary file before returning. */
1fac938e 565 __gnat_stat (temp_file, &stat_result);
566 unlink (temp_file);
567 return stat_result.st_nlink == 2;
568}
569#endif
570
571/* Return the maximum file name length. */
572
573int
6f2c2693 574__gnat_get_maximum_file_name_length (void)
1fac938e 575{
30592778 576#if defined (VMS)
1fac938e 577 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
578 return -1;
579 else
580 return 39;
581#else
582 return -1;
583#endif
584}
585
1fac938e 586/* Return nonzero if file names are case sensitive. */
587
588int
6f2c2693 589__gnat_get_file_names_case_sensitive (void)
1fac938e 590{
cd2495b4 591 const char *sensitive = getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
592
593 if (sensitive != NULL
594 && (sensitive[0] == '0' || sensitive[0] == '1')
595 && sensitive[1] == '\0')
596 return sensitive[0] - '0';
597 else
6cba2d6a 598#if defined (VMS) || defined (WINNT) || defined (__APPLE__)
cd2495b4 599 return 0;
1fac938e 600#else
cd2495b4 601 return 1;
1fac938e 602#endif
603}
604
a027cdc7 605/* Return nonzero if environment variables are case sensitive. */
606
607int
608__gnat_get_env_vars_case_sensitive (void)
609{
610#if defined (VMS) || defined (WINNT)
611 return 0;
612#else
613 return 1;
614#endif
615}
616
1fac938e 617char
6f2c2693 618__gnat_get_default_identifier_character_set (void)
1fac938e 619{
1fac938e 620 return '1';
1fac938e 621}
622
f15731c4 623/* Return the current working directory. */
1fac938e 624
625void
9dfe12ae 626__gnat_get_current_dir (char *dir, int *length)
1fac938e 627{
3b18b370 628#if defined (__MINGW32__)
629 TCHAR wdir[GNAT_MAX_PATH_LEN];
630
631 _tgetcwd (wdir, *length);
632
f60cc57d 633 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
3b18b370 634
635#elif defined (VMS)
1fac938e 636 /* Force Unix style, which is what GNAT uses internally. */
637 getcwd (dir, *length, 0);
638#else
639 getcwd (dir, *length);
640#endif
641
642 *length = strlen (dir);
643
9dfe12ae 644 if (dir [*length - 1] != DIR_SEPARATOR)
645 {
646 dir [*length] = DIR_SEPARATOR;
647 ++(*length);
648 }
f15731c4 649 dir[*length] = '\0';
1fac938e 650}
651
f15731c4 652/* Return the suffix for object files. */
1fac938e 653
654void
9dfe12ae 655__gnat_get_object_suffix_ptr (int *len, const char **value)
1fac938e 656{
657 *value = HOST_OBJECT_SUFFIX;
658
659 if (*value == 0)
660 *len = 0;
661 else
662 *len = strlen (*value);
663
664 return;
665}
666
f15731c4 667/* Return the suffix for executable files. */
1fac938e 668
669void
9dfe12ae 670__gnat_get_executable_suffix_ptr (int *len, const char **value)
1fac938e 671{
672 *value = HOST_EXECUTABLE_SUFFIX;
673 if (!*value)
674 *len = 0;
675 else
676 *len = strlen (*value);
677
678 return;
679}
680
681/* Return the suffix for debuggable files. Usually this is the same as the
f15731c4 682 executable extension. */
1fac938e 683
684void
9dfe12ae 685__gnat_get_debuggable_suffix_ptr (int *len, const char **value)
1fac938e 686{
1fac938e 687 *value = HOST_EXECUTABLE_SUFFIX;
1fac938e 688
689 if (*value == 0)
690 *len = 0;
691 else
692 *len = strlen (*value);
693
694 return;
695}
696
1aa4b9ce 697/* Returns the OS filename and corresponding encoding. */
698
699void
12e8797f 700__gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
701 char *w_filename ATTRIBUTE_UNUSED,
1aa4b9ce 702 char *os_name, int *o_length,
c62e34a4 703 char *encoding ATTRIBUTE_UNUSED, int *e_length)
1aa4b9ce 704{
8c7d3bad 705#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
7bb7733e 706 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
1aa4b9ce 707 *o_length = strlen (os_name);
708 strcpy (encoding, "encoding=utf8");
709 *e_length = strlen (encoding);
710#else
711 strcpy (os_name, filename);
712 *o_length = strlen (filename);
713 *e_length = 0;
714#endif
715}
716
13320214 717/* Delete a file. */
718
719int
720__gnat_unlink (char *path)
721{
8c7d3bad 722#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
13320214 723 {
724 TCHAR wpath[GNAT_MAX_PATH_LEN];
725
f60cc57d 726 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
13320214 727 return _tunlink (wpath);
728 }
729#else
730 return unlink (path);
731#endif
732}
733
734/* Rename a file. */
735
736int
737__gnat_rename (char *from, char *to)
738{
8c7d3bad 739#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
13320214 740 {
741 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
742
f60cc57d 743 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
744 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
13320214 745 return _trename (wfrom, wto);
746 }
747#else
748 return rename (from, to);
749#endif
750}
751
a8d94a8f 752/* Changing directory. */
753
754int
755__gnat_chdir (char *path)
756{
8c7d3bad 757#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
a8d94a8f 758 {
759 TCHAR wpath[GNAT_MAX_PATH_LEN];
760
f60cc57d 761 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
a8d94a8f 762 return _tchdir (wpath);
763 }
764#else
765 return chdir (path);
766#endif
767}
768
437991c2 769/* Removing a directory. */
770
771int
772__gnat_rmdir (char *path)
773{
8c7d3bad 774#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
437991c2 775 {
776 TCHAR wpath[GNAT_MAX_PATH_LEN];
777
f60cc57d 778 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
437991c2 779 return _trmdir (wpath);
780 }
2db7aef0 781#elif defined (VTHREADS)
782 /* rmdir not available */
783 return -1;
437991c2 784#else
785 return rmdir (path);
786#endif
787}
788
e2c62f37 789FILE *
c62e34a4 790__gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
e2c62f37 791{
8c7d3bad 792#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
e2c62f37 793 TCHAR wpath[GNAT_MAX_PATH_LEN];
794 TCHAR wmode[10];
795
e2c62f37 796 S2WS (wmode, mode, 10);
1e622f0e 797
f60cc57d 798 if (encoding == Encoding_Unspecified)
799 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
800 else if (encoding == Encoding_UTF8)
1e622f0e 801 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
802 else
803 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
804
e2c62f37 805 return _tfopen (wpath, wmode);
1e622f0e 806#elif defined (VMS)
807 return decc$fopen (path, mode);
e2c62f37 808#else
8cb516d7 809 return GNAT_FOPEN (path, mode);
7465a8fe 810#endif
e2c62f37 811}
812
e2c62f37 813FILE *
c62e34a4 814__gnat_freopen (char *path, char *mode, FILE *stream, int encoding ATTRIBUTE_UNUSED)
e2c62f37 815{
8c7d3bad 816#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
e2c62f37 817 TCHAR wpath[GNAT_MAX_PATH_LEN];
818 TCHAR wmode[10];
819
e2c62f37 820 S2WS (wmode, mode, 10);
1e622f0e 821
f60cc57d 822 if (encoding == Encoding_Unspecified)
823 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
824 else if (encoding == Encoding_UTF8)
1e622f0e 825 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
826 else
827 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
828
e2c62f37 829 return _tfreopen (wpath, wmode, stream);
1e622f0e 830#elif defined (VMS)
831 return decc$freopen (path, mode, stream);
e2c62f37 832#else
833 return freopen (path, mode, stream);
834#endif
835}
836
1fac938e 837int
9dfe12ae 838__gnat_open_read (char *path, int fmode)
1fac938e 839{
840 int fd;
841 int o_fmode = O_BINARY;
842
843 if (fmode)
844 o_fmode = O_TEXT;
845
f15731c4 846#if defined (VMS)
847 /* Optional arguments mbc,deq,fop increase read performance. */
1fac938e 848 fd = open (path, O_RDONLY | o_fmode, 0444,
849 "mbc=16", "deq=64", "fop=tef");
f15731c4 850#elif defined (__vxworks)
1fac938e 851 fd = open (path, O_RDONLY | o_fmode, 0444);
3b18b370 852#elif defined (__MINGW32__)
853 {
854 TCHAR wpath[GNAT_MAX_PATH_LEN];
855
f60cc57d 856 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 857 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
858 }
1fac938e 859#else
860 fd = open (path, O_RDONLY | o_fmode);
861#endif
f15731c4 862
1fac938e 863 return fd < 0 ? -1 : fd;
864}
865
30592778 866#if defined (__MINGW32__)
1fac938e 867#define PERM (S_IREAD | S_IWRITE)
9dfe12ae 868#elif defined (VMS)
869/* Excerpt from DECC C RTL Reference Manual:
870 To create files with OpenVMS RMS default protections using the UNIX
871 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
872 and open with a file-protection mode argument of 0777 in a program
873 that never specifically calls umask. These default protections include
874 correctly establishing protections based on ACLs, previous versions of
875 files, and so on. */
876#define PERM 0777
1fac938e 877#else
878#define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
879#endif
880
881int
9dfe12ae 882__gnat_open_rw (char *path, int fmode)
1fac938e 883{
884 int fd;
885 int o_fmode = O_BINARY;
886
887 if (fmode)
888 o_fmode = O_TEXT;
889
f15731c4 890#if defined (VMS)
1fac938e 891 fd = open (path, O_RDWR | o_fmode, PERM,
892 "mbc=16", "deq=64", "fop=tef");
3b18b370 893#elif defined (__MINGW32__)
894 {
895 TCHAR wpath[GNAT_MAX_PATH_LEN];
896
f60cc57d 897 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 898 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
899 }
1fac938e 900#else
901 fd = open (path, O_RDWR | o_fmode, PERM);
902#endif
903
904 return fd < 0 ? -1 : fd;
905}
906
907int
9dfe12ae 908__gnat_open_create (char *path, int fmode)
1fac938e 909{
910 int fd;
911 int o_fmode = O_BINARY;
912
913 if (fmode)
914 o_fmode = O_TEXT;
915
f15731c4 916#if defined (VMS)
1fac938e 917 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
918 "mbc=16", "deq=64", "fop=tef");
3b18b370 919#elif defined (__MINGW32__)
920 {
921 TCHAR wpath[GNAT_MAX_PATH_LEN];
922
f60cc57d 923 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 924 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
925 }
1fac938e 926#else
927 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
928#endif
929
930 return fd < 0 ? -1 : fd;
28ed91d4 931}
932
933int
934__gnat_create_output_file (char *path)
935{
936 int fd;
937#if defined (VMS)
938 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
939 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
940 "shr=del,get,put,upd");
3b18b370 941#elif defined (__MINGW32__)
942 {
943 TCHAR wpath[GNAT_MAX_PATH_LEN];
944
f60cc57d 945 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 946 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
947 }
28ed91d4 948#else
949 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
950#endif
951
952 return fd < 0 ? -1 : fd;
1fac938e 953}
954
df40eeb0 955int
956__gnat_create_output_file_new (char *path)
957{
958 int fd;
959#if defined (VMS)
960 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM,
961 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
962 "shr=del,get,put,upd");
963#elif defined (__MINGW32__)
964 {
965 TCHAR wpath[GNAT_MAX_PATH_LEN];
966
967 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
968 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
969 }
970#else
971 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
972#endif
973
974 return fd < 0 ? -1 : fd;
975}
976
1fac938e 977int
9dfe12ae 978__gnat_open_append (char *path, int fmode)
1fac938e 979{
980 int fd;
981 int o_fmode = O_BINARY;
982
983 if (fmode)
984 o_fmode = O_TEXT;
985
f15731c4 986#if defined (VMS)
1fac938e 987 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
988 "mbc=16", "deq=64", "fop=tef");
3b18b370 989#elif defined (__MINGW32__)
990 {
991 TCHAR wpath[GNAT_MAX_PATH_LEN];
992
f60cc57d 993 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 994 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
995 }
1fac938e 996#else
997 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
998#endif
999
1000 return fd < 0 ? -1 : fd;
1001}
1002
f15731c4 1003/* Open a new file. Return error (-1) if the file already exists. */
1fac938e 1004
1005int
9dfe12ae 1006__gnat_open_new (char *path, int fmode)
1fac938e 1007{
1008 int fd;
1009 int o_fmode = O_BINARY;
1010
1011 if (fmode)
1012 o_fmode = O_TEXT;
1013
f15731c4 1014#if defined (VMS)
1fac938e 1015 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1016 "mbc=16", "deq=64", "fop=tef");
3b18b370 1017#elif defined (__MINGW32__)
1018 {
1019 TCHAR wpath[GNAT_MAX_PATH_LEN];
1020
f60cc57d 1021 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 1022 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1023 }
1fac938e 1024#else
1025 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1026#endif
1027
1028 return fd < 0 ? -1 : fd;
1029}
1030
1031/* Open a new temp file. Return error (-1) if the file already exists.
f15731c4 1032 Special options for VMS allow the file to be shared between parent and child
1033 processes, however they really slow down output. Used in gnatchop. */
1fac938e 1034
1035int
9dfe12ae 1036__gnat_open_new_temp (char *path, int fmode)
1fac938e 1037{
1038 int fd;
1039 int o_fmode = O_BINARY;
1040
1041 strcpy (path, "GNAT-XXXXXX");
1042
e0324ff5 1043#if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
9d093602 1044 || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
1fac938e 1045 return mkstemp (path);
159eb63c 1046#elif defined (__Lynx__)
1047 mktemp (path);
5091bc2f 1048#elif defined (__nucleus__)
1049 return -1;
1fac938e 1050#else
1051 if (mktemp (path) == NULL)
1052 return -1;
1053#endif
1054
1055 if (fmode)
1056 o_fmode = O_TEXT;
1057
f15731c4 1058#if defined (VMS)
1fac938e 1059 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1060 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
1061 "mbc=16", "deq=64", "fop=tef");
1062#else
1063 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1064#endif
1065
1066 return fd < 0 ? -1 : fd;
1067}
1068
5f93bcbf 1069/****************************************************************
1070 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1071 ** as possible from it, storing the result in a cache for later reuse
1072 ****************************************************************/
1fac938e 1073
5f93bcbf 1074void
1075__gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
1fac938e 1076{
8cb516d7 1077 GNAT_STRUCT_STAT statbuf;
5f93bcbf 1078 int ret;
1fac938e 1079
5f93bcbf 1080 if (fd != -1)
1081 ret = GNAT_FSTAT (fd, &statbuf);
1082 else
1083 ret = __gnat_stat (name, &statbuf);
1084
1085 attr->regular = (!ret && S_ISREG (statbuf.st_mode));
1086 attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
1fac938e 1087
5f93bcbf 1088 if (!attr->regular)
1089 attr->file_length = 0;
1090 else
1091 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1092 don't return a useful value for files larger than 2 gigabytes in
1093 either case. */
1094 attr->file_length = statbuf.st_size; /* all systems */
1095
1096#ifndef __MINGW32__
1097 /* on Windows requires extra system call, see comment in __gnat_file_exists_attr */
1098 attr->exists = !ret;
1099#endif
1100
1101#if !defined (_WIN32) || defined (RTX)
1102 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1103 attr->readable = (!ret && (statbuf.st_mode & S_IRUSR));
1104 attr->writable = (!ret && (statbuf.st_mode & S_IWUSR));
1105 attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
1106#endif
1107
30592778 1108#if !defined (_WIN32) || defined (RTX)
5f93bcbf 1109 /* on Windows requires extra system call, see __gnat_file_time_name_attr */
1110 if (ret != 0) {
1111 attr->timestamp = (OS_Time)-1;
1112 } else {
1113#ifdef VMS
1114 /* VMS has file versioning. */
1115 attr->timestamp = (OS_Time)statbuf.st_ctime;
1116#else
1117 attr->timestamp = (OS_Time)statbuf.st_mtime;
1118#endif
1119 }
1120#endif
c85cfca7 1121
1fac938e 1122}
1123
5f93bcbf 1124/****************************************************************
1125 ** Return the number of bytes in the specified file
1126 ****************************************************************/
d24d7e81 1127
1128long
5f93bcbf 1129__gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
d24d7e81 1130{
5f93bcbf 1131 if (attr->file_length == -1) {
1132 __gnat_stat_to_attr (fd, name, attr);
1133 }
d24d7e81 1134
5f93bcbf 1135 return attr->file_length;
1136}
d24d7e81 1137
5f93bcbf 1138long
1139__gnat_file_length (int fd)
1140{
1141 struct file_attributes attr;
d2697a05 1142 __gnat_reset_attributes (&attr);
5f93bcbf 1143 return __gnat_file_length_attr (fd, NULL, &attr);
1144}
c85cfca7 1145
5f93bcbf 1146long
1147__gnat_named_file_length (char *name)
1148{
1149 struct file_attributes attr;
d2697a05 1150 __gnat_reset_attributes (&attr);
5f93bcbf 1151 return __gnat_file_length_attr (-1, name, &attr);
d24d7e81 1152}
1153
1fac938e 1154/* Create a temporary filename and put it in string pointed to by
f15731c4 1155 TMP_FILENAME. */
1fac938e 1156
1157void
9dfe12ae 1158__gnat_tmp_name (char *tmp_filename)
1fac938e 1159{
72772d89 1160#ifdef RTX
f5099270 1161 /* Variable used to create a series of unique names */
1162 static int counter = 0;
1163
1164 /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
1165 strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
1166 sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
72772d89 1167
1168#elif defined (__MINGW32__)
1fac938e 1169 {
1170 char *pname;
1171
1172 /* tempnam tries to create a temporary file in directory pointed to by
1173 TMP environment variable, in c:\temp if TMP is not set, and in
1174 directory specified by P_tmpdir in stdio.h if c:\temp does not
1175 exist. The filename will be created with the prefix "gnat-". */
1176
1177 pname = (char *) tempnam ("c:\\temp", "gnat-");
1178
9dfe12ae 1179 /* if pname is NULL, the file was not created properly, the disk is full
1180 or there is no more free temporary files */
1181
1182 if (pname == NULL)
1183 *tmp_filename = '\0';
1184
f15731c4 1185 /* If pname start with a back slash and not path information it means that
1186 the filename is valid for the current working directory. */
1fac938e 1187
9dfe12ae 1188 else if (pname[0] == '\\')
1fac938e 1189 {
1190 strcpy (tmp_filename, ".\\");
1191 strcat (tmp_filename, pname+1);
1192 }
1193 else
1194 strcpy (tmp_filename, pname);
1195
1196 free (pname);
1197 }
f15731c4 1198
e0324ff5 1199#elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
9d093602 1200 || defined (__OpenBSD__) || defined(__GLIBC__)
9dfe12ae 1201#define MAX_SAFE_PATH 1000
1fac938e 1202 char *tmpdir = getenv ("TMPDIR");
1203
9dfe12ae 1204 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1205 a buffer overflow. */
1206 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1fac938e 1207 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1208 else
9dfe12ae 1209 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1fac938e 1210
1211 close (mkstemp(tmp_filename));
1212#else
1213 tmpnam (tmp_filename);
1214#endif
1215}
1216
3b18b370 1217/* Open directory and returns a DIR pointer. */
1218
1219DIR* __gnat_opendir (char *name)
1220{
e2a33c18 1221#if defined (RTX)
1222 /* Not supported in RTX */
1223
1224 return NULL;
1225
1226#elif defined (__MINGW32__)
3b18b370 1227 TCHAR wname[GNAT_MAX_PATH_LEN];
1228
f60cc57d 1229 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
3b18b370 1230 return (DIR*)_topendir (wname);
1231
1232#else
1233 return opendir (name);
1234#endif
1235}
1236
1fac938e 1237/* Read the next entry in a directory. The returned string points somewhere
1238 in the buffer. */
1239
1240char *
3b18b370 1241__gnat_readdir (DIR *dirp, char *buffer, int *len)
1fac938e 1242{
e2a33c18 1243#if defined (RTX)
1244 /* Not supported in RTX */
1245
1246 return NULL;
8e726ab4 1247
e2a33c18 1248#elif defined (__MINGW32__)
3b18b370 1249 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1250
1251 if (dirent != NULL)
1252 {
f60cc57d 1253 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
3b18b370 1254 *len = strlen (buffer);
1255
1256 return buffer;
1257 }
1258 else
1259 return NULL;
1260
1261#elif defined (HAVE_READDIR_R)
1fac938e 1262 /* If possible, try to use the thread-safe version. */
1fac938e 1263 if (readdir_r (dirp, buffer) != NULL)
1aa4b9ce 1264 {
1265 *len = strlen (((struct dirent*) buffer)->d_name);
1266 return ((struct dirent*) buffer)->d_name;
1267 }
1fac938e 1268 else
1269 return NULL;
1270
1271#else
5b941af6 1272 struct dirent *dirent = (struct dirent *) readdir (dirp);
1fac938e 1273
1274 if (dirent != NULL)
1275 {
1276 strcpy (buffer, dirent->d_name);
3b18b370 1277 *len = strlen (buffer);
1fac938e 1278 return buffer;
1279 }
1280 else
1281 return NULL;
1282
1283#endif
1284}
1285
3b18b370 1286/* Close a directory entry. */
1287
1288int __gnat_closedir (DIR *dirp)
1289{
e2a33c18 1290#if defined (RTX)
1291 /* Not supported in RTX */
1292
1293 return 0;
1294
1295#elif defined (__MINGW32__)
3b18b370 1296 return _tclosedir ((_TDIR*)dirp);
1297
1298#else
1299 return closedir (dirp);
1300#endif
1301}
1302
1fac938e 1303/* Returns 1 if readdir is thread safe, 0 otherwise. */
1304
1305int
6f2c2693 1306__gnat_readdir_is_thread_safe (void)
1fac938e 1307{
1308#ifdef HAVE_READDIR_R
1309 return 1;
1310#else
1311 return 0;
1312#endif
1313}
1314
e2a33c18 1315#if defined (_WIN32) && !defined (RTX)
982e2721 1316/* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1317static const unsigned long long w32_epoch_offset = 11644473600ULL;
1fac938e 1318
1319/* Returns the file modification timestamp using Win32 routines which are
1320 immune against daylight saving time change. It is in fact not possible to
1321 use fstat for this purpose as the DST modify the st_mtime field of the
1322 stat structure. */
1323
1324static time_t
9dfe12ae 1325win32_filetime (HANDLE h)
1fac938e 1326{
982e2721 1327 union
1328 {
1329 FILETIME ft_time;
1330 unsigned long long ull_time;
1331 } t_write;
1fac938e 1332
1333 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1334 since <Jan 1st 1601>. This function must return the number of seconds
1335 since <Jan 1st 1970>. */
1336
982e2721 1337 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
3b18b370 1338 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
982e2721 1339 return (time_t) 0;
1fac938e 1340}
1341#endif
1342
1343/* Return a GNAT time stamp given a file name. */
1344
1bbc9831 1345OS_Time
5f93bcbf 1346__gnat_file_time_name_attr (char* name, struct file_attributes* attr)
1fac938e 1347{
5f93bcbf 1348 if (attr->timestamp == (OS_Time)-2) {
30592778 1349#if defined (_WIN32) && !defined (RTX)
5f93bcbf 1350 time_t ret = -1;
1351 TCHAR wname[GNAT_MAX_PATH_LEN];
1352 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
3b18b370 1353
5f93bcbf 1354 HANDLE h = CreateFile
1355 (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1356 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
fabb7dc5 1357
5f93bcbf 1358 if (h != INVALID_HANDLE_VALUE) {
1359 ret = win32_filetime (h);
1360 CloseHandle (h);
1361 }
1362 attr->timestamp = (OS_Time) ret;
1fac938e 1363#else
5f93bcbf 1364 __gnat_stat_to_attr (-1, name, attr);
1fac938e 1365#endif
1bbc9831 1366 }
5f93bcbf 1367 return attr->timestamp;
1368}
1369
1370OS_Time
1371__gnat_file_time_name (char *name)
1372{
1373 struct file_attributes attr;
d2697a05 1374 __gnat_reset_attributes (&attr);
5f93bcbf 1375 return __gnat_file_time_name_attr (name, &attr);
1fac938e 1376}
1377
1378/* Return a GNAT time stamp given a file descriptor. */
1379
1bbc9831 1380OS_Time
5f93bcbf 1381__gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
1fac938e 1382{
5f93bcbf 1383 if (attr->timestamp == (OS_Time)-2) {
30592778 1384#if defined (_WIN32) && !defined (RTX)
5f93bcbf 1385 HANDLE h = (HANDLE) _get_osfhandle (fd);
1386 time_t ret = win32_filetime (h);
1387 attr->timestamp = (OS_Time) ret;
1fac938e 1388
1389#else
5f93bcbf 1390 __gnat_stat_to_attr (fd, NULL, attr);
1fac938e 1391#endif
5f93bcbf 1392 }
1393
1394 return attr->timestamp;
1395}
1396
1397OS_Time
1398__gnat_file_time_fd (int fd)
1399{
1400 struct file_attributes attr;
d2697a05 1401 __gnat_reset_attributes (&attr);
5f93bcbf 1402 return __gnat_file_time_fd_attr (fd, &attr);
1fac938e 1403}
1404
f15731c4 1405/* Set the file time stamp. */
d8dd2062 1406
1407void
9dfe12ae 1408__gnat_set_file_time_name (char *name, time_t time_stamp)
d8dd2062 1409{
30592778 1410#if defined (__vxworks)
71a3e619 1411
f15731c4 1412/* Code to implement __gnat_set_file_time_name for these systems. */
71a3e619 1413
e2a33c18 1414#elif defined (_WIN32) && !defined (RTX)
982e2721 1415 union
1416 {
1417 FILETIME ft_time;
1418 unsigned long long ull_time;
1419 } t_write;
3b18b370 1420 TCHAR wname[GNAT_MAX_PATH_LEN];
fabb7dc5 1421
f60cc57d 1422 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
3b18b370 1423
1424 HANDLE h = CreateFile
1425 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1426 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1427 NULL);
982e2721 1428 if (h == INVALID_HANDLE_VALUE)
1429 return;
1430 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1431 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1432 /* Convert to 100 nanosecond units */
1433 t_write.ull_time *= 10000000ULL;
1434
1435 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1436 CloseHandle (h);
1437 return;
1438
d8dd2062 1439#elif defined (VMS)
1440 struct FAB fab;
1441 struct NAM nam;
1442
1443 struct
1444 {
1445 unsigned long long backup, create, expire, revise;
8620a406 1446 unsigned int uic;
d8dd2062 1447 union
1448 {
1449 unsigned short value;
1450 struct
1451 {
1452 unsigned system : 4;
1453 unsigned owner : 4;
1454 unsigned group : 4;
1455 unsigned world : 4;
1456 } bits;
1457 } prot;
f15731c4 1458 } Fat = { 0, 0, 0, 0, 0, { 0 }};
d8dd2062 1459
f15731c4 1460 ATRDEF atrlst[]
d8dd2062 1461 = {
1462 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1463 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1464 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1465 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
f15731c4 1466 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
d8dd2062 1467 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1468 { 0, 0, 0}
1469 };
1470
1471 FIBDEF fib;
1472 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1473
1474 struct IOSB iosb;
1475
1476 unsigned long long newtime;
1477 unsigned long long revtime;
1478 long status;
1479 short chan;
1480
1481 struct vstring file;
1482 struct dsc$descriptor_s filedsc
1483 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1484 struct vstring device;
1485 struct dsc$descriptor_s devicedsc
1486 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1487 struct vstring timev;
1488 struct dsc$descriptor_s timedsc
1489 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1490 struct vstring result;
1491 struct dsc$descriptor_s resultdsc
1492 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1493
3b18b370 1494 /* Convert parameter name (a file spec) to host file form. Note that this
1495 is needed on VMS to prepare for subsequent calls to VMS RMS library
1496 routines. Note that it would not work to call __gnat_to_host_dir_spec
1497 as was done in a previous version, since this fails silently unless
1498 the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1499 (directory not found) condition is signalled. */
1500 tryfile = (char *) __gnat_to_host_file_spec (name);
d8dd2062 1501
f15731c4 1502 /* Allocate and initialize a FAB and NAM structures. */
d8dd2062 1503 fab = cc$rms_fab;
1504 nam = cc$rms_nam;
1505
1506 nam.nam$l_esa = file.string;
1507 nam.nam$b_ess = NAM$C_MAXRSS;
1508 nam.nam$l_rsa = result.string;
1509 nam.nam$b_rss = NAM$C_MAXRSS;
1510 fab.fab$l_fna = tryfile;
1511 fab.fab$b_fns = strlen (tryfile);
1512 fab.fab$l_nam = &nam;
1513
f15731c4 1514 /* Validate filespec syntax and device existence. */
d8dd2062 1515 status = SYS$PARSE (&fab, 0, 0);
1516 if ((status & 1) != 1)
1517 LIB$SIGNAL (status);
1518
f15731c4 1519 file.string[nam.nam$b_esl] = 0;
d8dd2062 1520
f15731c4 1521 /* Find matching filespec. */
d8dd2062 1522 status = SYS$SEARCH (&fab, 0, 0);
1523 if ((status & 1) != 1)
1524 LIB$SIGNAL (status);
1525
f15731c4 1526 file.string[nam.nam$b_esl] = 0;
1527 result.string[result.length=nam.nam$b_rsl] = 0;
d8dd2062 1528
f15731c4 1529 /* Get the device name and assign an IO channel. */
d8dd2062 1530 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1531 devicedsc.dsc$w_length = nam.nam$b_dev;
1532 chan = 0;
1533 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1534 if ((status & 1) != 1)
1535 LIB$SIGNAL (status);
1536
f15731c4 1537 /* Initialize the FIB and fill in the directory id field. */
1538 memset (&fib, 0, sizeof (fib));
1539 fib.fib$w_did[0] = nam.nam$w_did[0];
1540 fib.fib$w_did[1] = nam.nam$w_did[1];
1541 fib.fib$w_did[2] = nam.nam$w_did[2];
d8dd2062 1542 fib.fib$l_acctl = 0;
1543 fib.fib$l_wcc = 0;
1544 strcpy (file.string, (strrchr (result.string, ']') + 1));
1545 filedsc.dsc$w_length = strlen (file.string);
f15731c4 1546 result.string[result.length = 0] = 0;
d8dd2062 1547
1548 /* Open and close the file to fill in the attributes. */
1549 status
1550 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1551 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1552 if ((status & 1) != 1)
1553 LIB$SIGNAL (status);
1554 if ((iosb.status & 1) != 1)
1555 LIB$SIGNAL (iosb.status);
1556
f15731c4 1557 result.string[result.length] = 0;
1558 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1559 &atrlst, 0);
d8dd2062 1560 if ((status & 1) != 1)
1561 LIB$SIGNAL (status);
1562 if ((iosb.status & 1) != 1)
1563 LIB$SIGNAL (iosb.status);
1564
d8dd2062 1565 {
1566 time_t t;
f15731c4 1567
1568 /* Set creation time to requested time. */
9dfe12ae 1569 unix_time_to_vms (time_stamp, newtime);
f15731c4 1570
d8dd2062 1571 t = time ((time_t) 0);
d8dd2062 1572
f15731c4 1573 /* Set revision time to now in local time. */
9dfe12ae 1574 unix_time_to_vms (t, revtime);
d8dd2062 1575 }
1576
f15731c4 1577 /* Reopen the file, modify the times and then close. */
d8dd2062 1578 fib.fib$l_acctl = FIB$M_WRITE;
1579 status
1580 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1581 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1582 if ((status & 1) != 1)
1583 LIB$SIGNAL (status);
1584 if ((iosb.status & 1) != 1)
1585 LIB$SIGNAL (iosb.status);
1586
1587 Fat.create = newtime;
1588 Fat.revise = revtime;
1589
1590 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1591 &fibdsc, 0, 0, 0, &atrlst, 0);
1592 if ((status & 1) != 1)
1593 LIB$SIGNAL (status);
1594 if ((iosb.status & 1) != 1)
1595 LIB$SIGNAL (iosb.status);
1596
f15731c4 1597 /* Deassign the channel and exit. */
d8dd2062 1598 status = SYS$DASSGN (chan);
1599 if ((status & 1) != 1)
1600 LIB$SIGNAL (status);
1601#else
1602 struct utimbuf utimbuf;
1603 time_t t;
1604
f15731c4 1605 /* Set modification time to requested time. */
d8dd2062 1606 utimbuf.modtime = time_stamp;
1607
f15731c4 1608 /* Set access time to now in local time. */
d8dd2062 1609 t = time ((time_t) 0);
1610 utimbuf.actime = mktime (localtime (&t));
1611
1612 utime (name, &utimbuf);
1613#endif
1614}
1615
1fac938e 1616/* Get the list of installed standard libraries from the
1617 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1618 key. */
1619
1620char *
6f2c2693 1621__gnat_get_libraries_from_registry (void)
1fac938e 1622{
69d33a1d 1623 char *result = (char *) xmalloc (1);
1624
1625 result[0] = '\0';
1fac938e 1626
8c7d3bad 1627#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS) \
1628 && ! defined (RTX)
1fac938e 1629
1630 HKEY reg_key;
1631 DWORD name_size, value_size;
1632 char name[256];
1633 char value[256];
1634 DWORD type;
1635 DWORD index;
1636 LONG res;
1637
1638 /* First open the key. */
1639 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1640
1641 if (res == ERROR_SUCCESS)
1642 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1643 KEY_READ, &reg_key);
1644
1645 if (res == ERROR_SUCCESS)
1646 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1647
1648 if (res == ERROR_SUCCESS)
1649 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1650
1651 /* If the key exists, read out all the values in it and concatenate them
1652 into a path. */
1653 for (index = 0; res == ERROR_SUCCESS; index++)
1654 {
1655 value_size = name_size = 256;
2726b813 1656 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
e2c62f37 1657 &type, (LPBYTE)value, &value_size);
1fac938e 1658
1659 if (res == ERROR_SUCCESS && type == REG_SZ)
1660 {
1661 char *old_result = result;
1662
1663 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1664 strcpy (result, old_result);
1665 strcat (result, value);
1666 strcat (result, ";");
69d33a1d 1667 free (old_result);
1fac938e 1668 }
1669 }
1670
1671 /* Remove the trailing ";". */
1672 if (result[0] != 0)
1673 result[strlen (result) - 1] = 0;
2b4d7555 1674
69d33a1d 1675#endif
1fac938e 1676 return result;
1677}
1678
1679int
8cb516d7 1680__gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1fac938e 1681{
3b18b370 1682#ifdef __MINGW32__
1fac938e 1683 /* Under Windows the directory name for the stat function must not be
8234fccd 1684 terminated by a directory separator except if just after a drive name
1685 or with UNC path without directory (only the name of the shared
1686 resource), for example: \\computer\share\ */
1687
3b18b370 1688 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
8234fccd 1689 int name_len, k;
3b18b370 1690 TCHAR last_char;
8234fccd 1691 int dirsep_count = 0;
3b18b370 1692
f60cc57d 1693 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
3b18b370 1694 name_len = _tcslen (wname);
e7b2d6bc 1695
1696 if (name_len > GNAT_MAX_PATH_LEN)
1697 return -1;
1fac938e 1698
3b18b370 1699 last_char = wname[name_len - 1];
1fac938e 1700
3b18b370 1701 while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1fac938e 1702 {
3b18b370 1703 wname[name_len - 1] = _T('\0');
1fac938e 1704 name_len--;
3b18b370 1705 last_char = wname[name_len - 1];
1fac938e 1706 }
1707
8234fccd 1708 /* Count back-slashes. */
1709
1710 for (k=0; k<name_len; k++)
1711 if (wname[k] == _T('\\') || wname[k] == _T('/'))
1712 dirsep_count++;
1713
3b18b370 1714 /* Only a drive letter followed by ':', we must add a directory separator
1715 for the stat routine to work properly. */
8234fccd 1716 if ((name_len == 2 && wname[1] == _T(':'))
1717 || (name_len > 3 && wname[0] == _T('\\') && wname[1] == _T('\\')
1718 && dirsep_count == 3))
3b18b370 1719 _tcscat (wname, _T("\\"));
1fac938e 1720
2726b813 1721 return _tstat (wname, (struct _stat *)statbuf);
1fac938e 1722
1723#else
8cb516d7 1724 return GNAT_STAT (name, statbuf);
1fac938e 1725#endif
1726}
1727
5f93bcbf 1728/*************************************************************************
1729 ** Check whether a file exists
1730 *************************************************************************/
1731
1fac938e 1732int
5f93bcbf 1733__gnat_file_exists_attr (char* name, struct file_attributes* attr)
1fac938e 1734{
bce992c9 1735 if (attr->exists == ATTR_UNSET) {
8e726ab4 1736#ifdef __MINGW32__
5f93bcbf 1737 /* On Windows do not use __gnat_stat() because of a bug in Microsoft
1738 _stat() routine. When the system time-zone is set with a negative
1739 offset the _stat() routine fails on specific files like CON: */
1740 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1741 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1742 attr->exists = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1aa4b9ce 1743#else
5f93bcbf 1744 __gnat_stat_to_attr (-1, name, attr);
1aa4b9ce 1745#endif
5f93bcbf 1746 }
1747
1748 return attr->exists;
1fac938e 1749}
1750
5f93bcbf 1751int
1752__gnat_file_exists (char *name)
1753{
1754 struct file_attributes attr;
d2697a05 1755 __gnat_reset_attributes (&attr);
5f93bcbf 1756 return __gnat_file_exists_attr (name, &attr);
1757}
1758
1759/**********************************************************************
1760 ** Whether name is an absolute path
1761 **********************************************************************/
1762
9dfe12ae 1763int
4a3f445c 1764__gnat_is_absolute_path (char *name, int length)
1fac938e 1765{
8620a406 1766#ifdef __vxworks
1767 /* On VxWorks systems, an absolute path can be represented (depending on
1768 the host platform) as either /dir/file, or device:/dir/file, or
1769 device:drive_letter:/dir/file. */
1770
1771 int index;
1772
1773 if (name[0] == '/')
1774 return 1;
1775
1776 for (index = 0; index < length; index++)
1777 {
1778 if (name[index] == ':' &&
1779 ((name[index + 1] == '/') ||
1780 (isalpha (name[index + 1]) && index + 2 <= length &&
1781 name[index + 2] == '/')))
1782 return 1;
1783
1784 else if (name[index] == '/')
1785 return 0;
1786 }
1787 return 0;
1788#else
4a3f445c 1789 return (length != 0) &&
1790 (*name == '/' || *name == DIR_SEPARATOR
30592778 1791#if defined (WINNT)
a4f295eb 1792 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1fac938e 1793#endif
69d33a1d 1794 );
8620a406 1795#endif
1fac938e 1796}
1797
5f93bcbf 1798int
1799__gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
1800{
bce992c9 1801 if (attr->regular == ATTR_UNSET) {
5f93bcbf 1802 __gnat_stat_to_attr (-1, name, attr);
1803 }
1804
1805 return attr->regular;
1806}
1807
1fac938e 1808int
9dfe12ae 1809__gnat_is_regular_file (char *name)
1fac938e 1810{
5f93bcbf 1811 struct file_attributes attr;
d2697a05 1812 __gnat_reset_attributes (&attr);
5f93bcbf 1813 return __gnat_is_regular_file_attr (name, &attr);
1814}
1815
1816int
1817__gnat_is_directory_attr (char* name, struct file_attributes* attr)
1818{
bce992c9 1819 if (attr->directory == ATTR_UNSET) {
5f93bcbf 1820 __gnat_stat_to_attr (-1, name, attr);
1821 }
1fac938e 1822
5f93bcbf 1823 return attr->directory;
1fac938e 1824}
1825
1826int
9dfe12ae 1827__gnat_is_directory (char *name)
1fac938e 1828{
5f93bcbf 1829 struct file_attributes attr;
d2697a05 1830 __gnat_reset_attributes (&attr);
5f93bcbf 1831 return __gnat_is_directory_attr (name, &attr);
1fac938e 1832}
1833
7db1ef17 1834#if defined (_WIN32) && !defined (RTX)
57ecb969 1835
1836/* Returns the same constant as GetDriveType but takes a pathname as
1837 argument. */
1838
1839static UINT
1840GetDriveTypeFromPath (TCHAR *wfullpath)
1841{
1842 TCHAR wdrv[MAX_PATH];
1843 TCHAR wpath[MAX_PATH];
1844 TCHAR wfilename[MAX_PATH];
1845 TCHAR wext[MAX_PATH];
1846
1847 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1848
1849 if (_tcslen (wdrv) != 0)
1850 {
1851 /* we have a drive specified. */
1852 _tcscat (wdrv, _T("\\"));
1853 return GetDriveType (wdrv);
1854 }
1855 else
1856 {
1857 /* No drive specified. */
1858
1859 /* Is this a relative path, if so get current drive type. */
1860 if (wpath[0] != _T('\\') ||
69d33a1d 1861 (_tcslen (wpath) > 2 && wpath[0] == _T('\\') && wpath[1] != _T('\\')))
1862 return GetDriveType (NULL);
57ecb969 1863
1864 UINT result = GetDriveType (wpath);
1865
1866 /* Cannot guess the drive type, is this \\.\ ? */
1867
1868 if (result == DRIVE_NO_ROOT_DIR &&
69d33a1d 1869 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1870 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1871 {
1872 if (_tcslen (wpath) == 4)
1873 _tcscat (wpath, wfilename);
57ecb969 1874
69d33a1d 1875 LPTSTR p = &wpath[4];
1876 LPTSTR b = _tcschr (p, _T('\\'));
57ecb969 1877
69d33a1d 1878 if (b != NULL)
1879 { /* logical drive \\.\c\dir\file */
1880 *b++ = _T(':');
1881 *b++ = _T('\\');
1882 *b = _T('\0');
1883 }
1884 else
1885 _tcscat (p, _T(":\\"));
57ecb969 1886
69d33a1d 1887 return GetDriveType (p);
1888 }
57ecb969 1889
1890 return result;
1891 }
1892}
1893
7db1ef17 1894/* This MingW section contains code to work with ACL. */
1895static int
1896__gnat_check_OWNER_ACL
3855c659 1897(TCHAR *wname,
7db1ef17 1898 DWORD CheckAccessDesired,
1899 GENERIC_MAPPING CheckGenericMapping)
1900{
7db1ef17 1901 DWORD dwAccessDesired, dwAccessAllowed;
1902 PRIVILEGE_SET PrivilegeSet;
1903 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1904 BOOL fAccessGranted = FALSE;
f060ec3a 1905 HANDLE hToken = NULL;
1906 DWORD nLength = 0;
7db1ef17 1907 SECURITY_DESCRIPTOR* pSD = NULL;
1908
7db1ef17 1909 GetFileSecurity
1910 (wname, OWNER_SECURITY_INFORMATION |
1911 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1912 NULL, 0, &nLength);
1913
1914 if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
1915 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1916 return 0;
1917
1918 /* Obtain the security descriptor. */
1919
1920 if (!GetFileSecurity
1921 (wname, OWNER_SECURITY_INFORMATION |
1922 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1923 pSD, nLength, &nLength))
f060ec3a 1924 goto error;
7db1ef17 1925
1926 if (!ImpersonateSelf (SecurityImpersonation))
f060ec3a 1927 goto error;
7db1ef17 1928
1929 if (!OpenThreadToken
1930 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
f060ec3a 1931 goto error;
7db1ef17 1932
1933 /* Undoes the effect of ImpersonateSelf. */
1934
1935 RevertToSelf ();
1936
1937 /* We want to test for write permissions. */
1938
1939 dwAccessDesired = CheckAccessDesired;
1940
1941 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1942
1943 if (!AccessCheck
1944 (pSD , /* security descriptor to check */
1945 hToken, /* impersonation token */
1946 dwAccessDesired, /* requested access rights */
1947 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1948 &PrivilegeSet, /* receives privileges used in check */
1949 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1950 &dwAccessAllowed, /* receives mask of allowed access rights */
1951 &fAccessGranted))
f060ec3a 1952 goto error;
7db1ef17 1953
f060ec3a 1954 CloseHandle (hToken);
1955 HeapFree (GetProcessHeap (), 0, pSD);
7db1ef17 1956 return fAccessGranted;
f060ec3a 1957
1958 error:
1959 if (hToken)
1960 CloseHandle (hToken);
1961 HeapFree (GetProcessHeap (), 0, pSD);
1962 return 0;
7db1ef17 1963}
1964
1965static void
1966__gnat_set_OWNER_ACL
3855c659 1967(TCHAR *wname,
7db1ef17 1968 DWORD AccessMode,
1969 DWORD AccessPermissions)
1970{
4c4697b8 1971 PACL pOldDACL = NULL;
1972 PACL pNewDACL = NULL;
1973 PSECURITY_DESCRIPTOR pSD = NULL;
7db1ef17 1974 EXPLICIT_ACCESS ea;
1975 TCHAR username [100];
1976 DWORD unsize = 100;
1977
7db1ef17 1978 /* Get current user, he will act as the owner */
1979
1980 if (!GetUserName (username, &unsize))
1981 return;
1982
0b3929a6 1983 if (GetNamedSecurityInfo
1984 (wname,
7db1ef17 1985 SE_FILE_OBJECT,
1986 DACL_SECURITY_INFORMATION,
1987 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1988 return;
1989
0b3929a6 1990 BuildExplicitAccessWithName
1991 (&ea, username, AccessPermissions, AccessMode, NO_INHERITANCE);
7db1ef17 1992
1993 if (AccessMode == SET_ACCESS)
1994 {
1995 /* SET_ACCESS, we want to set an explicte set of permissions, do not
69d33a1d 1996 merge with current DACL. */
7db1ef17 1997 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
69d33a1d 1998 return;
7db1ef17 1999 }
2000 else
2001 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
2002 return;
2003
0b3929a6 2004 if (SetNamedSecurityInfo
2005 (wname, SE_FILE_OBJECT,
7db1ef17 2006 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
2007 return;
2008
2009 LocalFree (pSD);
2010 LocalFree (pNewDACL);
7db1ef17 2011}
57ecb969 2012
2013/* Check if it is possible to use ACL for wname, the file must not be on a
2014 network drive. */
2015
2016static int
2017__gnat_can_use_acl (TCHAR *wname)
2018{
2019 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
2020}
2021
7db1ef17 2022#endif /* defined (_WIN32) && !defined (RTX) */
2023
1fac938e 2024int
5f93bcbf 2025__gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
9dfe12ae 2026{
bce992c9 2027 if (attr->readable == ATTR_UNSET) {
7db1ef17 2028#if defined (_WIN32) && !defined (RTX)
5f93bcbf 2029 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2030 GENERIC_MAPPING GenericMapping;
3855c659 2031
5f93bcbf 2032 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
7db1ef17 2033
5f93bcbf 2034 if (__gnat_can_use_acl (wname))
2035 {
2036 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2037 GenericMapping.GenericRead = GENERIC_READ;
2038 attr->readable = __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
2039 }
2040 else
2041 attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
7db1ef17 2042#else
5f93bcbf 2043 __gnat_stat_to_attr (-1, name, attr);
7db1ef17 2044#endif
5f93bcbf 2045 }
2046
2047 return attr->readable;
9dfe12ae 2048}
2049
2050int
5f93bcbf 2051__gnat_is_readable_file (char *name)
2052{
2053 struct file_attributes attr;
d2697a05 2054 __gnat_reset_attributes (&attr);
5f93bcbf 2055 return __gnat_is_readable_file_attr (name, &attr);
2056}
2057
2058int
2059__gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
1fac938e 2060{
bce992c9 2061 if (attr->writable == ATTR_UNSET) {
7db1ef17 2062#if defined (_WIN32) && !defined (RTX)
5f93bcbf 2063 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2064 GENERIC_MAPPING GenericMapping;
3855c659 2065
5f93bcbf 2066 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
3855c659 2067
5f93bcbf 2068 if (__gnat_can_use_acl (wname))
2069 {
2070 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2071 GenericMapping.GenericWrite = GENERIC_WRITE;
2726b813 2072
5f93bcbf 2073 attr->writable = __gnat_check_OWNER_ACL
2074 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
2075 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2076 }
2077 else
2078 attr->writable = !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
7db1ef17 2079
7db1ef17 2080#else
5f93bcbf 2081 __gnat_stat_to_attr (-1, name, attr);
7db1ef17 2082#endif
5f93bcbf 2083 }
2084
2085 return attr->writable;
7db1ef17 2086}
2087
2088int
5f93bcbf 2089__gnat_is_writable_file (char *name)
7db1ef17 2090{
5f93bcbf 2091 struct file_attributes attr;
d2697a05 2092 __gnat_reset_attributes (&attr);
5f93bcbf 2093 return __gnat_is_writable_file_attr (name, &attr);
2094}
2095
2096int
2097__gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
2098{
bce992c9 2099 if (attr->executable == ATTR_UNSET) {
7db1ef17 2100#if defined (_WIN32) && !defined (RTX)
5f93bcbf 2101 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2102 GENERIC_MAPPING GenericMapping;
3855c659 2103
5f93bcbf 2104 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
3855c659 2105
5f93bcbf 2106 if (__gnat_can_use_acl (wname))
2107 {
2108 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2109 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2726b813 2110
5f93bcbf 2111 attr->executable = __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2112 }
2113 else
2114 attr->executable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2115 && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
7db1ef17 2116#else
5f93bcbf 2117 __gnat_stat_to_attr (-1, name, attr);
7db1ef17 2118#endif
5f93bcbf 2119 }
2120
2121 return attr->executable;
2122}
2123
2124int
2125__gnat_is_executable_file (char *name)
2126{
2127 struct file_attributes attr;
d2697a05 2128 __gnat_reset_attributes (&attr);
5f93bcbf 2129 return __gnat_is_executable_file_attr (name, &attr);
1fac938e 2130}
2131
9dfe12ae 2132void
2133__gnat_set_writable (char *name)
2134{
7db1ef17 2135#if defined (_WIN32) && !defined (RTX)
3855c659 2136 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2137
f60cc57d 2138 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
3855c659 2139
57ecb969 2140 if (__gnat_can_use_acl (wname))
2726b813 2141 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2142
3855c659 2143 SetFileAttributes
2144 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
7db1ef17 2145#elif ! defined (__vxworks) && ! defined(__nucleus__)
8cb516d7 2146 GNAT_STRUCT_STAT statbuf;
9dfe12ae 2147
8cb516d7 2148 if (GNAT_STAT (name, &statbuf) == 0)
0e9e8338 2149 {
2150 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2151 chmod (name, statbuf.st_mode);
2152 }
9dfe12ae 2153#endif
2154}
2155
5329ca64 2156void
2157__gnat_set_executable (char *name)
2158{
7db1ef17 2159#if defined (_WIN32) && !defined (RTX)
3855c659 2160 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2161
57ecb969 2162 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2163
2164 if (__gnat_can_use_acl (wname))
2165 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
3855c659 2166
7db1ef17 2167#elif ! defined (__vxworks) && ! defined(__nucleus__)
8cb516d7 2168 GNAT_STRUCT_STAT statbuf;
5329ca64 2169
8cb516d7 2170 if (GNAT_STAT (name, &statbuf) == 0)
0e9e8338 2171 {
2172 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2173 chmod (name, statbuf.st_mode);
2174 }
5329ca64 2175#endif
2176}
2177
9dfe12ae 2178void
2ab009c7 2179__gnat_set_non_writable (char *name)
9dfe12ae 2180{
7db1ef17 2181#if defined (_WIN32) && !defined (RTX)
3855c659 2182 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2183
f60cc57d 2184 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
3855c659 2185
57ecb969 2186 if (__gnat_can_use_acl (wname))
2726b813 2187 __gnat_set_OWNER_ACL
2188 (wname, DENY_ACCESS,
2189 FILE_WRITE_DATA | FILE_APPEND_DATA |
2190 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2191
3855c659 2192 SetFileAttributes
2193 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
7db1ef17 2194#elif ! defined (__vxworks) && ! defined(__nucleus__)
8cb516d7 2195 GNAT_STRUCT_STAT statbuf;
9dfe12ae 2196
8cb516d7 2197 if (GNAT_STAT (name, &statbuf) == 0)
0b3929a6 2198 {
2199 statbuf.st_mode = statbuf.st_mode & 07577;
2200 chmod (name, statbuf.st_mode);
2201 }
2202#endif
2203}
2204
2205void
2206__gnat_set_readable (char *name)
2207{
2208#if defined (_WIN32) && !defined (RTX)
2209 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2210
57ecb969 2211 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2212
2213 if (__gnat_can_use_acl (wname))
2214 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
0b3929a6 2215
e31ad175 2216#elif ! defined (__vxworks) && ! defined(__nucleus__)
8cb516d7 2217 GNAT_STRUCT_STAT statbuf;
0b3929a6 2218
8cb516d7 2219 if (GNAT_STAT (name, &statbuf) == 0)
0b3929a6 2220 {
2221 chmod (name, statbuf.st_mode | S_IREAD);
2222 }
2223#endif
2224}
2225
2226void
2227__gnat_set_non_readable (char *name)
2228{
2229#if defined (_WIN32) && !defined (RTX)
2230 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2231
57ecb969 2232 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2233
2234 if (__gnat_can_use_acl (wname))
2235 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
0b3929a6 2236
e31ad175 2237#elif ! defined (__vxworks) && ! defined(__nucleus__)
8cb516d7 2238 GNAT_STRUCT_STAT statbuf;
0b3929a6 2239
8cb516d7 2240 if (GNAT_STAT (name, &statbuf) == 0)
0b3929a6 2241 {
2242 chmod (name, statbuf.st_mode & (~S_IREAD));
2243 }
9dfe12ae 2244#endif
2245}
2246
2247int
5f93bcbf 2248__gnat_is_symbolic_link_attr (char* name, struct file_attributes* attr)
9dfe12ae 2249{
bce992c9 2250 if (attr->symbolic_link == ATTR_UNSET) {
5091bc2f 2251#if defined (__vxworks) || defined (__nucleus__)
5f93bcbf 2252 attr->symbolic_link = 0;
9dfe12ae 2253
8e761191 2254#elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
5f93bcbf 2255 int ret;
2256 GNAT_STRUCT_STAT statbuf;
2257 ret = GNAT_LSTAT (name, &statbuf);
2258 attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
9dfe12ae 2259#else
5f93bcbf 2260 attr->symbolic_link = 0;
9dfe12ae 2261#endif
5f93bcbf 2262 }
2263 return attr->symbolic_link;
2264}
2265
2266int
2267__gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2268{
2269 struct file_attributes attr;
d2697a05 2270 __gnat_reset_attributes (&attr);
5f93bcbf 2271 return __gnat_is_symbolic_link_attr (name, &attr);
2272
9dfe12ae 2273}
2274
1fac938e 2275#if defined (sun) && defined (__SVR4)
2276/* Using fork on Solaris will duplicate all the threads. fork1, which
2277 duplicates only the active thread, must be used instead, or spawning
2278 subprocess from a program with tasking will lead into numerous problems. */
2279#define fork fork1
2280#endif
2281
2282int
9dfe12ae 2283__gnat_portable_spawn (char *args[])
1fac938e 2284{
2285 int status = 0;
f0a28ccb 2286 int finished ATTRIBUTE_UNUSED;
2287 int pid ATTRIBUTE_UNUSED;
1fac938e 2288
e2a33c18 2289#if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
2290 return -1;
2291
30592778 2292#elif defined (_WIN32)
f270dc82 2293 /* args[0] must be quotes as it could contain a full pathname with spaces */
38750fcd 2294 char *args_0 = args[0];
f270dc82 2295 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2296 strcpy (args[0], "\"");
2297 strcat (args[0], args_0);
2298 strcat (args[0], "\"");
2299
0b9eca83 2300 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
f270dc82 2301
2302 /* restore previous value */
2303 free (args[0]);
8e761191 2304 args[0] = (char *)args_0;
f270dc82 2305
1fac938e 2306 if (status < 0)
f15731c4 2307 return -1;
1fac938e 2308 else
2309 return status;
2310
1fac938e 2311#else
2312
1fac938e 2313 pid = fork ();
f15731c4 2314 if (pid < 0)
2315 return -1;
1fac938e 2316
f15731c4 2317 if (pid == 0)
2318 {
2319 /* The child. */
6d9c3443 2320 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
f15731c4 2321#if defined (VMS)
69d33a1d 2322 return -1; /* execv is in parent context on VMS. */
f15731c4 2323#else
69d33a1d 2324 _exit (1);
f15731c4 2325#endif
2326 }
1fac938e 2327
f15731c4 2328 /* The parent. */
1fac938e 2329 finished = waitpid (pid, &status, 0);
2330
2331 if (finished != pid || WIFEXITED (status) == 0)
f15731c4 2332 return -1;
1fac938e 2333
2334 return WEXITSTATUS (status);
2335#endif
f15731c4 2336
1fac938e 2337 return 0;
2338}
2339
8e761191 2340/* Create a copy of the given file descriptor.
2341 Return -1 if an error occurred. */
2342
2343int
2344__gnat_dup (int oldfd)
2345{
8ffbc401 2346#if defined (__vxworks) && !defined (__RTP__)
2347 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2348 RTPs. */
2349 return -1;
8e761191 2350#else
8ffbc401 2351 return dup (oldfd);
8e761191 2352#endif
2353}
2354
2355/* Make newfd be the copy of oldfd, closing newfd first if necessary.
5e947a95 2356 Return -1 if an error occurred. */
8e761191 2357
2358int
2359__gnat_dup2 (int oldfd, int newfd)
2360{
8ffbc401 2361#if defined (__vxworks) && !defined (__RTP__)
2362 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2363 RTPs. */
8e761191 2364 return -1;
2365#else
2366 return dup2 (oldfd, newfd);
2367#endif
2368}
2369
ed8e5b83 2370int
2371__gnat_number_of_cpus (void)
2372{
2373 int cores = 1;
2374
f7479d84 2375#if defined (linux) || defined (sun) || defined (AIX) \
2376 || (defined (__alpha__) && defined (_osf_)) || defined (__APPLE__)
2377 cores = (int) sysconf (_SC_NPROCESSORS_ONLN);
90bc406c 2378
2379#elif (defined (__mips) && defined (__sgi))
f7479d84 2380 cores = (int) sysconf (_SC_NPROC_ONLN);
90bc406c 2381
2382#elif defined (__hpux__)
f7479d84 2383 struct pst_dynamic psd;
2384 if (pstat_getdynamic (&psd, sizeof (psd), 1, 0) != -1)
2385 cores = (int) psd.psd_proc_cnt;
90bc406c 2386
ee0d6223 2387#elif defined (_WIN32)
2388 SYSTEM_INFO sysinfo;
2389 GetSystemInfo (&sysinfo);
2390 cores = (int) sysinfo.dwNumberOfProcessors;
ed8e5b83 2391#endif
2392
2393 return cores;
2394}
2395
f15731c4 2396/* WIN32 code to implement a wait call that wait for any child process. */
2397
e2a33c18 2398#if defined (_WIN32) && !defined (RTX)
1fac938e 2399
2400/* Synchronization code, to be thread safe. */
2401
51fa65dc 2402#ifdef CERT
1fac938e 2403
51fa65dc 2404/* For the Cert run times on native Windows we use dummy functions
2405 for locking and unlocking tasks since we do not support multiple
2406 threads on this configuration (Cert run time on native Windows). */
1fac938e 2407
51fa65dc 2408void dummy (void) {}
1fac938e 2409
51fa65dc 2410void (*Lock_Task) () = &dummy;
2411void (*Unlock_Task) () = &dummy;
2412
2413#else
2414
2415#define Lock_Task system__soft_links__lock_task
2416extern void (*Lock_Task) (void);
2417
2418#define Unlock_Task system__soft_links__unlock_task
2419extern void (*Unlock_Task) (void);
2420
2421#endif
1fac938e 2422
4c4697b8 2423static HANDLE *HANDLES_LIST = NULL;
2424static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
1fac938e 2425
2426static void
14d22a3f 2427add_handle (HANDLE h, int pid)
1fac938e 2428{
1fac938e 2429
1fac938e 2430 /* -------------------- critical section -------------------- */
51fa65dc 2431 (*Lock_Task) ();
2432
4c4697b8 2433 if (plist_length == plist_max_length)
2434 {
2435 plist_max_length += 1000;
2436 HANDLES_LIST =
2437 xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2438 PID_LIST =
2439 xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2440 }
2441
2442 HANDLES_LIST[plist_length] = h;
14d22a3f 2443 PID_LIST[plist_length] = pid;
1fac938e 2444 ++plist_length;
1fac938e 2445
51fa65dc 2446 (*Unlock_Task) ();
2447 /* -------------------- critical section -------------------- */
1fac938e 2448}
2449
4c4697b8 2450void
2451__gnat_win32_remove_handle (HANDLE h, int pid)
1fac938e 2452{
4c4697b8 2453 int j;
1fac938e 2454
1fac938e 2455 /* -------------------- critical section -------------------- */
51fa65dc 2456 (*Lock_Task) ();
2457
4c4697b8 2458 for (j = 0; j < plist_length; j++)
1fac938e 2459 {
4c4697b8 2460 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
1fac938e 2461 {
4c4697b8 2462 CloseHandle (h);
2463 --plist_length;
2464 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2465 PID_LIST[j] = PID_LIST[plist_length];
1fac938e 2466 break;
2467 }
1fac938e 2468 }
2469
51fa65dc 2470 (*Unlock_Task) ();
2471 /* -------------------- critical section -------------------- */
1fac938e 2472}
2473
14d22a3f 2474static void
2475win32_no_block_spawn (char *command, char *args[], HANDLE *h, int *pid)
1fac938e 2476{
2477 BOOL result;
2478 STARTUPINFO SI;
2479 PROCESS_INFORMATION PI;
2480 SECURITY_ATTRIBUTES SA;
f15731c4 2481 int csize = 1;
2482 char *full_command;
1fac938e 2483 int k;
2484
f15731c4 2485 /* compute the total command line length */
2486 k = 0;
2487 while (args[k])
2488 {
2489 csize += strlen (args[k]) + 1;
2490 k++;
2491 }
2492
2493 full_command = (char *) xmalloc (csize);
2494
1fac938e 2495 /* Startup info. */
2496 SI.cb = sizeof (STARTUPINFO);
2497 SI.lpReserved = NULL;
2498 SI.lpReserved2 = NULL;
2499 SI.lpDesktop = NULL;
2500 SI.cbReserved2 = 0;
2501 SI.lpTitle = NULL;
2502 SI.dwFlags = 0;
2503 SI.wShowWindow = SW_HIDE;
2504
2505 /* Security attributes. */
2506 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2507 SA.bInheritHandle = TRUE;
2508 SA.lpSecurityDescriptor = NULL;
2509
2510 /* Prepare the command string. */
2511 strcpy (full_command, command);
2512 strcat (full_command, " ");
2513
2514 k = 1;
2515 while (args[k])
2516 {
2517 strcat (full_command, args[k]);
2518 strcat (full_command, " ");
2519 k++;
2520 }
2521
3b18b370 2522 {
2523 int wsize = csize * 2;
2524 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2525
f60cc57d 2526 S2WSC (wcommand, full_command, wsize);
3b18b370 2527
2528 free (full_command);
1fac938e 2529
3b18b370 2530 result = CreateProcess
2531 (NULL, wcommand, &SA, NULL, TRUE,
2532 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2533
2534 free (wcommand);
2535 }
f15731c4 2536
1fac938e 2537 if (result == TRUE)
2538 {
1fac938e 2539 CloseHandle (PI.hThread);
14d22a3f 2540 *h = PI.hProcess;
2541 *pid = PI.dwProcessId;
1fac938e 2542 }
2543 else
14d22a3f 2544 {
2545 *h = NULL;
2546 *pid = 0;
2547 }
1fac938e 2548}
2549
2550static int
9dfe12ae 2551win32_wait (int *status)
1fac938e 2552{
4c4697b8 2553 DWORD exitcode, pid;
1fac938e 2554 HANDLE *hl;
2555 HANDLE h;
2556 DWORD res;
2557 int k;
e41b023d 2558 int hl_len;
1fac938e 2559
2560 if (plist_length == 0)
2561 {
2562 errno = ECHILD;
2563 return -1;
2564 }
2565
1fac938e 2566 k = 0;
51fa65dc 2567
2568 /* -------------------- critical section -------------------- */
2569 (*Lock_Task) ();
1fac938e 2570
e41b023d 2571 hl_len = plist_length;
2572
e41b023d 2573 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2574
4c4697b8 2575 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
1fac938e 2576
51fa65dc 2577 (*Unlock_Task) ();
2578 /* -------------------- critical section -------------------- */
1fac938e 2579
e41b023d 2580 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
f15731c4 2581 h = hl[res - WAIT_OBJECT_0];
1fac938e 2582
2583 GetExitCodeProcess (h, &exitcode);
14d22a3f 2584 pid = PID_LIST [res - WAIT_OBJECT_0];
4c4697b8 2585 __gnat_win32_remove_handle (h, -1);
2586
2587 free (hl);
1fac938e 2588
2589 *status = (int) exitcode;
4c4697b8 2590 return (int) pid;
1fac938e 2591}
2592
2593#endif
2594
2595int
9dfe12ae 2596__gnat_portable_no_block_spawn (char *args[])
1fac938e 2597{
1fac938e 2598
e2a33c18 2599#if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2600 return -1;
2601
1fac938e 2602#elif defined (_WIN32)
2603
4c4697b8 2604 HANDLE h = NULL;
14d22a3f 2605 int pid;
4c4697b8 2606
14d22a3f 2607 win32_no_block_spawn (args[0], args, &h, &pid);
4c4697b8 2608 if (h != NULL)
5d56d161 2609 {
14d22a3f 2610 add_handle (h, pid);
2611 return pid;
5d56d161 2612 }
2613 else
2614 return -1;
1fac938e 2615
1fac938e 2616#else
4c4697b8 2617
2618 int pid = fork ();
1fac938e 2619
f15731c4 2620 if (pid == 0)
2621 {
2622 /* The child. */
6d9c3443 2623 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
f15731c4 2624#if defined (VMS)
69d33a1d 2625 return -1; /* execv is in parent context on VMS. */
9dfe12ae 2626#else
69d33a1d 2627 _exit (1);
f15731c4 2628#endif
2629 }
2630
1fac938e 2631 return pid;
4c4697b8 2632
2633 #endif
1fac938e 2634}
2635
2636int
9dfe12ae 2637__gnat_portable_wait (int *process_status)
1fac938e 2638{
2639 int status = 0;
2640 int pid = 0;
2641
e2a33c18 2642#if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
30592778 2643 /* Not sure what to do here, so do nothing but return zero. */
e2a33c18 2644
2645#elif defined (_WIN32)
1fac938e 2646
2647 pid = win32_wait (&status);
2648
1fac938e 2649#else
2650
1fac938e 2651 pid = waitpid (-1, &status, 0);
1fac938e 2652 status = status & 0xffff;
2653#endif
2654
2655 *process_status = status;
2656 return pid;
2657}
2658
2659void
9dfe12ae 2660__gnat_os_exit (int status)
1fac938e 2661{
1fac938e 2662 exit (status);
1fac938e 2663}
2664
f15731c4 2665/* Locate a regular file, give a Path value. */
1fac938e 2666
2667char *
9dfe12ae 2668__gnat_locate_regular_file (char *file_name, char *path_val)
1fac938e 2669{
2670 char *ptr;
5703e222 2671 char *file_path = (char *) alloca (strlen (file_name) + 1);
c69ba469 2672 int absolute;
2673
b51bcb1c 2674 /* Return immediately if file_name is empty */
2675
2676 if (*file_name == '\0')
2677 return 0;
2678
c69ba469 2679 /* Remove quotes around file_name if present */
2680
2681 ptr = file_name;
2682 if (*ptr == '"')
2683 ptr++;
2684
2685 strcpy (file_path, ptr);
2686
2687 ptr = file_path + strlen (file_path) - 1;
2688
2689 if (*ptr == '"')
2690 *ptr = '\0';
1fac938e 2691
f15731c4 2692 /* Handle absolute pathnames. */
c69ba469 2693
2694 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2695
9dfe12ae 2696 if (absolute)
2697 {
c69ba469 2698 if (__gnat_is_regular_file (file_path))
2699 return xstrdup (file_path);
9dfe12ae 2700
2701 return 0;
2702 }
2703
2704 /* If file_name include directory separator(s), try it first as
2705 a path name relative to the current directory */
1fac938e 2706 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2707 ;
2708
9dfe12ae 2709 if (*ptr != 0)
1fac938e 2710 {
2711 if (__gnat_is_regular_file (file_name))
2712 return xstrdup (file_name);
1fac938e 2713 }
2714
2715 if (path_val == 0)
2716 return 0;
2717
2718 {
2719 /* The result has to be smaller than path_val + file_name. */
5703e222 2720 char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
1fac938e 2721
2722 for (;;)
2723 {
c69ba469 2724 /* Skip the starting quote */
2725
2726 if (*path_val == '"')
69d33a1d 2727 path_val++;
c69ba469 2728
1fac938e 2729 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
69d33a1d 2730 *ptr++ = *path_val++;
1fac938e 2731
5c182b3b 2732 /* If directory is empty, it is the current directory*/
2733
2734 if (ptr == file_path)
2735 {
2736 *ptr = '.';
2737 }
2738 else
2739 ptr--;
c69ba469 2740
2741 /* Skip the ending quote */
2742
2743 if (*ptr == '"')
69d33a1d 2744 ptr--;
c69ba469 2745
1fac938e 2746 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2747 *++ptr = DIR_SEPARATOR;
2748
2749 strcpy (++ptr, file_name);
2750
2751 if (__gnat_is_regular_file (file_path))
2752 return xstrdup (file_path);
5c182b3b 2753
2754 if (*path_val == 0)
2755 return 0;
2756
2757 /* Skip path separator */
2758
2759 path_val++;
1fac938e 2760 }
2761 }
2762
2763 return 0;
2764}
2765
1fac938e 2766/* Locate an executable given a Path argument. This routine is only used by
2767 gnatbl and should not be used otherwise. Use locate_exec_on_path
f15731c4 2768 instead. */
1fac938e 2769
2770char *
9dfe12ae 2771__gnat_locate_exec (char *exec_name, char *path_val)
1fac938e 2772{
fb31b465 2773 char *ptr;
1fac938e 2774 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2775 {
2776 char *full_exec_name
5703e222 2777 = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
1fac938e 2778
2779 strcpy (full_exec_name, exec_name);
2780 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
fb31b465 2781 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2782
2783 if (ptr == 0)
2784 return __gnat_locate_regular_file (exec_name, path_val);
2785 return ptr;
1fac938e 2786 }
2787 else
2788 return __gnat_locate_regular_file (exec_name, path_val);
2789}
2790
f15731c4 2791/* Locate an executable using the Systems default PATH. */
1fac938e 2792
2793char *
9dfe12ae 2794__gnat_locate_exec_on_path (char *exec_name)
1fac938e 2795{
9dfe12ae 2796 char *apath_val;
3b18b370 2797
e2a33c18 2798#if defined (_WIN32) && !defined (RTX)
3b18b370 2799 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2800 TCHAR *wapath_val;
9dfe12ae 2801 /* In Win32 systems we expand the PATH as for XP environment
c69ba469 2802 variables are not automatically expanded. We also prepend the
2803 ".;" to the path to match normal NT path search semantics */
9dfe12ae 2804
c69ba469 2805 #define EXPAND_BUFFER_SIZE 32767
9dfe12ae 2806
3b18b370 2807 wapath_val = alloca (EXPAND_BUFFER_SIZE);
c69ba469 2808
3b18b370 2809 wapath_val [0] = '.';
2810 wapath_val [1] = ';';
1fac938e 2811
c69ba469 2812 DWORD res = ExpandEnvironmentStrings
3b18b370 2813 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2814
2815 if (!res) wapath_val [0] = _T('\0');
2816
2817 apath_val = alloca (EXPAND_BUFFER_SIZE);
2818
f60cc57d 2819 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
3b18b370 2820 return __gnat_locate_exec (exec_name, apath_val);
c69ba469 2821
c69ba469 2822#else
3b18b370 2823
2824#ifdef VMS
2825 char *path_val = "/VAXC$PATH";
2826#else
2827 char *path_val = getenv ("PATH");
2828#endif
e2c62f37 2829 if (path_val == NULL) return NULL;
5703e222 2830 apath_val = (char *) alloca (strlen (path_val) + 1);
1fac938e 2831 strcpy (apath_val, path_val);
2832 return __gnat_locate_exec (exec_name, apath_val);
3b18b370 2833#endif
1fac938e 2834}
2835
2836#ifdef VMS
2837
2838/* These functions are used to translate to and from VMS and Unix syntax
f15731c4 2839 file, directory and path specifications. */
1fac938e 2840
9dfe12ae 2841#define MAXPATH 256
1fac938e 2842#define MAXNAMES 256
2843#define NEW_CANONICAL_FILELIST_INCREMENT 64
2844
9dfe12ae 2845static char new_canonical_dirspec [MAXPATH];
2846static char new_canonical_filespec [MAXPATH];
2847static char new_canonical_pathspec [MAXNAMES*MAXPATH];
1fac938e 2848static unsigned new_canonical_filelist_index;
2849static unsigned new_canonical_filelist_in_use;
2850static unsigned new_canonical_filelist_allocated;
2851static char **new_canonical_filelist;
9dfe12ae 2852static char new_host_pathspec [MAXNAMES*MAXPATH];
2853static char new_host_dirspec [MAXPATH];
2854static char new_host_filespec [MAXPATH];
1fac938e 2855
2856/* Routine is called repeatedly by decc$from_vms via
9dfe12ae 2857 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2858 runs out. */
1fac938e 2859
2860static int
9dfe12ae 2861wildcard_translate_unix (char *name)
1fac938e 2862{
2863 char *ver;
9dfe12ae 2864 char buff [MAXPATH];
1fac938e 2865
9dfe12ae 2866 strncpy (buff, name, MAXPATH);
2867 buff [MAXPATH - 1] = (char) 0;
1fac938e 2868 ver = strrchr (buff, '.');
2869
f15731c4 2870 /* Chop off the version. */
1fac938e 2871 if (ver)
2872 *ver = 0;
2873
f15731c4 2874 /* Dynamically extend the allocation by the increment. */
1fac938e 2875 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2876 {
2877 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
f15731c4 2878 new_canonical_filelist = (char **) xrealloc
69d33a1d 2879 (new_canonical_filelist,
2880 new_canonical_filelist_allocated * sizeof (char *));
1fac938e 2881 }
2882
2883 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2884
2885 return 1;
2886}
2887
f15731c4 2888/* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2889 full translation and copy the results into a list (_init), then return them
2890 one at a time (_next). If onlydirs set, only expand directory files. */
1fac938e 2891
2892int
9dfe12ae 2893__gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
1fac938e 2894{
2895 int len;
9dfe12ae 2896 char buff [MAXPATH];
1fac938e 2897
2898 len = strlen (filespec);
9dfe12ae 2899 strncpy (buff, filespec, MAXPATH);
2900
2901 /* Only look for directories */
2902 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2903 strncat (buff, "*.dir", MAXPATH);
1fac938e 2904
9dfe12ae 2905 buff [MAXPATH - 1] = (char) 0;
1fac938e 2906
2907 decc$from_vms (buff, wildcard_translate_unix, 1);
2908
f15731c4 2909 /* Remove the .dir extension. */
1fac938e 2910 if (onlydirs)
2911 {
2912 int i;
2913 char *ext;
2914
2915 for (i = 0; i < new_canonical_filelist_in_use; i++)
69d33a1d 2916 {
2917 ext = strstr (new_canonical_filelist[i], ".dir");
2918 if (ext)
2919 *ext = 0;
2920 }
1fac938e 2921 }
2922
2923 return new_canonical_filelist_in_use;
2924}
2925
f15731c4 2926/* Return the next filespec in the list. */
1fac938e 2927
2928char *
2929__gnat_to_canonical_file_list_next ()
2930{
f15731c4 2931 return new_canonical_filelist[new_canonical_filelist_index++];
1fac938e 2932}
2933
f15731c4 2934/* Free storage used in the wildcard expansion. */
1fac938e 2935
2936void
2937__gnat_to_canonical_file_list_free ()
2938{
2939 int i;
2940
2941 for (i = 0; i < new_canonical_filelist_in_use; i++)
f15731c4 2942 free (new_canonical_filelist[i]);
1fac938e 2943
2944 free (new_canonical_filelist);
2945
2946 new_canonical_filelist_in_use = 0;
2947 new_canonical_filelist_allocated = 0;
2948 new_canonical_filelist_index = 0;
2949 new_canonical_filelist = 0;
2950}
2951
b12d3a0b 2952/* The functional equivalent of decc$translate_vms routine.
2953 Designed to produce the same output, but is protected against
2954 malformed paths (original version ACCVIOs in this case) and
2955 does not require VMS-specific DECC RTL */
2956
2957#define NAM$C_MAXRSS 1024
2958
2959char *
2960__gnat_translate_vms (char *src)
2961{
2962 static char retbuf [NAM$C_MAXRSS+1];
2963 char *srcendpos, *pos1, *pos2, *retpos;
2964 int disp, path_present = 0;
2965
2966 if (!src) return NULL;
2967
2968 srcendpos = strchr (src, '\0');
2969 retpos = retbuf;
2970
2971 /* Look for the node and/or device in front of the path */
2972 pos1 = src;
2973 pos2 = strchr (pos1, ':');
2974
2975 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2976 /* There is a node name. "node_name::" becomes "node_name!" */
2977 disp = pos2 - pos1;
2978 strncpy (retbuf, pos1, disp);
2979 retpos [disp] = '!';
2980 retpos = retpos + disp + 1;
2981 pos1 = pos2 + 2;
2982 pos2 = strchr (pos1, ':');
2983 }
2984
2985 if (pos2) {
2986 /* There is a device name. "dev_name:" becomes "/dev_name/" */
2987 *(retpos++) = '/';
2988 disp = pos2 - pos1;
2989 strncpy (retpos, pos1, disp);
2990 retpos = retpos + disp;
2991 pos1 = pos2 + 1;
2992 *(retpos++) = '/';
2993 }
2994 else
2995 /* No explicit device; we must look ahead and prepend /sys$disk/ if
2996 the path is absolute */
2997 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2998 && !strchr (".-]>", *(pos1 + 1))) {
2999 strncpy (retpos, "/sys$disk/", 10);
3000 retpos += 10;
3001 }
3002
3003 /* Process the path part */
3004 while (*pos1 == '[' || *pos1 == '<') {
3005 path_present++;
3006 pos1++;
3007 if (*pos1 == ']' || *pos1 == '>') {
3008 /* Special case, [] translates to '.' */
3009 *(retpos++) = '.';
3010 pos1++;
3011 }
3012 else {
3013 /* '[000000' means root dir. It can be present in the middle of
3014 the path due to expansion of logical devices, in which case
3015 we skip it */
3016 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
3017 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
3018 pos1 += 6;
3019 if (*pos1 == '.') pos1++;
3020 }
3021 else if (*pos1 == '.') {
3022 /* Relative path */
3023 *(retpos++) = '.';
3024 }
3025
2359306a 3026 /* There is a qualified path */
3027 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
b12d3a0b 3028 switch (*pos1) {
3029 case '.':
3030 /* '.' is used to separate directories. Replace it with '/' but
3031 only if there isn't already '/' just before */
3032 if (*(retpos - 1) != '/') *(retpos++) = '/';
3033 pos1++;
3034 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
3035 /* ellipsis refers to entire subtree; replace with '**' */
3036 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
3037 pos1 += 2;
3038 }
3039 break;
3040 case '-' :
2359306a 3041 /* When after '.' '[' '<' is equivalent to Unix ".." but there
3042 may be several in a row */
3043 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
3044 *(pos1 - 1) == '<') {
3045 while (*pos1 == '-') {
3046 pos1++;
3047 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
3048 }
3049 retpos--;
3050 break;
b12d3a0b 3051 }
2359306a 3052 /* otherwise fall through to default */
b12d3a0b 3053 default:
3054 *(retpos++) = *(pos1++);
3055 }
3056 }
3057 pos1++;
3058 }
3059 }
3060
3061 if (pos1 < srcendpos) {
3062 /* Now add the actual file name, until the version suffix if any */
3063 if (path_present) *(retpos++) = '/';
3064 pos2 = strchr (pos1, ';');
3065 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
3066 strncpy (retpos, pos1, disp);
3067 retpos += disp;
3068 if (pos2 && pos2 < srcendpos) {
3069 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
3070 *retpos++ = '.';
3071 disp = srcendpos - pos2 - 1;
3072 strncpy (retpos, pos2 + 1, disp);
3073 retpos += disp;
3074 }
3075 }
3076
3077 *retpos = '\0';
3078
3079 return retbuf;
3080
3081}
3082
f15731c4 3083/* Translate a VMS syntax directory specification in to Unix syntax. If
3084 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
3085 found, return input string. Also translate a dirname that contains no
3086 slashes, in case it's a logical name. */
1fac938e 3087
3088char *
9dfe12ae 3089__gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
1fac938e 3090{
3091 int len;
3092
3093 strcpy (new_canonical_dirspec, "");
3094 if (strlen (dirspec))
3095 {
3096 char *dirspec1;
3097
3098 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
69d33a1d 3099 {
3100 strncpy (new_canonical_dirspec,
3101 __gnat_translate_vms (dirspec),
3102 MAXPATH);
3103 }
1fac938e 3104 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
69d33a1d 3105 {
3106 strncpy (new_canonical_dirspec,
3107 __gnat_translate_vms (dirspec1),
3108 MAXPATH);
3109 }
1fac938e 3110 else
69d33a1d 3111 {
3112 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
3113 }
1fac938e 3114 }
3115
3116 len = strlen (new_canonical_dirspec);
9dfe12ae 3117 if (prefixflag && new_canonical_dirspec [len-1] != '/')
3118 strncat (new_canonical_dirspec, "/", MAXPATH);
3119
3120 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3121
3122 return new_canonical_dirspec;
3123
3124}
3125
3126/* Translate a VMS syntax file specification into Unix syntax.
3cc2671a 3127 If no indicators of VMS syntax found, check if it's an uppercase
23c6b287 3128 alphanumeric_ name and if so try it out as an environment
3129 variable (logical name). If all else fails return the
3130 input string. */
1fac938e 3131
3132char *
9dfe12ae 3133__gnat_to_canonical_file_spec (char *filespec)
1fac938e 3134{
23c6b287 3135 char *filespec1;
3136
9dfe12ae 3137 strncpy (new_canonical_filespec, "", MAXPATH);
3138
1fac938e 3139 if (strchr (filespec, ']') || strchr (filespec, ':'))
9dfe12ae 3140 {
2359306a 3141 char *tspec = (char *) __gnat_translate_vms (filespec);
c69ba469 3142
3143 if (tspec != (char *) -1)
69d33a1d 3144 strncpy (new_canonical_filespec, tspec, MAXPATH);
23c6b287 3145 }
3146 else if ((strlen (filespec) == strspn (filespec,
69d33a1d 3147 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
3148 && (filespec1 = getenv (filespec)))
23c6b287 3149 {
2359306a 3150 char *tspec = (char *) __gnat_translate_vms (filespec1);
c69ba469 3151
3152 if (tspec != (char *) -1)
69d33a1d 3153 strncpy (new_canonical_filespec, tspec, MAXPATH);
9dfe12ae 3154 }
1fac938e 3155 else
9dfe12ae 3156 {
3157 strncpy (new_canonical_filespec, filespec, MAXPATH);
3158 }
3159
3160 new_canonical_filespec [MAXPATH - 1] = (char) 0;
1fac938e 3161
3162 return new_canonical_filespec;
3163}
3164
3165/* Translate a VMS syntax path specification into Unix syntax.
f15731c4 3166 If no indicators of VMS syntax found, return input string. */
1fac938e 3167
3168char *
9dfe12ae 3169__gnat_to_canonical_path_spec (char *pathspec)
1fac938e 3170{
9dfe12ae 3171 char *curr, *next, buff [MAXPATH];
1fac938e 3172
3173 if (pathspec == 0)
3174 return pathspec;
3175
f15731c4 3176 /* If there are /'s, assume it's a Unix path spec and return. */
1fac938e 3177 if (strchr (pathspec, '/'))
3178 return pathspec;
3179
f15731c4 3180 new_canonical_pathspec[0] = 0;
1fac938e 3181 curr = pathspec;
3182
3183 for (;;)
3184 {
3185 next = strchr (curr, ',');
3186 if (next == 0)
3187 next = strchr (curr, 0);
3188
3189 strncpy (buff, curr, next - curr);
f15731c4 3190 buff[next - curr] = 0;
1fac938e 3191
f15731c4 3192 /* Check for wildcards and expand if present. */
1fac938e 3193 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
3194 {
3195 int i, dirs;
3196
3197 dirs = __gnat_to_canonical_file_list_init (buff, 1);
3198 for (i = 0; i < dirs; i++)
3199 {
3200 char *next_dir;
3201
3202 next_dir = __gnat_to_canonical_file_list_next ();
9dfe12ae 3203 strncat (new_canonical_pathspec, next_dir, MAXPATH);
1fac938e 3204
f15731c4 3205 /* Don't append the separator after the last expansion. */
1fac938e 3206 if (i+1 < dirs)
9dfe12ae 3207 strncat (new_canonical_pathspec, ":", MAXPATH);
1fac938e 3208 }
3209
69d33a1d 3210 __gnat_to_canonical_file_list_free ();
1fac938e 3211 }
3212 else
69d33a1d 3213 strncat (new_canonical_pathspec,
3214 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
1fac938e 3215
3216 if (*next == 0)
3217 break;
3218
9dfe12ae 3219 strncat (new_canonical_pathspec, ":", MAXPATH);
1fac938e 3220 curr = next + 1;
3221 }
3222
9dfe12ae 3223 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
3224
1fac938e 3225 return new_canonical_pathspec;
3226}
3227
9dfe12ae 3228static char filename_buff [MAXPATH];
1fac938e 3229
3230static int
9dfe12ae 3231translate_unix (char *name, int type)
1fac938e 3232{
9dfe12ae 3233 strncpy (filename_buff, name, MAXPATH);
3234 filename_buff [MAXPATH - 1] = (char) 0;
1fac938e 3235 return 0;
3236}
3237
f15731c4 3238/* Translate a Unix syntax path spec into a VMS style (comma separated list of
3239 directories. */
1fac938e 3240
3241static char *
9dfe12ae 3242to_host_path_spec (char *pathspec)
1fac938e 3243{
9dfe12ae 3244 char *curr, *next, buff [MAXPATH];
1fac938e 3245
3246 if (pathspec == 0)
3247 return pathspec;
3248
f15731c4 3249 /* Can't very well test for colons, since that's the Unix separator! */
1fac938e 3250 if (strchr (pathspec, ']') || strchr (pathspec, ','))
3251 return pathspec;
3252
f15731c4 3253 new_host_pathspec[0] = 0;
1fac938e 3254 curr = pathspec;
3255
3256 for (;;)
3257 {
3258 next = strchr (curr, ':');
3259 if (next == 0)
3260 next = strchr (curr, 0);
3261
3262 strncpy (buff, curr, next - curr);
f15731c4 3263 buff[next - curr] = 0;
1fac938e 3264
9dfe12ae 3265 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
1fac938e 3266 if (*next == 0)
3267 break;
9dfe12ae 3268 strncat (new_host_pathspec, ",", MAXPATH);
1fac938e 3269 curr = next + 1;
3270 }
3271
9dfe12ae 3272 new_host_pathspec [MAXPATH - 1] = (char) 0;
3273
1fac938e 3274 return new_host_pathspec;
3275}
3276
f15731c4 3277/* Translate a Unix syntax directory specification into VMS syntax. The
3278 PREFIXFLAG has no effect, but is kept for symmetry with
3279 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3280 string. */
1fac938e 3281
3282char *
9dfe12ae 3283__gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3284{
3285 int len = strlen (dirspec);
3286
9dfe12ae 3287 strncpy (new_host_dirspec, dirspec, MAXPATH);
3288 new_host_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3289
3290 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3291 return new_host_dirspec;
3292
f15731c4 3293 while (len > 1 && new_host_dirspec[len - 1] == '/')
1fac938e 3294 {
f15731c4 3295 new_host_dirspec[len - 1] = 0;
1fac938e 3296 len--;
3297 }
3298
3299 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
9dfe12ae 3300 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3301 new_host_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3302
3303 return new_host_dirspec;
1fac938e 3304}
3305
3306/* Translate a Unix syntax file specification into VMS syntax.
f15731c4 3307 If indicators of VMS syntax found, return input string. */
1fac938e 3308
3309char *
9dfe12ae 3310__gnat_to_host_file_spec (char *filespec)
1fac938e 3311{
9dfe12ae 3312 strncpy (new_host_filespec, "", MAXPATH);
1fac938e 3313 if (strchr (filespec, ']') || strchr (filespec, ':'))
9dfe12ae 3314 {
3315 strncpy (new_host_filespec, filespec, MAXPATH);
3316 }
1fac938e 3317 else
3318 {
3319 decc$to_vms (filespec, translate_unix, 1, 1);
9dfe12ae 3320 strncpy (new_host_filespec, filename_buff, MAXPATH);
1fac938e 3321 }
3322
9dfe12ae 3323 new_host_filespec [MAXPATH - 1] = (char) 0;
3324
1fac938e 3325 return new_host_filespec;
3326}
3327
3328void
3329__gnat_adjust_os_resource_limits ()
3330{
3331 SYS$ADJWSL (131072, 0);
3332}
3333
9dfe12ae 3334#else /* VMS */
1fac938e 3335
f15731c4 3336/* Dummy functions for Osint import for non-VMS systems. */
1fac938e 3337
3338int
9dfe12ae 3339__gnat_to_canonical_file_list_init
3340 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
1fac938e 3341{
3342 return 0;
3343}
3344
3345char *
6f2c2693 3346__gnat_to_canonical_file_list_next (void)
1fac938e 3347{
4c4697b8 3348 static char *empty = "";
3349 return empty;
1fac938e 3350}
3351
3352void
6f2c2693 3353__gnat_to_canonical_file_list_free (void)
1fac938e 3354{
3355}
3356
3357char *
9dfe12ae 3358__gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3359{
3360 return dirspec;
3361}
3362
3363char *
9dfe12ae 3364__gnat_to_canonical_file_spec (char *filespec)
1fac938e 3365{
3366 return filespec;
3367}
3368
3369char *
9dfe12ae 3370__gnat_to_canonical_path_spec (char *pathspec)
1fac938e 3371{
3372 return pathspec;
3373}
3374
3375char *
9dfe12ae 3376__gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3377{
3378 return dirspec;
3379}
3380
3381char *
9dfe12ae 3382__gnat_to_host_file_spec (char *filespec)
1fac938e 3383{
3384 return filespec;
3385}
3386
3387void
6f2c2693 3388__gnat_adjust_os_resource_limits (void)
1fac938e 3389{
3390}
3391
3392#endif
3393
1fac938e 3394#if defined (__mips_vxworks)
9dfe12ae 3395int
3396_flush_cache()
1fac938e 3397{
3398 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3399}
3400#endif
3401
8c7d3bad 3402#if defined (IS_CROSS) \
a3b0f4f2 3403 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3404 && defined (__SVR4)) \
c69ba469 3405 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
a3b0f4f2 3406 && ! (defined (linux) && defined (__ia64__)) \
547371fa 3407 && ! (defined (linux) && defined (powerpc)) \
40a4417a 3408 && ! defined (__FreeBSD__) \
571e421a 3409 && ! defined (__Lynx__) \
21a87c1d 3410 && ! defined (__hpux__) \
ba706ed3 3411 && ! defined (__APPLE__) \
9dfe12ae 3412 && ! defined (_AIX) \
1fac938e 3413 && ! (defined (__alpha__) && defined (__osf__)) \
3b18b370 3414 && ! defined (VMS) \
80d4fec4 3415 && ! defined (__MINGW32__) \
3416 && ! (defined (__mips) && defined (__sgi)))
f15731c4 3417
a3b0f4f2 3418/* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3419 just above for a list of native platforms that provide a non-dummy
3420 version of this procedure in libaddr2line.a. */
1fac938e 3421
3422void
1e622f0e 3423convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3424 void *addrs ATTRIBUTE_UNUSED,
9dfe12ae 3425 int n_addr ATTRIBUTE_UNUSED,
3426 void *buf ATTRIBUTE_UNUSED,
3427 int *len ATTRIBUTE_UNUSED)
1fac938e 3428{
3429 *len = 0;
3430}
3431#endif
f15731c4 3432
3433#if defined (_WIN32)
3434int __gnat_argument_needs_quote = 1;
3435#else
3436int __gnat_argument_needs_quote = 0;
3437#endif
9dfe12ae 3438
3439/* This option is used to enable/disable object files handling from the
3440 binder file by the GNAT Project module. For example, this is disabled on
e0f42093 3441 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3442 Stating with GCC 3.4 the shared libraries are not based on mdll
3443 anymore as it uses the GCC's -shared option */
3444#if defined (_WIN32) \
3445 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
9dfe12ae 3446int __gnat_prj_add_obj_files = 0;
3447#else
3448int __gnat_prj_add_obj_files = 1;
3449#endif
3450
3451/* char used as prefix/suffix for environment variables */
3452#if defined (_WIN32)
3453char __gnat_environment_char = '%';
3454#else
3455char __gnat_environment_char = '$';
3456#endif
3457
3458/* This functions copy the file attributes from a source file to a
3459 destination file.
3460
3461 mode = 0 : In this mode copy only the file time stamps (last access and
3462 last modification time stamps).
3463
3464 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3465 copied.
3466
3467 Returns 0 if operation was successful and -1 in case of error. */
3468
3469int
3470__gnat_copy_attribs (char *from, char *to, int mode)
3471{
5091bc2f 3472#if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
9dfe12ae 3473 return -1;
6a85c251 3474
3475#elif defined (_WIN32) && !defined (RTX)
3476 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3477 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3478 BOOL res;
3479 FILETIME fct, flat, flwt;
3480 HANDLE hfrom, hto;
3481
3482 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3483 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3484
3485 /* retrieve from times */
3486
3487 hfrom = CreateFile
3488 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3489
3490 if (hfrom == INVALID_HANDLE_VALUE)
3491 return -1;
3492
3493 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3494
3495 CloseHandle (hfrom);
3496
3497 if (res == 0)
3498 return -1;
3499
3500 /* retrieve from times */
3501
3502 hto = CreateFile
3503 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3504
3505 if (hto == INVALID_HANDLE_VALUE)
3506 return -1;
3507
3508 res = SetFileTime (hto, NULL, &flat, &flwt);
3509
3510 CloseHandle (hto);
3511
3512 if (res == 0)
3513 return -1;
3514
3515 /* Set file attributes in full mode. */
3516
3517 if (mode == 1)
3518 {
3519 DWORD attribs = GetFileAttributes (wfrom);
3520
3521 if (attribs == INVALID_FILE_ATTRIBUTES)
3522 return -1;
3523
3524 res = SetFileAttributes (wto, attribs);
3525 if (res == 0)
3526 return -1;
3527 }
3528
3529 return 0;
3530
9dfe12ae 3531#else
8cb516d7 3532 GNAT_STRUCT_STAT fbuf;
9dfe12ae 3533 struct utimbuf tbuf;
3534
8cb516d7 3535 if (GNAT_STAT (from, &fbuf) == -1)
9dfe12ae 3536 {
3537 return -1;
3538 }
3539
3540 tbuf.actime = fbuf.st_atime;
3541 tbuf.modtime = fbuf.st_mtime;
3542
3543 if (utime (to, &tbuf) == -1)
3544 {
3545 return -1;
3546 }
3547
3548 if (mode == 1)
3549 {
3550 if (chmod (to, fbuf.st_mode) == -1)
3551 {
3552 return -1;
3553 }
3554 }
3555
3556 return 0;
3557#endif
3558}
3559
cf6d853e 3560int
3561__gnat_lseek (int fd, long offset, int whence)
3562{
3563 return (int) lseek (fd, offset, whence);
3564}
0914a918 3565
e2c62f37 3566/* This function returns the major version number of GCC being used. */
0914a918 3567int
3568get_gcc_version (void)
3569{
e2c62f37 3570#ifdef IN_RTS
3571 return __GNUC__;
3572#else
3573 return (int) (version_string[0] - '0');
3574#endif
0914a918 3575}
6d9c3443 3576
3577int
de10c095 3578__gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
0e9e8338 3579 int close_on_exec_p ATTRIBUTE_UNUSED)
6d9c3443 3580{
3581#if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3582 int flags = fcntl (fd, F_GETFD, 0);
3583 if (flags < 0)
3584 return flags;
3585 if (close_on_exec_p)
3586 flags |= FD_CLOEXEC;
3587 else
3588 flags &= ~FD_CLOEXEC;
3589 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
07f34887 3590#elif defined(_WIN32)
3591 HANDLE h = (HANDLE) _get_osfhandle (fd);
3592 if (h == (HANDLE) -1)
3593 return -1;
3594 if (close_on_exec_p)
3595 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
bcf0a1b1 3596 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
07f34887 3597 HANDLE_FLAG_INHERIT);
6d9c3443 3598#else
07f34887 3599 /* TODO: Unimplemented. */
6d9c3443 3600 return -1;
6d9c3443 3601#endif
3602}
fb31b465 3603
3604/* Indicates if platforms supports automatic initialization through the
3605 constructor mechanism */
3606int
c88e6a4f 3607__gnat_binder_supports_auto_init (void)
fb31b465 3608{
3609#ifdef VMS
3610 return 0;
3611#else
3612 return 1;
3613#endif
3614}
3615
3616/* Indicates that Stand-Alone Libraries are automatically initialized through
3617 the constructor mechanism */
3618int
c88e6a4f 3619__gnat_sals_init_using_constructors (void)
fb31b465 3620{
3621#if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3622 return 0;
3623#else
3624 return 1;
3625#endif
3626}
e2a33c18 3627
8e726ab4 3628#ifdef RTX
3629
e2a33c18 3630/* In RTX mode, the procedure to get the time (as file time) is different
3631 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3632 we introduce an intermediate procedure to link against the corresponding
3633 one in each situation. */
8e726ab4 3634
3635extern void GetTimeAsFileTime(LPFILETIME pTime);
e2a33c18 3636
3637void GetTimeAsFileTime(LPFILETIME pTime)
3638{
3639#ifdef RTSS
3640 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3641#else
3642 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3643#endif
3644}
8e726ab4 3645
3646#ifdef RTSS
3647/* Add symbol that is required to link. It would otherwise be taken from
3648 libgcc.a and it would try to use the gcc constructors that are not
3649 supported by Microsoft linker. */
3650
3651extern void __main (void);
3652
3653void __main (void) {}
3654#endif
e2a33c18 3655#endif
3656
9d093602 3657#if defined (linux) || defined(__GLIBC__)
e2a33c18 3658/* pthread affinity support */
3659
c62e34a4 3660int __gnat_pthread_setaffinity_np (pthread_t th,
3661 size_t cpusetsize,
3662 const void *cpuset);
3663
e2a33c18 3664#ifdef CPU_SETSIZE
3665#include <pthread.h>
3666int
3667__gnat_pthread_setaffinity_np (pthread_t th,
3668 size_t cpusetsize,
3669 const cpu_set_t *cpuset)
3670{
3671 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3672}
3673#else
3674int
c62e34a4 3675__gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3676 size_t cpusetsize ATTRIBUTE_UNUSED,
3677 const void *cpuset ATTRIBUTE_UNUSED)
e2a33c18 3678{
3679 return 0;
3680}
3681#endif
3682#endif
a0d9619f 3683
3684#if defined (linux)
3685/* There is no function in the glibc to retrieve the LWP of the current
3686 thread. We need to do a system call in order to retrieve this
3687 information. */
3688#include <sys/syscall.h>
12e8797f 3689void *__gnat_lwp_self (void)
3690{
a0d9619f 3691 return (void *) syscall (__NR_gettid);
3692}
3693#endif