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