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