]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ada/adaint.c
c++: Handle multiple aggregate overloads [PR95319].
[thirdparty/gcc.git] / gcc / ada / adaint.c
CommitLineData
d23b8f57
RK
1/****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
d23b8f57
RK
7 * C Implementation File *
8 * *
1d005acc 9 * Copyright (C) 1992-2019, Free Software Foundation, Inc. *
d23b8f57
RK
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- *
748086b7 13 * ware Foundation; either version 3, or (at your option) any later ver- *
d23b8f57
RK
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 *
748086b7
JJ
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/>. *
d23b8f57
RK
26 * *
27 * GNAT was originally developed by the GNAT team at New York University. *
71ff80dc 28 * Extensive contributions were provided by Ada Core Technologies Inc. *
d23b8f57
RK
29 * *
30 ****************************************************************************/
31
07fc65c4
GB
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. */
d23b8f57 36
783d035b 37/* Ensure access to errno is thread safe. */
5c7cf10a
AC
38
39#ifndef _REENTRANT
6907542d 40#define _REENTRANT
5c7cf10a
AC
41#endif
42
43#ifndef _THREAD_SAFE
6907542d 44#define _THREAD_SAFE
5c7cf10a 45#endif
6907542d 46
ddbc55d8 47/* Use 64 bit Large File API */
9820b389
JL
48#if defined (__QNX__)
49#define _LARGEFILE64_SOURCE 1
50#elif !defined(_LARGEFILE_SOURCE)
ddbc55d8
AC
51#define _LARGEFILE_SOURCE
52#endif
53#define _FILE_OFFSET_BITS 64
54
d23b8f57 55#ifdef __vxworks
07fc65c4
GB
56
57/* No need to redefine exit here. */
d23b8f57 58#undef exit
07fc65c4 59
d23b8f57
RK
60/* We want to use the POSIX variants of include files. */
61#define POSIX
62#include "vxWorks.h"
63
64#if defined (__mips_vxworks)
65#include "cacheLib.h"
66#endif /* __mips_vxworks */
67
6a2e5d0f
AC
68/* If SMP, access vxCpuConfiguredGet */
69#ifdef _WRS_CONFIG_SMP
70#include <vxCpuLib.h>
71#endif /* _WRS_CONFIG_SMP */
72
406935b6
AC
73/* We need to know the VxWorks version because some file operations
74 (such as chmod) are only available on VxWorks 6. */
75#include "version.h"
76
82fa20a2
FK
77/* vwModNum.h and dosFsLib.h are needed for the VxWorks 6 rename workaround.
78 See below. */
79#if (_WRS_VXWORKS_MAJOR == 6)
80#include <vwModNum.h>
81#include <dosFsLib.h>
82#endif /* 6.x */
d23b8f57
RK
83#endif /* VxWorks */
84
b24513a1 85#if defined (__APPLE__)
20261dc1
AC
86#include <unistd.h>
87#endif
88
89#if defined (__hpux__)
90#include <sys/param.h>
91#include <sys/pstat.h>
92#endif
93
a1d3851b
AC
94#ifdef __PikeOS__
95#define __BSD_VISIBLE 1
96#endif
97
9820b389
JL
98#ifdef __QNX__
99#include <sys/syspage.h>
c9e80306
JL
100#endif
101
d23b8f57 102#ifdef IN_RTS
a6fc663e
AC
103
104#ifdef STANDALONE
105#include <errno.h>
106#include <sys/types.h>
107#include <sys/stat.h>
108#include <unistd.h>
109#include <stdlib.h>
110#include <string.h>
111
112/* for CPU_SET/CPU_ZERO */
113#define _GNU_SOURCE
114#define __USE_GNU
115
116#include "runtime.h"
117
118#else
d23b8f57
RK
119#include "tconfig.h"
120#include "tsystem.h"
a6fc663e
AC
121#endif
122
d23b8f57
RK
123#include <sys/stat.h>
124#include <fcntl.h>
125#include <time.h>
126
3c55062f
BB
127#if defined (__vxworks) || defined (__ANDROID__)
128/* S_IREAD and S_IWRITE are not defined in VxWorks or Android */
406935b6
AC
129#ifndef S_IREAD
130#define S_IREAD (S_IRUSR | S_IRGRP | S_IROTH)
131#endif
132
133#ifndef S_IWRITE
134#define S_IWRITE (S_IWUSR)
135#endif
136#endif
137
07fc65c4 138/* We don't have libiberty, so use malloc. */
d23b8f57 139#define xmalloc(S) malloc (S)
07fc65c4 140#define xrealloc(V,S) realloc (V,S)
d23b8f57
RK
141#else
142#include "config.h"
143#include "system.h"
18f22284 144#include "version.h"
d23b8f57 145#endif
fbf5a39b 146
8afd02aa
EB
147#ifdef __cplusplus
148extern "C" {
149#endif
150
91f2eb13
AP
151#if defined (__DJGPP__)
152
153/* For isalpha-like tests in the compiler, we're expected to resort to
154 safe-ctype.h/ISALPHA. This isn't available for the runtime library
155 build, so we fallback on ctype.h/isalpha there. */
156
157#ifdef IN_RTS
158#include <ctype.h>
159#define ISALPHA isalpha
160#endif
161
162#elif defined (__MINGW32__) || defined (__CYGWIN__)
4017021b 163
fbf5a39b 164#include "mingw32.h"
ffec8e81 165
c624298a 166/* Current code page and CCS encoding to use, set in initialize.c. */
ca0eb951
AC
167UINT __gnat_current_codepage;
168UINT __gnat_current_ccs_encoding;
4017021b 169
fbf5a39b 170#include <sys/utime.h>
dd7ac716
OH
171
172/* For isalpha-like tests in the compiler, we're expected to resort to
173 safe-ctype.h/ISALPHA. This isn't available for the runtime library
174 build, so we fallback on ctype.h/isalpha there. */
175
176#ifdef IN_RTS
25412599 177#include <ctype.h>
dd7ac716
OH
178#define ISALPHA isalpha
179#endif
8dfea8e7
OH
180
181#elif defined (__Lynx__)
182
183/* Lynx utime.h only defines the entities of interest to us if
184 defined (VMOS_DEV), so ... */
185#define VMOS_DEV
186#include <utime.h>
187#undef VMOS_DEV
188
e08add8e 189#else
fbf5a39b 190#include <utime.h>
fbf5a39b
AC
191#endif
192
aace458a 193/* wait.h processing */
fbf5a39b 194#ifdef __MINGW32__
a1d3851b
AC
195# if OLD_MINGW
196# include <sys/wait.h>
197# endif
b9260c3d 198#elif defined (__vxworks) && defined (__RTP__)
a1d3851b 199# include <wait.h>
8dfea8e7
OH
200#elif defined (__Lynx__)
201/* ??? We really need wait.h and it includes resource.h on Lynx. GCC
202 has a resource.h header as well, included instead of the lynx
203 version in our setup, causing lots of errors. We don't really need
204 the lynx contents of this file, so just workaround the issue by
205 preventing the inclusion of the GCC header from doing anything. */
a1d3851b
AC
206# define GCC_RESOURCE_H
207# include <sys/wait.h>
5ae7c3cf 208#elif defined (__PikeOS__)
5644b7e8 209/* No wait() or waitpid() calls available. */
fbf5a39b 210#else
5644b7e8 211/* Default case. */
fbf5a39b
AC
212#include <sys/wait.h>
213#endif
d23b8f57 214
91f2eb13 215#if defined (__DJGPP__)
d23b8f57 216#include <process.h>
3fee081a 217#include <signal.h>
d23b8f57 218#include <dir.h>
91f2eb13
AP
219#include <utime.h>
220#undef DIR_SEPARATOR
221#define DIR_SEPARATOR '\\'
222
223#elif defined (_WIN32)
224
d23b8f57 225#include <windows.h>
d559d5c6
AC
226#include <accctrl.h>
227#include <aclapi.h>
287aa0ed 228#include <tlhelp32.h>
061ee396 229#include <signal.h>
3984e89a
AC
230#undef DIR_SEPARATOR
231#define DIR_SEPARATOR '\\'
e08add8e
AC
232
233#else
234#include <utime.h>
d23b8f57
RK
235#endif
236
237#include "adaint.h"
238
239/* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
240 defined in the current system. On DOS-like systems these flags control
241 whether the file is opened/created in text-translation mode (CR/LF in
242 external file mapped to LF in internal file), but in Unix-like systems,
243 no text translation is required, so these flags have no effect. */
244
d23b8f57
RK
245#ifndef O_BINARY
246#define O_BINARY 0
247#endif
248
249#ifndef O_TEXT
250#define O_TEXT 0
251#endif
252
253#ifndef HOST_EXECUTABLE_SUFFIX
254#define HOST_EXECUTABLE_SUFFIX ""
255#endif
256
257#ifndef HOST_OBJECT_SUFFIX
258#define HOST_OBJECT_SUFFIX ".o"
259#endif
260
261#ifndef PATH_SEPARATOR
262#define PATH_SEPARATOR ':'
263#endif
264
265#ifndef DIR_SEPARATOR
266#define DIR_SEPARATOR '/'
267#endif
268
5644b7e8 269/* Check for cross-compilation. */
bf327c92
AC
270#if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
271#define IS_CROSS 1
514c9ddc
AC
272int __gnat_is_cross_compiler = 1;
273#else
bf327c92 274#undef IS_CROSS
514c9ddc
AC
275int __gnat_is_cross_compiler = 0;
276#endif
277
d23b8f57
RK
278char __gnat_dir_separator = DIR_SEPARATOR;
279
280char __gnat_path_separator = PATH_SEPARATOR;
281
282/* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
283 the base filenames that libraries specified with -lsomelib options
284 may have. This is used by GNATMAKE to check whether an executable
285 is up-to-date or not. The syntax is
286
287 library_template ::= { pattern ; } pattern NUL
288 pattern ::= [ prefix ] * [ postfix ]
289
290 These should only specify names of static libraries as it makes
291 no sense to determine at link time if dynamic-link libraries are
292 up to date or not. Any libraries that are not found are supposed
293 to be up-to-date:
294
295 * if they are needed but not present, the link
296 will fail,
297
298 * otherwise they are libraries in the system paths and so
299 they are considered part of the system and not checked
300 for that reason.
301
302 ??? This should be part of a GNAT host-specific compiler
303 file instead of being included in all user applications
07fc65c4 304 as well. This is only a temporary work-around for 3.11b. */
d23b8f57
RK
305
306#ifndef GNAT_LIBRARY_TEMPLATE
d23b8f57
RK
307#define GNAT_LIBRARY_TEMPLATE "lib*.a"
308#endif
d23b8f57
RK
309
310const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
311
5ae7c3cf 312#if defined (__vxworks)
fbf5a39b
AC
313#define GNAT_MAX_PATH_LEN PATH_MAX
314
315#else
316
317#if defined (__MINGW32__)
318#include "mingw32.h"
319
320#if OLD_MINGW
321#include <sys/param.h>
322#endif
019310ac
FW
323
324#else
325#include <sys/param.h>
fbf5a39b
AC
326#endif
327
b654d8ce 328#ifdef MAXPATHLEN
fbf5a39b 329#define GNAT_MAX_PATH_LEN MAXPATHLEN
b654d8ce
AC
330#else
331#define GNAT_MAX_PATH_LEN 256
332#endif
019310ac
FW
333
334#endif
335
c6d2191a
AC
336/* Used for runtime check that Ada constant File_Attributes_Size is no
337 less than the actual size of struct file_attributes (see Osint
338 initialization). */
9e9bd455 339int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
48263c9a 340
48263c9a
EB
341void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
342
fbf5a39b
AC
343/* The __gnat_max_path_len variable is used to export the maximum
344 length of a path name to Ada code. max_path_len is also provided
345 for compatibility with older GNAT versions, please do not use
346 it. */
347
348int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
349int max_path_len = GNAT_MAX_PATH_LEN;
350
03b64787
AC
351/* Control whether we can use ACL on Windows. */
352
353int __gnat_use_acl = 1;
354
d23b8f57 355/* The following macro HAVE_READDIR_R should be defined if the
07aff4e3
AC
356 system provides the routine readdir_r.
357 ... but we never define it anywhere??? */
d23b8f57 358#undef HAVE_READDIR_R
8d3e8018 359
cc892b2c 360#define MAYBE_TO_PTR32(argv) argv
cc892b2c 361
9f5b6c7f 362static const char ATTR_UNSET = 127;
96867674 363
8c5b2819
AC
364/* Reset the file attributes as if no system call had been performed */
365
48263c9a 366void
5644b7e8 367__gnat_reset_attributes (struct file_attributes* attr)
48263c9a 368{
96867674 369 attr->exists = ATTR_UNSET;
c6d2191a 370 attr->error = EINVAL;
48263c9a 371
96867674
AC
372 attr->writable = ATTR_UNSET;
373 attr->readable = ATTR_UNSET;
374 attr->executable = ATTR_UNSET;
48263c9a 375
96867674
AC
376 attr->regular = ATTR_UNSET;
377 attr->symbolic_link = ATTR_UNSET;
378 attr->directory = ATTR_UNSET;
48263c9a
EB
379
380 attr->timestamp = (OS_Time)-2;
381 attr->file_length = -1;
382}
383
c6d2191a
AC
384int
385__gnat_error_attributes (struct file_attributes *attr) {
386 return attr->error;
387}
388
c99c095f 389OS_Time
5644b7e8 390__gnat_current_time (void)
c99c095f
OH
391{
392 time_t res = time (NULL);
393 return (OS_Time) res;
394}
395
9392454c
HK
396/* Return the current local time as a string in the ISO 8601 format of
397 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
398 long. */
399
400void
5644b7e8 401__gnat_current_time_string (char *result)
9392454c
HK
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
d23b8f57 419void
5644b7e8
AC
420__gnat_to_gm_time (OS_Time *p_time, int *p_year, int *p_month, int *p_day,
421 int *p_hours, int *p_mins, int *p_secs)
d23b8f57
RK
422{
423 struct tm *res;
fbf5a39b 424 time_t time = (time_t) *p_time;
d23b8f57 425
d23b8f57 426 res = gmtime (&time);
d23b8f57
RK
427 if (res)
428 {
429 *p_year = res->tm_year;
430 *p_month = res->tm_mon;
431 *p_day = res->tm_mday;
432 *p_hours = res->tm_hour;
433 *p_mins = res->tm_min;
434 *p_secs = res->tm_sec;
07fc65c4 435 }
d23b8f57
RK
436 else
437 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
438}
439
c3d01e19
PO
440void
441__gnat_to_os_time (OS_Time *p_time, int year, int month, int day,
442 int hours, int mins, int secs)
443{
444 struct tm v;
445
446 v.tm_year = year;
447 v.tm_mon = month;
448 v.tm_mday = day;
449 v.tm_hour = hours;
450 v.tm_min = mins;
451 v.tm_sec = secs;
36428cc4 452 v.tm_isdst = -1;
c3d01e19
PO
453
454 /* returns -1 of failing, this is s-os_lib Invalid_Time */
455
456 *p_time = (OS_Time) mktime (&v);
457}
458
d23b8f57
RK
459/* Place the contents of the symbolic link named PATH in the buffer BUF,
460 which has size BUFSIZ. If PATH is a symbolic link, then return the number
aace458a
GB
461 of characters of its content in BUF. Otherwise, return -1.
462 For systems not supporting symbolic links, always return -1. */
d23b8f57 463
fbf5a39b 464int
25412599
DS
465__gnat_readlink (char *path ATTRIBUTE_UNUSED,
466 char *buf ATTRIBUTE_UNUSED,
467 size_t bufsiz ATTRIBUTE_UNUSED)
d23b8f57 468{
e08add8e 469#if defined (_WIN32) \
5ae7c3cf 470 || defined(__vxworks) || defined (__PikeOS__)
d23b8f57
RK
471 return -1;
472#else
473 return readlink (path, buf, bufsiz);
474#endif
475}
476
aace458a
GB
477/* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
478 If NEWPATH exists it will NOT be overwritten.
479 For systems not supporting symbolic links, always return -1. */
d23b8f57
RK
480
481int
25412599
DS
482__gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
483 char *newpath ATTRIBUTE_UNUSED)
d23b8f57 484{
e08add8e 485#if defined (_WIN32) \
5ae7c3cf 486 || defined(__vxworks) || defined (__PikeOS__)
d23b8f57
RK
487 return -1;
488#else
489 return symlink (oldpath, newpath);
490#endif
491}
492
07fc65c4 493/* Try to lock a file, return 1 if success. */
d23b8f57 494
5ae7c3cf 495#if defined (__vxworks) \
e08add8e 496 || defined (_WIN32) || defined (__PikeOS__)
d23b8f57
RK
497
498/* Version that does not use link. */
499
500int
fbf5a39b 501__gnat_try_lock (char *dir, char *file)
d23b8f57 502{
d23b8f57 503 int fd;
0022d9e3
PO
504#ifdef __MINGW32__
505 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
506 TCHAR wfile[GNAT_MAX_PATH_LEN];
507 TCHAR wdir[GNAT_MAX_PATH_LEN];
508
ffec8e81
AC
509 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
510 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
0022d9e3 511
bc3c2eca
AC
512 /* ??? the code below crash on MingW64 for obscure reasons, a ticket
513 has been opened here:
514
515 https://sourceforge.net/p/mingw-w64/bugs/414/
516
517 As a workaround an equivalent set of code has been put in place below.
518
0022d9e3 519 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
bc3c2eca
AC
520 */
521
522 _tcscpy (wfull_path, wdir);
523 _tcscat (wfull_path, L"\\");
524 _tcscat (wfull_path, wfile);
525
0022d9e3
PO
526 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
527#else
528 char full_path[256];
d23b8f57
RK
529
530 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
531 fd = open (full_path, O_CREAT | O_EXCL, 0600);
0022d9e3
PO
532#endif
533
07fc65c4 534 if (fd < 0)
d23b8f57 535 return 0;
07fc65c4 536
d23b8f57
RK
537 close (fd);
538 return 1;
539}
540
d23b8f57 541#else
07fc65c4 542
d23b8f57 543/* Version using link(), more secure over NFS. */
fbf5a39b 544/* See TN 6913-016 for discussion ??? */
d23b8f57
RK
545
546int
fbf5a39b 547__gnat_try_lock (char *dir, char *file)
d23b8f57 548{
07fc65c4
GB
549 char full_path[256];
550 char temp_file[256];
f6c7fcc0 551 GNAT_STRUCT_STAT stat_result;
d23b8f57
RK
552 int fd;
553
554 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
cc4f0de1
AC
555 sprintf (temp_file, "%s%cTMP-%ld-%ld",
556 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
d23b8f57 557
07fc65c4 558 /* Create the temporary file and write the process number. */
d23b8f57
RK
559 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
560 if (fd < 0)
561 return 0;
562
563 close (fd);
564
07fc65c4 565 /* Link it with the new file. */
d23b8f57
RK
566 link (temp_file, full_path);
567
568 /* Count the references on the old one. If we have a count of two, then
07fc65c4 569 the link did succeed. Remove the temporary file before returning. */
d23b8f57
RK
570 __gnat_stat (temp_file, &stat_result);
571 unlink (temp_file);
572 return stat_result.st_nlink == 2;
573}
574#endif
575
576/* Return the maximum file name length. */
577
578int
9373164a 579__gnat_get_maximum_file_name_length (void)
d23b8f57 580{
d23b8f57 581 return -1;
d23b8f57
RK
582}
583
d23b8f57
RK
584/* Return nonzero if file names are case sensitive. */
585
b191a125
AC
586static int file_names_case_sensitive_cache = -1;
587
d23b8f57 588int
9373164a 589__gnat_get_file_names_case_sensitive (void)
d23b8f57 590{
b191a125
AC
591 if (file_names_case_sensitive_cache == -1)
592 {
593 const char *sensitive = getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
61619168 594
b191a125
AC
595 if (sensitive != NULL
596 && (sensitive[0] == '0' || sensitive[0] == '1')
597 && sensitive[1] == '\0')
598 file_names_case_sensitive_cache = sensitive[0] - '0';
599 else
e699b76e
AC
600 {
601 /* By default, we suppose filesystems aren't case sensitive on
602 Windows and Darwin (but they are on arm-darwin). */
91f2eb13 603#if defined (WINNT) || defined (__DJGPP__) \
b54d1d39 604 || (defined (__APPLE__) && !(defined (__arm__) || defined (__arm64__)))
e699b76e 605 file_names_case_sensitive_cache = 0;
d23b8f57 606#else
e699b76e 607 file_names_case_sensitive_cache = 1;
d23b8f57 608#endif
e699b76e 609 }
b191a125
AC
610 }
611 return file_names_case_sensitive_cache;
d23b8f57
RK
612}
613
0e35524d
VC
614/* Return nonzero if environment variables are case sensitive. */
615
616int
617__gnat_get_env_vars_case_sensitive (void)
618{
91f2eb13 619#if defined (WINNT) || defined (__DJGPP__)
0e35524d
VC
620 return 0;
621#else
622 return 1;
623#endif
624}
625
d23b8f57 626char
9373164a 627__gnat_get_default_identifier_character_set (void)
d23b8f57 628{
d23b8f57 629 return '1';
d23b8f57
RK
630}
631
07fc65c4 632/* Return the current working directory. */
d23b8f57
RK
633
634void
fbf5a39b 635__gnat_get_current_dir (char *dir, int *length)
d23b8f57 636{
0022d9e3
PO
637#if defined (__MINGW32__)
638 TCHAR wdir[GNAT_MAX_PATH_LEN];
639
640 _tgetcwd (wdir, *length);
641
ffec8e81 642 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
0022d9e3 643
d23b8f57 644#else
7a71a7c4
AC
645 char* result = getcwd (dir, *length);
646 /* If the current directory does not exist, set length = 0
647 to indicate error. That can't happen on windows, where
648 you can't delete a directory if it is the current
649 directory of some process. */
650 if (!result)
651 {
652 *length = 0;
653 return;
654 }
d23b8f57
RK
655#endif
656
657 *length = strlen (dir);
658
fbf5a39b
AC
659 if (dir [*length - 1] != DIR_SEPARATOR)
660 {
661 dir [*length] = DIR_SEPARATOR;
662 ++(*length);
663 }
07fc65c4 664 dir[*length] = '\0';
d23b8f57
RK
665}
666
07fc65c4 667/* Return the suffix for object files. */
d23b8f57
RK
668
669void
fbf5a39b 670__gnat_get_object_suffix_ptr (int *len, const char **value)
d23b8f57
RK
671{
672 *value = HOST_OBJECT_SUFFIX;
673
674 if (*value == 0)
675 *len = 0;
676 else
677 *len = strlen (*value);
678
679 return;
680}
681
07fc65c4 682/* Return the suffix for executable files. */
d23b8f57
RK
683
684void
fbf5a39b 685__gnat_get_executable_suffix_ptr (int *len, const char **value)
d23b8f57
RK
686{
687 *value = HOST_EXECUTABLE_SUFFIX;
005f870e 688
d23b8f57
RK
689 if (!*value)
690 *len = 0;
691 else
692 *len = strlen (*value);
693
694 return;
695}
696
697/* Return the suffix for debuggable files. Usually this is the same as the
07fc65c4 698 executable extension. */
d23b8f57
RK
699
700void
fbf5a39b 701__gnat_get_debuggable_suffix_ptr (int *len, const char **value)
d23b8f57 702{
d23b8f57 703 *value = HOST_EXECUTABLE_SUFFIX;
d23b8f57
RK
704
705 if (*value == 0)
706 *len = 0;
707 else
708 *len = strlen (*value);
709
710 return;
711}
712
d7598e11
PO
713/* Returns the OS filename and corresponding encoding. */
714
715void
9549767b
AC
716__gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
717 char *w_filename ATTRIBUTE_UNUSED,
d7598e11 718 char *os_name, int *o_length,
640bd0bf 719 char *encoding ATTRIBUTE_UNUSED, int *e_length)
d7598e11 720{
bf327c92 721#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
0727601a 722 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
d7598e11
PO
723 *o_length = strlen (os_name);
724 strcpy (encoding, "encoding=utf8");
725 *e_length = strlen (encoding);
726#else
727 strcpy (os_name, filename);
728 *o_length = strlen (filename);
729 *e_length = 0;
730#endif
731}
732
55cc1a05
AC
733/* Delete a file. */
734
735int
736__gnat_unlink (char *path)
737{
bf327c92 738#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
55cc1a05
AC
739 {
740 TCHAR wpath[GNAT_MAX_PATH_LEN];
741
ffec8e81 742 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
55cc1a05
AC
743 return _tunlink (wpath);
744 }
745#else
746 return unlink (path);
747#endif
748}
749
750/* Rename a file. */
751
752int
753__gnat_rename (char *from, char *to)
754{
bf327c92 755#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
55cc1a05
AC
756 {
757 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
758
ffec8e81
AC
759 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
760 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
55cc1a05
AC
761 return _trename (wfrom, wto);
762 }
82fa20a2
FK
763#elif defined (__vxworks) && (_WRS_VXWORKS_MAJOR == 6)
764 {
765 /* When used on a dos filesystem under VxWorks 6.9 rename will trigger a
766 S_dosFsLib_FILE_NOT_FOUND errno when the file is not found. Let's map
767 that to ENOENT so Ada.Directory.Rename can detect that and raise the
768 Name_Error exception. */
769 int ret = rename (from, to);
770
771 if (ret && (errno == S_dosFsLib_FILE_NOT_FOUND))
772 {
773 errno = ENOENT;
774 }
775 return ret;
776 }
55cc1a05
AC
777#else
778 return rename (from, to);
779#endif
780}
781
4e0079cc
AC
782/* Changing directory. */
783
784int
785__gnat_chdir (char *path)
786{
bf327c92 787#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
4e0079cc
AC
788 {
789 TCHAR wpath[GNAT_MAX_PATH_LEN];
790
ffec8e81 791 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
4e0079cc
AC
792 return _tchdir (wpath);
793 }
794#else
795 return chdir (path);
796#endif
797}
798
468ee337
PO
799/* Removing a directory. */
800
801int
802__gnat_rmdir (char *path)
803{
bf327c92 804#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
468ee337
PO
805 {
806 TCHAR wpath[GNAT_MAX_PATH_LEN];
807
ffec8e81 808 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
468ee337
PO
809 return _trmdir (wpath);
810 }
33374829
AC
811#elif defined (VTHREADS)
812 /* rmdir not available */
813 return -1;
468ee337
PO
814#else
815 return rmdir (path);
816#endif
817}
818
329be64b 819#if defined (_WIN32) || defined (__linux__) || defined (__sun__) \
c9e80306 820 || defined (__FreeBSD__) || defined(__DragonFly__) || defined (__QNX__)
4b03d946
AC
821#define HAS_TARGET_WCHAR_T
822#endif
823
824#ifdef HAS_TARGET_WCHAR_T
825#include <wchar.h>
826#endif
827
50ea6357
AC
828int
829__gnat_fputwc(int c, FILE *stream)
830{
4b03d946 831#ifdef HAS_TARGET_WCHAR_T
50ea6357
AC
832 return fputwc ((wchar_t)c, stream);
833#else
834 return fputc (c, stream);
835#endif
836}
837
18f22284 838FILE *
4d49c6e1 839__gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
18f22284 840{
bf327c92 841#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
18f22284
PO
842 TCHAR wpath[GNAT_MAX_PATH_LEN];
843 TCHAR wmode[10];
844
18f22284 845 S2WS (wmode, mode, 10);
c99c095f 846
ffec8e81
AC
847 if (encoding == Encoding_Unspecified)
848 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
849 else if (encoding == Encoding_UTF8)
c99c095f
OH
850 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
851 else
852 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
853
18f22284 854 return _tfopen (wpath, wmode);
e08add8e 855
18f22284 856#else
f6c7fcc0 857 return GNAT_FOPEN (path, mode);
2995ebee 858#endif
18f22284
PO
859}
860
18f22284 861FILE *
8918fe18
AC
862__gnat_freopen (char *path,
863 char *mode,
864 FILE *stream,
4d49c6e1 865 int encoding ATTRIBUTE_UNUSED)
18f22284 866{
bf327c92 867#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
18f22284
PO
868 TCHAR wpath[GNAT_MAX_PATH_LEN];
869 TCHAR wmode[10];
870
18f22284 871 S2WS (wmode, mode, 10);
c99c095f 872
ffec8e81
AC
873 if (encoding == Encoding_Unspecified)
874 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
875 else if (encoding == Encoding_UTF8)
c99c095f
OH
876 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
877 else
878 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
879
18f22284
PO
880 return _tfreopen (wpath, wmode, stream);
881#else
882 return freopen (path, mode, stream);
883#endif
884}
885
d23b8f57 886int
fbf5a39b 887__gnat_open_read (char *path, int fmode)
d23b8f57
RK
888{
889 int fd;
890 int o_fmode = O_BINARY;
891
892 if (fmode)
893 o_fmode = O_TEXT;
894
e08add8e 895#if defined (__vxworks)
d23b8f57 896 fd = open (path, O_RDONLY | o_fmode, 0444);
0022d9e3
PO
897#elif defined (__MINGW32__)
898 {
899 TCHAR wpath[GNAT_MAX_PATH_LEN];
900
ffec8e81 901 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
0022d9e3
PO
902 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
903 }
d23b8f57 904#else
2b9fbec9 905 fd = GNAT_OPEN (path, O_RDONLY | o_fmode);
d23b8f57 906#endif
07fc65c4 907
d23b8f57
RK
908 return fd < 0 ? -1 : fd;
909}
910
ea7f928b 911#if defined (__MINGW32__)
d23b8f57
RK
912#define PERM (S_IREAD | S_IWRITE)
913#else
914#define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
915#endif
916
917int
fbf5a39b 918__gnat_open_rw (char *path, int fmode)
d23b8f57
RK
919{
920 int fd;
921 int o_fmode = O_BINARY;
922
923 if (fmode)
924 o_fmode = O_TEXT;
925
e08add8e 926#if defined (__MINGW32__)
0022d9e3
PO
927 {
928 TCHAR wpath[GNAT_MAX_PATH_LEN];
929
ffec8e81 930 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
0022d9e3
PO
931 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
932 }
d23b8f57 933#else
2b9fbec9 934 fd = GNAT_OPEN (path, O_RDWR | o_fmode, PERM);
d23b8f57
RK
935#endif
936
937 return fd < 0 ? -1 : fd;
938}
939
940int
fbf5a39b 941__gnat_open_create (char *path, int fmode)
d23b8f57
RK
942{
943 int fd;
944 int o_fmode = O_BINARY;
945
946 if (fmode)
947 o_fmode = O_TEXT;
948
e08add8e 949#if defined (__MINGW32__)
0022d9e3
PO
950 {
951 TCHAR wpath[GNAT_MAX_PATH_LEN];
952
ffec8e81 953 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
0022d9e3
PO
954 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
955 }
d23b8f57 956#else
2b9fbec9 957 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
d23b8f57
RK
958#endif
959
960 return fd < 0 ? -1 : fd;
e6f69614
AC
961}
962
963int
964__gnat_create_output_file (char *path)
965{
966 int fd;
e08add8e 967#if defined (__MINGW32__)
0022d9e3
PO
968 {
969 TCHAR wpath[GNAT_MAX_PATH_LEN];
970
ffec8e81 971 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
0022d9e3
PO
972 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
973 }
e6f69614 974#else
2b9fbec9 975 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
e6f69614
AC
976#endif
977
978 return fd < 0 ? -1 : fd;
d23b8f57
RK
979}
980
fdfcc663
AC
981int
982__gnat_create_output_file_new (char *path)
983{
984 int fd;
e08add8e 985#if defined (__MINGW32__)
fdfcc663
AC
986 {
987 TCHAR wpath[GNAT_MAX_PATH_LEN];
988
989 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
990 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
991 }
992#else
2b9fbec9 993 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
fdfcc663
AC
994#endif
995
996 return fd < 0 ? -1 : fd;
997}
998
d23b8f57 999int
fbf5a39b 1000__gnat_open_append (char *path, int fmode)
d23b8f57
RK
1001{
1002 int fd;
1003 int o_fmode = O_BINARY;
1004
1005 if (fmode)
1006 o_fmode = O_TEXT;
1007
e08add8e 1008#if defined (__MINGW32__)
0022d9e3
PO
1009 {
1010 TCHAR wpath[GNAT_MAX_PATH_LEN];
1011
ffec8e81 1012 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
0022d9e3
PO
1013 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
1014 }
d23b8f57 1015#else
2b9fbec9 1016 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
d23b8f57
RK
1017#endif
1018
1019 return fd < 0 ? -1 : fd;
1020}
1021
07fc65c4 1022/* Open a new file. Return error (-1) if the file already exists. */
d23b8f57
RK
1023
1024int
fbf5a39b 1025__gnat_open_new (char *path, int fmode)
d23b8f57
RK
1026{
1027 int fd;
1028 int o_fmode = O_BINARY;
1029
1030 if (fmode)
1031 o_fmode = O_TEXT;
1032
e08add8e 1033#if defined (__MINGW32__)
0022d9e3
PO
1034 {
1035 TCHAR wpath[GNAT_MAX_PATH_LEN];
1036
ffec8e81 1037 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
0022d9e3
PO
1038 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1039 }
d23b8f57 1040#else
2b9fbec9 1041 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
d23b8f57
RK
1042#endif
1043
1044 return fd < 0 ? -1 : fd;
1045}
1046
e08add8e 1047/* Open a new temp file. Return error (-1) if the file already exists. */
d23b8f57
RK
1048
1049int
fbf5a39b 1050__gnat_open_new_temp (char *path, int fmode)
d23b8f57
RK
1051{
1052 int fd;
1053 int o_fmode = O_BINARY;
1054
1055 strcpy (path, "GNAT-XXXXXX");
1056
e0658eda 1057#if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
a9fdbccb 1058 || defined (__linux__) || defined (__GLIBC__) || defined (__ANDROID__) \
8d9a1ba7 1059 || defined (__DragonFly__) || defined (__QNX__)) && !defined (__vxworks)
d23b8f57 1060 return mkstemp (path);
226ada7a
GB
1061#elif defined (__Lynx__)
1062 mktemp (path);
d23b8f57
RK
1063#else
1064 if (mktemp (path) == NULL)
1065 return -1;
1066#endif
1067
1068 if (fmode)
1069 o_fmode = O_TEXT;
1070
2b9fbec9 1071 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
d23b8f57
RK
1072 return fd < 0 ? -1 : fd;
1073}
1074
479f9059
PO
1075int
1076__gnat_open (char *path, int fmode)
1077{
1078 int fd;
1079
e08add8e 1080#if defined (__MINGW32__)
479f9059
PO
1081 {
1082 TCHAR wpath[GNAT_MAX_PATH_LEN];
1083
1084 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1085 fd = _topen (wpath, fmode, PERM);
1086 }
1087#else
1088 fd = GNAT_OPEN (path, fmode, PERM);
1089#endif
1090
1091 return fd < 0 ? -1 : fd;
1092}
1093
48263c9a
EB
1094/****************************************************************
1095 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1096 ** as possible from it, storing the result in a cache for later reuse
1097 ****************************************************************/
d23b8f57 1098
48263c9a
EB
1099void
1100__gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
d23b8f57 1101{
f6c7fcc0 1102 GNAT_STRUCT_STAT statbuf;
c6d2191a 1103 int ret, error;
d23b8f57 1104
c6d2191a
AC
1105 if (fd != -1) {
1106 /* GNAT_FSTAT returns -1 and sets errno for failure */
48263c9a 1107 ret = GNAT_FSTAT (fd, &statbuf);
c6d2191a
AC
1108 error = ret ? errno : 0;
1109
1110 } else {
1111 /* __gnat_stat returns errno value directly */
1112 error = __gnat_stat (name, &statbuf);
1113 ret = error ? -1 : 0;
1114 }
1115
1116 /*
1117 * A missing file is reported as an attr structure with error == 0 and
1118 * exists == 0.
1119 */
1120
1121 if (error == 0 || error == ENOENT)
1122 attr->error = 0;
48263c9a 1123 else
c6d2191a 1124 attr->error = error;
48263c9a
EB
1125
1126 attr->regular = (!ret && S_ISREG (statbuf.st_mode));
1127 attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
d23b8f57 1128
48263c9a
EB
1129 if (!attr->regular)
1130 attr->file_length = 0;
1131 else
1132 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1133 don't return a useful value for files larger than 2 gigabytes in
1134 either case. */
1135 attr->file_length = statbuf.st_size; /* all systems */
1136
48263c9a 1137 attr->exists = !ret;
48263c9a 1138
5ae7c3cf 1139#if !defined (_WIN32)
48263c9a
EB
1140 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1141 attr->readable = (!ret && (statbuf.st_mode & S_IRUSR));
1142 attr->writable = (!ret && (statbuf.st_mode & S_IWUSR));
1143 attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
1144#endif
1145
48263c9a
EB
1146 if (ret != 0) {
1147 attr->timestamp = (OS_Time)-1;
1148 } else {
48263c9a 1149 attr->timestamp = (OS_Time)statbuf.st_mtime;
48263c9a 1150 }
d23b8f57
RK
1151}
1152
48263c9a
EB
1153/****************************************************************
1154 ** Return the number of bytes in the specified file
1155 ****************************************************************/
30c20106 1156
148c744a 1157__int64
48263c9a 1158__gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
30c20106 1159{
48263c9a
EB
1160 if (attr->file_length == -1) {
1161 __gnat_stat_to_attr (fd, name, attr);
1162 }
30c20106 1163
48263c9a
EB
1164 return attr->file_length;
1165}
30c20106 1166
148c744a 1167__int64
48263c9a
EB
1168__gnat_file_length (int fd)
1169{
1170 struct file_attributes attr;
6528a7ed 1171 __gnat_reset_attributes (&attr);
48263c9a
EB
1172 return __gnat_file_length_attr (fd, NULL, &attr);
1173}
03456e44 1174
935a9145
AC
1175long
1176__gnat_file_length_long (int fd)
1177{
1178 struct file_attributes attr;
1179 __gnat_reset_attributes (&attr);
1180 return (long)__gnat_file_length_attr (fd, NULL, &attr);
1181}
1182
148c744a 1183__int64
48263c9a
EB
1184__gnat_named_file_length (char *name)
1185{
1186 struct file_attributes attr;
6528a7ed 1187 __gnat_reset_attributes (&attr);
48263c9a 1188 return __gnat_file_length_attr (-1, name, &attr);
30c20106
AC
1189}
1190
d23b8f57 1191/* Create a temporary filename and put it in string pointed to by
07fc65c4 1192 TMP_FILENAME. */
d23b8f57
RK
1193
1194void
fbf5a39b 1195__gnat_tmp_name (char *tmp_filename)
d23b8f57 1196{
5ae7c3cf 1197#if defined (__MINGW32__)
d23b8f57
RK
1198 {
1199 char *pname;
a0fb8fe8 1200 char prefix[25];
d23b8f57
RK
1201
1202 /* tempnam tries to create a temporary file in directory pointed to by
1203 TMP environment variable, in c:\temp if TMP is not set, and in
1204 directory specified by P_tmpdir in stdio.h if c:\temp does not
1205 exist. The filename will be created with the prefix "gnat-". */
1206
a0fb8fe8
AC
1207 sprintf (prefix, "gnat-%d-", (int)getpid());
1208 pname = (char *) _tempnam ("c:\\temp", prefix);
d23b8f57 1209
fbf5a39b
AC
1210 /* if pname is NULL, the file was not created properly, the disk is full
1211 or there is no more free temporary files */
1212
1213 if (pname == NULL)
1214 *tmp_filename = '\0';
1215
07fc65c4
GB
1216 /* If pname start with a back slash and not path information it means that
1217 the filename is valid for the current working directory. */
d23b8f57 1218
fbf5a39b 1219 else if (pname[0] == '\\')
d23b8f57
RK
1220 {
1221 strcpy (tmp_filename, ".\\");
1222 strcat (tmp_filename, pname+1);
1223 }
1224 else
1225 strcpy (tmp_filename, pname);
1226
1227 free (pname);
1228 }
07fc65c4 1229
329be64b 1230#elif defined (__linux__) || defined (__FreeBSD__) || defined (__NetBSD__) \
90af5990 1231 || defined (__OpenBSD__) || defined (__GLIBC__) || defined (__ANDROID__) \
8d9a1ba7 1232 || defined (__DragonFly__) || defined (__QNX__)
fbf5a39b 1233#define MAX_SAFE_PATH 1000
d23b8f57
RK
1234 char *tmpdir = getenv ("TMPDIR");
1235
fbf5a39b
AC
1236 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1237 a buffer overflow. */
1238 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
93a87598
AC
1239#ifdef __ANDROID__
1240 strcpy (tmp_filename, "/cache/gnat-XXXXXX");
1241#else
d23b8f57 1242 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
93a87598 1243#endif
d23b8f57 1244 else
fbf5a39b 1245 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
d23b8f57
RK
1246
1247 close (mkstemp(tmp_filename));
50ef946c
AC
1248#elif defined (__vxworks) && !defined (VTHREADS)
1249 int index;
1250 char *pos;
1251 char *savepos;
a95be2d4
AC
1252 static ushort_t seed = 0; /* used to generate unique name */
1253
50ef946c 1254 /* Generate a unique name. */
a95be2d4
AC
1255 strcpy (tmp_filename, "tmp");
1256
a95be2d4 1257 index = 5;
50ef946c 1258 savepos = pos = tmp_filename + strlen (tmp_filename) + index;
a95be2d4
AC
1259 *pos = '\0';
1260
50ef946c
AC
1261 while (1)
1262 {
1263 FILE *f;
1264 ushort_t t;
1265
1266 /* Fill up the name buffer from the last position. */
1267 seed++;
01512446 1268 for (t = seed; --index >= 0; t >>= 3)
50ef946c
AC
1269 *--pos = '0' + (t & 07);
1270
1271 /* Check to see if its unique, if not bump the seed and try again. */
1272 f = fopen (tmp_filename, "r");
1273 if (f == NULL)
1274 break;
1275 fclose (f);
1276 pos = savepos;
1277 index = 5;
1278 }
d23b8f57
RK
1279#else
1280 tmpnam (tmp_filename);
1281#endif
1282}
1283
0022d9e3
PO
1284/* Open directory and returns a DIR pointer. */
1285
1286DIR* __gnat_opendir (char *name)
1287{
5ae7c3cf 1288#if defined (__MINGW32__)
0022d9e3
PO
1289 TCHAR wname[GNAT_MAX_PATH_LEN];
1290
ffec8e81 1291 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
0022d9e3
PO
1292 return (DIR*)_topendir (wname);
1293
1294#else
1295 return opendir (name);
1296#endif
1297}
1298
d23b8f57
RK
1299/* Read the next entry in a directory. The returned string points somewhere
1300 in the buffer. */
1301
329be64b 1302#if defined (__sun__)
07aff4e3
AC
1303/* For Solaris, be sure to use the 64-bit version, otherwise NFS reads may
1304 fail with EOVERFLOW if the server uses 64-bit cookies. */
1305#define dirent dirent64
1306#define readdir readdir64
1307#endif
1308
d23b8f57 1309char *
0022d9e3 1310__gnat_readdir (DIR *dirp, char *buffer, int *len)
d23b8f57 1311{
5ae7c3cf 1312#if defined (__MINGW32__)
0022d9e3
PO
1313 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1314
1315 if (dirent != NULL)
1316 {
ffec8e81 1317 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
0022d9e3
PO
1318 *len = strlen (buffer);
1319
1320 return buffer;
1321 }
1322 else
1323 return NULL;
1324
1325#elif defined (HAVE_READDIR_R)
d23b8f57 1326 /* If possible, try to use the thread-safe version. */
d23b8f57 1327 if (readdir_r (dirp, buffer) != NULL)
d7598e11
PO
1328 {
1329 *len = strlen (((struct dirent*) buffer)->d_name);
1330 return ((struct dirent*) buffer)->d_name;
1331 }
d23b8f57
RK
1332 else
1333 return NULL;
1334
1335#else
0fb2ea01 1336 struct dirent *dirent = (struct dirent *) readdir (dirp);
d23b8f57
RK
1337
1338 if (dirent != NULL)
1339 {
1340 strcpy (buffer, dirent->d_name);
0022d9e3 1341 *len = strlen (buffer);
d23b8f57
RK
1342 return buffer;
1343 }
1344 else
1345 return NULL;
1346
1347#endif
1348}
1349
0022d9e3
PO
1350/* Close a directory entry. */
1351
1352int __gnat_closedir (DIR *dirp)
1353{
5ae7c3cf 1354#if defined (__MINGW32__)
0022d9e3
PO
1355 return _tclosedir ((_TDIR*)dirp);
1356
1357#else
1358 return closedir (dirp);
1359#endif
1360}
1361
d23b8f57
RK
1362/* Returns 1 if readdir is thread safe, 0 otherwise. */
1363
1364int
9373164a 1365__gnat_readdir_is_thread_safe (void)
d23b8f57
RK
1366{
1367#ifdef HAVE_READDIR_R
1368 return 1;
1369#else
1370 return 0;
1371#endif
1372}
1373
5ae7c3cf 1374#if defined (_WIN32)
8f4eb34b
DS
1375/* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1376static const unsigned long long w32_epoch_offset = 11644473600ULL;
d23b8f57
RK
1377
1378/* Returns the file modification timestamp using Win32 routines which are
1379 immune against daylight saving time change. It is in fact not possible to
1380 use fstat for this purpose as the DST modify the st_mtime field of the
1381 stat structure. */
1382
1383static time_t
fbf5a39b 1384win32_filetime (HANDLE h)
d23b8f57 1385{
8f4eb34b
DS
1386 union
1387 {
1388 FILETIME ft_time;
1389 unsigned long long ull_time;
1390 } t_write;
d23b8f57
RK
1391
1392 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1393 since <Jan 1st 1601>. This function must return the number of seconds
1394 since <Jan 1st 1970>. */
1395
8f4eb34b 1396 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
0022d9e3 1397 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
8f4eb34b 1398 return (time_t) 0;
d23b8f57 1399}
f6b5dc8e
AC
1400
1401/* As above but starting from a FILETIME. */
ff2efe85 1402static void
7b536495 1403f2t (const FILETIME *ft, __time64_t *t)
f6b5dc8e
AC
1404{
1405 union
1406 {
1407 FILETIME ft_time;
1408 unsigned long long ull_time;
1409 } t_write;
1410
1411 t_write.ft_time = *ft;
7b536495 1412 *t = (__time64_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
f6b5dc8e 1413}
d23b8f57
RK
1414#endif
1415
1416/* Return a GNAT time stamp given a file name. */
1417
aa720a54 1418OS_Time
48263c9a 1419__gnat_file_time_name_attr (char* name, struct file_attributes* attr)
d23b8f57 1420{
48263c9a 1421 if (attr->timestamp == (OS_Time)-2) {
5ae7c3cf 1422#if defined (_WIN32)
ff2efe85
AC
1423 BOOL res;
1424 WIN32_FILE_ATTRIBUTE_DATA fad;
7b536495 1425 __time64_t ret = -1;
48263c9a
EB
1426 TCHAR wname[GNAT_MAX_PATH_LEN];
1427 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
0022d9e3 1428
c228a069 1429 if ((res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad)))
ff2efe85 1430 f2t (&fad.ftLastWriteTime, &ret);
48263c9a 1431 attr->timestamp = (OS_Time) ret;
d23b8f57 1432#else
48263c9a 1433 __gnat_stat_to_attr (-1, name, attr);
d23b8f57 1434#endif
aa720a54 1435 }
48263c9a
EB
1436 return attr->timestamp;
1437}
1438
1439OS_Time
1440__gnat_file_time_name (char *name)
1441{
1442 struct file_attributes attr;
6528a7ed 1443 __gnat_reset_attributes (&attr);
48263c9a 1444 return __gnat_file_time_name_attr (name, &attr);
d23b8f57
RK
1445}
1446
1447/* Return a GNAT time stamp given a file descriptor. */
1448
aa720a54 1449OS_Time
48263c9a 1450__gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
d23b8f57 1451{
48263c9a 1452 if (attr->timestamp == (OS_Time)-2) {
5ae7c3cf 1453#if defined (_WIN32)
48263c9a
EB
1454 HANDLE h = (HANDLE) _get_osfhandle (fd);
1455 time_t ret = win32_filetime (h);
1456 attr->timestamp = (OS_Time) ret;
d23b8f57
RK
1457
1458#else
48263c9a 1459 __gnat_stat_to_attr (fd, NULL, attr);
d23b8f57 1460#endif
48263c9a
EB
1461 }
1462
1463 return attr->timestamp;
1464}
1465
1466OS_Time
1467__gnat_file_time_fd (int fd)
1468{
1469 struct file_attributes attr;
6528a7ed 1470 __gnat_reset_attributes (&attr);
48263c9a 1471 return __gnat_file_time_fd_attr (fd, &attr);
d23b8f57
RK
1472}
1473
07fc65c4 1474/* Set the file time stamp. */
9678de49
DR
1475
1476void
fbf5a39b 1477__gnat_set_file_time_name (char *name, time_t time_stamp)
9678de49 1478{
ea7f928b 1479#if defined (__vxworks)
5917e80d 1480
07fc65c4 1481/* Code to implement __gnat_set_file_time_name for these systems. */
5917e80d 1482
5ae7c3cf 1483#elif defined (_WIN32)
8f4eb34b
DS
1484 union
1485 {
1486 FILETIME ft_time;
1487 unsigned long long ull_time;
1488 } t_write;
0022d9e3 1489 TCHAR wname[GNAT_MAX_PATH_LEN];
6d244bbe 1490
ffec8e81 1491 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
0022d9e3
PO
1492
1493 HANDLE h = CreateFile
1494 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1495 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1496 NULL);
8f4eb34b
DS
1497 if (h == INVALID_HANDLE_VALUE)
1498 return;
1499 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1500 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1501 /* Convert to 100 nanosecond units */
1502 t_write.ull_time *= 10000000ULL;
1503
1504 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1505 CloseHandle (h);
1506 return;
1507
9678de49
DR
1508#else
1509 struct utimbuf utimbuf;
1510 time_t t;
1511
07fc65c4 1512 /* Set modification time to requested time. */
9678de49
DR
1513 utimbuf.modtime = time_stamp;
1514
07fc65c4 1515 /* Set access time to now in local time. */
192d0b15 1516 t = time (NULL);
9678de49
DR
1517 utimbuf.actime = mktime (localtime (&t));
1518
1519 utime (name, &utimbuf);
1520#endif
1521}
1522
d23b8f57
RK
1523/* Get the list of installed standard libraries from the
1524 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1525 key. */
1526
1527char *
9373164a 1528__gnat_get_libraries_from_registry (void)
d23b8f57 1529{
262991d8
PO
1530 char *result = (char *) xmalloc (1);
1531
1532 result[0] = '\0';
d23b8f57 1533
5ae7c3cf 1534#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
d23b8f57
RK
1535
1536 HKEY reg_key;
1537 DWORD name_size, value_size;
1538 char name[256];
1539 char value[256];
1540 DWORD type;
1541 DWORD index;
1542 LONG res;
1543
1544 /* First open the key. */
1545 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1546
1547 if (res == ERROR_SUCCESS)
1548 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1549 KEY_READ, &reg_key);
1550
1551 if (res == ERROR_SUCCESS)
1552 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1553
1554 if (res == ERROR_SUCCESS)
1555 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1556
1557 /* If the key exists, read out all the values in it and concatenate them
1558 into a path. */
1559 for (index = 0; res == ERROR_SUCCESS; index++)
1560 {
1561 value_size = name_size = 256;
03b64787 1562 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
18f22284 1563 &type, (LPBYTE)value, &value_size);
d23b8f57
RK
1564
1565 if (res == ERROR_SUCCESS && type == REG_SZ)
1566 {
1567 char *old_result = result;
1568
1569 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1570 strcpy (result, old_result);
1571 strcat (result, value);
1572 strcat (result, ";");
262991d8 1573 free (old_result);
d23b8f57
RK
1574 }
1575 }
1576
1577 /* Remove the trailing ";". */
1578 if (result[0] != 0)
1579 result[strlen (result) - 1] = 0;
d0f8d157 1580
262991d8 1581#endif
d23b8f57
RK
1582 return result;
1583}
1584
c6d2191a
AC
1585/* Query information for the given file NAME and return it in STATBUF.
1586 * Returns 0 for success, or errno value for failure.
1587 */
d23b8f57 1588int
f6c7fcc0 1589__gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
d23b8f57 1590{
0022d9e3 1591#ifdef __MINGW32__
f6b5dc8e 1592 WIN32_FILE_ATTRIBUTE_DATA fad;
0022d9e3 1593 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
f6b5dc8e
AC
1594 int name_len;
1595 BOOL res;
47e11d08 1596 DWORD error;
0022d9e3 1597
ffec8e81 1598 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
0022d9e3 1599 name_len = _tcslen (wname);
9596236a
AC
1600
1601 if (name_len > GNAT_MAX_PATH_LEN)
c6d2191a 1602 return EINVAL;
d23b8f57 1603
f6b5dc8e
AC
1604 ZeroMemory (statbuf, sizeof(GNAT_STRUCT_STAT));
1605
1606 res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad);
1607
47e11d08
AC
1608 if (res == FALSE) {
1609 error = GetLastError();
1610
1611 /* Check file existence using GetFileAttributes() which does not fail on
1612 special Windows files like con:, aux:, nul: etc... */
1613
1614 if (GetFileAttributes(wname) != INVALID_FILE_ATTRIBUTES) {
1615 /* Just pretend that it is a regular and readable file */
1616 statbuf->st_mode = S_IFREG | S_IREAD | S_IWRITE;
1617 return 0;
1618 }
1619
1620 switch (error) {
ff2efe85
AC
1621 case ERROR_ACCESS_DENIED:
1622 case ERROR_SHARING_VIOLATION:
1623 case ERROR_LOCK_VIOLATION:
1624 case ERROR_SHARING_BUFFER_EXCEEDED:
1625 return EACCES;
1626 case ERROR_BUFFER_OVERFLOW:
1627 return ENAMETOOLONG;
1628 case ERROR_NOT_ENOUGH_MEMORY:
1629 return ENOMEM;
1630 default:
1631 return ENOENT;
d23b8f57 1632 }
47e11d08 1633 }
d23b8f57 1634
f6b5dc8e
AC
1635 f2t (&fad.ftCreationTime, &statbuf->st_ctime);
1636 f2t (&fad.ftLastWriteTime, &statbuf->st_mtime);
1637 f2t (&fad.ftLastAccessTime, &statbuf->st_atime);
223eab97 1638
24228312
AC
1639 statbuf->st_size =
1640 (__int64)fad.nFileSizeLow | (__int64)fad.nFileSizeHigh << 32;
223eab97 1641
f6b5dc8e
AC
1642 /* We do not have the S_IEXEC attribute, but this is not used on GNAT. */
1643 statbuf->st_mode = S_IREAD;
d23b8f57 1644
f6b5dc8e
AC
1645 if (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1646 statbuf->st_mode |= S_IFDIR;
1647 else
1648 statbuf->st_mode |= S_IFREG;
1649
1650 if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1651 statbuf->st_mode |= S_IWRITE;
1652
1653 return 0;
d23b8f57
RK
1654
1655#else
c6d2191a 1656 return GNAT_STAT (name, statbuf) == 0 ? 0 : errno;
d23b8f57
RK
1657#endif
1658}
1659
48263c9a
EB
1660/*************************************************************************
1661 ** Check whether a file exists
1662 *************************************************************************/
1663
d23b8f57 1664int
48263c9a 1665__gnat_file_exists_attr (char* name, struct file_attributes* attr)
d23b8f57 1666{
5644b7e8
AC
1667 if (attr->exists == ATTR_UNSET)
1668 __gnat_stat_to_attr (-1, name, attr);
48263c9a
EB
1669
1670 return attr->exists;
d23b8f57
RK
1671}
1672
48263c9a
EB
1673int
1674__gnat_file_exists (char *name)
1675{
1676 struct file_attributes attr;
6528a7ed 1677 __gnat_reset_attributes (&attr);
48263c9a
EB
1678 return __gnat_file_exists_attr (name, &attr);
1679}
1680
1681/**********************************************************************
1682 ** Whether name is an absolute path
1683 **********************************************************************/
1684
fbf5a39b 1685int
cc4f0de1 1686__gnat_is_absolute_path (char *name, int length)
d23b8f57 1687{
fdcf961c
JR
1688#ifdef __vxworks
1689 /* On VxWorks systems, an absolute path can be represented (depending on
1690 the host platform) as either /dir/file, or device:/dir/file, or
1691 device:drive_letter:/dir/file. */
1692
1693 int index;
1694
1695 if (name[0] == '/')
1696 return 1;
1697
1698 for (index = 0; index < length; index++)
1699 {
1700 if (name[index] == ':' &&
1701 ((name[index + 1] == '/') ||
1702 (isalpha (name[index + 1]) && index + 2 <= length &&
1703 name[index + 2] == '/')))
1704 return 1;
1705
1706 else if (name[index] == '/')
1707 return 0;
1708 }
1709 return 0;
1710#else
cc4f0de1
AC
1711 return (length != 0) &&
1712 (*name == '/' || *name == DIR_SEPARATOR
91f2eb13 1713#if defined (WINNT) || defined(__DJGPP__)
dd7ac716 1714 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
d23b8f57 1715#endif
262991d8 1716 );
fdcf961c 1717#endif
d23b8f57
RK
1718}
1719
48263c9a
EB
1720int
1721__gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
1722{
5644b7e8
AC
1723 if (attr->regular == ATTR_UNSET)
1724 __gnat_stat_to_attr (-1, name, attr);
48263c9a
EB
1725
1726 return attr->regular;
1727}
1728
d23b8f57 1729int
fbf5a39b 1730__gnat_is_regular_file (char *name)
d23b8f57 1731{
48263c9a 1732 struct file_attributes attr;
5644b7e8 1733
6528a7ed 1734 __gnat_reset_attributes (&attr);
48263c9a
EB
1735 return __gnat_is_regular_file_attr (name, &attr);
1736}
1737
fce54763
AC
1738int
1739__gnat_is_regular_file_fd (int fd)
1740{
1741 int ret;
1742 GNAT_STRUCT_STAT statbuf;
1743
1744 ret = GNAT_FSTAT (fd, &statbuf);
1745 return (!ret && S_ISREG (statbuf.st_mode));
1746}
1747
48263c9a
EB
1748int
1749__gnat_is_directory_attr (char* name, struct file_attributes* attr)
1750{
5644b7e8
AC
1751 if (attr->directory == ATTR_UNSET)
1752 __gnat_stat_to_attr (-1, name, attr);
d23b8f57 1753
48263c9a 1754 return attr->directory;
d23b8f57
RK
1755}
1756
1757int
fbf5a39b 1758__gnat_is_directory (char *name)
d23b8f57 1759{
48263c9a 1760 struct file_attributes attr;
5644b7e8 1761
6528a7ed 1762 __gnat_reset_attributes (&attr);
48263c9a 1763 return __gnat_is_directory_attr (name, &attr);
d23b8f57
RK
1764}
1765
5ae7c3cf 1766#if defined (_WIN32)
f8b86c2d
AC
1767
1768/* Returns the same constant as GetDriveType but takes a pathname as
1769 argument. */
1770
1771static UINT
1772GetDriveTypeFromPath (TCHAR *wfullpath)
1773{
1774 TCHAR wdrv[MAX_PATH];
1775 TCHAR wpath[MAX_PATH];
1776 TCHAR wfilename[MAX_PATH];
1777 TCHAR wext[MAX_PATH];
1778
1779 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1780
1781 if (_tcslen (wdrv) != 0)
1782 {
1783 /* we have a drive specified. */
1784 _tcscat (wdrv, _T("\\"));
1785 return GetDriveType (wdrv);
1786 }
1787 else
1788 {
1789 /* No drive specified. */
1790
1791 /* Is this a relative path, if so get current drive type. */
1792 if (wpath[0] != _T('\\') ||
5644b7e8
AC
1793 (_tcslen (wpath) > 2 && wpath[0] == _T('\\')
1794 && wpath[1] != _T('\\')))
262991d8 1795 return GetDriveType (NULL);
f8b86c2d
AC
1796
1797 UINT result = GetDriveType (wpath);
1798
1799 /* Cannot guess the drive type, is this \\.\ ? */
1800
1801 if (result == DRIVE_NO_ROOT_DIR &&
262991d8
PO
1802 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1803 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1804 {
1805 if (_tcslen (wpath) == 4)
1806 _tcscat (wpath, wfilename);
f8b86c2d 1807
262991d8
PO
1808 LPTSTR p = &wpath[4];
1809 LPTSTR b = _tcschr (p, _T('\\'));
f8b86c2d 1810
262991d8 1811 if (b != NULL)
5644b7e8
AC
1812 {
1813 /* logical drive \\.\c\dir\file */
262991d8
PO
1814 *b++ = _T(':');
1815 *b++ = _T('\\');
1816 *b = _T('\0');
1817 }
1818 else
1819 _tcscat (p, _T(":\\"));
f8b86c2d 1820
262991d8
PO
1821 return GetDriveType (p);
1822 }
f8b86c2d
AC
1823
1824 return result;
1825 }
1826}
1827
5644b7e8 1828/* This MingW section contains code to work with ACL. */
d559d5c6 1829static int
5644b7e8
AC
1830__gnat_check_OWNER_ACL (TCHAR *wname,
1831 DWORD CheckAccessDesired,
1832 GENERIC_MAPPING CheckGenericMapping)
d559d5c6 1833{
d559d5c6
AC
1834 DWORD dwAccessDesired, dwAccessAllowed;
1835 PRIVILEGE_SET PrivilegeSet;
1836 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1837 BOOL fAccessGranted = FALSE;
4fd1e8b0
AC
1838 HANDLE hToken = NULL;
1839 DWORD nLength = 0;
7b536495 1840 PSECURITY_DESCRIPTOR pSD = NULL;
d559d5c6 1841
d559d5c6
AC
1842 GetFileSecurity
1843 (wname, OWNER_SECURITY_INFORMATION |
1844 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1845 NULL, 0, &nLength);
1846
ba1a9233 1847 if ((pSD = (SECURITY_DESCRIPTOR *) HeapAlloc
d559d5c6
AC
1848 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1849 return 0;
1850
5644b7e8 1851 /* Obtain the security descriptor. */
d559d5c6
AC
1852
1853 if (!GetFileSecurity
1854 (wname, OWNER_SECURITY_INFORMATION |
1855 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1856 pSD, nLength, &nLength))
4fd1e8b0 1857 goto error;
d559d5c6
AC
1858
1859 if (!ImpersonateSelf (SecurityImpersonation))
4fd1e8b0 1860 goto error;
d559d5c6
AC
1861
1862 if (!OpenThreadToken
1863 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
4fd1e8b0 1864 goto error;
d559d5c6
AC
1865
1866 /* Undoes the effect of ImpersonateSelf. */
1867
1868 RevertToSelf ();
1869
1870 /* We want to test for write permissions. */
1871
1872 dwAccessDesired = CheckAccessDesired;
1873
1874 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1875
1876 if (!AccessCheck
1877 (pSD , /* security descriptor to check */
1878 hToken, /* impersonation token */
1879 dwAccessDesired, /* requested access rights */
1880 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1881 &PrivilegeSet, /* receives privileges used in check */
1882 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1883 &dwAccessAllowed, /* receives mask of allowed access rights */
1884 &fAccessGranted))
4fd1e8b0 1885 goto error;
d559d5c6 1886
4fd1e8b0
AC
1887 CloseHandle (hToken);
1888 HeapFree (GetProcessHeap (), 0, pSD);
d559d5c6 1889 return fAccessGranted;
4fd1e8b0
AC
1890
1891 error:
1892 if (hToken)
1893 CloseHandle (hToken);
1894 HeapFree (GetProcessHeap (), 0, pSD);
1895 return 0;
d559d5c6
AC
1896}
1897
1898static void
5644b7e8 1899__gnat_set_OWNER_ACL (TCHAR *wname,
7b536495 1900 ACCESS_MODE AccessMode,
5644b7e8 1901 DWORD AccessPermissions)
d559d5c6 1902{
75069667
VF
1903 PACL pOldDACL = NULL;
1904 PACL pNewDACL = NULL;
1905 PSECURITY_DESCRIPTOR pSD = NULL;
d559d5c6
AC
1906 EXPLICIT_ACCESS ea;
1907 TCHAR username [100];
1908 DWORD unsize = 100;
1909
d559d5c6
AC
1910 /* Get current user, he will act as the owner */
1911
1912 if (!GetUserName (username, &unsize))
1913 return;
1914
43540ec6
AC
1915 if (GetNamedSecurityInfo
1916 (wname,
d559d5c6
AC
1917 SE_FILE_OBJECT,
1918 DACL_SECURITY_INFORMATION,
1919 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1920 return;
1921
43540ec6 1922 BuildExplicitAccessWithName
ba1a9233 1923 (&ea, username, AccessPermissions, (ACCESS_MODE) AccessMode, NO_INHERITANCE);
d559d5c6
AC
1924
1925 if (AccessMode == SET_ACCESS)
1926 {
1927 /* SET_ACCESS, we want to set an explicte set of permissions, do not
262991d8 1928 merge with current DACL. */
d559d5c6 1929 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
262991d8 1930 return;
d559d5c6
AC
1931 }
1932 else
1933 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1934 return;
1935
43540ec6
AC
1936 if (SetNamedSecurityInfo
1937 (wname, SE_FILE_OBJECT,
d559d5c6
AC
1938 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
1939 return;
1940
1941 LocalFree (pSD);
1942 LocalFree (pNewDACL);
d559d5c6 1943}
f8b86c2d
AC
1944
1945/* Check if it is possible to use ACL for wname, the file must not be on a
1946 network drive. */
1947
1948static int
1949__gnat_can_use_acl (TCHAR *wname)
1950{
1951 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
1952}
1953
5ae7c3cf 1954#endif /* defined (_WIN32) */
d559d5c6 1955
d23b8f57 1956int
48263c9a 1957__gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
fbf5a39b 1958{
5644b7e8
AC
1959 if (attr->readable == ATTR_UNSET)
1960 {
5ae7c3cf 1961#if defined (_WIN32)
5644b7e8
AC
1962 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1963 GENERIC_MAPPING GenericMapping;
a07c3593 1964
5644b7e8 1965 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
d559d5c6 1966
5644b7e8
AC
1967 if (__gnat_can_use_acl (wname))
1968 {
1969 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1970 GenericMapping.GenericRead = GENERIC_READ;
1971 attr->readable =
1972 __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
1973 }
1974 else
1975 attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
d559d5c6 1976#else
5644b7e8 1977 __gnat_stat_to_attr (-1, name, attr);
d559d5c6 1978#endif
5644b7e8 1979 }
48263c9a
EB
1980
1981 return attr->readable;
fbf5a39b
AC
1982}
1983
0640c7d1
AC
1984int
1985__gnat_is_read_accessible_file (char *name)
1986{
1987#if defined (_WIN32)
1988 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1989
1990 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1991
86ec3bfb
AC
1992 return !_waccess (wname, 4);
1993
1994#elif defined (__vxworks)
1995 int fd;
1996
833c1dbc 1997 if ((fd = open (name, O_RDONLY, 0)) < 0)
86ec3bfb
AC
1998 return 0;
1999 close (fd);
2000 return 1;
2001
0640c7d1
AC
2002#else
2003 return !access (name, R_OK);
2004#endif
2005}
2006
fbf5a39b 2007int
48263c9a
EB
2008__gnat_is_readable_file (char *name)
2009{
2010 struct file_attributes attr;
5644b7e8 2011
6528a7ed 2012 __gnat_reset_attributes (&attr);
48263c9a
EB
2013 return __gnat_is_readable_file_attr (name, &attr);
2014}
2015
2016int
2017__gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
d23b8f57 2018{
5644b7e8
AC
2019 if (attr->writable == ATTR_UNSET)
2020 {
5ae7c3cf 2021#if defined (_WIN32)
5644b7e8
AC
2022 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2023 GENERIC_MAPPING GenericMapping;
a07c3593 2024
5644b7e8 2025 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
a07c3593 2026
5644b7e8
AC
2027 if (__gnat_can_use_acl (wname))
2028 {
2029 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2030 GenericMapping.GenericWrite = GENERIC_WRITE;
03b64787 2031
5644b7e8 2032 attr->writable = __gnat_check_OWNER_ACL
48263c9a
EB
2033 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
2034 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
5644b7e8
AC
2035 }
2036 else
2037 attr->writable =
2038 !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
d559d5c6 2039
d559d5c6 2040#else
5644b7e8 2041 __gnat_stat_to_attr (-1, name, attr);
d559d5c6 2042#endif
5644b7e8 2043 }
48263c9a
EB
2044
2045 return attr->writable;
d559d5c6
AC
2046}
2047
2048int
48263c9a 2049__gnat_is_writable_file (char *name)
d559d5c6 2050{
48263c9a 2051 struct file_attributes attr;
5644b7e8 2052
6528a7ed 2053 __gnat_reset_attributes (&attr);
48263c9a
EB
2054 return __gnat_is_writable_file_attr (name, &attr);
2055}
2056
0640c7d1
AC
2057int
2058__gnat_is_write_accessible_file (char *name)
2059{
2060#if defined (_WIN32)
2061 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2062
2063 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2064
86ec3bfb
AC
2065 return !_waccess (wname, 2);
2066
2067#elif defined (__vxworks)
2068 int fd;
2069
833c1dbc 2070 if ((fd = open (name, O_WRONLY, 0)) < 0)
86ec3bfb
AC
2071 return 0;
2072 close (fd);
2073 return 1;
2074
0640c7d1
AC
2075#else
2076 return !access (name, W_OK);
2077#endif
2078}
2079
48263c9a
EB
2080int
2081__gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
2082{
5644b7e8
AC
2083 if (attr->executable == ATTR_UNSET)
2084 {
5ae7c3cf 2085#if defined (_WIN32)
5644b7e8
AC
2086 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2087 GENERIC_MAPPING GenericMapping;
a07c3593 2088
5644b7e8 2089 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
a07c3593 2090
5644b7e8
AC
2091 if (__gnat_can_use_acl (wname))
2092 {
2093 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2094 GenericMapping.GenericExecute = GENERIC_EXECUTE;
03b64787 2095
5644b7e8
AC
2096 attr->executable =
2097 __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2098 }
2099 else
2100 {
2101 TCHAR *l, *last = _tcsstr(wname, _T(".exe"));
53f29d4f 2102
5644b7e8
AC
2103 /* look for last .exe */
2104 if (last)
2105 while ((l = _tcsstr(last+1, _T(".exe"))))
2106 last = l;
53f29d4f 2107
5644b7e8
AC
2108 attr->executable =
2109 GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2110 && (last - wname) == (int) (_tcslen (wname) - 4);
2111 }
d559d5c6 2112#else
5644b7e8 2113 __gnat_stat_to_attr (-1, name, attr);
d559d5c6 2114#endif
5644b7e8 2115 }
48263c9a 2116
3699edc4 2117 return attr->regular && attr->executable;
48263c9a
EB
2118}
2119
2120int
2121__gnat_is_executable_file (char *name)
2122{
2123 struct file_attributes attr;
5644b7e8 2124
6528a7ed 2125 __gnat_reset_attributes (&attr);
48263c9a 2126 return __gnat_is_executable_file_attr (name, &attr);
d23b8f57
RK
2127}
2128
fbf5a39b
AC
2129void
2130__gnat_set_writable (char *name)
2131{
5ae7c3cf 2132#if defined (_WIN32)
a07c3593
AC
2133 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2134
ffec8e81 2135 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
a07c3593 2136
f8b86c2d 2137 if (__gnat_can_use_acl (wname))
03b64787
AC
2138 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2139
a07c3593
AC
2140 SetFileAttributes
2141 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
5ae7c3cf 2142#elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
f6c7fcc0 2143 GNAT_STRUCT_STAT statbuf;
fbf5a39b 2144
f6c7fcc0 2145 if (GNAT_STAT (name, &statbuf) == 0)
e5fe4251
PO
2146 {
2147 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2148 chmod (name, statbuf.st_mode);
2149 }
fbf5a39b
AC
2150#endif
2151}
2152
d2d8b2a7
AC
2153/* must match definition in s-os_lib.ads */
2154#define S_OWNER 1
2155#define S_GROUP 2
2156#define S_OTHERS 4
2157
7324bf49 2158void
7b536495 2159__gnat_set_executable (char *name, int mode ATTRIBUTE_UNUSED)
7324bf49 2160{
5ae7c3cf 2161#if defined (_WIN32)
a07c3593
AC
2162 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2163
f8b86c2d
AC
2164 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2165
2166 if (__gnat_can_use_acl (wname))
2167 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
a07c3593 2168
5ae7c3cf 2169#elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
f6c7fcc0 2170 GNAT_STRUCT_STAT statbuf;
7324bf49 2171
f6c7fcc0 2172 if (GNAT_STAT (name, &statbuf) == 0)
e5fe4251 2173 {
d2d8b2a7
AC
2174 if (mode & S_OWNER)
2175 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2176 if (mode & S_GROUP)
2177 statbuf.st_mode = statbuf.st_mode | S_IXGRP;
2178 if (mode & S_OTHERS)
2179 statbuf.st_mode = statbuf.st_mode | S_IXOTH;
e5fe4251
PO
2180 chmod (name, statbuf.st_mode);
2181 }
7324bf49
AC
2182#endif
2183}
2184
fbf5a39b 2185void
8b79ad42 2186__gnat_set_non_writable (char *name)
fbf5a39b 2187{
5ae7c3cf 2188#if defined (_WIN32)
a07c3593
AC
2189 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2190
ffec8e81 2191 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
a07c3593 2192
f8b86c2d 2193 if (__gnat_can_use_acl (wname))
03b64787
AC
2194 __gnat_set_OWNER_ACL
2195 (wname, DENY_ACCESS,
2196 FILE_WRITE_DATA | FILE_APPEND_DATA |
2197 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2198
a07c3593
AC
2199 SetFileAttributes
2200 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
5ae7c3cf 2201#elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
f6c7fcc0 2202 GNAT_STRUCT_STAT statbuf;
fbf5a39b 2203
f6c7fcc0 2204 if (GNAT_STAT (name, &statbuf) == 0)
43540ec6
AC
2205 {
2206 statbuf.st_mode = statbuf.st_mode & 07577;
2207 chmod (name, statbuf.st_mode);
2208 }
2209#endif
2210}
2211
2212void
2213__gnat_set_readable (char *name)
2214{
5ae7c3cf 2215#if defined (_WIN32)
43540ec6
AC
2216 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2217
f8b86c2d
AC
2218 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2219
2220 if (__gnat_can_use_acl (wname))
2221 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
43540ec6 2222
5ae7c3cf 2223#elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
f6c7fcc0 2224 GNAT_STRUCT_STAT statbuf;
43540ec6 2225
f6c7fcc0 2226 if (GNAT_STAT (name, &statbuf) == 0)
43540ec6
AC
2227 {
2228 chmod (name, statbuf.st_mode | S_IREAD);
2229 }
2230#endif
2231}
2232
2233void
2234__gnat_set_non_readable (char *name)
2235{
5ae7c3cf 2236#if defined (_WIN32)
43540ec6
AC
2237 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2238
f8b86c2d
AC
2239 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2240
2241 if (__gnat_can_use_acl (wname))
2242 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
43540ec6 2243
5ae7c3cf 2244#elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
f6c7fcc0 2245 GNAT_STRUCT_STAT statbuf;
43540ec6 2246
f6c7fcc0 2247 if (GNAT_STAT (name, &statbuf) == 0)
43540ec6
AC
2248 {
2249 chmod (name, statbuf.st_mode & (~S_IREAD));
2250 }
fbf5a39b
AC
2251#endif
2252}
2253
2254int
8b3c6430
AC
2255__gnat_is_symbolic_link_attr (char* name ATTRIBUTE_UNUSED,
2256 struct file_attributes* attr)
fbf5a39b 2257{
5644b7e8
AC
2258 if (attr->symbolic_link == ATTR_UNSET)
2259 {
5ae7c3cf 2260#if defined (__vxworks)
5644b7e8 2261 attr->symbolic_link = 0;
fbf5a39b 2262
f5a0cbf1 2263#elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
5644b7e8
AC
2264 int ret;
2265 GNAT_STRUCT_STAT statbuf;
2266 ret = GNAT_LSTAT (name, &statbuf);
2267 attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
fbf5a39b 2268#else
5644b7e8 2269 attr->symbolic_link = 0;
fbf5a39b 2270#endif
5644b7e8 2271 }
48263c9a
EB
2272 return attr->symbolic_link;
2273}
2274
2275int
2276__gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2277{
2278 struct file_attributes attr;
5644b7e8 2279
6528a7ed 2280 __gnat_reset_attributes (&attr);
48263c9a 2281 return __gnat_is_symbolic_link_attr (name, &attr);
fbf5a39b
AC
2282}
2283
329be64b 2284#if defined (__sun__)
d23b8f57
RK
2285/* Using fork on Solaris will duplicate all the threads. fork1, which
2286 duplicates only the active thread, must be used instead, or spawning
2287 subprocess from a program with tasking will lead into numerous problems. */
2288#define fork fork1
2289#endif
2290
2291int
a1d3851b 2292__gnat_portable_spawn (char *args[] ATTRIBUTE_UNUSED)
d23b8f57 2293{
a1d3851b 2294 int status ATTRIBUTE_UNUSED = 0;
25412599
DS
2295 int finished ATTRIBUTE_UNUSED;
2296 int pid ATTRIBUTE_UNUSED;
d23b8f57 2297
5ae7c3cf 2298#if defined (__vxworks) || defined(__PikeOS__)
b41ab480
PO
2299 return -1;
2300
91f2eb13 2301#elif defined (__DJGPP__) || defined (_WIN32)
af4b9434 2302 /* args[0] must be quotes as it could contain a full pathname with spaces */
aa75e737 2303 char *args_0 = args[0];
af4b9434
AC
2304 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2305 strcpy (args[0], "\"");
2306 strcat (args[0], args_0);
2307 strcat (args[0], "\"");
2308
7b536495 2309 status = spawnvp (P_WAIT, args_0, (char ** const)args);
af4b9434
AC
2310
2311 /* restore previous value */
2312 free (args[0]);
f5a0cbf1 2313 args[0] = (char *)args_0;
af4b9434 2314
d23b8f57 2315 if (status < 0)
07fc65c4 2316 return -1;
d23b8f57
RK
2317 else
2318 return status;
2319
d23b8f57
RK
2320#else
2321
d23b8f57 2322 pid = fork ();
07fc65c4
GB
2323 if (pid < 0)
2324 return -1;
d23b8f57 2325
07fc65c4
GB
2326 if (pid == 0)
2327 {
2328 /* The child. */
cc892b2c 2329 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
262991d8 2330 _exit (1);
07fc65c4 2331 }
d23b8f57 2332
07fc65c4 2333 /* The parent. */
d23b8f57
RK
2334 finished = waitpid (pid, &status, 0);
2335
2336 if (finished != pid || WIFEXITED (status) == 0)
07fc65c4 2337 return -1;
d23b8f57
RK
2338
2339 return WEXITSTATUS (status);
2340#endif
07fc65c4 2341
d23b8f57
RK
2342 return 0;
2343}
2344
f5a0cbf1
AC
2345/* Create a copy of the given file descriptor.
2346 Return -1 if an error occurred. */
2347
2348int
2349__gnat_dup (int oldfd)
2350{
b9260c3d
AC
2351#if defined (__vxworks) && !defined (__RTP__)
2352 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2353 RTPs. */
2354 return -1;
f5a0cbf1 2355#else
b9260c3d 2356 return dup (oldfd);
f5a0cbf1
AC
2357#endif
2358}
2359
2360/* Make newfd be the copy of oldfd, closing newfd first if necessary.
45f7cb60 2361 Return -1 if an error occurred. */
f5a0cbf1
AC
2362
2363int
a1d3851b 2364__gnat_dup2 (int oldfd ATTRIBUTE_UNUSED, int newfd ATTRIBUTE_UNUSED)
f5a0cbf1 2365{
b9260c3d
AC
2366#if defined (__vxworks) && !defined (__RTP__)
2367 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2368 RTPs. */
f5a0cbf1 2369 return -1;
a1d3851b 2370#elif defined (__PikeOS__)
36357cf3 2371 /* Not supported. */
a1d3851b 2372 return -1;
d2d4b355
AC
2373#elif defined (_WIN32)
2374 /* Special case when oldfd and newfd are identical and are the standard
2375 input, output or error as this makes Windows XP hangs. Note that we
2376 do that only for standard file descriptors that are known to be valid. */
2377 if (oldfd == newfd && newfd >= 0 && newfd <= 2)
2378 return newfd;
2379 else
2380 return dup2 (oldfd, newfd);
f5a0cbf1
AC
2381#else
2382 return dup2 (oldfd, newfd);
2383#endif
2384}
2385
7a259f2e
VC
2386int
2387__gnat_number_of_cpus (void)
2388{
2389 int cores = 1;
2390
329be64b 2391#if defined (__linux__) || defined (__sun__) || defined (_AIX) \
90af5990 2392 || defined (__APPLE__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
9820b389 2393 || defined (__DragonFly__) || defined (__NetBSD__)
313d6f2c 2394 cores = (int) sysconf (_SC_NPROCESSORS_ONLN);
20261dc1 2395
9820b389
JL
2396#elif defined (__QNX__)
2397 cores = (int) _syspage_ptr->num_cpu;
2398
20261dc1 2399#elif defined (__hpux__)
313d6f2c
AC
2400 struct pst_dynamic psd;
2401 if (pstat_getdynamic (&psd, sizeof (psd), 1, 0) != -1)
2402 cores = (int) psd.psd_proc_cnt;
20261dc1 2403
2551782d
AC
2404#elif defined (_WIN32)
2405 SYSTEM_INFO sysinfo;
2406 GetSystemInfo (&sysinfo);
2407 cores = (int) sysinfo.dwNumberOfProcessors;
a043e735 2408
24558db8 2409#elif defined (_WRS_CONFIG_SMP)
6a2e5d0f
AC
2410 unsigned int vxCpuConfiguredGet (void);
2411
2412 cores = vxCpuConfiguredGet ();
2413
7a259f2e
VC
2414#endif
2415
2416 return cores;
2417}
2418
07fc65c4
GB
2419/* WIN32 code to implement a wait call that wait for any child process. */
2420
5ae7c3cf 2421#if defined (_WIN32)
d23b8f57
RK
2422
2423/* Synchronization code, to be thread safe. */
2424
af90c55a 2425#ifdef CERT
d23b8f57 2426
af90c55a
PO
2427/* For the Cert run times on native Windows we use dummy functions
2428 for locking and unlocking tasks since we do not support multiple
2429 threads on this configuration (Cert run time on native Windows). */
d23b8f57 2430
6c802906
AC
2431static void EnterCS (void) {}
2432static void LeaveCS (void) {}
2433static void SignalListChanged (void) {}
af90c55a
PO
2434
2435#else
2436
6c802906 2437CRITICAL_SECTION ProcListCS;
07e188be 2438HANDLE ProcListEvt = NULL;
6c802906
AC
2439
2440static void EnterCS (void)
2441{
2442 EnterCriticalSection(&ProcListCS);
2443}
af90c55a 2444
6c802906
AC
2445static void LeaveCS (void)
2446{
2447 LeaveCriticalSection(&ProcListCS);
2448}
2449
2450static void SignalListChanged (void)
2451{
2452 SetEvent (ProcListEvt);
2453}
af90c55a
PO
2454
2455#endif
d23b8f57 2456
75069667
VF
2457static HANDLE *HANDLES_LIST = NULL;
2458static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
d23b8f57
RK
2459
2460static void
aa9ea6a1 2461add_handle (HANDLE h, int pid)
d23b8f57 2462{
d23b8f57 2463 /* -------------------- critical section -------------------- */
6c802906 2464 EnterCS();
af90c55a 2465
75069667
VF
2466 if (plist_length == plist_max_length)
2467 {
4b963531 2468 plist_max_length += 100;
75069667 2469 HANDLES_LIST =
7b536495 2470 (HANDLE *) xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
75069667 2471 PID_LIST =
ba1a9233 2472 (int *) xrealloc (PID_LIST, sizeof (int) * plist_max_length);
75069667
VF
2473 }
2474
2475 HANDLES_LIST[plist_length] = h;
aa9ea6a1 2476 PID_LIST[plist_length] = pid;
d23b8f57 2477 ++plist_length;
d23b8f57 2478
6c802906
AC
2479 SignalListChanged();
2480 LeaveCS();
af90c55a 2481 /* -------------------- critical section -------------------- */
d23b8f57
RK
2482}
2483
6c802906
AC
2484int
2485__gnat_win32_remove_handle (HANDLE h, int pid)
d23b8f57 2486{
75069667 2487 int j;
6c802906
AC
2488 int found = 0;
2489
2490 /* -------------------- critical section -------------------- */
2491 EnterCS();
d23b8f57 2492
75069667 2493 for (j = 0; j < plist_length; j++)
d23b8f57 2494 {
75069667 2495 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
d23b8f57 2496 {
75069667
VF
2497 CloseHandle (h);
2498 --plist_length;
2499 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2500 PID_LIST[j] = PID_LIST[plist_length];
6c802906 2501 found = 1;
d23b8f57
RK
2502 break;
2503 }
d23b8f57 2504 }
6654786e 2505
6c802906 2506 LeaveCS();
6654786e 2507 /* -------------------- critical section -------------------- */
6654786e 2508
6c802906
AC
2509 if (found)
2510 SignalListChanged();
d23b8f57 2511
6c802906 2512 return found;
d23b8f57
RK
2513}
2514
aa9ea6a1
AC
2515static void
2516win32_no_block_spawn (char *command, char *args[], HANDLE *h, int *pid)
d23b8f57
RK
2517{
2518 BOOL result;
2519 STARTUPINFO SI;
2520 PROCESS_INFORMATION PI;
2521 SECURITY_ATTRIBUTES SA;
07fc65c4
GB
2522 int csize = 1;
2523 char *full_command;
d23b8f57
RK
2524 int k;
2525
07fc65c4
GB
2526 /* compute the total command line length */
2527 k = 0;
2528 while (args[k])
2529 {
2530 csize += strlen (args[k]) + 1;
2531 k++;
2532 }
2533
2534 full_command = (char *) xmalloc (csize);
2535
d23b8f57
RK
2536 /* Startup info. */
2537 SI.cb = sizeof (STARTUPINFO);
2538 SI.lpReserved = NULL;
2539 SI.lpReserved2 = NULL;
2540 SI.lpDesktop = NULL;
2541 SI.cbReserved2 = 0;
2542 SI.lpTitle = NULL;
2543 SI.dwFlags = 0;
2544 SI.wShowWindow = SW_HIDE;
2545
2546 /* Security attributes. */
2547 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2548 SA.bInheritHandle = TRUE;
2549 SA.lpSecurityDescriptor = NULL;
2550
2551 /* Prepare the command string. */
2552 strcpy (full_command, command);
2553 strcat (full_command, " ");
2554
2555 k = 1;
2556 while (args[k])
2557 {
2558 strcat (full_command, args[k]);
2559 strcat (full_command, " ");
2560 k++;
2561 }
2562
0022d9e3
PO
2563 {
2564 int wsize = csize * 2;
2565 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2566
ffec8e81 2567 S2WSC (wcommand, full_command, wsize);
0022d9e3
PO
2568
2569 free (full_command);
d23b8f57 2570
0022d9e3
PO
2571 result = CreateProcess
2572 (NULL, wcommand, &SA, NULL, TRUE,
2573 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2574
2575 free (wcommand);
2576 }
07fc65c4 2577
d23b8f57
RK
2578 if (result == TRUE)
2579 {
d23b8f57 2580 CloseHandle (PI.hThread);
aa9ea6a1
AC
2581 *h = PI.hProcess;
2582 *pid = PI.dwProcessId;
d23b8f57
RK
2583 }
2584 else
aa9ea6a1
AC
2585 {
2586 *h = NULL;
2587 *pid = 0;
2588 }
d23b8f57
RK
2589}
2590
2591static int
fbf5a39b 2592win32_wait (int *status)
d23b8f57 2593{
75069667 2594 DWORD exitcode, pid;
d23b8f57
RK
2595 HANDLE *hl;
2596 HANDLE h;
6c802906 2597 int *pidl;
d23b8f57 2598 DWORD res;
23922a2f 2599 int hl_len;
6c802906 2600 int found;
61b14896 2601 int pos;
d23b8f57 2602
6c802906 2603 START_WAIT:
6654786e 2604
d23b8f57
RK
2605 if (plist_length == 0)
2606 {
2607 errno = ECHILD;
2608 return -1;
2609 }
2610
6c802906
AC
2611 /* -------------------- critical section -------------------- */
2612 EnterCS();
2613
61b14896
PMR
2614 /* ??? We can't wait for more than MAXIMUM_WAIT_OBJECTS due to a Win32
2615 limitation */
2616 if (plist_length < MAXIMUM_WAIT_OBJECTS)
23922a2f 2617 hl_len = plist_length;
61b14896
PMR
2618 else
2619 {
2620 errno = EINVAL;
2621 return -1;
2622 }
23922a2f 2623
6c802906 2624#ifdef CERT
23922a2f 2625 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
75069667 2626 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
6c802906
AC
2627 pidl = (int *) xmalloc (sizeof (int) * hl_len);
2628 memmove (pidl, PID_LIST, sizeof (int) * hl_len);
2629#else
3fbbbd1e 2630 /* Note that index 0 contains the event handle that is signaled when the
6c802906 2631 process list has changed */
c2d2963d 2632 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * (hl_len + 1));
6c802906
AC
2633 hl[0] = ProcListEvt;
2634 memmove (&hl[1], HANDLES_LIST, sizeof (HANDLE) * hl_len);
c2d2963d 2635 pidl = (int *) xmalloc (sizeof (int) * (hl_len + 1));
6c802906
AC
2636 memmove (&pidl[1], PID_LIST, sizeof (int) * hl_len);
2637 hl_len++;
2638#endif
2639
2640 LeaveCS();
2641 /* -------------------- critical section -------------------- */
d23b8f57 2642
23922a2f 2643 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
d23b8f57 2644
61b14896
PMR
2645 /* If there was an error, exit now */
2646 if (res == WAIT_FAILED)
2647 {
cd742f4a
PO
2648 free (hl);
2649 free (pidl);
61b14896
PMR
2650 errno = EINVAL;
2651 return -1;
2652 }
2653
6c802906
AC
2654 /* if the ProcListEvt has been signaled then the list of processes has been
2655 updated to add or remove a handle, just loop over */
2656
2657 if (res - WAIT_OBJECT_0 == 0)
2658 {
2659 free (hl);
2660 free (pidl);
2661 goto START_WAIT;
2662 }
2663
61b14896
PMR
2664 /* Handle two distinct groups of return codes: finished waits and abandoned
2665 waits */
2666
2667 if (res < WAIT_ABANDONED_0)
2668 pos = res - WAIT_OBJECT_0;
2669 else
2670 pos = res - WAIT_ABANDONED_0;
2671
2672 h = hl[pos];
d23b8f57 2673 GetExitCodeProcess (h, &exitcode);
61b14896 2674 pid = pidl [pos];
6c802906
AC
2675
2676 found = __gnat_win32_remove_handle (h, -1);
75069667
VF
2677
2678 free (hl);
6c802906
AC
2679 free (pidl);
2680
2681 /* if not found another process waiting has already handled this process */
2682
2683 if (!found)
2684 {
2685 goto START_WAIT;
2686 }
d23b8f57
RK
2687
2688 *status = (int) exitcode;
75069667 2689 return (int) pid;
d23b8f57
RK
2690}
2691
2692#endif
2693
2694int
a1d3851b 2695__gnat_portable_no_block_spawn (char *args[] ATTRIBUTE_UNUSED)
d23b8f57 2696{
d23b8f57 2697
5ae7c3cf 2698#if defined (__vxworks) || defined (__PikeOS__)
a1d3851b 2699 /* Not supported. */
b41ab480
PO
2700 return -1;
2701
91f2eb13
AP
2702#elif defined(__DJGPP__)
2703 if (spawnvp (P_WAIT, args[0], args) != 0)
2704 return -1;
2705 else
2706 return 0;
2707
d23b8f57
RK
2708#elif defined (_WIN32)
2709
75069667 2710 HANDLE h = NULL;
aa9ea6a1 2711 int pid;
75069667 2712
aa9ea6a1 2713 win32_no_block_spawn (args[0], args, &h, &pid);
75069667 2714 if (h != NULL)
a7209434 2715 {
aa9ea6a1
AC
2716 add_handle (h, pid);
2717 return pid;
a7209434
AC
2718 }
2719 else
2720 return -1;
d23b8f57 2721
d23b8f57 2722#else
75069667
VF
2723
2724 int pid = fork ();
d23b8f57 2725
07fc65c4
GB
2726 if (pid == 0)
2727 {
2728 /* The child. */
cc892b2c 2729 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
262991d8 2730 _exit (1);
07fc65c4
GB
2731 }
2732
d23b8f57 2733 return pid;
75069667
VF
2734
2735 #endif
d23b8f57
RK
2736}
2737
2738int
fbf5a39b 2739__gnat_portable_wait (int *process_status)
d23b8f57
RK
2740{
2741 int status = 0;
2742 int pid = 0;
2743
5ae7c3cf 2744#if defined (__vxworks) || defined (__PikeOS__)
ea7f928b 2745 /* Not sure what to do here, so do nothing but return zero. */
b41ab480
PO
2746
2747#elif defined (_WIN32)
d23b8f57
RK
2748
2749 pid = win32_wait (&status);
2750
91f2eb13
AP
2751#elif defined (__DJGPP__)
2752 /* Child process has already ended in case of DJGPP.
2753 No need to do anything. Just return success. */
d23b8f57
RK
2754#else
2755
d23b8f57 2756 pid = waitpid (-1, &status, 0);
d23b8f57 2757 status = status & 0xffff;
36357cf3
AC
2758#endif
2759
2760 *process_status = status;
2761 return pid;
2762}
2763
2764int
2765__gnat_portable_no_block_wait (int *process_status)
2766{
2767 int status = 0;
2768 int pid = 0;
2769
2770#if defined (__vxworks) || defined (__PikeOS__) || defined (_WIN32)
2771 /* Not supported. */
2772 status = -1;
2773
2774#else
2775
2776 pid = waitpid (-1, &status, WNOHANG);
2777 status = status & 0xffff;
d23b8f57
RK
2778#endif
2779
2780 *process_status = status;
2781 return pid;
2782}
2783
2784void
fbf5a39b 2785__gnat_os_exit (int status)
d23b8f57 2786{
d23b8f57 2787 exit (status);
d23b8f57
RK
2788}
2789
876f1624
AC
2790int
2791__gnat_current_process_id (void)
2792{
2793#if defined (__vxworks) || defined (__PikeOS__)
2794 return -1;
2795
2796#elif defined (_WIN32)
2797
2798 return (int)GetCurrentProcessId();
2799
2800#else
2801
2802 return (int)getpid();
2803#endif
2804}
2805
052e0603 2806/* Locate file on path, that matches a predicate */
d23b8f57
RK
2807
2808char *
5644b7e8
AC
2809__gnat_locate_file_with_predicate (char *file_name, char *path_val,
2810 int (*predicate)(char *))
d23b8f57
RK
2811{
2812 char *ptr;
7d71283c 2813 char *file_path = (char *) alloca (strlen (file_name) + 1);
99b97b2e
DR
2814 int absolute;
2815
e51b97be
NS
2816 /* Return immediately if file_name is empty */
2817
2818 if (*file_name == '\0')
2819 return 0;
2820
99b97b2e
DR
2821 /* Remove quotes around file_name if present */
2822
2823 ptr = file_name;
2824 if (*ptr == '"')
2825 ptr++;
2826
2827 strcpy (file_path, ptr);
2828
2829 ptr = file_path + strlen (file_path) - 1;
2830
2831 if (*ptr == '"')
2832 *ptr = '\0';
d23b8f57 2833
07fc65c4 2834 /* Handle absolute pathnames. */
99b97b2e
DR
2835
2836 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2837
fbf5a39b
AC
2838 if (absolute)
2839 {
052e0603 2840 if (predicate (file_path))
99b97b2e 2841 return xstrdup (file_path);
fbf5a39b
AC
2842
2843 return 0;
2844 }
2845
2846 /* If file_name include directory separator(s), try it first as
2847 a path name relative to the current directory */
d23b8f57
RK
2848 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2849 ;
2850
fbf5a39b 2851 if (*ptr != 0)
d23b8f57 2852 {
052e0603 2853 if (predicate (file_name))
d23b8f57 2854 return xstrdup (file_name);
d23b8f57
RK
2855 }
2856
2857 if (path_val == 0)
2858 return 0;
2859
2860 {
2861 /* The result has to be smaller than path_val + file_name. */
8918fe18
AC
2862 char *file_path =
2863 (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
d23b8f57
RK
2864
2865 for (;;)
2866 {
99b97b2e
DR
2867 /* Skip the starting quote */
2868
2869 if (*path_val == '"')
262991d8 2870 path_val++;
99b97b2e 2871
d23b8f57 2872 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
262991d8 2873 *ptr++ = *path_val++;
d23b8f57 2874
47d3b920
AC
2875 /* If directory is empty, it is the current directory*/
2876
2877 if (ptr == file_path)
2878 {
2879 *ptr = '.';
2880 }
2881 else
2882 ptr--;
99b97b2e
DR
2883
2884 /* Skip the ending quote */
2885
2886 if (*ptr == '"')
262991d8 2887 ptr--;
99b97b2e 2888
d23b8f57
RK
2889 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2890 *++ptr = DIR_SEPARATOR;
2891
2892 strcpy (++ptr, file_name);
2893
052e0603 2894 if (predicate (file_path))
d23b8f57 2895 return xstrdup (file_path);
47d3b920
AC
2896
2897 if (*path_val == 0)
2898 return 0;
2899
2900 /* Skip path separator */
2901
2902 path_val++;
d23b8f57
RK
2903 }
2904 }
2905
2906 return 0;
2907}
2908
052e0603
AC
2909/* Locate an executable file, give a Path value. */
2910
2911char *
2912__gnat_locate_executable_file (char *file_name, char *path_val)
2913{
2914 return __gnat_locate_file_with_predicate
2915 (file_name, path_val, &__gnat_is_executable_file);
2916}
2917
2918/* Locate a regular file, give a Path value. */
2919
2920char *
2921__gnat_locate_regular_file (char *file_name, char *path_val)
2922{
2923 return __gnat_locate_file_with_predicate
2924 (file_name, path_val, &__gnat_is_regular_file);
2925}
2926
d23b8f57
RK
2927/* Locate an executable given a Path argument. This routine is only used by
2928 gnatbl and should not be used otherwise. Use locate_exec_on_path
07fc65c4 2929 instead. */
d23b8f57
RK
2930
2931char *
fbf5a39b 2932__gnat_locate_exec (char *exec_name, char *path_val)
d23b8f57 2933{
005f870e 2934 const unsigned int len = strlen (HOST_EXECUTABLE_SUFFIX);
b87520cd 2935 char *ptr;
005f870e
EB
2936
2937 if (len > 0 && !strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
d23b8f57 2938 {
005f870e 2939 char *full_exec_name = (char *) alloca (strlen (exec_name) + len + 1);
d23b8f57
RK
2940
2941 strcpy (full_exec_name, exec_name);
2942 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
052e0603 2943 ptr = __gnat_locate_executable_file (full_exec_name, path_val);
b87520cd
VC
2944
2945 if (ptr == 0)
052e0603 2946 return __gnat_locate_executable_file (exec_name, path_val);
b87520cd 2947 return ptr;
d23b8f57
RK
2948 }
2949 else
052e0603 2950 return __gnat_locate_executable_file (exec_name, path_val);
d23b8f57
RK
2951}
2952
07fc65c4 2953/* Locate an executable using the Systems default PATH. */
d23b8f57
RK
2954
2955char *
fbf5a39b 2956__gnat_locate_exec_on_path (char *exec_name)
d23b8f57 2957{
fbf5a39b 2958 char *apath_val;
0022d9e3 2959
5ae7c3cf 2960#if defined (_WIN32)
0022d9e3
PO
2961 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2962 TCHAR *wapath_val;
fbf5a39b 2963 /* In Win32 systems we expand the PATH as for XP environment
99b97b2e
DR
2964 variables are not automatically expanded. We also prepend the
2965 ".;" to the path to match normal NT path search semantics */
fbf5a39b 2966
99b97b2e 2967 #define EXPAND_BUFFER_SIZE 32767
fbf5a39b 2968
ba1a9233 2969 wapath_val = (TCHAR *) alloca (EXPAND_BUFFER_SIZE);
99b97b2e 2970
0022d9e3
PO
2971 wapath_val [0] = '.';
2972 wapath_val [1] = ';';
d23b8f57 2973
99b97b2e 2974 DWORD res = ExpandEnvironmentStrings
0022d9e3
PO
2975 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2976
2977 if (!res) wapath_val [0] = _T('\0');
2978
ba1a9233 2979 apath_val = (char *) alloca (EXPAND_BUFFER_SIZE);
0022d9e3 2980
ffec8e81 2981 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
99b97b2e 2982
0022d9e3 2983#else
4c0f272c 2984 const char *path_val = getenv ("PATH");
e08add8e 2985
ec6cfc5d
AC
2986 /* If PATH is not defined, proceed with __gnat_locate_exec anyway, so we can
2987 find files that contain directory names. */
2988
2989 if (path_val == NULL) path_val = "";
7d71283c 2990 apath_val = (char *) alloca (strlen (path_val) + 1);
d23b8f57 2991 strcpy (apath_val, path_val);
0022d9e3 2992#endif
ec6cfc5d
AC
2993
2994 return __gnat_locate_exec (exec_name, apath_val);
d23b8f57
RK
2995}
2996
e08add8e
AC
2997/* Dummy functions for Osint import for non-VMS systems.
2998 ??? To be removed. */
d23b8f57
RK
2999
3000int
5644b7e8
AC
3001__gnat_to_canonical_file_list_init (char *dirspec ATTRIBUTE_UNUSED,
3002 int onlydirs ATTRIBUTE_UNUSED)
d23b8f57
RK
3003{
3004 return 0;
3005}
3006
3007char *
9373164a 3008__gnat_to_canonical_file_list_next (void)
d23b8f57 3009{
52d0a7ac 3010 static char empty[] = "";
75069667 3011 return empty;
d23b8f57
RK
3012}
3013
3014void
9373164a 3015__gnat_to_canonical_file_list_free (void)
d23b8f57
RK
3016{
3017}
3018
3019char *
fbf5a39b 3020__gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
d23b8f57
RK
3021{
3022 return dirspec;
3023}
3024
3025char *
fbf5a39b 3026__gnat_to_canonical_file_spec (char *filespec)
d23b8f57
RK
3027{
3028 return filespec;
3029}
3030
3031char *
fbf5a39b 3032__gnat_to_canonical_path_spec (char *pathspec)
d23b8f57
RK
3033{
3034 return pathspec;
3035}
3036
3037char *
fbf5a39b 3038__gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
d23b8f57
RK
3039{
3040 return dirspec;
3041}
3042
3043char *
fbf5a39b 3044__gnat_to_host_file_spec (char *filespec)
d23b8f57
RK
3045{
3046 return filespec;
3047}
3048
3049void
9373164a 3050__gnat_adjust_os_resource_limits (void)
d23b8f57
RK
3051{
3052}
3053
d23b8f57 3054#if defined (__mips_vxworks)
fbf5a39b 3055int
5644b7e8 3056_flush_cache (void)
d23b8f57
RK
3057{
3058 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3059}
3060#endif
3061
07fc65c4
GB
3062#if defined (_WIN32)
3063int __gnat_argument_needs_quote = 1;
3064#else
3065int __gnat_argument_needs_quote = 0;
3066#endif
fbf5a39b
AC
3067
3068/* This option is used to enable/disable object files handling from the
3069 binder file by the GNAT Project module. For example, this is disabled on
4c46b835
AC
3070 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3071 Stating with GCC 3.4 the shared libraries are not based on mdll
3072 anymore as it uses the GCC's -shared option */
3073#if defined (_WIN32) \
3074 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
fbf5a39b
AC
3075int __gnat_prj_add_obj_files = 0;
3076#else
3077int __gnat_prj_add_obj_files = 1;
3078#endif
3079
3080/* char used as prefix/suffix for environment variables */
3081#if defined (_WIN32)
3082char __gnat_environment_char = '%';
3083#else
3084char __gnat_environment_char = '$';
3085#endif
3086
3087/* This functions copy the file attributes from a source file to a
3088 destination file.
3089
3090 mode = 0 : In this mode copy only the file time stamps (last access and
3091 last modification time stamps).
3092
3093 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3094 copied.
3095
2f97d24c
AC
3096 mode = 2 : In this mode, only read/write/execute attributes are copied
3097
fbf5a39b
AC
3098 Returns 0 if operation was successful and -1 in case of error. */
3099
3100int
f146302c
AC
3101__gnat_copy_attribs (char *from ATTRIBUTE_UNUSED, char *to ATTRIBUTE_UNUSED,
3102 int mode ATTRIBUTE_UNUSED)
fbf5a39b 3103{
5ae7c3cf 3104#if (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
fbf5a39b 3105 return -1;
35117aa8 3106
5ae7c3cf 3107#elif defined (_WIN32)
35117aa8
AC
3108 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3109 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3110 BOOL res;
3111 FILETIME fct, flat, flwt;
3112 HANDLE hfrom, hto;
3113
3114 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3115 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3116
2f97d24c 3117 /* Do we need to copy the timestamp ? */
35117aa8 3118
2f97d24c
AC
3119 if (mode != 2) {
3120 /* retrieve from times */
35117aa8 3121
2f97d24c
AC
3122 hfrom = CreateFile
3123 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING,
3124 FILE_ATTRIBUTE_NORMAL, NULL);
35117aa8 3125
2f97d24c
AC
3126 if (hfrom == INVALID_HANDLE_VALUE)
3127 return -1;
35117aa8 3128
2f97d24c 3129 res = GetFileTime (hfrom, &fct, &flat, &flwt);
35117aa8 3130
2f97d24c 3131 CloseHandle (hfrom);
35117aa8 3132
2f97d24c
AC
3133 if (res == 0)
3134 return -1;
35117aa8 3135
2f97d24c 3136 /* retrieve from times */
35117aa8 3137
2f97d24c
AC
3138 hto = CreateFile
3139 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
3140 FILE_ATTRIBUTE_NORMAL, NULL);
35117aa8 3141
2f97d24c
AC
3142 if (hto == INVALID_HANDLE_VALUE)
3143 return -1;
35117aa8 3144
2f97d24c 3145 res = SetFileTime (hto, NULL, &flat, &flwt);
35117aa8 3146
2f97d24c 3147 CloseHandle (hto);
35117aa8 3148
2f97d24c
AC
3149 if (res == 0)
3150 return -1;
3151 }
3152
3153 /* Do we need to copy the permissions ? */
35117aa8
AC
3154 /* Set file attributes in full mode. */
3155
2f97d24c 3156 if (mode != 0)
35117aa8
AC
3157 {
3158 DWORD attribs = GetFileAttributes (wfrom);
3159
3160 if (attribs == INVALID_FILE_ATTRIBUTES)
3161 return -1;
3162
3163 res = SetFileAttributes (wto, attribs);
3164 if (res == 0)
3165 return -1;
3166 }
3167
3168 return 0;
3169
fbf5a39b 3170#else
f6c7fcc0 3171 GNAT_STRUCT_STAT fbuf;
fbf5a39b
AC
3172 struct utimbuf tbuf;
3173
2f97d24c
AC
3174 if (GNAT_STAT (from, &fbuf) == -1) {
3175 return -1;
3176 }
fbf5a39b 3177
2f97d24c
AC
3178 /* Do we need to copy timestamp ? */
3179 if (mode != 2) {
3180 tbuf.actime = fbuf.st_atime;
3181 tbuf.modtime = fbuf.st_mtime;
fbf5a39b 3182
2f97d24c
AC
3183 if (utime (to, &tbuf) == -1) {
3184 return -1;
3185 }
3186 }
fbf5a39b 3187
2f97d24c
AC
3188 /* Do we need to copy file permissions ? */
3189 if (mode != 0 && (chmod (to, fbuf.st_mode) == -1)) {
fbf5a39b 3190 return -1;
2f97d24c 3191 }
fbf5a39b
AC
3192
3193 return 0;
3194#endif
3195}
3196
efdfd311
AC
3197int
3198__gnat_lseek (int fd, long offset, int whence)
3199{
3200 return (int) lseek (fd, offset, whence);
3201}
9bc43c53 3202
18f22284 3203/* This function returns the major version number of GCC being used. */
9bc43c53
AC
3204int
3205get_gcc_version (void)
3206{
18f22284
PO
3207#ifdef IN_RTS
3208 return __GNUC__;
3209#else
3210 return (int) (version_string[0] - '0');
3211#endif
9bc43c53 3212}
cc892b2c 3213
860917b6
TQ
3214/*
3215 * Set Close_On_Exec as indicated.
3216 * Note: this is used for both GNAT.OS_Lib and GNAT.Sockets.
3217 */
3218
cc892b2c 3219int
e6e375cc 3220__gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
e5fe4251 3221 int close_on_exec_p ATTRIBUTE_UNUSED)
cc892b2c
DR
3222{
3223#if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3224 int flags = fcntl (fd, F_GETFD, 0);
3225 if (flags < 0)
3226 return flags;
3227 if (close_on_exec_p)
3228 flags |= FD_CLOEXEC;
3229 else
3230 flags &= ~FD_CLOEXEC;
4887624e 3231 return fcntl (fd, F_SETFD, flags);
c8bbc9ef
AL
3232#elif defined(_WIN32)
3233 HANDLE h = (HANDLE) _get_osfhandle (fd);
3234 if (h == (HANDLE) -1)
3235 return -1;
3236 if (close_on_exec_p)
3237 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
18ec2bda 3238 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
c8bbc9ef 3239 HANDLE_FLAG_INHERIT);
cc892b2c 3240#else
c8bbc9ef 3241 /* TODO: Unimplemented. */
cc892b2c 3242 return -1;
cc892b2c
DR
3243#endif
3244}
b87520cd
VC
3245
3246/* Indicates if platforms supports automatic initialization through the
3247 constructor mechanism */
3248int
c6bd4220 3249__gnat_binder_supports_auto_init (void)
b87520cd 3250{
e08add8e 3251 return 1;
b87520cd
VC
3252}
3253
3254/* Indicates that Stand-Alone Libraries are automatically initialized through
3255 the constructor mechanism */
3256int
c6bd4220 3257__gnat_sals_init_using_constructors (void)
b87520cd 3258{
e08add8e 3259#if defined (__vxworks) || defined (__Lynx__)
b87520cd
VC
3260 return 0;
3261#else
3262 return 1;
3263#endif
3264}
b41ab480 3265
02886c2e 3266#if defined (__linux__) || defined (__ANDROID__)
442dd5fb
NR
3267/* There is no function in the glibc to retrieve the LWP of the current
3268 thread. We need to do a system call in order to retrieve this
3269 information. */
3270#include <sys/syscall.h>
5644b7e8
AC
3271void *
3272__gnat_lwp_self (void)
9549767b 3273{
442dd5fb
NR
3274 return (void *) syscall (__NR_gettid);
3275}
02886c2e 3276#endif
6b81741c 3277
009c0268 3278#if defined (__APPLE__)
3f5c0b6b
IS
3279# if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060
3280# include <mach/thread_info.h>
3281# include <mach/mach_init.h>
3282# include <mach/thread_act.h>
3283# else
3284# include <pthread.h>
3285# endif
009c0268
AC
3286
3287/* System-wide thread identifier. Note it could be truncated on 32 bit
3288 hosts.
3289 Previously was: pthread_mach_thread_np (pthread_self ()). */
3290void *
3291__gnat_lwp_self (void)
3292{
3f5c0b6b 3293#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060
009c0268
AC
3294 thread_identifier_info_data_t data;
3295 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
3296 kern_return_t kret;
3297
3298 kret = thread_info (mach_thread_self (), THREAD_IDENTIFIER_INFO,
3299 (thread_info_t) &data, &count);
3300 if (kret == KERN_SUCCESS)
3301 return (void *)(uintptr_t)data.thread_id;
3302 else
3303 return 0;
3f5c0b6b
IS
3304#else
3305 return (void *)pthread_mach_thread_np (pthread_self ());
3306#endif
009c0268
AC
3307}
3308#endif
3309
02886c2e 3310#if defined (__linux__)
6b81741c
AC
3311#include <sched.h>
3312
9f55bc62
AC
3313/* glibc versions earlier than 2.7 do not define the routines to handle
3314 dynamically allocated CPU sets. For these targets, we use the static
3315 versions. */
3316
3317#ifdef CPU_ALLOC
3318
3319/* Dynamic cpu sets */
3320
5644b7e8
AC
3321cpu_set_t *
3322__gnat_cpu_alloc (size_t count)
6b81741c 3323{
9d1e0e72 3324 return CPU_ALLOC (count);
6b81741c
AC
3325}
3326
5644b7e8
AC
3327size_t
3328__gnat_cpu_alloc_size (size_t count)
9d1e0e72
JR
3329{
3330 return CPU_ALLOC_SIZE (count);
3331}
3332
5644b7e8
AC
3333void
3334__gnat_cpu_free (cpu_set_t *set)
9d1e0e72
JR
3335{
3336 CPU_FREE (set);
3337}
3338
5644b7e8
AC
3339void
3340__gnat_cpu_zero (size_t count, cpu_set_t *set)
9d1e0e72
JR
3341{
3342 CPU_ZERO_S (count, set);
3343}
3344
5644b7e8
AC
3345void
3346__gnat_cpu_set (int cpu, size_t count, cpu_set_t *set)
6b81741c
AC
3347{
3348 /* Ada handles CPU numbers starting from 1, while C identifies the first
3349 CPU by a 0, so we need to adjust. */
9d1e0e72 3350 CPU_SET_S (cpu - 1, count, set);
6b81741c 3351}
9f55bc62 3352
747412b8 3353#else /* !CPU_ALLOC */
9f55bc62
AC
3354
3355/* Static cpu sets */
3356
5644b7e8
AC
3357cpu_set_t *
3358__gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED)
9f55bc62
AC
3359{
3360 return (cpu_set_t *) xmalloc (sizeof (cpu_set_t));
3361}
3362
5644b7e8
AC
3363size_t
3364__gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED)
9f55bc62
AC
3365{
3366 return sizeof (cpu_set_t);
3367}
3368
5644b7e8
AC
3369void
3370__gnat_cpu_free (cpu_set_t *set)
9f55bc62
AC
3371{
3372 free (set);
3373}
3374
5644b7e8
AC
3375void
3376__gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
9f55bc62
AC
3377{
3378 CPU_ZERO (set);
3379}
3380
5644b7e8
AC
3381void
3382__gnat_cpu_set (int cpu, size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
9f55bc62
AC
3383{
3384 /* Ada handles CPU numbers starting from 1, while C identifies the first
3385 CPU by a 0, so we need to adjust. */
3386 CPU_SET (cpu - 1, set);
3387}
747412b8 3388#endif /* !CPU_ALLOC */
329be64b 3389#endif /* __linux__ */
747412b8
AC
3390
3391/* Return the load address of the executable, or 0 if not known. In the
3392 specific case of error, (void *)-1 can be returned. Beware: this unit may
3393 be in a shared library. As low-level units are needed, we allow #include
3394 here. */
3395
3396#if defined (__APPLE__)
3397#include <mach-o/dyld.h>
442dd5fb 3398#endif
747412b8
AC
3399
3400const void *
3401__gnat_get_executable_load_address (void)
3402{
3403#if defined (__APPLE__)
3404 return _dyld_get_image_header (0);
3405
055416a8
AC
3406#elif 0 && defined (__linux__)
3407 /* Currently disabled as it needs at least -ldl. */
747412b8
AC
3408 struct link_map *map = _r_debug.r_map;
3409
3410 return (const void *)map->l_addr;
3411
747412b8
AC
3412#else
3413 return NULL;
b7c9777e 3414#endif
747412b8 3415}
9e9bd455 3416
3fee081a
PO
3417void
3418__gnat_kill (int pid, int sig, int close ATTRIBUTE_UNUSED)
3419{
3420#if defined(_WIN32)
3421 HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
3422 if (h == NULL)
3423 return;
3424 if (sig == 9)
3425 {
9ba9f4c0 3426 TerminateProcess (h, 1);
3fee081a
PO
3427 }
3428 else if (sig == SIGINT)
3429 GenerateConsoleCtrlEvent (CTRL_C_EVENT, pid);
3430 else if (sig == SIGBREAK)
3431 GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid);
3432 /* ??? The last two alternatives don't really work. SIGBREAK requires setting
3433 up process groups at start time which we don't do; treating SIGINT is just
3434 not possible apparently. So we really only support signal 9. Fortunately
3435 that's all we use in GNAT.Expect */
3436
3437 CloseHandle (h);
3438#elif defined (__vxworks)
3439 /* Not implemented */
3440#else
3441 kill (pid, sig);
3442#endif
3443}
3444
287aa0ed
AC
3445void __gnat_killprocesstree (int pid, int sig_num)
3446{
3447#if defined(_WIN32)
287aa0ed
AC
3448 PROCESSENTRY32 pe;
3449
3450 memset(&pe, 0, sizeof(PROCESSENTRY32));
3451 pe.dwSize = sizeof(PROCESSENTRY32);
3452
3453 HANDLE hSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
3454
3455 /* cannot take snapshot, just kill the parent process */
3456
3457 if (hSnap == INVALID_HANDLE_VALUE)
3458 {
3459 __gnat_kill (pid, sig_num, 1);
3460 return;
3461 }
3462
3463 if (Process32First(hSnap, &pe))
3464 {
3465 BOOL bContinue = TRUE;
3466
3467 /* kill child processes first */
3468
3469 while (bContinue)
3470 {
86ec3bfb 3471 if (pe.th32ParentProcessID == (DWORD)pid)
287aa0ed
AC
3472 __gnat_killprocesstree (pe.th32ProcessID, sig_num);
3473
3474 bContinue = Process32Next (hSnap, &pe);
3475 }
3476 }
3477
3478 CloseHandle (hSnap);
3479
3480 /* kill process */
3481
3482 __gnat_kill (pid, sig_num, 1);
5904016a
AC
3483
3484#elif defined (__vxworks)
3485 /* not implemented */
3486
3487#elif defined (__linux__)
287aa0ed
AC
3488 DIR *dir;
3489 struct dirent *d;
3490
3491 /* read all processes' pid and ppid */
3492
3493 dir = opendir ("/proc");
3494
3495 /* cannot open proc, just kill the parent process */
3496
3497 if (!dir)
3498 {
3499 __gnat_kill (pid, sig_num, 1);
3500 return;
3501 }
3502
3503 /* kill child processes first */
3504
e9dcf0a4 3505 while ((d = readdir (dir)) != NULL)
287aa0ed
AC
3506 {
3507 if ((d->d_type & DT_DIR) == DT_DIR)
3508 {
372db67b 3509 char statfile[64];
287aa0ed
AC
3510 int _pid, _ppid;
3511
3512 /* read /proc/<PID>/stat */
3513
60ab8595 3514 if (strlen (d->d_name) >= sizeof (statfile) - strlen ("/proc//stat"))
372db67b
EB
3515 continue;
3516 strcpy (statfile, "/proc/");
3517 strcat (statfile, d->d_name);
3518 strcat (statfile, "/stat");
287aa0ed
AC
3519
3520 FILE *fd = fopen (statfile, "r");
3521
3522 if (fd)
3523 {
3524 const int match = fscanf (fd, "%d %*s %*s %d", &_pid, &_ppid);
3525 fclose (fd);
3526
3527 if (match == 2 && _ppid == pid)
3528 __gnat_killprocesstree (_pid, sig_num);
3529 }
3530 }
3531 }
3532
3533 closedir (dir);
3534
3535 /* kill process */
3536
5904016a
AC
3537 __gnat_kill (pid, sig_num, 1);
3538#else
287aa0ed
AC
3539 __gnat_kill (pid, sig_num, 1);
3540#endif
3541 /* Note on Solaris it is possible to read /proc/<PID>/status.
3542 The 5th and 6th words are the pid and the 7th and 8th the ppid.
3543 See: /usr/include/sys/procfs.h (struct pstatus).
3544 */
3545}
3546
9e9bd455
LG
3547#ifdef __cplusplus
3548}
3549#endif