Add mi_thunk support for vcalls on hppa.
[official-gcc.git] / gcc / ada / adaint.c
blob0a90c92402cd00bcf2ea2fc3672b4a39e1830bcb
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 1992-2020, Free Software Foundation, Inc. *
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- *
13 * ware Foundation; either version 3, or (at your option) any later ver- *
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 *
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/>. *
26 * *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
29 * *
30 ****************************************************************************/
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. */
37 /* Ensure access to errno is thread safe. */
39 #ifndef _REENTRANT
40 #define _REENTRANT
41 #endif
43 #ifndef _THREAD_SAFE
44 #define _THREAD_SAFE
45 #endif
47 /* Use 64 bit Large File API */
48 #if defined (__QNX__)
49 #define _LARGEFILE64_SOURCE 1
50 #elif !defined(_LARGEFILE_SOURCE)
51 #define _LARGEFILE_SOURCE
52 #endif
53 #define _FILE_OFFSET_BITS 64
55 #ifdef __vxworks
57 /* No need to redefine exit here. */
58 #undef exit
60 /* We want to use the POSIX variants of include files. */
61 #define POSIX
62 #include "vxWorks.h"
63 #include <sys/time.h>
65 #if defined (__mips_vxworks)
66 #include "cacheLib.h"
67 #endif /* __mips_vxworks */
69 /* If SMP, access vxCpuConfiguredGet */
70 #ifdef _WRS_CONFIG_SMP
71 #include <vxCpuLib.h>
72 #endif /* _WRS_CONFIG_SMP */
74 /* We need to know the VxWorks version because some file operations
75 (such as chmod) are only available on VxWorks 6. */
76 #include "version.h"
78 /* vwModNum.h and dosFsLib.h are needed for the VxWorks 6 rename workaround.
79 See below. */
80 #if (_WRS_VXWORKS_MAJOR == 6)
81 #include <vwModNum.h>
82 #include <dosFsLib.h>
83 #endif /* 6.x */
84 #endif /* VxWorks */
86 #if defined (__APPLE__)
87 #include <unistd.h>
88 #endif
90 #if defined (__hpux__)
91 #include <sys/param.h>
92 #include <sys/pstat.h>
93 #endif
95 #ifdef __PikeOS__
96 #define __BSD_VISIBLE 1
97 #endif
99 #ifdef __QNX__
100 #include <sys/syspage.h>
101 #endif
103 #ifdef IN_RTS
105 #ifdef STANDALONE
106 #include <errno.h>
107 #include <sys/types.h>
108 #include <sys/stat.h>
109 #include <unistd.h>
110 #include <stdlib.h>
111 #include <string.h>
113 /* for CPU_SET/CPU_ZERO */
114 #define _GNU_SOURCE
115 #define __USE_GNU
117 #include "runtime.h"
119 #else
120 #include "tconfig.h"
121 #include "tsystem.h"
122 #endif
124 #include <sys/stat.h>
125 #include <fcntl.h>
126 #include <time.h>
128 #if defined (__vxworks) || defined (__ANDROID__)
129 /* S_IREAD and S_IWRITE are not defined in VxWorks or Android */
130 #ifndef S_IREAD
131 #define S_IREAD (S_IRUSR | S_IRGRP | S_IROTH)
132 #endif
134 #ifndef S_IWRITE
135 #define S_IWRITE (S_IWUSR)
136 #endif
137 #endif
139 /* We don't have libiberty, so use malloc. */
140 #define xmalloc(S) malloc (S)
141 #define xrealloc(V,S) realloc (V,S)
142 #else
143 #include "config.h"
144 #include "system.h"
145 #include "version.h"
146 #endif
148 /* limits.h is needed for LLONG_MIN. */
149 #ifdef __cplusplus
150 #include <climits>
151 #else
152 #include <limits.h>
153 #endif
155 #ifdef __cplusplus
156 extern "C" {
157 #endif
159 #if defined (__DJGPP__)
161 /* For isalpha-like tests in the compiler, we're expected to resort to
162 safe-ctype.h/ISALPHA. This isn't available for the runtime library
163 build, so we fallback on ctype.h/isalpha there. */
165 #ifdef IN_RTS
166 #include <ctype.h>
167 #define ISALPHA isalpha
168 #endif
170 #elif defined (__MINGW32__) || defined (__CYGWIN__)
172 #include "mingw32.h"
174 /* Current code page and CCS encoding to use, set in initialize.c. */
175 UINT __gnat_current_codepage;
176 UINT __gnat_current_ccs_encoding;
178 #include <sys/utime.h>
180 /* For isalpha-like tests in the compiler, we're expected to resort to
181 safe-ctype.h/ISALPHA. This isn't available for the runtime library
182 build, so we fallback on ctype.h/isalpha there. */
184 #ifdef IN_RTS
185 #include <ctype.h>
186 #define ISALPHA isalpha
187 #endif
189 #elif defined (__Lynx__)
191 /* Lynx utime.h only defines the entities of interest to us if
192 defined (VMOS_DEV), so ... */
193 #define VMOS_DEV
194 #include <utime.h>
195 #undef VMOS_DEV
197 #else
198 #include <utime.h>
199 #endif
201 /* wait.h processing */
202 #ifdef __MINGW32__
203 # if OLD_MINGW
204 # include <sys/wait.h>
205 # endif
206 #elif defined (__vxworks) && defined (__RTP__)
207 # include <wait.h>
208 #elif defined (__Lynx__)
209 /* ??? We really need wait.h and it includes resource.h on Lynx. GCC
210 has a resource.h header as well, included instead of the lynx
211 version in our setup, causing lots of errors. We don't really need
212 the lynx contents of this file, so just workaround the issue by
213 preventing the inclusion of the GCC header from doing anything. */
214 # define GCC_RESOURCE_H
215 # include <sys/wait.h>
216 #elif defined (__PikeOS__)
217 /* No wait() or waitpid() calls available. */
218 #else
219 /* Default case. */
220 #include <sys/wait.h>
221 #endif
223 #if defined (__DJGPP__)
224 #include <process.h>
225 #include <signal.h>
226 #include <dir.h>
227 #include <utime.h>
228 #undef DIR_SEPARATOR
229 #define DIR_SEPARATOR '\\'
231 #elif defined (_WIN32)
233 #include <windows.h>
234 #include <accctrl.h>
235 #include <aclapi.h>
236 #include <tlhelp32.h>
237 #include <signal.h>
238 #undef DIR_SEPARATOR
239 #define DIR_SEPARATOR '\\'
241 #else
242 #include <utime.h>
243 #endif
245 #include "adaint.h"
247 int __gnat_in_child_after_fork = 0;
249 #if defined (__APPLE__) && defined (st_mtime)
250 #define st_atim st_atimespec
251 #define st_mtim st_mtimespec
252 #endif
254 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
255 defined in the current system. On DOS-like systems these flags control
256 whether the file is opened/created in text-translation mode (CR/LF in
257 external file mapped to LF in internal file), but in Unix-like systems,
258 no text translation is required, so these flags have no effect. */
260 #ifndef O_BINARY
261 #define O_BINARY 0
262 #endif
264 #ifndef O_TEXT
265 #define O_TEXT 0
266 #endif
268 #ifndef HOST_EXECUTABLE_SUFFIX
269 #define HOST_EXECUTABLE_SUFFIX ""
270 #endif
272 #ifndef HOST_OBJECT_SUFFIX
273 #define HOST_OBJECT_SUFFIX ".o"
274 #endif
276 #ifndef PATH_SEPARATOR
277 #define PATH_SEPARATOR ':'
278 #endif
280 #ifndef DIR_SEPARATOR
281 #define DIR_SEPARATOR '/'
282 #define IS_DIRECTORY_SEPARATOR(c) ((c) == DIR_SEPARATOR)
283 #else
284 #define IS_DIRECTORY_SEPARATOR(c) ((c) == '/' || (c) == DIR_SEPARATOR)
285 #endif
287 /* Check for cross-compilation. */
288 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
289 #define IS_CROSS 1
290 int __gnat_is_cross_compiler = 1;
291 #else
292 #undef IS_CROSS
293 int __gnat_is_cross_compiler = 0;
294 #endif
296 char __gnat_dir_separator = DIR_SEPARATOR;
298 char __gnat_path_separator = PATH_SEPARATOR;
300 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
301 the base filenames that libraries specified with -lsomelib options
302 may have. This is used by GNATMAKE to check whether an executable
303 is up-to-date or not. The syntax is
305 library_template ::= { pattern ; } pattern NUL
306 pattern ::= [ prefix ] * [ postfix ]
308 These should only specify names of static libraries as it makes
309 no sense to determine at link time if dynamic-link libraries are
310 up to date or not. Any libraries that are not found are supposed
311 to be up-to-date:
313 * if they are needed but not present, the link
314 will fail,
316 * otherwise they are libraries in the system paths and so
317 they are considered part of the system and not checked
318 for that reason.
320 ??? This should be part of a GNAT host-specific compiler
321 file instead of being included in all user applications
322 as well. This is only a temporary work-around for 3.11b. */
324 #ifndef GNAT_LIBRARY_TEMPLATE
325 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
326 #endif
328 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
330 #if defined (__vxworks)
331 #define GNAT_MAX_PATH_LEN PATH_MAX
333 #else
335 #if defined (__MINGW32__)
336 #include "mingw32.h"
338 #if OLD_MINGW
339 #include <sys/param.h>
340 #endif
342 #else
343 #include <sys/param.h>
344 #endif
346 #ifdef MAXPATHLEN
347 #define GNAT_MAX_PATH_LEN MAXPATHLEN
348 #else
349 #define GNAT_MAX_PATH_LEN 256
350 #endif
352 #endif
354 /* Used for runtime check that Ada constant File_Attributes_Size is no
355 less than the actual size of struct file_attributes (see Osint
356 initialization). */
357 int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
359 void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
361 /* The __gnat_max_path_len variable is used to export the maximum
362 length of a path name to Ada code. max_path_len is also provided
363 for compatibility with older GNAT versions, please do not use
364 it. */
366 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
367 int max_path_len = GNAT_MAX_PATH_LEN;
369 /* Control whether we can use ACL on Windows. */
371 int __gnat_use_acl = 1;
373 /* The following macro HAVE_READDIR_R should be defined if the
374 system provides the routine readdir_r.
375 ... but we never define it anywhere??? */
376 #undef HAVE_READDIR_R
378 #define MAYBE_TO_PTR32(argv) argv
380 static const char ATTR_UNSET = 127;
382 /* Reset the file attributes as if no system call had been performed */
384 void
385 __gnat_reset_attributes (struct file_attributes* attr)
387 attr->exists = ATTR_UNSET;
388 attr->error = EINVAL;
390 attr->writable = ATTR_UNSET;
391 attr->readable = ATTR_UNSET;
392 attr->executable = ATTR_UNSET;
394 attr->regular = ATTR_UNSET;
395 attr->symbolic_link = ATTR_UNSET;
396 attr->directory = ATTR_UNSET;
398 attr->timestamp = (OS_Time)-2;
399 attr->file_length = -1;
403 __gnat_error_attributes (struct file_attributes *attr) {
404 return attr->error;
407 OS_Time
408 __gnat_current_time (void)
410 time_t res = time (NULL);
411 return (OS_Time) res;
414 /* Return the current local time as a string in the ISO 8601 format of
415 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
416 long. */
418 void
419 __gnat_current_time_string (char *result)
421 const char *format = "%Y-%m-%d %H:%M:%S";
422 /* Format string necessary to describe the ISO 8601 format */
424 const time_t t_val = time (NULL);
426 strftime (result, 22, format, localtime (&t_val));
427 /* Convert the local time into a string following the ISO format, copying
428 at most 22 characters into the result string. */
430 result [19] = '.';
431 result [20] = '0';
432 result [21] = '0';
433 /* The sub-seconds are manually set to zero since type time_t lacks the
434 precision necessary for nanoseconds. */
437 void
438 __gnat_to_gm_time (OS_Time *p_time, int *p_year, int *p_month, int *p_day,
439 int *p_hours, int *p_mins, int *p_secs)
441 struct tm *res;
442 time_t time = (time_t) *p_time;
444 res = gmtime (&time);
445 if (res)
447 *p_year = res->tm_year;
448 *p_month = res->tm_mon;
449 *p_day = res->tm_mday;
450 *p_hours = res->tm_hour;
451 *p_mins = res->tm_min;
452 *p_secs = res->tm_sec;
454 else
455 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
458 void
459 __gnat_to_os_time (OS_Time *p_time, int year, int month, int day,
460 int hours, int mins, int secs)
462 struct tm v;
464 v.tm_year = year;
465 v.tm_mon = month;
466 v.tm_mday = day;
467 v.tm_hour = hours;
468 v.tm_min = mins;
469 v.tm_sec = secs;
470 v.tm_isdst = -1;
472 /* returns -1 of failing, this is s-os_lib Invalid_Time */
474 *p_time = (OS_Time) mktime (&v);
477 /* Place the contents of the symbolic link named PATH in the buffer BUF,
478 which has size BUFSIZ. If PATH is a symbolic link, then return the number
479 of characters of its content in BUF. Otherwise, return -1.
480 For systems not supporting symbolic links, always return -1. */
483 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
484 char *buf ATTRIBUTE_UNUSED,
485 size_t bufsiz ATTRIBUTE_UNUSED)
487 #if defined (_WIN32) \
488 || defined(__vxworks) || defined (__PikeOS__)
489 return -1;
490 #else
491 return readlink (path, buf, bufsiz);
492 #endif
495 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
496 If NEWPATH exists it will NOT be overwritten.
497 For systems not supporting symbolic links, always return -1. */
500 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
501 char *newpath ATTRIBUTE_UNUSED)
503 #if defined (_WIN32) \
504 || defined(__vxworks) || defined (__PikeOS__)
505 return -1;
506 #else
507 return symlink (oldpath, newpath);
508 #endif
511 /* Try to lock a file, return 1 if success. */
513 #if defined (__vxworks) \
514 || defined (_WIN32) || defined (__PikeOS__)
516 /* Version that does not use link. */
519 __gnat_try_lock (char *dir, char *file)
521 int fd;
522 #ifdef __MINGW32__
523 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
524 TCHAR wfile[GNAT_MAX_PATH_LEN];
525 TCHAR wdir[GNAT_MAX_PATH_LEN];
527 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
528 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
530 /* ??? the code below crash on MingW64 for obscure reasons, a ticket
531 has been opened here:
533 https://sourceforge.net/p/mingw-w64/bugs/414/
535 As a workaround an equivalent set of code has been put in place below.
537 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
540 _tcscpy (wfull_path, wdir);
541 _tcscat (wfull_path, L"\\");
542 _tcscat (wfull_path, wfile);
544 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
545 #else
546 char full_path[256];
548 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
549 fd = open (full_path, O_CREAT | O_EXCL, 0600);
550 #endif
552 if (fd < 0)
553 return 0;
555 close (fd);
556 return 1;
559 #else
561 /* Version using link(), more secure over NFS. */
562 /* See TN 6913-016 for discussion ??? */
565 __gnat_try_lock (char *dir, char *file)
567 char full_path[256];
568 char temp_file[256];
569 GNAT_STRUCT_STAT stat_result;
570 int fd;
572 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
573 sprintf (temp_file, "%s%cTMP-%ld-%ld",
574 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
576 /* Create the temporary file and write the process number. */
577 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
578 if (fd < 0)
579 return 0;
581 close (fd);
583 /* Link it with the new file. */
584 link (temp_file, full_path);
586 /* Count the references on the old one. If we have a count of two, then
587 the link did succeed. Remove the temporary file before returning. */
588 __gnat_stat (temp_file, &stat_result);
589 unlink (temp_file);
590 return stat_result.st_nlink == 2;
592 #endif
594 /* Return the maximum file name length. */
597 __gnat_get_maximum_file_name_length (void)
599 return -1;
602 /* Return nonzero if file names are case sensitive. */
604 static int file_names_case_sensitive_cache = -1;
607 __gnat_get_file_names_case_sensitive (void)
609 if (file_names_case_sensitive_cache == -1)
611 const char *sensitive = getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
613 if (sensitive != NULL
614 && (sensitive[0] == '0' || sensitive[0] == '1')
615 && sensitive[1] == '\0')
616 file_names_case_sensitive_cache = sensitive[0] - '0';
617 else
619 /* By default, we suppose filesystems aren't case sensitive on
620 Windows and Darwin (but they are on arm-darwin). */
621 #if defined (WINNT) || defined (__DJGPP__) \
622 || (defined (__APPLE__) && !(defined (__arm__) || defined (__arm64__)))
623 file_names_case_sensitive_cache = 0;
624 #else
625 file_names_case_sensitive_cache = 1;
626 #endif
629 return file_names_case_sensitive_cache;
632 /* Return nonzero if environment variables are case sensitive. */
635 __gnat_get_env_vars_case_sensitive (void)
637 #if defined (WINNT) || defined (__DJGPP__)
638 return 0;
639 #else
640 return 1;
641 #endif
644 char
645 __gnat_get_default_identifier_character_set (void)
647 return '1';
650 /* Return the current working directory. */
652 void
653 __gnat_get_current_dir (char *dir, int *length)
655 #if defined (__MINGW32__)
656 TCHAR wdir[GNAT_MAX_PATH_LEN];
658 _tgetcwd (wdir, *length);
660 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
662 #else
663 char* result = getcwd (dir, *length);
664 /* If the current directory does not exist, set length = 0
665 to indicate error. That can't happen on windows, where
666 you can't delete a directory if it is the current
667 directory of some process. */
668 if (!result)
670 *length = 0;
671 return;
673 #endif
675 *length = strlen (dir);
677 if (dir [*length - 1] != DIR_SEPARATOR)
679 dir [*length] = DIR_SEPARATOR;
680 ++(*length);
682 dir[*length] = '\0';
685 /* Return the suffix for object files. */
687 void
688 __gnat_get_object_suffix_ptr (int *len, const char **value)
690 *value = HOST_OBJECT_SUFFIX;
692 if (*value == 0)
693 *len = 0;
694 else
695 *len = strlen (*value);
697 return;
700 /* Return the suffix for executable files. */
702 void
703 __gnat_get_executable_suffix_ptr (int *len, const char **value)
705 *value = HOST_EXECUTABLE_SUFFIX;
707 if (!*value)
708 *len = 0;
709 else
710 *len = strlen (*value);
712 return;
715 /* Return the suffix for debuggable files. Usually this is the same as the
716 executable extension. */
718 void
719 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
721 *value = HOST_EXECUTABLE_SUFFIX;
723 if (*value == 0)
724 *len = 0;
725 else
726 *len = strlen (*value);
728 return;
731 /* Returns the OS filename and corresponding encoding. */
733 void
734 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
735 char *w_filename ATTRIBUTE_UNUSED,
736 char *os_name, int *o_length,
737 char *encoding ATTRIBUTE_UNUSED, int *e_length)
739 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
740 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
741 *o_length = strlen (os_name);
742 strcpy (encoding, "encoding=utf8");
743 *e_length = strlen (encoding);
744 #else
745 strcpy (os_name, filename);
746 *o_length = strlen (filename);
747 *e_length = 0;
748 #endif
751 /* Delete a file. */
754 __gnat_unlink (char *path)
756 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
758 TCHAR wpath[GNAT_MAX_PATH_LEN];
760 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
761 return _tunlink (wpath);
763 #else
764 return unlink (path);
765 #endif
768 /* Rename a file. */
771 __gnat_rename (char *from, char *to)
773 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
775 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
777 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
778 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
779 return _trename (wfrom, wto);
781 #elif defined (__vxworks) && (_WRS_VXWORKS_MAJOR == 6)
783 /* When used on a dos filesystem under VxWorks 6.9 rename will trigger a
784 S_dosFsLib_FILE_NOT_FOUND errno when the file is not found. Let's map
785 that to ENOENT so Ada.Directory.Rename can detect that and raise the
786 Name_Error exception. */
787 int ret = rename (from, to);
789 if (ret && (errno == S_dosFsLib_FILE_NOT_FOUND))
791 errno = ENOENT;
793 return ret;
795 #else
796 return rename (from, to);
797 #endif
800 /* Changing directory. */
803 __gnat_chdir (char *path)
805 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
807 TCHAR wpath[GNAT_MAX_PATH_LEN];
809 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
810 return _tchdir (wpath);
812 #else
813 return chdir (path);
814 #endif
817 /* Removing a directory. */
820 __gnat_rmdir (char *path)
822 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
824 TCHAR wpath[GNAT_MAX_PATH_LEN];
826 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
827 return _trmdir (wpath);
829 #elif defined (VTHREADS)
830 /* rmdir not available */
831 return -1;
832 #else
833 return rmdir (path);
834 #endif
837 #if defined (_WIN32) || defined (__linux__) || defined (__sun__) \
838 || defined (__FreeBSD__) || defined(__DragonFly__) || defined (__QNX__)
839 #define HAS_TARGET_WCHAR_T
840 #endif
842 #ifdef HAS_TARGET_WCHAR_T
843 #include <wchar.h>
844 #endif
847 __gnat_fputwc(int c, FILE *stream)
849 #ifdef HAS_TARGET_WCHAR_T
850 return fputwc ((wchar_t)c, stream);
851 #else
852 return fputc (c, stream);
853 #endif
856 FILE *
857 __gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
859 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
860 TCHAR wpath[GNAT_MAX_PATH_LEN];
861 TCHAR wmode[10];
863 S2WS (wmode, mode, 10);
865 if (encoding == Encoding_Unspecified)
866 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
867 else if (encoding == Encoding_UTF8)
868 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
869 else
870 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
872 return _tfopen (wpath, wmode);
874 #else
875 return GNAT_FOPEN (path, mode);
876 #endif
879 FILE *
880 __gnat_freopen (char *path,
881 char *mode,
882 FILE *stream,
883 int encoding ATTRIBUTE_UNUSED)
885 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
886 TCHAR wpath[GNAT_MAX_PATH_LEN];
887 TCHAR wmode[10];
889 S2WS (wmode, mode, 10);
891 if (encoding == Encoding_Unspecified)
892 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
893 else if (encoding == Encoding_UTF8)
894 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
895 else
896 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
898 return _tfreopen (wpath, wmode, stream);
899 #else
900 return freopen (path, mode, stream);
901 #endif
905 __gnat_open_read (char *path, int fmode)
907 int fd;
908 int o_fmode = O_BINARY;
910 if (fmode)
911 o_fmode = O_TEXT;
913 #if defined (__vxworks)
914 fd = open (path, O_RDONLY | o_fmode, 0444);
915 #elif defined (__MINGW32__)
917 TCHAR wpath[GNAT_MAX_PATH_LEN];
919 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
920 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
922 #else
923 fd = GNAT_OPEN (path, O_RDONLY | o_fmode);
924 #endif
926 return fd < 0 ? -1 : fd;
929 #if defined (__MINGW32__)
930 #define PERM (S_IREAD | S_IWRITE)
931 #else
932 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
933 #endif
936 __gnat_open_rw (char *path, int fmode)
938 int fd;
939 int o_fmode = O_BINARY;
941 if (fmode)
942 o_fmode = O_TEXT;
944 #if defined (__MINGW32__)
946 TCHAR wpath[GNAT_MAX_PATH_LEN];
948 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
949 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
951 #else
952 fd = GNAT_OPEN (path, O_RDWR | o_fmode, PERM);
953 #endif
955 return fd < 0 ? -1 : fd;
959 __gnat_open_create (char *path, int fmode)
961 int fd;
962 int o_fmode = O_BINARY;
964 if (fmode)
965 o_fmode = O_TEXT;
967 #if defined (__MINGW32__)
969 TCHAR wpath[GNAT_MAX_PATH_LEN];
971 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
972 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
974 #else
975 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
976 #endif
978 return fd < 0 ? -1 : fd;
982 __gnat_create_output_file (char *path)
984 int fd;
985 #if defined (__MINGW32__)
987 TCHAR wpath[GNAT_MAX_PATH_LEN];
989 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
990 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
992 #else
993 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
994 #endif
996 return fd < 0 ? -1 : fd;
1000 __gnat_create_output_file_new (char *path)
1002 int fd;
1003 #if defined (__MINGW32__)
1005 TCHAR wpath[GNAT_MAX_PATH_LEN];
1007 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1008 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
1010 #else
1011 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
1012 #endif
1014 return fd < 0 ? -1 : fd;
1018 __gnat_open_append (char *path, int fmode)
1020 int fd;
1021 int o_fmode = O_BINARY;
1023 if (fmode)
1024 o_fmode = O_TEXT;
1026 #if defined (__MINGW32__)
1028 TCHAR wpath[GNAT_MAX_PATH_LEN];
1030 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1031 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
1033 #else
1034 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
1035 #endif
1037 return fd < 0 ? -1 : fd;
1040 /* Open a new file. Return error (-1) if the file already exists. */
1043 __gnat_open_new (char *path, int fmode)
1045 int fd;
1046 int o_fmode = O_BINARY;
1048 if (fmode)
1049 o_fmode = O_TEXT;
1051 #if defined (__MINGW32__)
1053 TCHAR wpath[GNAT_MAX_PATH_LEN];
1055 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1056 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1058 #else
1059 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1060 #endif
1062 return fd < 0 ? -1 : fd;
1065 /* Open a new temp file. Return error (-1) if the file already exists. */
1068 __gnat_open_new_temp (char *path, int fmode)
1070 int fd;
1071 int o_fmode = O_BINARY;
1073 strcpy (path, "GNAT-XXXXXX");
1075 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
1076 || defined (__linux__) || defined (__GLIBC__) || defined (__ANDROID__) \
1077 || defined (__DragonFly__) || defined (__QNX__)) && !defined (__vxworks)
1078 return mkstemp (path);
1079 #elif defined (__Lynx__)
1080 mktemp (path);
1081 #else
1082 if (mktemp (path) == NULL)
1083 return -1;
1084 #endif
1086 if (fmode)
1087 o_fmode = O_TEXT;
1089 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1090 return fd < 0 ? -1 : fd;
1094 __gnat_open (char *path, int fmode)
1096 int fd;
1098 #if defined (__MINGW32__)
1100 TCHAR wpath[GNAT_MAX_PATH_LEN];
1102 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1103 fd = _topen (wpath, fmode, PERM);
1105 #else
1106 fd = GNAT_OPEN (path, fmode, PERM);
1107 #endif
1109 return fd < 0 ? -1 : fd;
1112 /****************************************************************
1113 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1114 ** as possible from it, storing the result in a cache for later reuse
1115 ****************************************************************/
1117 void
1118 __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
1120 GNAT_STRUCT_STAT statbuf;
1121 int ret, error;
1123 if (fd != -1) {
1124 /* GNAT_FSTAT returns -1 and sets errno for failure */
1125 ret = GNAT_FSTAT (fd, &statbuf);
1126 error = ret ? errno : 0;
1128 } else {
1129 /* __gnat_stat returns errno value directly */
1130 error = __gnat_stat (name, &statbuf);
1131 ret = error ? -1 : 0;
1135 * A missing file is reported as an attr structure with error == 0 and
1136 * exists == 0.
1139 if (error == 0 || error == ENOENT)
1140 attr->error = 0;
1141 else
1142 attr->error = error;
1144 attr->regular = (!ret && S_ISREG (statbuf.st_mode));
1145 attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
1147 if (!attr->regular)
1148 attr->file_length = 0;
1149 else
1150 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1151 don't return a useful value for files larger than 2 gigabytes in
1152 either case. */
1153 attr->file_length = statbuf.st_size; /* all systems */
1155 attr->exists = !ret;
1157 #if !defined (_WIN32)
1158 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1159 attr->readable = (!ret && (statbuf.st_mode & S_IRUSR));
1160 attr->writable = (!ret && (statbuf.st_mode & S_IWUSR));
1161 attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
1162 #endif
1164 if (ret != 0) {
1165 attr->timestamp = (OS_Time)-1;
1166 } else {
1167 attr->timestamp = (OS_Time)statbuf.st_mtime;
1171 /****************************************************************
1172 ** Return the number of bytes in the specified file
1173 ****************************************************************/
1175 __int64
1176 __gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
1178 if (attr->file_length == -1) {
1179 __gnat_stat_to_attr (fd, name, attr);
1182 return attr->file_length;
1185 __int64
1186 __gnat_file_length (int fd)
1188 struct file_attributes attr;
1189 __gnat_reset_attributes (&attr);
1190 return __gnat_file_length_attr (fd, NULL, &attr);
1193 long
1194 __gnat_file_length_long (int fd)
1196 struct file_attributes attr;
1197 __gnat_reset_attributes (&attr);
1198 return (long)__gnat_file_length_attr (fd, NULL, &attr);
1201 __int64
1202 __gnat_named_file_length (char *name)
1204 struct file_attributes attr;
1205 __gnat_reset_attributes (&attr);
1206 return __gnat_file_length_attr (-1, name, &attr);
1209 /* Create a temporary filename and put it in string pointed to by
1210 TMP_FILENAME. */
1212 void
1213 __gnat_tmp_name (char *tmp_filename)
1215 #if defined (__MINGW32__)
1217 char *pname;
1218 char prefix[25];
1220 /* tempnam tries to create a temporary file in directory pointed to by
1221 TMP environment variable, in c:\temp if TMP is not set, and in
1222 directory specified by P_tmpdir in stdio.h if c:\temp does not
1223 exist. The filename will be created with the prefix "gnat-". */
1225 sprintf (prefix, "gnat-%d-", (int)getpid());
1226 pname = (char *) _tempnam ("c:\\temp", prefix);
1228 /* if pname is NULL, the file was not created properly, the disk is full
1229 or there is no more free temporary files */
1231 if (pname == NULL)
1232 *tmp_filename = '\0';
1234 /* If pname start with a back slash and not path information it means that
1235 the filename is valid for the current working directory. */
1237 else if (pname[0] == '\\')
1239 strcpy (tmp_filename, ".\\");
1240 strcat (tmp_filename, pname+1);
1242 else
1243 strcpy (tmp_filename, pname);
1245 free (pname);
1248 #elif defined (__linux__) || defined (__FreeBSD__) || defined (__NetBSD__) \
1249 || defined (__OpenBSD__) || defined (__GLIBC__) || defined (__ANDROID__) \
1250 || defined (__DragonFly__) || defined (__QNX__)
1251 #define MAX_SAFE_PATH 1000
1252 char *tmpdir = getenv ("TMPDIR");
1254 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1255 a buffer overflow. */
1256 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1257 #ifdef __ANDROID__
1258 strcpy (tmp_filename, "/cache/gnat-XXXXXX");
1259 #else
1260 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1261 #endif
1262 else
1263 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1265 close (mkstemp(tmp_filename));
1266 #elif defined (__vxworks) && !defined (VTHREADS)
1267 int index;
1268 char *pos;
1269 char *savepos;
1270 static ushort_t seed = 0; /* used to generate unique name */
1272 /* Generate a unique name. */
1273 strcpy (tmp_filename, "tmp");
1275 index = 5;
1276 savepos = pos = tmp_filename + strlen (tmp_filename) + index;
1277 *pos = '\0';
1279 while (1)
1281 FILE *f;
1282 ushort_t t;
1284 /* Fill up the name buffer from the last position. */
1285 seed++;
1286 for (t = seed; --index >= 0; t >>= 3)
1287 *--pos = '0' + (t & 07);
1289 /* Check to see if its unique, if not bump the seed and try again. */
1290 f = fopen (tmp_filename, "r");
1291 if (f == NULL)
1292 break;
1293 fclose (f);
1294 pos = savepos;
1295 index = 5;
1297 #else
1298 tmpnam (tmp_filename);
1299 #endif
1302 /* Open directory and returns a DIR pointer. */
1304 DIR* __gnat_opendir (char *name)
1306 #if defined (__MINGW32__)
1307 TCHAR wname[GNAT_MAX_PATH_LEN];
1309 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1310 return (DIR*)_topendir (wname);
1312 #else
1313 return opendir (name);
1314 #endif
1317 /* Read the next entry in a directory. The returned string points somewhere
1318 in the buffer. */
1320 #if defined (__sun__)
1321 /* For Solaris, be sure to use the 64-bit version, otherwise NFS reads may
1322 fail with EOVERFLOW if the server uses 64-bit cookies. */
1323 #define dirent dirent64
1324 #define readdir readdir64
1325 #endif
1327 char *
1328 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1330 #if defined (__MINGW32__)
1331 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1333 if (dirent != NULL)
1335 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1336 *len = strlen (buffer);
1338 return buffer;
1340 else
1341 return NULL;
1343 #elif defined (HAVE_READDIR_R)
1344 /* If possible, try to use the thread-safe version. */
1345 if (readdir_r (dirp, buffer) != NULL)
1347 *len = strlen (((struct dirent*) buffer)->d_name);
1348 return ((struct dirent*) buffer)->d_name;
1350 else
1351 return NULL;
1353 #else
1354 struct dirent *dirent = (struct dirent *) readdir (dirp);
1356 if (dirent != NULL)
1358 strcpy (buffer, dirent->d_name);
1359 *len = strlen (buffer);
1360 return buffer;
1362 else
1363 return NULL;
1365 #endif
1368 /* Close a directory entry. */
1370 int __gnat_closedir (DIR *dirp)
1372 #if defined (__MINGW32__)
1373 return _tclosedir ((_TDIR*)dirp);
1375 #else
1376 return closedir (dirp);
1377 #endif
1380 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1383 __gnat_readdir_is_thread_safe (void)
1385 #ifdef HAVE_READDIR_R
1386 return 1;
1387 #else
1388 return 0;
1389 #endif
1392 #if defined (_WIN32)
1393 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1394 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1396 /* Returns the file modification timestamp using Win32 routines which are
1397 immune against daylight saving time change. It is in fact not possible to
1398 use fstat for this purpose as the DST modify the st_mtime field of the
1399 stat structure. */
1401 static time_t
1402 win32_filetime (HANDLE h)
1404 union
1406 FILETIME ft_time;
1407 unsigned long long ull_time;
1408 } t_write;
1410 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1411 since <Jan 1st 1601>. This function must return the number of seconds
1412 since <Jan 1st 1970>. */
1414 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1415 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1416 return (time_t) 0;
1419 /* As above but starting from a FILETIME. */
1420 static void
1421 f2t (const FILETIME *ft, __time64_t *t)
1423 union
1425 FILETIME ft_time;
1426 unsigned long long ull_time;
1427 } t_write;
1429 t_write.ft_time = *ft;
1430 *t = (__time64_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1432 #endif
1434 /* Return a GNAT time stamp given a file name. */
1436 OS_Time
1437 __gnat_file_time_name_attr (char* name, struct file_attributes* attr)
1439 if (attr->timestamp == (OS_Time)-2) {
1440 #if defined (_WIN32)
1441 BOOL res;
1442 WIN32_FILE_ATTRIBUTE_DATA fad;
1443 __time64_t ret = -1;
1444 TCHAR wname[GNAT_MAX_PATH_LEN];
1445 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1447 if ((res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad)))
1448 f2t (&fad.ftLastWriteTime, &ret);
1449 attr->timestamp = (OS_Time) ret;
1450 #else
1451 __gnat_stat_to_attr (-1, name, attr);
1452 #endif
1454 return attr->timestamp;
1457 OS_Time
1458 __gnat_file_time_name (char *name)
1460 struct file_attributes attr;
1461 __gnat_reset_attributes (&attr);
1462 return __gnat_file_time_name_attr (name, &attr);
1465 /* Return a GNAT time stamp given a file descriptor. */
1467 OS_Time
1468 __gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
1470 if (attr->timestamp == (OS_Time)-2) {
1471 #if defined (_WIN32)
1472 HANDLE h = (HANDLE) _get_osfhandle (fd);
1473 time_t ret = win32_filetime (h);
1474 attr->timestamp = (OS_Time) ret;
1476 #else
1477 __gnat_stat_to_attr (fd, NULL, attr);
1478 #endif
1481 return attr->timestamp;
1484 OS_Time
1485 __gnat_file_time_fd (int fd)
1487 struct file_attributes attr;
1488 __gnat_reset_attributes (&attr);
1489 return __gnat_file_time_fd_attr (fd, &attr);
1492 extern long long __gnat_file_time(char* name)
1494 long long result;
1496 if (name == NULL) {
1497 return LLONG_MIN;
1499 /* Number of seconds between <Jan 1st 1970> and <Jan 1st 2150>. */
1500 static const long long ada_epoch_offset = (136 * 365 + 44 * 366) * 86400LL;
1501 #if defined(_WIN32)
1503 /* Number of 100 nanoseconds between <Jan 1st 1601> and <Jan 1st 2150>. */
1504 static const long long w32_epoch_offset =
1505 (11644473600LL + ada_epoch_offset) * 1E7;
1507 WIN32_FILE_ATTRIBUTE_DATA fad;
1508 union
1510 FILETIME ft_time;
1511 long long ll_time;
1512 } t_write;
1514 if (!GetFileAttributesExA(name, GetFileExInfoStandard, &fad)) {
1515 return LLONG_MIN;
1518 t_write.ft_time = fad.ftLastWriteTime;
1520 #if defined(__GNUG__) && __GNUG__ <= 4
1521 result = (t_write.ll_time - w32_epoch_offset) * 100;
1522 #else
1523 /* Next code similar to (t_write.ll_time - w32_epoch_offset) * 100
1524 but on overflow returns LLONG_MIN value. */
1526 if (__builtin_ssubll_overflow(t_write.ll_time, w32_epoch_offset, &result)) {
1527 return LLONG_MIN;
1530 if (__builtin_smulll_overflow(result, 100, &result)) {
1531 return LLONG_MIN;
1533 #endif
1535 #else
1537 struct stat sb;
1538 if (stat(name, &sb) != 0) {
1539 return LLONG_MIN;
1542 #if defined(__GNUG__) && __GNUG__ <= 4
1543 result = (sb.st_mtime - ada_epoch_offset) * 1E9;
1544 #if defined(st_mtime)
1545 result += sb.st_mtim.tv_nsec;
1546 #endif
1547 #else
1548 /* Next code similar to
1549 (sb.st_mtime - ada_epoch_offset) * 1E9 + sb.st_mtim.tv_nsec
1550 but on overflow returns LLONG_MIN value. */
1552 if (__builtin_ssubll_overflow(sb.st_mtime, ada_epoch_offset, &result)) {
1553 return LLONG_MIN;
1556 if (__builtin_smulll_overflow(result, 1E9, &result)) {
1557 return LLONG_MIN;
1560 #if defined(st_mtime)
1561 if (__builtin_saddll_overflow(result, sb.st_mtim.tv_nsec, &result)) {
1562 return LLONG_MIN;
1564 #endif
1565 #endif
1566 #endif
1567 return result;
1570 /* Set the file time stamp. */
1572 void
1573 __gnat_set_file_time_name (char *name, time_t time_stamp)
1575 #if defined (__vxworks)
1577 /* Code to implement __gnat_set_file_time_name for these systems. */
1579 #elif defined (_WIN32)
1580 union
1582 FILETIME ft_time;
1583 unsigned long long ull_time;
1584 } t_write;
1585 TCHAR wname[GNAT_MAX_PATH_LEN];
1587 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1589 HANDLE h = CreateFile
1590 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1591 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1592 NULL);
1593 if (h == INVALID_HANDLE_VALUE)
1594 return;
1595 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1596 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1597 /* Convert to 100 nanosecond units */
1598 t_write.ull_time *= 10000000ULL;
1600 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1601 CloseHandle (h);
1602 return;
1604 #else
1605 struct utimbuf utimbuf;
1606 time_t t;
1608 /* Set modification time to requested time. */
1609 utimbuf.modtime = time_stamp;
1611 /* Set access time to now in local time. */
1612 t = time (NULL);
1613 utimbuf.actime = mktime (localtime (&t));
1615 utime (name, &utimbuf);
1616 #endif
1619 /* Get the list of installed standard libraries from the
1620 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1621 key. */
1623 char *
1624 __gnat_get_libraries_from_registry (void)
1626 char *result = (char *) xmalloc (1);
1628 result[0] = '\0';
1630 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
1632 HKEY reg_key;
1633 DWORD name_size, value_size;
1634 char name[256];
1635 char value[256];
1636 DWORD type;
1637 DWORD index;
1638 LONG res;
1640 /* First open the key. */
1641 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1643 if (res == ERROR_SUCCESS)
1644 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1645 KEY_READ, &reg_key);
1647 if (res == ERROR_SUCCESS)
1648 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1650 if (res == ERROR_SUCCESS)
1651 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1653 /* If the key exists, read out all the values in it and concatenate them
1654 into a path. */
1655 for (index = 0; res == ERROR_SUCCESS; index++)
1657 value_size = name_size = 256;
1658 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
1659 &type, (LPBYTE)value, &value_size);
1661 if (res == ERROR_SUCCESS && type == REG_SZ)
1663 char *old_result = result;
1665 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1666 strcpy (result, old_result);
1667 strcat (result, value);
1668 strcat (result, ";");
1669 free (old_result);
1673 /* Remove the trailing ";". */
1674 if (result[0] != 0)
1675 result[strlen (result) - 1] = 0;
1677 #endif
1678 return result;
1681 /* Query information for the given file NAME and return it in STATBUF.
1682 * Returns 0 for success, or errno value for failure.
1685 __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1687 #ifdef __MINGW32__
1688 WIN32_FILE_ATTRIBUTE_DATA fad;
1689 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1690 int name_len;
1691 BOOL res;
1692 DWORD error;
1694 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1695 name_len = _tcslen (wname);
1697 if (name_len > GNAT_MAX_PATH_LEN)
1698 return EINVAL;
1700 ZeroMemory (statbuf, sizeof(GNAT_STRUCT_STAT));
1702 res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad);
1704 if (res == FALSE) {
1705 error = GetLastError();
1707 /* Check file existence using GetFileAttributes() which does not fail on
1708 special Windows files like con:, aux:, nul: etc... */
1710 if (GetFileAttributes(wname) != INVALID_FILE_ATTRIBUTES) {
1711 /* Just pretend that it is a regular and readable file */
1712 statbuf->st_mode = S_IFREG | S_IREAD | S_IWRITE;
1713 return 0;
1716 switch (error) {
1717 case ERROR_ACCESS_DENIED:
1718 case ERROR_SHARING_VIOLATION:
1719 case ERROR_LOCK_VIOLATION:
1720 case ERROR_SHARING_BUFFER_EXCEEDED:
1721 return EACCES;
1722 case ERROR_BUFFER_OVERFLOW:
1723 return ENAMETOOLONG;
1724 case ERROR_NOT_ENOUGH_MEMORY:
1725 return ENOMEM;
1726 default:
1727 return ENOENT;
1731 f2t (&fad.ftCreationTime, &statbuf->st_ctime);
1732 f2t (&fad.ftLastWriteTime, &statbuf->st_mtime);
1733 f2t (&fad.ftLastAccessTime, &statbuf->st_atime);
1735 statbuf->st_size =
1736 (__int64)fad.nFileSizeLow | (__int64)fad.nFileSizeHigh << 32;
1738 /* We do not have the S_IEXEC attribute, but this is not used on GNAT. */
1739 statbuf->st_mode = S_IREAD;
1741 if (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1742 statbuf->st_mode |= S_IFDIR;
1743 else
1744 statbuf->st_mode |= S_IFREG;
1746 if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1747 statbuf->st_mode |= S_IWRITE;
1749 return 0;
1751 #else
1752 return GNAT_STAT (name, statbuf) == 0 ? 0 : errno;
1753 #endif
1756 /*************************************************************************
1757 ** Check whether a file exists
1758 *************************************************************************/
1761 __gnat_file_exists_attr (char* name, struct file_attributes* attr)
1763 if (attr->exists == ATTR_UNSET)
1764 __gnat_stat_to_attr (-1, name, attr);
1766 return attr->exists;
1770 __gnat_file_exists (char *name)
1772 struct file_attributes attr;
1773 __gnat_reset_attributes (&attr);
1774 return __gnat_file_exists_attr (name, &attr);
1777 /**********************************************************************
1778 ** Whether name is an absolute path
1779 **********************************************************************/
1782 __gnat_is_absolute_path (char *name, int length)
1784 #ifdef __vxworks
1785 /* On VxWorks systems, an absolute path can be represented (depending on
1786 the host platform) as either /dir/file, or device:/dir/file, or
1787 device:drive_letter:/dir/file. */
1789 int index;
1791 if (name[0] == '/')
1792 return 1;
1794 for (index = 0; index < length; index++)
1796 if (name[index] == ':' &&
1797 ((name[index + 1] == '/') ||
1798 (isalpha (name[index + 1]) && index + 2 <= length &&
1799 name[index + 2] == '/')))
1800 return 1;
1802 else if (name[index] == '/')
1803 return 0;
1805 return 0;
1806 #else
1807 return (length != 0) &&
1808 (IS_DIRECTORY_SEPARATOR(*name)
1809 #if defined (WINNT) || defined(__DJGPP__)
1810 || (length > 2 && ISALPHA (name[0]) && name[1] == ':'
1811 && IS_DIRECTORY_SEPARATOR(name[2]))
1812 #endif
1814 #endif
1818 __gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
1820 if (attr->regular == ATTR_UNSET)
1821 __gnat_stat_to_attr (-1, name, attr);
1823 return attr->regular;
1827 __gnat_is_regular_file (char *name)
1829 struct file_attributes attr;
1831 __gnat_reset_attributes (&attr);
1832 return __gnat_is_regular_file_attr (name, &attr);
1836 __gnat_is_regular_file_fd (int fd)
1838 int ret;
1839 GNAT_STRUCT_STAT statbuf;
1841 ret = GNAT_FSTAT (fd, &statbuf);
1842 return (!ret && S_ISREG (statbuf.st_mode));
1846 __gnat_is_directory_attr (char* name, struct file_attributes* attr)
1848 if (attr->directory == ATTR_UNSET)
1849 __gnat_stat_to_attr (-1, name, attr);
1851 return attr->directory;
1855 __gnat_is_directory (char *name)
1857 struct file_attributes attr;
1859 __gnat_reset_attributes (&attr);
1860 return __gnat_is_directory_attr (name, &attr);
1863 #if defined (_WIN32)
1865 /* Returns the same constant as GetDriveType but takes a pathname as
1866 argument. */
1868 static UINT
1869 GetDriveTypeFromPath (TCHAR *wfullpath)
1871 TCHAR wdrv[MAX_PATH];
1872 TCHAR wpath[MAX_PATH];
1873 TCHAR wfilename[MAX_PATH];
1874 TCHAR wext[MAX_PATH];
1876 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1878 if (_tcslen (wdrv) != 0)
1880 /* we have a drive specified. */
1881 _tcscat (wdrv, _T("\\"));
1882 return GetDriveType (wdrv);
1884 else
1886 /* No drive specified. */
1888 /* Is this a relative path, if so get current drive type. */
1889 if (wpath[0] != _T('\\') ||
1890 (_tcslen (wpath) > 2 && wpath[0] == _T('\\')
1891 && wpath[1] != _T('\\')))
1892 return GetDriveType (NULL);
1894 UINT result = GetDriveType (wpath);
1896 /* Cannot guess the drive type, is this \\.\ ? */
1898 if (result == DRIVE_NO_ROOT_DIR &&
1899 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1900 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1902 if (_tcslen (wpath) == 4)
1903 _tcscat (wpath, wfilename);
1905 LPTSTR p = &wpath[4];
1906 LPTSTR b = _tcschr (p, _T('\\'));
1908 if (b != NULL)
1910 /* logical drive \\.\c\dir\file */
1911 *b++ = _T(':');
1912 *b++ = _T('\\');
1913 *b = _T('\0');
1915 else
1916 _tcscat (p, _T(":\\"));
1918 return GetDriveType (p);
1921 return result;
1925 /* This MingW section contains code to work with ACL. */
1926 static int
1927 __gnat_check_OWNER_ACL (TCHAR *wname,
1928 DWORD CheckAccessDesired,
1929 GENERIC_MAPPING CheckGenericMapping)
1931 DWORD dwAccessDesired, dwAccessAllowed;
1932 PRIVILEGE_SET PrivilegeSet;
1933 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1934 BOOL fAccessGranted = FALSE;
1935 HANDLE hToken = NULL;
1936 DWORD nLength = 0;
1937 PSECURITY_DESCRIPTOR pSD = NULL;
1939 GetFileSecurity
1940 (wname, OWNER_SECURITY_INFORMATION |
1941 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1942 NULL, 0, &nLength);
1944 if ((pSD = (SECURITY_DESCRIPTOR *) HeapAlloc
1945 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1946 return 0;
1948 /* Obtain the security descriptor. */
1950 if (!GetFileSecurity
1951 (wname, OWNER_SECURITY_INFORMATION |
1952 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1953 pSD, nLength, &nLength))
1954 goto error;
1956 if (!ImpersonateSelf (SecurityImpersonation))
1957 goto error;
1959 if (!OpenThreadToken
1960 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1961 goto error;
1963 /* Undoes the effect of ImpersonateSelf. */
1965 RevertToSelf ();
1967 /* We want to test for write permissions. */
1969 dwAccessDesired = CheckAccessDesired;
1971 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1973 if (!AccessCheck
1974 (pSD , /* security descriptor to check */
1975 hToken, /* impersonation token */
1976 dwAccessDesired, /* requested access rights */
1977 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1978 &PrivilegeSet, /* receives privileges used in check */
1979 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1980 &dwAccessAllowed, /* receives mask of allowed access rights */
1981 &fAccessGranted))
1982 goto error;
1984 CloseHandle (hToken);
1985 HeapFree (GetProcessHeap (), 0, pSD);
1986 return fAccessGranted;
1988 error:
1989 if (hToken)
1990 CloseHandle (hToken);
1991 HeapFree (GetProcessHeap (), 0, pSD);
1992 return 0;
1995 static void
1996 __gnat_set_OWNER_ACL (TCHAR *wname,
1997 ACCESS_MODE AccessMode,
1998 DWORD AccessPermissions)
2000 PACL pOldDACL = NULL;
2001 PACL pNewDACL = NULL;
2002 PSECURITY_DESCRIPTOR pSD = NULL;
2003 EXPLICIT_ACCESS ea;
2004 TCHAR username [100];
2005 DWORD unsize = 100;
2007 /* Get current user, he will act as the owner */
2009 if (!GetUserName (username, &unsize))
2010 return;
2012 if (GetNamedSecurityInfo
2013 (wname,
2014 SE_FILE_OBJECT,
2015 DACL_SECURITY_INFORMATION,
2016 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
2017 return;
2019 BuildExplicitAccessWithName
2020 (&ea, username, AccessPermissions, (ACCESS_MODE) AccessMode, NO_INHERITANCE);
2022 if (AccessMode == SET_ACCESS)
2024 /* SET_ACCESS, we want to set an explicte set of permissions, do not
2025 merge with current DACL. */
2026 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
2027 return;
2029 else
2030 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
2031 return;
2033 if (SetNamedSecurityInfo
2034 (wname, SE_FILE_OBJECT,
2035 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
2036 return;
2038 LocalFree (pSD);
2039 LocalFree (pNewDACL);
2042 /* Check if it is possible to use ACL for wname, the file must not be on a
2043 network drive. */
2045 static int
2046 __gnat_can_use_acl (TCHAR *wname)
2048 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
2051 #endif /* defined (_WIN32) */
2054 __gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
2056 if (attr->readable == ATTR_UNSET)
2058 #if defined (_WIN32)
2059 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2060 GENERIC_MAPPING GenericMapping;
2062 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2064 if (__gnat_can_use_acl (wname))
2066 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2067 GenericMapping.GenericRead = GENERIC_READ;
2068 attr->readable =
2069 __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
2071 else
2072 attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
2073 #else
2074 __gnat_stat_to_attr (-1, name, attr);
2075 #endif
2078 return attr->readable;
2082 __gnat_is_read_accessible_file (char *name)
2084 #if defined (_WIN32)
2085 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2087 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2089 return !_waccess (wname, 4);
2091 #elif defined (__vxworks)
2092 int fd;
2094 if ((fd = open (name, O_RDONLY, 0)) < 0)
2095 return 0;
2096 close (fd);
2097 return 1;
2099 #else
2100 return !access (name, R_OK);
2101 #endif
2105 __gnat_is_readable_file (char *name)
2107 struct file_attributes attr;
2109 __gnat_reset_attributes (&attr);
2110 return __gnat_is_readable_file_attr (name, &attr);
2114 __gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
2116 if (attr->writable == ATTR_UNSET)
2118 #if defined (_WIN32)
2119 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2120 GENERIC_MAPPING GenericMapping;
2122 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2124 if (__gnat_can_use_acl (wname))
2126 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2127 GenericMapping.GenericWrite = GENERIC_WRITE;
2129 attr->writable = __gnat_check_OWNER_ACL
2130 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
2131 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2133 else
2134 attr->writable =
2135 !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2137 #else
2138 __gnat_stat_to_attr (-1, name, attr);
2139 #endif
2142 return attr->writable;
2146 __gnat_is_writable_file (char *name)
2148 struct file_attributes attr;
2150 __gnat_reset_attributes (&attr);
2151 return __gnat_is_writable_file_attr (name, &attr);
2155 __gnat_is_write_accessible_file (char *name)
2157 #if defined (_WIN32)
2158 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2160 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2162 return !_waccess (wname, 2);
2164 #elif defined (__vxworks)
2165 int fd;
2167 if ((fd = open (name, O_WRONLY, 0)) < 0)
2168 return 0;
2169 close (fd);
2170 return 1;
2172 #else
2173 return !access (name, W_OK);
2174 #endif
2178 __gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
2180 if (attr->executable == ATTR_UNSET)
2182 #if defined (_WIN32)
2183 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2184 GENERIC_MAPPING GenericMapping;
2186 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2188 if (__gnat_can_use_acl (wname))
2190 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2191 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2193 attr->executable =
2194 __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2196 else
2198 TCHAR *l, *last = _tcsstr(wname, _T(".exe"));
2200 /* look for last .exe */
2201 if (last)
2202 while ((l = _tcsstr(last+1, _T(".exe"))))
2203 last = l;
2205 attr->executable =
2206 GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2207 && (last - wname) == (int) (_tcslen (wname) - 4);
2209 #else
2210 __gnat_stat_to_attr (-1, name, attr);
2211 #endif
2214 return attr->regular && attr->executable;
2218 __gnat_is_executable_file (char *name)
2220 struct file_attributes attr;
2222 __gnat_reset_attributes (&attr);
2223 return __gnat_is_executable_file_attr (name, &attr);
2226 void
2227 __gnat_set_writable (char *name)
2229 #if defined (_WIN32)
2230 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2232 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2234 if (__gnat_can_use_acl (wname))
2235 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2237 SetFileAttributes
2238 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
2239 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2240 GNAT_STRUCT_STAT statbuf;
2242 if (GNAT_STAT (name, &statbuf) == 0)
2244 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2245 chmod (name, statbuf.st_mode);
2247 #endif
2250 /* must match definition in s-os_lib.ads */
2251 #define S_OWNER 1
2252 #define S_GROUP 2
2253 #define S_OTHERS 4
2255 void
2256 __gnat_set_executable (char *name, int mode ATTRIBUTE_UNUSED)
2258 #if defined (_WIN32)
2259 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2261 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2263 if (__gnat_can_use_acl (wname))
2264 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
2266 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2267 GNAT_STRUCT_STAT statbuf;
2269 if (GNAT_STAT (name, &statbuf) == 0)
2271 if (mode & S_OWNER)
2272 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2273 if (mode & S_GROUP)
2274 statbuf.st_mode = statbuf.st_mode | S_IXGRP;
2275 if (mode & S_OTHERS)
2276 statbuf.st_mode = statbuf.st_mode | S_IXOTH;
2277 chmod (name, statbuf.st_mode);
2279 #endif
2282 void
2283 __gnat_set_non_writable (char *name)
2285 #if defined (_WIN32)
2286 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2288 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2290 if (__gnat_can_use_acl (wname))
2291 __gnat_set_OWNER_ACL
2292 (wname, DENY_ACCESS,
2293 FILE_WRITE_DATA | FILE_APPEND_DATA |
2294 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2296 SetFileAttributes
2297 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
2298 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2299 GNAT_STRUCT_STAT statbuf;
2301 if (GNAT_STAT (name, &statbuf) == 0)
2303 statbuf.st_mode = statbuf.st_mode & 07577;
2304 chmod (name, statbuf.st_mode);
2306 #endif
2309 void
2310 __gnat_set_readable (char *name)
2312 #if defined (_WIN32)
2313 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2315 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2317 if (__gnat_can_use_acl (wname))
2318 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
2320 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2321 GNAT_STRUCT_STAT statbuf;
2323 if (GNAT_STAT (name, &statbuf) == 0)
2325 chmod (name, statbuf.st_mode | S_IREAD);
2327 #endif
2330 void
2331 __gnat_set_non_readable (char *name)
2333 #if defined (_WIN32)
2334 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2336 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2338 if (__gnat_can_use_acl (wname))
2339 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
2341 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2342 GNAT_STRUCT_STAT statbuf;
2344 if (GNAT_STAT (name, &statbuf) == 0)
2346 chmod (name, statbuf.st_mode & (~S_IREAD));
2348 #endif
2352 __gnat_is_symbolic_link_attr (char* name ATTRIBUTE_UNUSED,
2353 struct file_attributes* attr)
2355 if (attr->symbolic_link == ATTR_UNSET)
2357 #if defined (__vxworks)
2358 attr->symbolic_link = 0;
2360 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2361 int ret;
2362 GNAT_STRUCT_STAT statbuf;
2363 ret = GNAT_LSTAT (name, &statbuf);
2364 attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
2365 #else
2366 attr->symbolic_link = 0;
2367 #endif
2369 return attr->symbolic_link;
2373 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2375 struct file_attributes attr;
2377 __gnat_reset_attributes (&attr);
2378 return __gnat_is_symbolic_link_attr (name, &attr);
2381 #if defined (__sun__)
2382 /* Using fork on Solaris will duplicate all the threads. fork1, which
2383 duplicates only the active thread, must be used instead, or spawning
2384 subprocess from a program with tasking will lead into numerous problems. */
2385 #define fork fork1
2386 #endif
2389 __gnat_portable_spawn (char *args[] ATTRIBUTE_UNUSED)
2391 int status ATTRIBUTE_UNUSED = 0;
2392 int finished ATTRIBUTE_UNUSED;
2393 int pid ATTRIBUTE_UNUSED;
2395 #if defined (__vxworks) || defined(__PikeOS__)
2396 return -1;
2398 #elif defined (__DJGPP__) || defined (_WIN32)
2399 /* args[0] must be quotes as it could contain a full pathname with spaces */
2400 char *args_0 = args[0];
2401 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2402 strcpy (args[0], "\"");
2403 strcat (args[0], args_0);
2404 strcat (args[0], "\"");
2406 status = spawnvp (P_WAIT, args_0, (char ** const)args);
2408 /* restore previous value */
2409 free (args[0]);
2410 args[0] = (char *)args_0;
2412 if (status < 0)
2413 return -1;
2414 else
2415 return status;
2417 #else
2419 pid = fork ();
2420 if (pid < 0)
2421 return -1;
2423 if (pid == 0)
2425 /* The child. */
2426 __gnat_in_child_after_fork = 1;
2427 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2428 _exit (1);
2431 /* The parent. */
2432 finished = waitpid (pid, &status, 0);
2434 if (finished != pid || WIFEXITED (status) == 0)
2435 return -1;
2437 return WEXITSTATUS (status);
2438 #endif
2440 return 0;
2443 /* Create a copy of the given file descriptor.
2444 Return -1 if an error occurred. */
2447 __gnat_dup (int oldfd)
2449 #if defined (__vxworks) && !defined (__RTP__)
2450 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2451 RTPs. */
2452 return -1;
2453 #else
2454 return dup (oldfd);
2455 #endif
2458 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2459 Return -1 if an error occurred. */
2462 __gnat_dup2 (int oldfd ATTRIBUTE_UNUSED, int newfd ATTRIBUTE_UNUSED)
2464 #if defined (__vxworks) && !defined (__RTP__)
2465 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2466 RTPs. */
2467 return -1;
2468 #elif defined (__PikeOS__)
2469 /* Not supported. */
2470 return -1;
2471 #elif defined (_WIN32)
2472 /* Special case when oldfd and newfd are identical and are the standard
2473 input, output or error as this makes Windows XP hangs. Note that we
2474 do that only for standard file descriptors that are known to be valid. */
2475 if (oldfd == newfd && newfd >= 0 && newfd <= 2)
2476 return newfd;
2477 else
2478 return dup2 (oldfd, newfd);
2479 #else
2480 return dup2 (oldfd, newfd);
2481 #endif
2485 __gnat_number_of_cpus (void)
2487 int cores = 1;
2489 #ifdef _SC_NPROCESSORS_ONLN
2490 cores = (int) sysconf (_SC_NPROCESSORS_ONLN);
2492 #elif defined (__QNX__)
2493 cores = (int) _syspage_ptr->num_cpu;
2495 #elif defined (__hpux__)
2496 struct pst_dynamic psd;
2497 if (pstat_getdynamic (&psd, sizeof (psd), 1, 0) != -1)
2498 cores = (int) psd.psd_proc_cnt;
2500 #elif defined (_WIN32)
2501 SYSTEM_INFO sysinfo;
2502 GetSystemInfo (&sysinfo);
2503 cores = (int) sysinfo.dwNumberOfProcessors;
2505 #elif defined (_WRS_CONFIG_SMP)
2506 unsigned int vxCpuConfiguredGet (void);
2508 cores = vxCpuConfiguredGet ();
2510 #endif
2512 return cores;
2515 /* WIN32 code to implement a wait call that wait for any child process. */
2517 #if defined (_WIN32)
2519 /* Synchronization code, to be thread safe. */
2521 #ifdef CERT
2523 /* For the Cert run times on native Windows we use dummy functions
2524 for locking and unlocking tasks since we do not support multiple
2525 threads on this configuration (Cert run time on native Windows). */
2527 static void EnterCS (void) {}
2528 static void LeaveCS (void) {}
2529 static void SignalListChanged (void) {}
2531 #else
2533 CRITICAL_SECTION ProcListCS;
2534 HANDLE ProcListEvt = NULL;
2536 static void EnterCS (void)
2538 EnterCriticalSection(&ProcListCS);
2541 static void LeaveCS (void)
2543 LeaveCriticalSection(&ProcListCS);
2546 static void SignalListChanged (void)
2548 SetEvent (ProcListEvt);
2551 #endif
2553 static HANDLE *HANDLES_LIST = NULL;
2554 static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
2556 static void
2557 add_handle (HANDLE h, int pid)
2559 /* -------------------- critical section -------------------- */
2560 EnterCS();
2562 if (plist_length == plist_max_length)
2564 plist_max_length += 100;
2565 HANDLES_LIST =
2566 (HANDLE *) xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2567 PID_LIST =
2568 (int *) xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2571 HANDLES_LIST[plist_length] = h;
2572 PID_LIST[plist_length] = pid;
2573 ++plist_length;
2575 SignalListChanged();
2576 LeaveCS();
2577 /* -------------------- critical section -------------------- */
2581 __gnat_win32_remove_handle (HANDLE h, int pid)
2583 int j;
2584 int found = 0;
2586 /* -------------------- critical section -------------------- */
2587 EnterCS();
2589 for (j = 0; j < plist_length; j++)
2591 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
2593 CloseHandle (h);
2594 --plist_length;
2595 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2596 PID_LIST[j] = PID_LIST[plist_length];
2597 found = 1;
2598 break;
2602 LeaveCS();
2603 /* -------------------- critical section -------------------- */
2605 if (found)
2606 SignalListChanged();
2608 return found;
2611 static void
2612 win32_no_block_spawn (char *command, char *args[], HANDLE *h, int *pid)
2614 BOOL result;
2615 STARTUPINFO SI;
2616 PROCESS_INFORMATION PI;
2617 SECURITY_ATTRIBUTES SA;
2618 int csize = 1;
2619 char *full_command;
2620 int k;
2622 /* compute the total command line length */
2623 k = 0;
2624 while (args[k])
2626 csize += strlen (args[k]) + 1;
2627 k++;
2630 full_command = (char *) xmalloc (csize);
2632 /* Startup info. */
2633 SI.cb = sizeof (STARTUPINFO);
2634 SI.lpReserved = NULL;
2635 SI.lpReserved2 = NULL;
2636 SI.lpDesktop = NULL;
2637 SI.cbReserved2 = 0;
2638 SI.lpTitle = NULL;
2639 SI.dwFlags = 0;
2640 SI.wShowWindow = SW_HIDE;
2642 /* Security attributes. */
2643 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2644 SA.bInheritHandle = TRUE;
2645 SA.lpSecurityDescriptor = NULL;
2647 /* Prepare the command string. */
2648 strcpy (full_command, command);
2649 strcat (full_command, " ");
2651 k = 1;
2652 while (args[k])
2654 strcat (full_command, args[k]);
2655 strcat (full_command, " ");
2656 k++;
2660 int wsize = csize * 2;
2661 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2663 S2WSC (wcommand, full_command, wsize);
2665 free (full_command);
2667 result = CreateProcess
2668 (NULL, wcommand, &SA, NULL, TRUE,
2669 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2671 free (wcommand);
2674 if (result == TRUE)
2676 CloseHandle (PI.hThread);
2677 *h = PI.hProcess;
2678 *pid = PI.dwProcessId;
2680 else
2682 *h = NULL;
2683 *pid = 0;
2687 static int
2688 win32_wait (int *status)
2690 DWORD exitcode, pid;
2691 HANDLE *hl;
2692 HANDLE h;
2693 int *pidl;
2694 DWORD res;
2695 int hl_len;
2696 int found;
2697 int pos;
2699 START_WAIT:
2701 if (plist_length == 0)
2703 errno = ECHILD;
2704 return -1;
2707 /* -------------------- critical section -------------------- */
2708 EnterCS();
2710 /* ??? We can't wait for more than MAXIMUM_WAIT_OBJECTS due to a Win32
2711 limitation */
2712 if (plist_length < MAXIMUM_WAIT_OBJECTS)
2713 hl_len = plist_length;
2714 else
2716 errno = EINVAL;
2717 return -1;
2720 #ifdef CERT
2721 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2722 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
2723 pidl = (int *) xmalloc (sizeof (int) * hl_len);
2724 memmove (pidl, PID_LIST, sizeof (int) * hl_len);
2725 #else
2726 /* Note that index 0 contains the event handle that is signaled when the
2727 process list has changed */
2728 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * (hl_len + 1));
2729 hl[0] = ProcListEvt;
2730 memmove (&hl[1], HANDLES_LIST, sizeof (HANDLE) * hl_len);
2731 pidl = (int *) xmalloc (sizeof (int) * (hl_len + 1));
2732 memmove (&pidl[1], PID_LIST, sizeof (int) * hl_len);
2733 hl_len++;
2734 #endif
2736 LeaveCS();
2737 /* -------------------- critical section -------------------- */
2739 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2741 /* If there was an error, exit now */
2742 if (res == WAIT_FAILED)
2744 free (hl);
2745 free (pidl);
2746 errno = EINVAL;
2747 return -1;
2750 /* if the ProcListEvt has been signaled then the list of processes has been
2751 updated to add or remove a handle, just loop over */
2753 if (res - WAIT_OBJECT_0 == 0)
2755 free (hl);
2756 free (pidl);
2757 goto START_WAIT;
2760 /* Handle two distinct groups of return codes: finished waits and abandoned
2761 waits */
2763 if (res < WAIT_ABANDONED_0)
2764 pos = res - WAIT_OBJECT_0;
2765 else
2766 pos = res - WAIT_ABANDONED_0;
2768 h = hl[pos];
2769 GetExitCodeProcess (h, &exitcode);
2770 pid = pidl [pos];
2772 found = __gnat_win32_remove_handle (h, -1);
2774 free (hl);
2775 free (pidl);
2777 /* if not found another process waiting has already handled this process */
2779 if (!found)
2781 goto START_WAIT;
2784 *status = (int) exitcode;
2785 return (int) pid;
2788 #endif
2791 __gnat_portable_no_block_spawn (char *args[] ATTRIBUTE_UNUSED)
2794 #if defined (__vxworks) || defined (__PikeOS__)
2795 /* Not supported. */
2796 return -1;
2798 #elif defined(__DJGPP__)
2799 if (spawnvp (P_WAIT, args[0], args) != 0)
2800 return -1;
2801 else
2802 return 0;
2804 #elif defined (_WIN32)
2806 HANDLE h = NULL;
2807 int pid;
2809 win32_no_block_spawn (args[0], args, &h, &pid);
2810 if (h != NULL)
2812 add_handle (h, pid);
2813 return pid;
2815 else
2816 return -1;
2818 #else
2820 int pid = fork ();
2822 if (pid == 0)
2824 /* The child. */
2825 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2826 _exit (1);
2829 return pid;
2831 #endif
2835 __gnat_portable_wait (int *process_status)
2837 int status = 0;
2838 int pid = 0;
2840 #if defined (__vxworks) || defined (__PikeOS__)
2841 /* Not sure what to do here, so do nothing but return zero. */
2843 #elif defined (_WIN32)
2845 pid = win32_wait (&status);
2847 #elif defined (__DJGPP__)
2848 /* Child process has already ended in case of DJGPP.
2849 No need to do anything. Just return success. */
2850 #else
2852 pid = waitpid (-1, &status, 0);
2853 status = status & 0xffff;
2854 #endif
2856 *process_status = status;
2857 return pid;
2861 __gnat_portable_no_block_wait (int *process_status)
2863 int status = 0;
2864 int pid = 0;
2866 #if defined (__vxworks) || defined (__PikeOS__) || defined (_WIN32)
2867 /* Not supported. */
2868 status = -1;
2870 #else
2872 pid = waitpid (-1, &status, WNOHANG);
2873 status = status & 0xffff;
2874 #endif
2876 *process_status = status;
2877 return pid;
2880 void
2881 __gnat_os_exit (int status)
2883 exit (status);
2887 __gnat_current_process_id (void)
2889 #if defined (__vxworks) || defined (__PikeOS__)
2890 return -1;
2892 #elif defined (_WIN32)
2894 return (int)GetCurrentProcessId();
2896 #else
2898 return (int)getpid();
2899 #endif
2902 /* Locate file on path, that matches a predicate */
2904 char *
2905 __gnat_locate_file_with_predicate (char *file_name, char *path_val,
2906 int (*predicate)(char *))
2908 char *ptr;
2909 char *file_path = (char *) alloca (strlen (file_name) + 1);
2910 int absolute;
2912 /* Return immediately if file_name is empty */
2914 if (*file_name == '\0')
2915 return 0;
2917 /* Remove quotes around file_name if present */
2919 ptr = file_name;
2920 if (*ptr == '"')
2921 ptr++;
2923 strcpy (file_path, ptr);
2925 ptr = file_path + strlen (file_path) - 1;
2927 if (*ptr == '"')
2928 *ptr = '\0';
2930 /* Handle absolute pathnames. */
2932 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2934 if (absolute)
2936 if (predicate (file_path))
2937 return xstrdup (file_path);
2939 return 0;
2942 /* If file_name include directory separator(s), try it first as
2943 a path name relative to the current directory */
2944 for (ptr = file_name; *ptr && !IS_DIRECTORY_SEPARATOR(*ptr); ptr++)
2947 if (*ptr != 0)
2949 if (predicate (file_name))
2950 return xstrdup (file_name);
2953 if (path_val == 0)
2954 return 0;
2957 /* The result has to be smaller than path_val + file_name. */
2958 char *file_path =
2959 (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2961 for (;;)
2963 /* Skip the starting quote */
2965 if (*path_val == '"')
2966 path_val++;
2968 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2969 *ptr++ = *path_val++;
2971 /* If directory is empty, it is the current directory*/
2973 if (ptr == file_path)
2975 *ptr = '.';
2977 else
2978 ptr--;
2980 /* Skip the ending quote */
2982 if (*ptr == '"')
2983 ptr--;
2985 if (!IS_DIRECTORY_SEPARATOR(*ptr))
2986 *++ptr = DIR_SEPARATOR;
2988 strcpy (++ptr, file_name);
2990 if (predicate (file_path))
2991 return xstrdup (file_path);
2993 if (*path_val == 0)
2994 return 0;
2996 /* Skip path separator */
2998 path_val++;
3002 return 0;
3005 /* Locate an executable file, give a Path value. */
3007 char *
3008 __gnat_locate_executable_file (char *file_name, char *path_val)
3010 return __gnat_locate_file_with_predicate
3011 (file_name, path_val, &__gnat_is_executable_file);
3014 /* Locate a regular file, give a Path value. */
3016 char *
3017 __gnat_locate_regular_file (char *file_name, char *path_val)
3019 return __gnat_locate_file_with_predicate
3020 (file_name, path_val, &__gnat_is_regular_file);
3023 /* Locate an executable given a Path argument. This routine is only used by
3024 gnatbl and should not be used otherwise. Use locate_exec_on_path
3025 instead. */
3027 char *
3028 __gnat_locate_exec (char *exec_name, char *path_val)
3030 const unsigned int len = strlen (HOST_EXECUTABLE_SUFFIX);
3031 char *ptr;
3033 if (len > 0 && !strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
3035 char *full_exec_name = (char *) alloca (strlen (exec_name) + len + 1);
3037 strcpy (full_exec_name, exec_name);
3038 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
3039 ptr = __gnat_locate_executable_file (full_exec_name, path_val);
3041 if (ptr == 0)
3042 return __gnat_locate_executable_file (exec_name, path_val);
3043 return ptr;
3045 else
3046 return __gnat_locate_executable_file (exec_name, path_val);
3049 /* Locate an executable using the Systems default PATH. */
3051 char *
3052 __gnat_locate_exec_on_path (char *exec_name)
3054 char *apath_val;
3056 #if defined (_WIN32)
3057 TCHAR *wpath_val = _tgetenv (_T("PATH"));
3058 TCHAR *wapath_val;
3059 /* In Win32 systems we expand the PATH as for XP environment
3060 variables are not automatically expanded. We also prepend the
3061 ".;" to the path to match normal NT path search semantics */
3063 #define EXPAND_BUFFER_SIZE 32767
3065 wapath_val = (TCHAR *) alloca (EXPAND_BUFFER_SIZE);
3067 wapath_val [0] = '.';
3068 wapath_val [1] = ';';
3070 DWORD res = ExpandEnvironmentStrings
3071 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
3073 if (!res) wapath_val [0] = _T('\0');
3075 apath_val = (char *) alloca (EXPAND_BUFFER_SIZE);
3077 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
3079 #else
3080 const char *path_val = getenv ("PATH");
3082 /* If PATH is not defined, proceed with __gnat_locate_exec anyway, so we can
3083 find files that contain directory names. */
3085 if (path_val == NULL) path_val = "";
3086 apath_val = (char *) alloca (strlen (path_val) + 1);
3087 strcpy (apath_val, path_val);
3088 #endif
3090 return __gnat_locate_exec (exec_name, apath_val);
3093 /* Dummy functions for Osint import for non-VMS systems.
3094 ??? To be removed. */
3097 __gnat_to_canonical_file_list_init (char *dirspec ATTRIBUTE_UNUSED,
3098 int onlydirs ATTRIBUTE_UNUSED)
3100 return 0;
3103 char *
3104 __gnat_to_canonical_file_list_next (void)
3106 static char empty[] = "";
3107 return empty;
3110 void
3111 __gnat_to_canonical_file_list_free (void)
3115 char *
3116 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3118 return dirspec;
3121 char *
3122 __gnat_to_canonical_file_spec (char *filespec)
3124 return filespec;
3127 char *
3128 __gnat_to_canonical_path_spec (char *pathspec)
3130 return pathspec;
3133 char *
3134 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3136 return dirspec;
3139 char *
3140 __gnat_to_host_file_spec (char *filespec)
3142 return filespec;
3145 void
3146 __gnat_adjust_os_resource_limits (void)
3150 #if defined (__mips_vxworks)
3152 _flush_cache (void)
3154 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3156 #endif
3158 #if defined (_WIN32)
3159 int __gnat_argument_needs_quote = 1;
3160 #else
3161 int __gnat_argument_needs_quote = 0;
3162 #endif
3164 /* This option is used to enable/disable object files handling from the
3165 binder file by the GNAT Project module. For example, this is disabled on
3166 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3167 Stating with GCC 3.4 the shared libraries are not based on mdll
3168 anymore as it uses the GCC's -shared option */
3169 #if defined (_WIN32) \
3170 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3171 int __gnat_prj_add_obj_files = 0;
3172 #else
3173 int __gnat_prj_add_obj_files = 1;
3174 #endif
3176 /* char used as prefix/suffix for environment variables */
3177 #if defined (_WIN32)
3178 char __gnat_environment_char = '%';
3179 #else
3180 char __gnat_environment_char = '$';
3181 #endif
3183 /* This functions copy the file attributes from a source file to a
3184 destination file.
3186 mode = 0 : In this mode copy only the file time stamps (last access and
3187 last modification time stamps).
3189 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3190 copied.
3192 mode = 2 : In this mode, only read/write/execute attributes are copied
3194 Returns 0 if operation was successful and -1 in case of error. */
3197 __gnat_copy_attribs (char *from ATTRIBUTE_UNUSED, char *to ATTRIBUTE_UNUSED,
3198 int mode ATTRIBUTE_UNUSED)
3200 #if (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
3201 return -1;
3203 #elif defined (_WIN32)
3204 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3205 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3206 BOOL res;
3207 FILETIME fct, flat, flwt;
3208 HANDLE hfrom, hto;
3210 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3211 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3213 /* Do we need to copy the timestamp ? */
3215 if (mode != 2) {
3216 /* retrieve from times */
3218 hfrom = CreateFile
3219 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING,
3220 FILE_ATTRIBUTE_NORMAL, NULL);
3222 if (hfrom == INVALID_HANDLE_VALUE)
3223 return -1;
3225 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3227 CloseHandle (hfrom);
3229 if (res == 0)
3230 return -1;
3232 /* retrieve from times */
3234 hto = CreateFile
3235 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
3236 FILE_ATTRIBUTE_NORMAL, NULL);
3238 if (hto == INVALID_HANDLE_VALUE)
3239 return -1;
3241 res = SetFileTime (hto, NULL, &flat, &flwt);
3243 CloseHandle (hto);
3245 if (res == 0)
3246 return -1;
3249 /* Do we need to copy the permissions ? */
3250 /* Set file attributes in full mode. */
3252 if (mode != 0)
3254 DWORD attribs = GetFileAttributes (wfrom);
3256 if (attribs == INVALID_FILE_ATTRIBUTES)
3257 return -1;
3259 res = SetFileAttributes (wto, attribs);
3260 if (res == 0)
3261 return -1;
3264 return 0;
3266 #else
3267 GNAT_STRUCT_STAT fbuf;
3269 if (GNAT_STAT (from, &fbuf) == -1) {
3270 return -1;
3273 #if (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 7)
3275 /* VxWorks prior to 7 only has utime. */
3277 /* Do we need to copy the timestamp ? */
3278 if (mode != 2) {
3279 struct utimbuf tbuf;
3281 tbuf.actime = fbuf.st_atime;
3282 tbuf.modtime = fbuf.st_mtime;
3284 if (utime (to, &tbuf) == -1)
3285 return -1;
3288 #elif _POSIX_C_SOURCE >= 200809L
3289 struct timespec tbuf[2];
3291 if (mode != 2) {
3292 tbuf[0] = fbuf.st_atim;
3293 tbuf[1] = fbuf.st_mtim;
3295 if (utimensat (AT_FDCWD, to, tbuf, 0) == -1) {
3296 return -1;
3300 #else
3301 struct timeval tbuf[2];
3302 /* Do we need to copy timestamp ? */
3304 if (mode != 2) {
3305 tbuf[0].tv_sec = fbuf.st_atime;
3306 tbuf[1].tv_sec = fbuf.st_mtime;
3308 #if defined(st_mtime)
3309 tbuf[0].tv_usec = fbuf.st_atim.tv_nsec / 1000;
3310 tbuf[1].tv_usec = fbuf.st_mtim.tv_nsec / 1000;
3311 #else
3312 tbuf[0].tv_usec = 0;
3313 tbuf[1].tv_usec = 0;
3314 #endif
3316 if (utimes (to, tbuf) == -1) {
3317 return -1;
3320 #endif
3322 /* Do we need to copy file permissions ? */
3323 if (mode != 0 && (chmod (to, fbuf.st_mode) == -1)) {
3324 return -1;
3327 return 0;
3328 #endif
3332 __gnat_lseek (int fd, long offset, int whence)
3334 return (int) lseek (fd, offset, whence);
3337 /* This function returns the major version number of GCC being used. */
3339 get_gcc_version (void)
3341 #ifdef IN_RTS
3342 return __GNUC__;
3343 #else
3344 return (int) (version_string[0] - '0');
3345 #endif
3349 * Set Close_On_Exec as indicated.
3350 * Note: this is used for both GNAT.OS_Lib and GNAT.Sockets.
3354 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3355 int close_on_exec_p ATTRIBUTE_UNUSED)
3357 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3358 int flags = fcntl (fd, F_GETFD, 0);
3359 if (flags < 0)
3360 return flags;
3361 if (close_on_exec_p)
3362 flags |= FD_CLOEXEC;
3363 else
3364 flags &= ~FD_CLOEXEC;
3365 return fcntl (fd, F_SETFD, flags);
3366 #elif defined(_WIN32)
3367 HANDLE h = (HANDLE) _get_osfhandle (fd);
3368 if (h == (HANDLE) -1)
3369 return -1;
3370 if (close_on_exec_p)
3371 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3372 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3373 HANDLE_FLAG_INHERIT);
3374 #else
3375 /* TODO: Unimplemented. */
3376 return -1;
3377 #endif
3380 /* Indicates if platforms supports automatic initialization through the
3381 constructor mechanism */
3383 __gnat_binder_supports_auto_init (void)
3385 return 1;
3388 /* Indicates that Stand-Alone Libraries are automatically initialized through
3389 the constructor mechanism */
3391 __gnat_sals_init_using_constructors (void)
3393 #if defined (__vxworks) || defined (__Lynx__)
3394 return 0;
3395 #else
3396 return 1;
3397 #endif
3400 #if defined (__linux__) || defined (__ANDROID__)
3401 /* There is no function in the glibc to retrieve the LWP of the current
3402 thread. We need to do a system call in order to retrieve this
3403 information. */
3404 #include <sys/syscall.h>
3405 void *
3406 __gnat_lwp_self (void)
3408 return (void *) syscall (__NR_gettid);
3410 #endif
3412 #if defined (__APPLE__)
3413 # if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060
3414 # include <mach/thread_info.h>
3415 # include <mach/mach_init.h>
3416 # include <mach/thread_act.h>
3417 # else
3418 # include <pthread.h>
3419 # endif
3421 /* System-wide thread identifier. Note it could be truncated on 32 bit
3422 hosts.
3423 Previously was: pthread_mach_thread_np (pthread_self ()). */
3424 void *
3425 __gnat_lwp_self (void)
3427 #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060
3428 thread_identifier_info_data_t data;
3429 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
3430 kern_return_t kret;
3432 kret = thread_info (mach_thread_self (), THREAD_IDENTIFIER_INFO,
3433 (thread_info_t) &data, &count);
3434 if (kret == KERN_SUCCESS)
3435 return (void *)(uintptr_t)data.thread_id;
3436 else
3437 return 0;
3438 #else
3439 return (void *)pthread_mach_thread_np (pthread_self ());
3440 #endif
3442 #endif
3444 #if defined (__linux__)
3445 #include <sched.h>
3447 /* glibc versions earlier than 2.7 do not define the routines to handle
3448 dynamically allocated CPU sets. For these targets, we use the static
3449 versions. */
3451 #ifdef CPU_ALLOC
3453 /* Dynamic cpu sets */
3455 cpu_set_t *
3456 __gnat_cpu_alloc (size_t count)
3458 return CPU_ALLOC (count);
3461 size_t
3462 __gnat_cpu_alloc_size (size_t count)
3464 return CPU_ALLOC_SIZE (count);
3467 void
3468 __gnat_cpu_free (cpu_set_t *set)
3470 CPU_FREE (set);
3473 void
3474 __gnat_cpu_zero (size_t count, cpu_set_t *set)
3476 CPU_ZERO_S (count, set);
3479 void
3480 __gnat_cpu_set (int cpu, size_t count, cpu_set_t *set)
3482 /* Ada handles CPU numbers starting from 1, while C identifies the first
3483 CPU by a 0, so we need to adjust. */
3484 CPU_SET_S (cpu - 1, count, set);
3487 #else /* !CPU_ALLOC */
3489 /* Static cpu sets */
3491 cpu_set_t *
3492 __gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED)
3494 return (cpu_set_t *) xmalloc (sizeof (cpu_set_t));
3497 size_t
3498 __gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED)
3500 return sizeof (cpu_set_t);
3503 void
3504 __gnat_cpu_free (cpu_set_t *set)
3506 free (set);
3509 void
3510 __gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3512 CPU_ZERO (set);
3515 void
3516 __gnat_cpu_set (int cpu, size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3518 /* Ada handles CPU numbers starting from 1, while C identifies the first
3519 CPU by a 0, so we need to adjust. */
3520 CPU_SET (cpu - 1, set);
3522 #endif /* !CPU_ALLOC */
3523 #endif /* __linux__ */
3525 /* Return the load address of the executable, or 0 if not known. In the
3526 specific case of error, (void *)-1 can be returned. Beware: this unit may
3527 be in a shared library. As low-level units are needed, we allow #include
3528 here. */
3530 #if defined (__APPLE__)
3531 #include <mach-o/dyld.h>
3532 #endif
3534 const void *
3535 __gnat_get_executable_load_address (void)
3537 #if defined (__APPLE__)
3538 return _dyld_get_image_header (0);
3540 #elif 0 && defined (__linux__)
3541 /* Currently disabled as it needs at least -ldl. */
3542 struct link_map *map = _r_debug.r_map;
3544 return (const void *)map->l_addr;
3546 #else
3547 return NULL;
3548 #endif
3551 void
3552 __gnat_kill (int pid, int sig, int close ATTRIBUTE_UNUSED)
3554 #if defined(_WIN32)
3555 HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
3556 if (h == NULL)
3557 return;
3558 if (sig == 9)
3560 TerminateProcess (h, 1);
3562 else if (sig == SIGINT)
3563 GenerateConsoleCtrlEvent (CTRL_C_EVENT, pid);
3564 else if (sig == SIGBREAK)
3565 GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid);
3566 /* ??? The last two alternatives don't really work. SIGBREAK requires setting
3567 up process groups at start time which we don't do; treating SIGINT is just
3568 not possible apparently. So we really only support signal 9. Fortunately
3569 that's all we use in GNAT.Expect */
3571 CloseHandle (h);
3572 #elif defined (__vxworks)
3573 /* Not implemented */
3574 #else
3575 kill (pid, sig);
3576 #endif
3579 void __gnat_killprocesstree (int pid, int sig_num)
3581 #if defined(_WIN32)
3582 PROCESSENTRY32 pe;
3584 memset(&pe, 0, sizeof(PROCESSENTRY32));
3585 pe.dwSize = sizeof(PROCESSENTRY32);
3587 HANDLE hSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
3589 /* cannot take snapshot, just kill the parent process */
3591 if (hSnap == INVALID_HANDLE_VALUE)
3593 __gnat_kill (pid, sig_num, 1);
3594 return;
3597 if (Process32First(hSnap, &pe))
3599 BOOL bContinue = TRUE;
3601 /* kill child processes first */
3603 while (bContinue)
3605 if (pe.th32ParentProcessID == (DWORD)pid)
3606 __gnat_killprocesstree (pe.th32ProcessID, sig_num);
3608 bContinue = Process32Next (hSnap, &pe);
3612 CloseHandle (hSnap);
3614 /* kill process */
3616 __gnat_kill (pid, sig_num, 1);
3618 #elif defined (__vxworks)
3619 /* not implemented */
3621 #elif defined (__linux__)
3622 DIR *dir;
3623 struct dirent *d;
3625 /* read all processes' pid and ppid */
3627 dir = opendir ("/proc");
3629 /* cannot open proc, just kill the parent process */
3631 if (!dir)
3633 __gnat_kill (pid, sig_num, 1);
3634 return;
3637 /* kill child processes first */
3639 while ((d = readdir (dir)) != NULL)
3641 if ((d->d_type & DT_DIR) == DT_DIR)
3643 char statfile[64];
3644 int _pid, _ppid;
3646 /* read /proc/<PID>/stat */
3648 if (strlen (d->d_name) >= sizeof (statfile) - strlen ("/proc//stat"))
3649 continue;
3650 strcpy (statfile, "/proc/");
3651 strcat (statfile, d->d_name);
3652 strcat (statfile, "/stat");
3654 FILE *fd = fopen (statfile, "r");
3656 if (fd)
3658 const int match = fscanf (fd, "%d %*s %*s %d", &_pid, &_ppid);
3659 fclose (fd);
3661 if (match == 2 && _ppid == pid)
3662 __gnat_killprocesstree (_pid, sig_num);
3667 closedir (dir);
3669 /* kill process */
3671 __gnat_kill (pid, sig_num, 1);
3672 #else
3673 __gnat_kill (pid, sig_num, 1);
3674 #endif
3675 /* Note on Solaris it is possible to read /proc/<PID>/status.
3676 The 5th and 6th words are the pid and the 7th and 8th the ppid.
3677 See: /usr/include/sys/procfs.h (struct pstatus).
3681 #ifdef __cplusplus
3683 #endif