Add assember CFI directives to millicode division and remainder routines.
[official-gcc.git] / gcc / ada / adaint.c
blob8522094164e07f92afe345a49b35967237d65b5e
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 1992-2023, 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 #include <sys/time.h>
102 #endif
104 #ifdef IN_RTS
106 #ifdef STANDALONE
107 #include <errno.h>
108 #include <sys/types.h>
109 #include <sys/stat.h>
110 #include <unistd.h>
111 #include <stdlib.h>
112 #include <string.h>
114 /* for CPU_SET/CPU_ZERO */
115 #define _GNU_SOURCE
116 #define __USE_GNU
118 #include "runtime.h"
120 #else
121 #include "tconfig.h"
122 #include "tsystem.h"
123 #endif
125 #include <sys/stat.h>
126 #include <fcntl.h>
127 #include <time.h>
129 #if defined (__vxworks) || defined (__ANDROID__)
130 /* S_IREAD and S_IWRITE are not defined in VxWorks or Android */
131 #ifndef S_IREAD
132 #define S_IREAD (S_IRUSR | S_IRGRP | S_IROTH)
133 #endif
135 #ifndef S_IWRITE
136 #define S_IWRITE (S_IWUSR)
137 #endif
138 #endif
140 /* We don't have libiberty, so use malloc. */
141 #define xmalloc(S) malloc (S)
142 #define xrealloc(V,S) realloc (V,S)
143 #else
144 #include "config.h"
145 #include "system.h"
146 #include "version.h"
147 #endif
149 /* limits.h is needed for LLONG_MIN. */
150 #ifdef __cplusplus
151 #include <climits>
152 #else
153 #include <limits.h>
154 #endif
156 #ifdef __cplusplus
157 extern "C" {
158 #endif
160 #if defined (__DJGPP__)
162 /* For isalpha-like tests in the compiler, we're expected to resort to
163 safe-ctype.h/ISALPHA. This isn't available for the runtime library
164 build, so we fallback on ctype.h/isalpha there. */
166 #ifdef IN_RTS
167 #include <ctype.h>
168 #define ISALPHA isalpha
169 #endif
171 #elif defined (__MINGW32__) || defined (__CYGWIN__)
173 #include "mingw32.h"
175 /* Current code page and CCS encoding to use, set in initialize.c. */
176 UINT __gnat_current_codepage;
177 UINT __gnat_current_ccs_encoding;
179 #include <sys/utime.h>
181 /* For isalpha-like tests in the compiler, we're expected to resort to
182 safe-ctype.h/ISALPHA. This isn't available for the runtime library
183 build, so we fallback on ctype.h/isalpha there. */
185 #ifdef IN_RTS
186 #include <ctype.h>
187 #define ISALPHA isalpha
188 #endif
190 #elif defined (__Lynx__)
192 /* Lynx utime.h only defines the entities of interest to us if
193 defined (VMOS_DEV), so ... */
194 #define VMOS_DEV
195 #include <utime.h>
196 #undef VMOS_DEV
198 #else
199 #include <utime.h>
200 #endif
202 /* wait.h processing */
203 #if defined (__vxworks) && defined (__RTP__)
204 # include <wait.h>
205 #elif defined (__Lynx__)
206 /* ??? We really need wait.h and it includes resource.h on Lynx. GCC
207 has a resource.h header as well, included instead of the lynx
208 version in our setup, causing lots of errors. We don't really need
209 the lynx contents of this file, so just workaround the issue by
210 preventing the inclusion of the GCC header from doing anything. */
211 # define GCC_RESOURCE_H
212 # include <sys/wait.h>
213 #elif defined (__PikeOS__) || defined (__MINGW32__)
214 /* No wait() or waitpid() calls available. */
215 #else
216 /* Default case. */
217 #include <sys/wait.h>
218 #endif
220 #if defined (__DJGPP__)
221 #include <process.h>
222 #include <signal.h>
223 #include <dir.h>
224 #include <utime.h>
225 #undef DIR_SEPARATOR
226 #define DIR_SEPARATOR '\\'
228 #elif defined (_WIN32)
230 #define WIN32_LEAN_AND_MEAN
231 #include <windows.h>
232 #include <accctrl.h>
233 #include <aclapi.h>
234 #include <tlhelp32.h>
235 #include <signal.h>
236 #undef DIR_SEPARATOR
237 #define DIR_SEPARATOR '\\'
239 #else
240 #include <utime.h>
241 #endif
243 #include "adaint.h"
245 int __gnat_in_child_after_fork = 0;
247 #if defined (__APPLE__) && defined (st_mtime)
248 #define st_atim st_atimespec
249 #define st_mtim st_mtimespec
250 #endif
252 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
253 defined in the current system. On DOS-like systems these flags control
254 whether the file is opened/created in text-translation mode (CR/LF in
255 external file mapped to LF in internal file), but in Unix-like systems,
256 no text translation is required, so these flags have no effect. */
258 #ifndef O_BINARY
259 #define O_BINARY 0
260 #endif
262 #ifndef O_TEXT
263 #define O_TEXT 0
264 #endif
266 #ifndef HOST_EXECUTABLE_SUFFIX
267 #define HOST_EXECUTABLE_SUFFIX ""
268 #endif
270 #ifndef HOST_OBJECT_SUFFIX
271 #define HOST_OBJECT_SUFFIX ".o"
272 #endif
274 #ifndef PATH_SEPARATOR
275 #define PATH_SEPARATOR ':'
276 #endif
278 #ifndef DIR_SEPARATOR
279 #define DIR_SEPARATOR '/'
280 #define IS_DIRECTORY_SEPARATOR(c) ((c) == DIR_SEPARATOR)
281 #else
282 #define IS_DIRECTORY_SEPARATOR(c) ((c) == '/' || (c) == DIR_SEPARATOR)
283 #endif
285 /* Check for cross-compilation. */
286 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
287 #define IS_CROSS 1
288 int __gnat_is_cross_compiler = 1;
289 #else
290 #undef IS_CROSS
291 int __gnat_is_cross_compiler = 0;
292 #endif
294 char __gnat_dir_separator = DIR_SEPARATOR;
296 char __gnat_path_separator = PATH_SEPARATOR;
298 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
299 the base filenames that libraries specified with -lsomelib options
300 may have. This is used by GNATMAKE to check whether an executable
301 is up-to-date or not. The syntax is
303 library_template ::= { pattern ; } pattern NUL
304 pattern ::= [ prefix ] * [ postfix ]
306 These should only specify names of static libraries as it makes
307 no sense to determine at link time if dynamic-link libraries are
308 up to date or not. Any libraries that are not found are supposed
309 to be up-to-date:
311 * if they are needed but not present, the link
312 will fail,
314 * otherwise they are libraries in the system paths and so
315 they are considered part of the system and not checked
316 for that reason.
318 ??? This should be part of a GNAT host-specific compiler
319 file instead of being included in all user applications
320 as well. This is only a temporary work-around for 3.11b. */
322 #ifndef GNAT_LIBRARY_TEMPLATE
323 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
324 #endif
326 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
328 #if defined (__vxworks)
329 #define GNAT_MAX_PATH_LEN PATH_MAX
331 #else
333 #if defined (__MINGW32__)
334 #include "mingw32.h"
335 #else
336 #include <sys/param.h>
337 #endif
339 #ifdef MAXPATHLEN
340 #define GNAT_MAX_PATH_LEN MAXPATHLEN
341 #else
342 #define GNAT_MAX_PATH_LEN 256
343 #endif
345 #endif
347 /* Used for runtime check that Ada constant File_Attributes_Size is no
348 less than the actual size of struct file_attributes (see Osint
349 initialization). */
350 int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
352 void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
354 /* The __gnat_max_path_len variable is used to export the maximum
355 length of a path name to Ada code. max_path_len is also provided
356 for compatibility with older GNAT versions, please do not use
357 it. */
359 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
360 int max_path_len = GNAT_MAX_PATH_LEN;
362 /* Control whether we can use ACL on Windows. */
364 int __gnat_use_acl = 1;
366 /* The following macro HAVE_READDIR_R should be defined if the
367 system provides the routine readdir_r.
368 ... but we never define it anywhere??? */
369 #undef HAVE_READDIR_R
371 #define MAYBE_TO_PTR32(argv) argv
373 static const char ATTR_UNSET = 127;
375 /* Reset the file attributes as if no system call had been performed */
377 void
378 __gnat_reset_attributes (struct file_attributes* attr)
380 attr->exists = ATTR_UNSET;
381 attr->error = EINVAL;
383 attr->writable = ATTR_UNSET;
384 attr->readable = ATTR_UNSET;
385 attr->executable = ATTR_UNSET;
387 attr->regular = ATTR_UNSET;
388 attr->symbolic_link = ATTR_UNSET;
389 attr->directory = ATTR_UNSET;
391 attr->timestamp = (OS_Time)-2;
392 attr->file_length = -1;
396 __gnat_error_attributes (struct file_attributes *attr) {
397 return attr->error;
400 OS_Time
401 __gnat_current_time (void)
403 time_t res = time (NULL);
404 return (OS_Time) res;
407 /* Return the current local time as a string in the ISO 8601 format of
408 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
409 long. */
411 void
412 __gnat_current_time_string (char *result)
414 const char *format = "%Y-%m-%d %H:%M:%S";
415 /* Format string necessary to describe the ISO 8601 format */
417 const time_t t_val = time (NULL);
419 strftime (result, 22, format, localtime (&t_val));
420 /* Convert the local time into a string following the ISO format, copying
421 at most 22 characters into the result string. */
423 result [19] = '.';
424 result [20] = '0';
425 result [21] = '0';
426 /* The sub-seconds are manually set to zero since type time_t lacks the
427 precision necessary for nanoseconds. */
430 void
431 __gnat_to_gm_time (OS_Time *p_time, int *p_year, int *p_month, int *p_day,
432 int *p_hours, int *p_mins, int *p_secs)
434 struct tm *res;
435 time_t time = (time_t) *p_time;
437 res = gmtime (&time);
438 if (res)
440 *p_year = res->tm_year;
441 *p_month = res->tm_mon;
442 *p_day = res->tm_mday;
443 *p_hours = res->tm_hour;
444 *p_mins = res->tm_min;
445 *p_secs = res->tm_sec;
447 else
448 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
451 void
452 __gnat_to_os_time (OS_Time *p_time, int year, int month, int day,
453 int hours, int mins, int secs)
455 struct tm v;
457 v.tm_year = year;
458 v.tm_mon = month;
459 v.tm_mday = day;
460 v.tm_hour = hours;
461 v.tm_min = mins;
462 v.tm_sec = secs;
463 v.tm_isdst = -1;
465 /* returns -1 of failing, this is s-os_lib Invalid_Time */
467 *p_time = (OS_Time) mktime (&v);
470 /* Place the contents of the symbolic link named PATH in the buffer BUF,
471 which has size BUFSIZ. If PATH is a symbolic link, then return the number
472 of characters of its content in BUF. Otherwise, return -1.
473 For systems not supporting symbolic links, always return -1. */
476 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
477 char *buf ATTRIBUTE_UNUSED,
478 size_t bufsiz ATTRIBUTE_UNUSED)
480 #if defined (_WIN32) \
481 || defined(__vxworks) || defined (__PikeOS__)
482 return -1;
483 #else
484 return readlink (path, buf, bufsiz);
485 #endif
488 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
489 If NEWPATH exists it will NOT be overwritten.
490 For systems not supporting symbolic links, always return -1. */
493 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
494 char *newpath ATTRIBUTE_UNUSED)
496 #if defined (_WIN32) \
497 || defined(__vxworks) || defined (__PikeOS__)
498 return -1;
499 #else
500 return symlink (oldpath, newpath);
501 #endif
504 /* Try to lock a file, return 1 if success. */
506 #if defined (__vxworks) \
507 || defined (_WIN32) || defined (__PikeOS__)
509 /* Version that does not use link. */
512 __gnat_try_lock (char *dir, char *file)
514 int fd;
515 #ifdef __MINGW32__
516 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
517 TCHAR wfile[GNAT_MAX_PATH_LEN];
518 TCHAR wdir[GNAT_MAX_PATH_LEN];
520 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
521 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
523 /* ??? the code below crash on MingW64 for obscure reasons, a ticket
524 has been opened here:
526 https://sourceforge.net/p/mingw-w64/bugs/414/
528 As a workaround an equivalent set of code has been put in place below.
530 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
533 _tcscpy (wfull_path, wdir);
534 _tcscat (wfull_path, L"\\");
535 _tcscat (wfull_path, wfile);
537 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
538 #else
539 char full_path[256];
541 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
542 fd = open (full_path, O_CREAT | O_EXCL, 0600);
543 #endif
545 if (fd < 0)
546 return 0;
548 close (fd);
549 return 1;
552 #else
554 /* Version using link(), more secure over NFS. */
555 /* See TN 6913-016 for discussion ??? */
558 __gnat_try_lock (char *dir, char *file)
560 char full_path[256];
561 char temp_file[256];
562 GNAT_STRUCT_STAT stat_result;
563 int fd;
565 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
566 sprintf (temp_file, "%s%cTMP-%ld-%ld",
567 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
569 /* Create the temporary file and write the process number. */
570 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
571 if (fd < 0)
572 return 0;
574 close (fd);
576 /* Link it with the new file. */
577 link (temp_file, full_path);
579 /* Count the references on the old one. If we have a count of two, then
580 the link did succeed. Remove the temporary file before returning. */
581 __gnat_stat (temp_file, &stat_result);
582 unlink (temp_file);
583 return stat_result.st_nlink == 2;
585 #endif
587 /* Return the maximum file name length. */
590 __gnat_get_maximum_file_name_length (void)
592 return -1;
595 /* Return nonzero if file names are case sensitive. */
597 static int file_names_case_sensitive_cache = -1;
600 __gnat_get_file_names_case_sensitive (void)
602 if (file_names_case_sensitive_cache == -1)
604 const char *sensitive = getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
606 if (sensitive != NULL
607 && (sensitive[0] == '0' || sensitive[0] == '1')
608 && sensitive[1] == '\0')
609 file_names_case_sensitive_cache = sensitive[0] - '0';
610 else
612 /* By default, we suppose filesystems aren't case sensitive on
613 Windows and Darwin (but they are on arm-darwin). */
614 #if defined (WINNT) || defined (__DJGPP__) \
615 || (defined (__APPLE__) && !(defined (__arm__) || defined (__arm64__)))
616 file_names_case_sensitive_cache = 0;
617 #else
618 file_names_case_sensitive_cache = 1;
619 #endif
622 return file_names_case_sensitive_cache;
625 /* Return nonzero if environment variables are case sensitive. */
628 __gnat_get_env_vars_case_sensitive (void)
630 #if defined (WINNT) || defined (__DJGPP__)
631 return 0;
632 #else
633 return 1;
634 #endif
637 char
638 __gnat_get_default_identifier_character_set (void)
640 return '1';
643 /* Return the current working directory. */
645 void
646 __gnat_get_current_dir (char *dir, int *length)
648 #if defined (__MINGW32__)
649 TCHAR wdir[GNAT_MAX_PATH_LEN];
651 _tgetcwd (wdir, *length);
653 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
655 #else
656 char* result = getcwd (dir, *length);
657 /* If the current directory does not exist, set length = 0
658 to indicate error. That can't happen on windows, where
659 you can't delete a directory if it is the current
660 directory of some process. */
661 if (!result)
663 *length = 0;
664 return;
666 #endif
668 *length = strlen (dir);
670 if (dir [*length - 1] != DIR_SEPARATOR)
672 dir [*length] = DIR_SEPARATOR;
673 ++(*length);
675 dir[*length] = '\0';
678 /* Return the suffix for object files. */
680 void
681 __gnat_get_object_suffix_ptr (int *len, const char **value)
683 *value = HOST_OBJECT_SUFFIX;
685 if (*value == 0)
686 *len = 0;
687 else
688 *len = strlen (*value);
690 return;
693 /* Return the suffix for executable files. */
695 void
696 __gnat_get_executable_suffix_ptr (int *len, const char **value)
698 *value = HOST_EXECUTABLE_SUFFIX;
700 if (!*value)
701 *len = 0;
702 else
703 *len = strlen (*value);
705 return;
708 /* Return the suffix for debuggable files. Usually this is the same as the
709 executable extension. */
711 void
712 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
714 *value = HOST_EXECUTABLE_SUFFIX;
716 if (*value == 0)
717 *len = 0;
718 else
719 *len = strlen (*value);
721 return;
724 /* Returns the OS filename and corresponding encoding. */
726 void
727 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
728 char *w_filename ATTRIBUTE_UNUSED,
729 char *os_name, int *o_length,
730 char *encoding ATTRIBUTE_UNUSED, int *e_length)
732 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
733 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
734 *o_length = strlen (os_name);
735 strcpy (encoding, "encoding=utf8");
736 *e_length = strlen (encoding);
737 #else
738 strcpy (os_name, filename);
739 *o_length = strlen (filename);
740 *e_length = 0;
741 #endif
744 /* Delete a file. */
747 __gnat_unlink (char *path)
749 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
751 TCHAR wpath[GNAT_MAX_PATH_LEN];
753 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
754 return _tunlink (wpath);
756 #else
757 return unlink (path);
758 #endif
761 /* Rename a file. */
764 __gnat_rename (char *from, char *to)
766 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
768 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
770 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
771 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
772 return _trename (wfrom, wto);
774 #elif defined (__vxworks) && (_WRS_VXWORKS_MAJOR == 6)
776 /* When used on a dos filesystem under VxWorks 6.9 rename will trigger a
777 S_dosFsLib_FILE_NOT_FOUND errno when the file is not found. Let's map
778 that to ENOENT so Ada.Directory.Rename can detect that and raise the
779 Name_Error exception. */
780 int ret = rename (from, to);
782 if (ret && (errno == S_dosFsLib_FILE_NOT_FOUND))
784 errno = ENOENT;
786 return ret;
788 #else
789 return rename (from, to);
790 #endif
793 /* Changing directory. */
796 __gnat_chdir (char *path)
798 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
800 TCHAR wpath[GNAT_MAX_PATH_LEN];
802 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
803 return _tchdir (wpath);
805 #else
806 return chdir (path);
807 #endif
810 /* Removing a directory. */
813 __gnat_rmdir (char *path)
815 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
817 TCHAR wpath[GNAT_MAX_PATH_LEN];
819 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
820 return _trmdir (wpath);
822 #elif defined (VTHREADS)
823 /* rmdir not available */
824 return -1;
825 #else
826 return rmdir (path);
827 #endif
830 #if defined (_WIN32) || defined (__linux__) || defined (__sun__) \
831 || defined (__FreeBSD__) || defined(__DragonFly__) || defined (__QNX__)
832 #define HAS_TARGET_WCHAR_T
833 #endif
835 #ifdef HAS_TARGET_WCHAR_T
836 #include <wchar.h>
837 #endif
840 __gnat_fputwc(int c, FILE *stream)
842 #ifdef HAS_TARGET_WCHAR_T
843 return fputwc ((wchar_t)c, stream);
844 #else
845 return fputc (c, stream);
846 #endif
849 FILE *
850 __gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
852 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
853 TCHAR wpath[GNAT_MAX_PATH_LEN];
854 TCHAR wmode[10];
856 S2WS (wmode, mode, 10);
858 if (encoding == Encoding_Unspecified)
859 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
860 else if (encoding == Encoding_UTF8)
861 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
862 else
863 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
865 return _tfopen (wpath, wmode);
867 #else
868 return GNAT_FOPEN (path, mode);
869 #endif
872 FILE *
873 __gnat_freopen (char *path,
874 char *mode,
875 FILE *stream,
876 int encoding ATTRIBUTE_UNUSED)
878 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
879 TCHAR wpath[GNAT_MAX_PATH_LEN];
880 TCHAR wmode[10];
882 S2WS (wmode, mode, 10);
884 if (encoding == Encoding_Unspecified)
885 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
886 else if (encoding == Encoding_UTF8)
887 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
888 else
889 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
891 return _tfreopen (wpath, wmode, stream);
892 #else
893 return freopen (path, mode, stream);
894 #endif
898 __gnat_open_read (char *path, int fmode)
900 int fd;
901 int o_fmode = O_BINARY;
903 if (fmode)
904 o_fmode = O_TEXT;
906 #if defined (__vxworks)
907 fd = open (path, O_RDONLY | o_fmode, 0444);
908 #elif defined (__MINGW32__)
910 TCHAR wpath[GNAT_MAX_PATH_LEN];
912 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
913 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
915 #else
916 fd = GNAT_OPEN (path, O_RDONLY | o_fmode);
917 #endif
919 return fd < 0 ? -1 : fd;
922 #if defined (__MINGW32__)
923 #define PERM (S_IREAD | S_IWRITE)
924 #else
925 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
926 #endif
929 __gnat_open_rw (char *path, int fmode)
931 int fd;
932 int o_fmode = O_BINARY;
934 if (fmode)
935 o_fmode = O_TEXT;
937 #if defined (__MINGW32__)
939 TCHAR wpath[GNAT_MAX_PATH_LEN];
941 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
942 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
944 #else
945 fd = GNAT_OPEN (path, O_RDWR | o_fmode, PERM);
946 #endif
948 return fd < 0 ? -1 : fd;
952 __gnat_open_create (char *path, int fmode)
954 int fd;
955 int o_fmode = O_BINARY;
957 if (fmode)
958 o_fmode = O_TEXT;
960 #if defined (__MINGW32__)
962 TCHAR wpath[GNAT_MAX_PATH_LEN];
964 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
965 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
967 #else
968 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
969 #endif
971 return fd < 0 ? -1 : fd;
975 __gnat_create_output_file (char *path)
977 int fd;
978 #if defined (__MINGW32__)
980 TCHAR wpath[GNAT_MAX_PATH_LEN];
982 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
983 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
985 #else
986 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
987 #endif
989 return fd < 0 ? -1 : fd;
993 __gnat_create_output_file_new (char *path)
995 int fd;
996 #if defined (__MINGW32__)
998 TCHAR wpath[GNAT_MAX_PATH_LEN];
1000 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1001 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
1003 #else
1004 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
1005 #endif
1007 return fd < 0 ? -1 : fd;
1011 __gnat_open_append (char *path, int fmode)
1013 int fd;
1014 int o_fmode = O_BINARY;
1016 if (fmode)
1017 o_fmode = O_TEXT;
1019 #if defined (__MINGW32__)
1021 TCHAR wpath[GNAT_MAX_PATH_LEN];
1023 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1024 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
1026 #else
1027 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
1028 #endif
1030 return fd < 0 ? -1 : fd;
1033 /* Open a new file. Return error (-1) if the file already exists. */
1036 __gnat_open_new (char *path, int fmode)
1038 int fd;
1039 int o_fmode = O_BINARY;
1041 if (fmode)
1042 o_fmode = O_TEXT;
1044 #if defined (__MINGW32__)
1046 TCHAR wpath[GNAT_MAX_PATH_LEN];
1048 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1049 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1051 #else
1052 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1053 #endif
1055 return fd < 0 ? -1 : fd;
1058 /* Open a new temp file. Return error (-1) if the file already exists. */
1061 __gnat_open_new_temp (char *path, int fmode)
1063 int fd;
1064 int o_fmode = O_BINARY;
1066 strcpy (path, "GNAT-XXXXXX");
1068 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
1069 || defined (__linux__) || defined (__GLIBC__) || defined (__ANDROID__) \
1070 || defined (__DragonFly__) || defined (__QNX__)) && !defined (__vxworks)
1071 return mkstemp (path);
1072 #elif defined (__Lynx__)
1073 mktemp (path);
1074 #else
1075 if (mktemp (path) == NULL)
1076 return -1;
1077 #endif
1079 if (fmode)
1080 o_fmode = O_TEXT;
1082 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1083 return fd < 0 ? -1 : fd;
1087 __gnat_open (char *path, int fmode)
1089 int fd;
1091 #if defined (__MINGW32__)
1093 TCHAR wpath[GNAT_MAX_PATH_LEN];
1095 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1096 fd = _topen (wpath, fmode, PERM);
1098 #else
1099 fd = GNAT_OPEN (path, fmode, PERM);
1100 #endif
1102 return fd < 0 ? -1 : fd;
1105 /****************************************************************
1106 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1107 ** as possible from it, storing the result in a cache for later reuse
1108 ****************************************************************/
1110 void
1111 __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
1113 GNAT_STRUCT_STAT statbuf;
1114 int ret, error;
1116 if (fd != -1) {
1117 /* GNAT_FSTAT returns -1 and sets errno for failure */
1118 ret = GNAT_FSTAT (fd, &statbuf);
1119 error = ret ? errno : 0;
1121 } else {
1122 /* __gnat_stat returns errno value directly */
1123 error = __gnat_stat (name, &statbuf);
1124 ret = error ? -1 : 0;
1128 * A missing file is reported as an attr structure with error == 0 and
1129 * exists == 0.
1132 if (error == 0 || error == ENOENT)
1133 attr->error = 0;
1134 else
1135 attr->error = error;
1137 attr->regular = (!ret && S_ISREG (statbuf.st_mode));
1138 attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
1140 if (!attr->regular)
1141 attr->file_length = 0;
1142 else
1143 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1144 don't return a useful value for files larger than 2 gigabytes in
1145 either case. */
1146 attr->file_length = statbuf.st_size; /* all systems */
1148 attr->exists = !ret;
1150 #if !defined (_WIN32)
1151 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1152 attr->readable = (!ret && (statbuf.st_mode & S_IRUSR));
1153 attr->writable = (!ret && (statbuf.st_mode & S_IWUSR));
1154 attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
1155 #endif
1157 if (ret != 0) {
1158 attr->timestamp = (OS_Time)-1;
1159 } else {
1160 attr->timestamp = (OS_Time)statbuf.st_mtime;
1164 /****************************************************************
1165 ** Return the number of bytes in the specified file
1166 ****************************************************************/
1168 __int64
1169 __gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
1171 if (attr->file_length == -1) {
1172 __gnat_stat_to_attr (fd, name, attr);
1175 return attr->file_length;
1178 __int64
1179 __gnat_file_length (int fd)
1181 struct file_attributes attr;
1182 __gnat_reset_attributes (&attr);
1183 return __gnat_file_length_attr (fd, NULL, &attr);
1186 long
1187 __gnat_file_length_long (int fd)
1189 struct file_attributes attr;
1190 __gnat_reset_attributes (&attr);
1191 return (long)__gnat_file_length_attr (fd, NULL, &attr);
1194 __int64
1195 __gnat_named_file_length (char *name)
1197 struct file_attributes attr;
1198 __gnat_reset_attributes (&attr);
1199 return __gnat_file_length_attr (-1, name, &attr);
1202 /* Create a temporary filename and put it in string pointed to by
1203 TMP_FILENAME. */
1205 void
1206 __gnat_tmp_name (char *tmp_filename)
1208 #if defined (__MINGW32__)
1210 char *pname;
1211 char prefix[25];
1213 /* tempnam tries to create a temporary file in directory pointed to by
1214 TMP environment variable, in c:\temp if TMP is not set, and in
1215 directory specified by P_tmpdir in stdio.h if c:\temp does not
1216 exist. The filename will be created with the prefix "gnat-". */
1218 sprintf (prefix, "gnat-%d-", (int)getpid());
1219 pname = (char *) _tempnam ("c:\\temp", prefix);
1221 /* if pname is NULL, the file was not created properly, the disk is full
1222 or there is no more free temporary files */
1224 if (pname == NULL)
1225 *tmp_filename = '\0';
1227 /* If pname start with a back slash and not path information it means that
1228 the filename is valid for the current working directory. */
1230 else if (pname[0] == '\\')
1232 strcpy (tmp_filename, ".\\");
1233 strcat (tmp_filename, pname+1);
1235 else
1236 strcpy (tmp_filename, pname);
1238 free (pname);
1241 #elif defined (__linux__) || defined (__FreeBSD__) || defined (__NetBSD__) \
1242 || defined (__OpenBSD__) || defined (__GLIBC__) || defined (__ANDROID__) \
1243 || defined (__DragonFly__) || defined (__QNX__)
1244 #define MAX_SAFE_PATH 1000
1245 char *tmpdir = getenv ("TMPDIR");
1247 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1248 a buffer overflow. */
1249 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1250 #ifdef __ANDROID__
1251 strcpy (tmp_filename, "/cache/gnat-XXXXXX");
1252 #else
1253 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1254 #endif
1255 else
1256 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1258 close (mkstemp(tmp_filename));
1259 #elif defined (__vxworks) && !defined (VTHREADS)
1260 int index;
1261 char *pos;
1262 char *savepos;
1263 static ushort_t seed = 0; /* used to generate unique name */
1265 /* Generate a unique name. */
1266 strcpy (tmp_filename, "tmp");
1268 index = 5;
1269 savepos = pos = tmp_filename + strlen (tmp_filename) + index;
1270 *pos = '\0';
1272 while (1)
1274 FILE *f;
1275 ushort_t t;
1277 /* Fill up the name buffer from the last position. */
1278 seed++;
1279 for (t = seed; --index >= 0; t >>= 3)
1280 *--pos = '0' + (t & 07);
1282 /* Check to see if its unique, if not bump the seed and try again. */
1283 f = fopen (tmp_filename, "r");
1284 if (f == NULL)
1285 break;
1286 fclose (f);
1287 pos = savepos;
1288 index = 5;
1290 #else
1291 tmpnam (tmp_filename);
1292 #endif
1295 /* Open directory and returns a DIR pointer. */
1297 DIR* __gnat_opendir (char *name)
1299 #if defined (__MINGW32__)
1300 TCHAR wname[GNAT_MAX_PATH_LEN];
1302 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1303 return (DIR*)_topendir (wname);
1305 #else
1306 return opendir (name);
1307 #endif
1310 /* Read the next entry in a directory. The returned string points somewhere
1311 in the buffer. */
1313 #if defined (__sun__)
1314 /* For Solaris, be sure to use the 64-bit version, otherwise NFS reads may
1315 fail with EOVERFLOW if the server uses 64-bit cookies. */
1316 #define dirent dirent64
1317 #define readdir readdir64
1318 #endif
1320 char *
1321 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1323 #if defined (__MINGW32__)
1324 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1326 if (dirent != NULL)
1328 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1329 *len = strlen (buffer);
1331 return buffer;
1333 else
1334 return NULL;
1336 #elif defined (HAVE_READDIR_R)
1337 /* If possible, try to use the thread-safe version. */
1338 if (readdir_r (dirp, buffer) != NULL)
1340 *len = strlen (((struct dirent*) buffer)->d_name);
1341 return ((struct dirent*) buffer)->d_name;
1343 else
1344 return NULL;
1346 #else
1347 struct dirent *dirent = (struct dirent *) readdir (dirp);
1349 if (dirent != NULL)
1351 strcpy (buffer, dirent->d_name);
1352 *len = strlen (buffer);
1353 return buffer;
1355 else
1356 return NULL;
1358 #endif
1361 /* Close a directory entry. */
1363 int __gnat_closedir (DIR *dirp)
1365 #if defined (__MINGW32__)
1366 return _tclosedir ((_TDIR*)dirp);
1368 #else
1369 return closedir (dirp);
1370 #endif
1373 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1376 __gnat_readdir_is_thread_safe (void)
1378 #ifdef HAVE_READDIR_R
1379 return 1;
1380 #else
1381 return 0;
1382 #endif
1385 #if defined (_WIN32)
1386 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1387 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1389 /* Returns the file modification timestamp using Win32 routines which are
1390 immune against daylight saving time change. It is in fact not possible to
1391 use fstat for this purpose as the DST modify the st_mtime field of the
1392 stat structure. */
1394 static time_t
1395 win32_filetime (HANDLE h)
1397 union
1399 FILETIME ft_time;
1400 unsigned long long ull_time;
1401 } t_write;
1403 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1404 since <Jan 1st 1601>. This function must return the number of seconds
1405 since <Jan 1st 1970>. */
1407 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1408 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1409 return (time_t) 0;
1412 /* As above but starting from a FILETIME. */
1413 static void
1414 f2t (const FILETIME *ft, __time64_t *t)
1416 union
1418 FILETIME ft_time;
1419 unsigned long long ull_time;
1420 } t_write;
1422 t_write.ft_time = *ft;
1423 *t = (__time64_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1425 #endif
1427 /* Return a GNAT time stamp given a file name. */
1429 OS_Time
1430 __gnat_file_time_name_attr (char* name, struct file_attributes* attr)
1432 if (attr->timestamp == (OS_Time)-2) {
1433 #if defined (_WIN32)
1434 BOOL res;
1435 WIN32_FILE_ATTRIBUTE_DATA fad;
1436 __time64_t ret = -1;
1437 TCHAR wname[GNAT_MAX_PATH_LEN];
1438 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1440 if ((res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad)))
1441 f2t (&fad.ftLastWriteTime, &ret);
1442 attr->timestamp = (OS_Time) ret;
1443 #else
1444 __gnat_stat_to_attr (-1, name, attr);
1445 #endif
1447 return attr->timestamp;
1450 OS_Time
1451 __gnat_file_time_name (char *name)
1453 struct file_attributes attr;
1454 __gnat_reset_attributes (&attr);
1455 return __gnat_file_time_name_attr (name, &attr);
1458 /* Return a GNAT time stamp given a file descriptor. */
1460 OS_Time
1461 __gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
1463 if (attr->timestamp == (OS_Time)-2) {
1464 #if defined (_WIN32)
1465 HANDLE h = (HANDLE) _get_osfhandle (fd);
1466 time_t ret = win32_filetime (h);
1467 attr->timestamp = (OS_Time) ret;
1469 #else
1470 __gnat_stat_to_attr (fd, NULL, attr);
1471 #endif
1474 return attr->timestamp;
1477 OS_Time
1478 __gnat_file_time_fd (int fd)
1480 struct file_attributes attr;
1481 __gnat_reset_attributes (&attr);
1482 return __gnat_file_time_fd_attr (fd, &attr);
1485 extern long long __gnat_file_time(char* name)
1487 long long result;
1489 if (name == NULL) {
1490 return LLONG_MIN;
1492 /* Number of seconds between <Jan 1st 1970> and <Jan 1st 2150>. */
1493 static const long long ada_epoch_offset = (136 * 365 + 44 * 366) * 86400LL;
1494 #if defined(_WIN32)
1496 /* Number of 100 nanoseconds between <Jan 1st 1601> and <Jan 1st 2150>. */
1497 static const long long w32_epoch_offset =
1498 (11644473600LL + ada_epoch_offset) * 1E7;
1500 WIN32_FILE_ATTRIBUTE_DATA fad;
1501 union
1503 FILETIME ft_time;
1504 long long ll_time;
1505 } t_write;
1507 if (!GetFileAttributesExA(name, GetFileExInfoStandard, &fad)) {
1508 return LLONG_MIN;
1511 t_write.ft_time = fad.ftLastWriteTime;
1513 #if defined(__GNUG__) && __GNUG__ <= 4
1514 result = (t_write.ll_time - w32_epoch_offset) * 100;
1515 #else
1516 /* Next code similar to (t_write.ll_time - w32_epoch_offset) * 100
1517 but on overflow returns LLONG_MIN value. */
1519 if (__builtin_ssubll_overflow(t_write.ll_time, w32_epoch_offset, &result)) {
1520 return LLONG_MIN;
1523 if (__builtin_smulll_overflow(result, 100, &result)) {
1524 return LLONG_MIN;
1526 #endif
1528 #else
1530 struct stat sb;
1531 if (stat(name, &sb) != 0) {
1532 return LLONG_MIN;
1535 #if defined(__GNUG__) && __GNUG__ <= 4
1536 result = (sb.st_mtime - ada_epoch_offset) * 1E9;
1537 #if defined(st_mtime)
1538 result += sb.st_mtim.tv_nsec;
1539 #endif
1540 #else
1541 /* Next code similar to
1542 (sb.st_mtime - ada_epoch_offset) * 1E9 + sb.st_mtim.tv_nsec
1543 but on overflow returns LLONG_MIN value. */
1545 if (__builtin_ssubll_overflow(sb.st_mtime, ada_epoch_offset, &result)) {
1546 return LLONG_MIN;
1549 if (__builtin_smulll_overflow(result, 1E9, &result)) {
1550 return LLONG_MIN;
1553 #if defined(st_mtime)
1554 if (__builtin_saddll_overflow(result, sb.st_mtim.tv_nsec, &result)) {
1555 return LLONG_MIN;
1557 #endif
1558 #endif
1559 #endif
1560 return result;
1563 /* Set the file time stamp. */
1565 void
1566 __gnat_set_file_time_name (char *name, OS_Time time_stamp)
1568 #if defined (__vxworks)
1570 /* Code to implement __gnat_set_file_time_name for these systems. */
1572 #elif defined (_WIN32)
1573 union
1575 FILETIME ft_time;
1576 unsigned long long ull_time;
1577 } t_write;
1578 TCHAR wname[GNAT_MAX_PATH_LEN];
1580 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1582 HANDLE h = CreateFile
1583 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1584 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1585 NULL);
1586 if (h == INVALID_HANDLE_VALUE)
1587 return;
1588 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1589 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1590 /* Convert to 100 nanosecond units */
1591 t_write.ull_time *= 10000000ULL;
1593 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1594 CloseHandle (h);
1595 return;
1597 #else
1598 struct utimbuf utimbuf;
1599 time_t t;
1601 /* Set modification time to requested time. */
1602 utimbuf.modtime = (time_t) time_stamp;
1604 /* Set access time to now in local time. */
1605 t = time (NULL);
1606 utimbuf.actime = mktime (localtime (&t));
1608 utime (name, &utimbuf);
1609 #endif
1612 /* Get the list of installed standard libraries from the
1613 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1614 key. */
1616 char *
1617 __gnat_get_libraries_from_registry (void)
1619 char *result = (char *) xmalloc (1);
1621 result[0] = '\0';
1623 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
1625 HKEY reg_key;
1626 DWORD name_size, value_size;
1627 char name[256];
1628 char value[256];
1629 DWORD type;
1630 DWORD index;
1631 LONG res;
1633 /* First open the key. */
1634 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1636 if (res == ERROR_SUCCESS)
1637 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1638 KEY_READ, &reg_key);
1640 if (res == ERROR_SUCCESS)
1641 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1643 if (res == ERROR_SUCCESS)
1644 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1646 /* If the key exists, read out all the values in it and concatenate them
1647 into a path. */
1648 for (index = 0; res == ERROR_SUCCESS; index++)
1650 value_size = name_size = 256;
1651 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
1652 &type, (LPBYTE)value, &value_size);
1654 if (res == ERROR_SUCCESS && type == REG_SZ)
1656 char *old_result = result;
1658 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1659 strcpy (result, old_result);
1660 strcat (result, value);
1661 strcat (result, ";");
1662 free (old_result);
1666 /* Remove the trailing ";". */
1667 if (result[0] != 0)
1668 result[strlen (result) - 1] = 0;
1670 #endif
1671 return result;
1674 /* Query information for the given file NAME and return it in STATBUF.
1675 * Returns 0 for success, or errno value for failure.
1678 __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1680 #ifdef __MINGW32__
1681 WIN32_FILE_ATTRIBUTE_DATA fad;
1682 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1683 int name_len;
1684 BOOL res;
1685 DWORD error;
1687 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1688 name_len = _tcslen (wname);
1690 if (name_len > GNAT_MAX_PATH_LEN)
1691 return EINVAL;
1693 ZeroMemory (statbuf, sizeof(GNAT_STRUCT_STAT));
1695 res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad);
1697 if (res == FALSE) {
1698 error = GetLastError();
1700 /* Check file existence using GetFileAttributes() which does not fail on
1701 special Windows files like con:, aux:, nul: etc... */
1703 if (GetFileAttributes(wname) != INVALID_FILE_ATTRIBUTES) {
1704 /* Just pretend that it is a regular and readable file */
1705 statbuf->st_mode = S_IFREG | S_IREAD | S_IWRITE;
1706 return 0;
1709 switch (error) {
1710 case ERROR_ACCESS_DENIED:
1711 case ERROR_SHARING_VIOLATION:
1712 case ERROR_LOCK_VIOLATION:
1713 case ERROR_SHARING_BUFFER_EXCEEDED:
1714 return EACCES;
1715 case ERROR_BUFFER_OVERFLOW:
1716 return ENAMETOOLONG;
1717 case ERROR_NOT_ENOUGH_MEMORY:
1718 return ENOMEM;
1719 default:
1720 return ENOENT;
1724 f2t (&fad.ftCreationTime, &statbuf->st_ctime);
1725 f2t (&fad.ftLastWriteTime, &statbuf->st_mtime);
1726 f2t (&fad.ftLastAccessTime, &statbuf->st_atime);
1728 statbuf->st_size =
1729 (__int64)fad.nFileSizeLow | (__int64)fad.nFileSizeHigh << 32;
1731 /* We do not have the S_IEXEC attribute, but this is not used on GNAT. */
1732 statbuf->st_mode = S_IREAD;
1734 if (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1735 statbuf->st_mode |= S_IFDIR;
1736 else
1737 statbuf->st_mode |= S_IFREG;
1739 if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1740 statbuf->st_mode |= S_IWRITE;
1742 return 0;
1744 #else
1745 return GNAT_STAT (name, statbuf) == 0 ? 0 : errno;
1746 #endif
1749 /*************************************************************************
1750 ** Check whether a file exists
1751 *************************************************************************/
1754 __gnat_file_exists_attr (char* name, struct file_attributes* attr)
1756 if (attr->exists == ATTR_UNSET)
1757 __gnat_stat_to_attr (-1, name, attr);
1759 return attr->exists;
1763 __gnat_file_exists (char *name)
1765 struct file_attributes attr;
1766 __gnat_reset_attributes (&attr);
1767 return __gnat_file_exists_attr (name, &attr);
1770 /**********************************************************************
1771 ** Whether name is an absolute path
1772 **********************************************************************/
1775 __gnat_is_absolute_path (char *name, int length)
1777 #ifdef __vxworks
1778 /* On VxWorks systems, an absolute path can be represented (depending on
1779 the host platform) as either /dir/file, or device:/dir/file, or
1780 device:drive_letter:/dir/file. */
1782 int index;
1784 if (name[0] == '/')
1785 return 1;
1787 for (index = 0; index < length; index++)
1789 if (name[index] == ':' &&
1790 ((name[index + 1] == '/') ||
1791 (isalpha (name[index + 1]) && index + 2 <= length &&
1792 name[index + 2] == '/')))
1793 return 1;
1795 else if (name[index] == '/')
1796 return 0;
1798 return 0;
1799 #else
1800 return (length != 0) &&
1801 (IS_DIRECTORY_SEPARATOR(*name)
1802 #if defined (WINNT) || defined(__DJGPP__)
1803 || (length > 2 && ISALPHA (name[0]) && name[1] == ':'
1804 && IS_DIRECTORY_SEPARATOR(name[2]))
1805 #endif
1807 #endif
1811 __gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
1813 if (attr->regular == ATTR_UNSET)
1814 __gnat_stat_to_attr (-1, name, attr);
1816 return attr->regular;
1820 __gnat_is_regular_file (char *name)
1822 struct file_attributes attr;
1824 __gnat_reset_attributes (&attr);
1825 return __gnat_is_regular_file_attr (name, &attr);
1829 __gnat_is_regular_file_fd (int fd)
1831 int ret;
1832 GNAT_STRUCT_STAT statbuf;
1834 ret = GNAT_FSTAT (fd, &statbuf);
1835 return (!ret && S_ISREG (statbuf.st_mode));
1839 __gnat_is_directory_attr (char* name, struct file_attributes* attr)
1841 if (attr->directory == ATTR_UNSET)
1842 __gnat_stat_to_attr (-1, name, attr);
1844 return attr->directory;
1848 __gnat_is_directory (char *name)
1850 struct file_attributes attr;
1852 __gnat_reset_attributes (&attr);
1853 return __gnat_is_directory_attr (name, &attr);
1856 #if defined (_WIN32)
1858 /* Returns the same constant as GetDriveType but takes a pathname as
1859 argument. */
1861 static UINT
1862 GetDriveTypeFromPath (TCHAR *wfullpath)
1864 TCHAR wdrv[MAX_PATH];
1865 TCHAR wpath[MAX_PATH];
1866 TCHAR wfilename[MAX_PATH];
1867 TCHAR wext[MAX_PATH];
1869 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1871 if (_tcslen (wdrv) != 0)
1873 /* we have a drive specified. */
1874 _tcscat (wdrv, _T("\\"));
1875 return GetDriveType (wdrv);
1877 else
1879 /* No drive specified. */
1881 /* Is this a relative path, if so get current drive type. */
1882 if (wpath[0] != _T('\\') ||
1883 (_tcslen (wpath) > 2 && wpath[0] == _T('\\')
1884 && wpath[1] != _T('\\')))
1885 return GetDriveType (NULL);
1887 UINT result = GetDriveType (wpath);
1889 /* Cannot guess the drive type, is this \\.\ ? */
1891 if (result == DRIVE_NO_ROOT_DIR &&
1892 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1893 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1895 if (_tcslen (wpath) == 4)
1896 _tcscat (wpath, wfilename);
1898 LPTSTR p = &wpath[4];
1899 LPTSTR b = _tcschr (p, _T('\\'));
1901 if (b != NULL)
1903 /* logical drive \\.\c\dir\file */
1904 *b++ = _T(':');
1905 *b++ = _T('\\');
1906 *b = _T('\0');
1908 else
1909 _tcscat (p, _T(":\\"));
1911 return GetDriveType (p);
1914 return result;
1918 /* This MingW section contains code to work with ACL. */
1919 static int
1920 __gnat_check_OWNER_ACL (TCHAR *wname,
1921 DWORD CheckAccessDesired,
1922 GENERIC_MAPPING CheckGenericMapping)
1924 DWORD dwAccessDesired, dwAccessAllowed;
1925 PRIVILEGE_SET PrivilegeSet;
1926 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1927 BOOL fAccessGranted = FALSE;
1928 HANDLE hToken = NULL;
1929 DWORD nLength = 0;
1930 PSECURITY_DESCRIPTOR pSD = NULL;
1932 GetFileSecurity
1933 (wname, OWNER_SECURITY_INFORMATION |
1934 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1935 NULL, 0, &nLength);
1937 if ((pSD = (SECURITY_DESCRIPTOR *) HeapAlloc
1938 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1939 return 0;
1941 /* Obtain the security descriptor. */
1943 if (!GetFileSecurity
1944 (wname, OWNER_SECURITY_INFORMATION |
1945 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1946 pSD, nLength, &nLength))
1947 goto error;
1949 if (!ImpersonateSelf (SecurityImpersonation))
1950 goto error;
1952 if (!OpenThreadToken
1953 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1954 goto error;
1956 /* Undoes the effect of ImpersonateSelf. */
1958 RevertToSelf ();
1960 /* We want to test for write permissions. */
1962 dwAccessDesired = CheckAccessDesired;
1964 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1966 if (!AccessCheck
1967 (pSD , /* security descriptor to check */
1968 hToken, /* impersonation token */
1969 dwAccessDesired, /* requested access rights */
1970 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1971 &PrivilegeSet, /* receives privileges used in check */
1972 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1973 &dwAccessAllowed, /* receives mask of allowed access rights */
1974 &fAccessGranted))
1975 goto error;
1977 CloseHandle (hToken);
1978 HeapFree (GetProcessHeap (), 0, pSD);
1979 return fAccessGranted;
1981 error:
1982 if (hToken)
1983 CloseHandle (hToken);
1984 HeapFree (GetProcessHeap (), 0, pSD);
1985 return 0;
1988 static void
1989 __gnat_set_OWNER_ACL (TCHAR *wname,
1990 ACCESS_MODE AccessMode,
1991 DWORD AccessPermissions)
1993 PACL pOldDACL = NULL;
1994 PACL pNewDACL = NULL;
1995 PSECURITY_DESCRIPTOR pSD = NULL;
1996 EXPLICIT_ACCESS ea;
1997 TCHAR username [100];
1998 DWORD unsize = 100;
2000 /* Get current user, he will act as the owner */
2002 if (!GetUserName (username, &unsize))
2003 return;
2005 if (GetNamedSecurityInfo
2006 (wname,
2007 SE_FILE_OBJECT,
2008 DACL_SECURITY_INFORMATION,
2009 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
2010 return;
2012 BuildExplicitAccessWithName
2013 (&ea, username, AccessPermissions, (ACCESS_MODE) AccessMode, NO_INHERITANCE);
2015 if (AccessMode == SET_ACCESS)
2017 /* SET_ACCESS, we want to set an explicte set of permissions, do not
2018 merge with current DACL. */
2019 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
2020 return;
2022 else
2023 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
2024 return;
2026 if (SetNamedSecurityInfo
2027 (wname, SE_FILE_OBJECT,
2028 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
2029 return;
2031 LocalFree (pSD);
2032 LocalFree (pNewDACL);
2035 /* Check if it is possible to use ACL for wname, the file must not be on a
2036 network drive. */
2038 static int
2039 __gnat_can_use_acl (TCHAR *wname)
2041 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
2044 #endif /* defined (_WIN32) */
2047 __gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
2049 if (attr->readable == ATTR_UNSET)
2051 #if defined (_WIN32)
2052 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2053 GENERIC_MAPPING GenericMapping;
2055 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2057 if (__gnat_can_use_acl (wname))
2059 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2060 GenericMapping.GenericRead = GENERIC_READ;
2061 attr->readable =
2062 __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
2064 else
2065 attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
2066 #else
2067 __gnat_stat_to_attr (-1, name, attr);
2068 #endif
2071 return attr->readable;
2075 __gnat_is_read_accessible_file (char *name)
2077 #if defined (_WIN32)
2078 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2080 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2082 return !_waccess (wname, 4);
2084 #elif defined (__vxworks)
2085 int fd;
2087 if ((fd = open (name, O_RDONLY, 0)) < 0)
2088 return 0;
2089 close (fd);
2090 return 1;
2092 #else
2093 return !access (name, R_OK);
2094 #endif
2098 __gnat_is_readable_file (char *name)
2100 struct file_attributes attr;
2102 __gnat_reset_attributes (&attr);
2103 return __gnat_is_readable_file_attr (name, &attr);
2107 __gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
2109 if (attr->writable == ATTR_UNSET)
2111 #if defined (_WIN32)
2112 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2113 GENERIC_MAPPING GenericMapping;
2115 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2117 if (__gnat_can_use_acl (wname))
2119 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2120 GenericMapping.GenericWrite = GENERIC_WRITE;
2122 attr->writable = __gnat_check_OWNER_ACL
2123 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
2124 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2126 else
2127 attr->writable =
2128 !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2130 #else
2131 __gnat_stat_to_attr (-1, name, attr);
2132 #endif
2135 return attr->writable;
2139 __gnat_is_writable_file (char *name)
2141 struct file_attributes attr;
2143 __gnat_reset_attributes (&attr);
2144 return __gnat_is_writable_file_attr (name, &attr);
2148 __gnat_is_write_accessible_file (char *name)
2150 #if defined (_WIN32)
2151 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2153 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2155 return !_waccess (wname, 2);
2157 #elif defined (__vxworks)
2158 int fd;
2160 if ((fd = open (name, O_WRONLY, 0)) < 0)
2161 return 0;
2162 close (fd);
2163 return 1;
2165 #else
2166 return !access (name, W_OK);
2167 #endif
2171 __gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
2173 if (attr->executable == ATTR_UNSET)
2175 #if defined (_WIN32)
2176 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2177 GENERIC_MAPPING GenericMapping;
2179 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2181 if (__gnat_can_use_acl (wname))
2183 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2184 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2186 attr->executable =
2187 __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2189 else
2191 TCHAR *l, *last = _tcsstr(wname, _T(".exe"));
2193 /* look for last .exe */
2194 if (last)
2195 while ((l = _tcsstr(last+1, _T(".exe"))))
2196 last = l;
2198 attr->executable =
2199 GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2200 && (last - wname) == (int) (_tcslen (wname) - 4);
2202 #else
2203 __gnat_stat_to_attr (-1, name, attr);
2204 #endif
2207 return attr->regular && attr->executable;
2211 __gnat_is_executable_file (char *name)
2213 struct file_attributes attr;
2215 __gnat_reset_attributes (&attr);
2216 return __gnat_is_executable_file_attr (name, &attr);
2219 void
2220 __gnat_set_writable (char *name)
2222 #if defined (_WIN32)
2223 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2225 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2227 if (__gnat_can_use_acl (wname))
2228 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2230 SetFileAttributes
2231 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
2232 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2233 GNAT_STRUCT_STAT statbuf;
2235 if (GNAT_STAT (name, &statbuf) == 0)
2237 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2238 chmod (name, statbuf.st_mode);
2240 #endif
2243 /* must match definition in s-os_lib.ads */
2244 #define S_OWNER 1
2245 #define S_GROUP 2
2246 #define S_OTHERS 4
2248 void
2249 __gnat_set_executable (char *name, int mode ATTRIBUTE_UNUSED)
2251 #if defined (_WIN32)
2252 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2254 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2256 if (__gnat_can_use_acl (wname))
2257 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
2259 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2260 GNAT_STRUCT_STAT statbuf;
2262 if (GNAT_STAT (name, &statbuf) == 0)
2264 if (mode & S_OWNER)
2265 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2266 if (mode & S_GROUP)
2267 statbuf.st_mode = statbuf.st_mode | S_IXGRP;
2268 if (mode & S_OTHERS)
2269 statbuf.st_mode = statbuf.st_mode | S_IXOTH;
2270 chmod (name, statbuf.st_mode);
2272 #endif
2275 void
2276 __gnat_set_non_writable (char *name)
2278 #if defined (_WIN32)
2279 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2281 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2283 if (__gnat_can_use_acl (wname))
2284 __gnat_set_OWNER_ACL
2285 (wname, DENY_ACCESS,
2286 FILE_WRITE_DATA | FILE_APPEND_DATA |
2287 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2289 SetFileAttributes
2290 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
2291 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2292 GNAT_STRUCT_STAT statbuf;
2294 if (GNAT_STAT (name, &statbuf) == 0)
2296 statbuf.st_mode = statbuf.st_mode & 07577;
2297 chmod (name, statbuf.st_mode);
2299 #endif
2302 void
2303 __gnat_set_readable (char *name)
2305 #if defined (_WIN32)
2306 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2308 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2310 if (__gnat_can_use_acl (wname))
2311 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
2313 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2314 GNAT_STRUCT_STAT statbuf;
2316 if (GNAT_STAT (name, &statbuf) == 0)
2318 chmod (name, statbuf.st_mode | S_IREAD);
2320 #endif
2323 void
2324 __gnat_set_non_readable (char *name)
2326 #if defined (_WIN32)
2327 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2329 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2331 if (__gnat_can_use_acl (wname))
2332 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
2334 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2335 GNAT_STRUCT_STAT statbuf;
2337 if (GNAT_STAT (name, &statbuf) == 0)
2339 chmod (name, statbuf.st_mode & (~S_IREAD));
2341 #endif
2345 __gnat_is_symbolic_link_attr (char* name ATTRIBUTE_UNUSED,
2346 struct file_attributes* attr)
2348 if (attr->symbolic_link == ATTR_UNSET)
2350 #if defined (__vxworks)
2351 attr->symbolic_link = 0;
2353 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2354 int ret;
2355 GNAT_STRUCT_STAT statbuf;
2356 ret = GNAT_LSTAT (name, &statbuf);
2357 attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
2358 #else
2359 attr->symbolic_link = 0;
2360 #endif
2362 return attr->symbolic_link;
2366 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2368 struct file_attributes attr;
2370 __gnat_reset_attributes (&attr);
2371 return __gnat_is_symbolic_link_attr (name, &attr);
2374 #if defined (__sun__)
2375 /* Using fork on Solaris will duplicate all the threads. fork1, which
2376 duplicates only the active thread, must be used instead, or spawning
2377 subprocess from a program with tasking will lead into numerous problems. */
2378 #define fork fork1
2379 #endif
2382 __gnat_portable_spawn (char *args[] ATTRIBUTE_UNUSED)
2384 int status ATTRIBUTE_UNUSED = 0;
2385 int finished ATTRIBUTE_UNUSED;
2386 int pid ATTRIBUTE_UNUSED;
2388 #if defined (__vxworks) || defined(__PikeOS__)
2389 return -1;
2391 #elif defined (__DJGPP__) || defined (_WIN32)
2392 /* args[0] must be quotes as it could contain a full pathname with spaces */
2393 char *args_0 = args[0];
2394 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2395 strcpy (args[0], "\"");
2396 strcat (args[0], args_0);
2397 strcat (args[0], "\"");
2399 status = spawnvp (P_WAIT, args_0, (char ** const)args);
2401 /* restore previous value */
2402 free (args[0]);
2403 args[0] = (char *)args_0;
2405 if (status < 0)
2406 return -1;
2407 else
2408 return status;
2410 #else
2412 pid = fork ();
2413 if (pid < 0)
2414 return -1;
2416 if (pid == 0)
2418 /* The child. */
2419 execv (args[0], MAYBE_TO_PTR32 (args));
2421 /* execv() returns only on error */
2422 _exit (1);
2425 /* The parent. */
2426 finished = waitpid (pid, &status, 0);
2428 if (finished != pid || WIFEXITED (status) == 0)
2429 return -1;
2431 return WEXITSTATUS (status);
2432 #endif
2434 return 0;
2437 /* Create a copy of the given file descriptor.
2438 Return -1 if an error occurred. */
2441 __gnat_dup (int oldfd)
2443 #if defined (__vxworks) && !defined (__RTP__)
2444 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2445 RTPs. */
2446 return -1;
2447 #else
2448 return dup (oldfd);
2449 #endif
2452 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2453 Return -1 if an error occurred. */
2456 __gnat_dup2 (int oldfd ATTRIBUTE_UNUSED, int newfd ATTRIBUTE_UNUSED)
2458 #if defined (__vxworks) && !defined (__RTP__)
2459 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2460 RTPs. */
2461 return -1;
2462 #elif defined (__PikeOS__)
2463 /* Not supported. */
2464 return -1;
2465 #elif defined (_WIN32)
2466 /* Special case when oldfd and newfd are identical and are the standard
2467 input, output or error as this makes Windows XP hangs. Note that we
2468 do that only for standard file descriptors that are known to be valid. */
2469 if (oldfd == newfd && newfd >= 0 && newfd <= 2)
2470 return newfd;
2471 else
2472 return dup2 (oldfd, newfd);
2473 #else
2474 return dup2 (oldfd, newfd);
2475 #endif
2479 __gnat_number_of_cpus (void)
2481 int cores = 1;
2483 #if defined (_SC_NPROCESSORS_ONLN)
2484 cores = (int) sysconf (_SC_NPROCESSORS_ONLN);
2486 #elif defined (__QNX__)
2487 cores = (int) _syspage_ptr->num_cpu;
2489 #elif defined (__hpux__)
2490 struct pst_dynamic psd;
2491 if (pstat_getdynamic (&psd, sizeof (psd), 1, 0) != -1)
2492 cores = (int) psd.psd_proc_cnt;
2494 #elif defined (_WIN32)
2495 SYSTEM_INFO sysinfo;
2496 GetSystemInfo (&sysinfo);
2497 cores = (int) sysinfo.dwNumberOfProcessors;
2499 #elif defined (_WRS_CONFIG_SMP)
2500 unsigned int vxCpuConfiguredGet (void);
2502 cores = vxCpuConfiguredGet ();
2504 #endif
2506 return cores;
2509 /* WIN32 code to implement a wait call that wait for any child process. */
2511 #if defined (_WIN32)
2513 /* Synchronization code, to be thread safe. */
2515 #ifdef CERT
2517 /* For the Cert run times on native Windows we use dummy functions
2518 for locking and unlocking tasks since we do not support multiple
2519 threads on this configuration (Cert run time on native Windows). */
2521 static void EnterCS (void) {}
2522 static void LeaveCS (void) {}
2523 static void SignalListChanged (void) {}
2525 #else
2527 CRITICAL_SECTION ProcListCS;
2528 HANDLE ProcListEvt = NULL;
2530 static void EnterCS (void)
2532 EnterCriticalSection(&ProcListCS);
2535 static void LeaveCS (void)
2537 LeaveCriticalSection(&ProcListCS);
2540 static void SignalListChanged (void)
2542 SetEvent (ProcListEvt);
2545 #endif
2547 static HANDLE *HANDLES_LIST = NULL;
2548 static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
2550 static void
2551 add_handle (HANDLE h, int pid)
2553 /* -------------------- critical section -------------------- */
2554 EnterCS();
2556 if (plist_length == plist_max_length)
2558 plist_max_length += 100;
2559 HANDLES_LIST =
2560 (HANDLE *) xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2561 PID_LIST =
2562 (int *) xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2565 HANDLES_LIST[plist_length] = h;
2566 PID_LIST[plist_length] = pid;
2567 ++plist_length;
2569 SignalListChanged();
2570 LeaveCS();
2571 /* -------------------- critical section -------------------- */
2575 __gnat_win32_remove_handle (HANDLE h, int pid)
2577 int j;
2578 int found = 0;
2580 /* -------------------- critical section -------------------- */
2581 EnterCS();
2583 for (j = 0; j < plist_length; j++)
2585 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
2587 CloseHandle (h);
2588 --plist_length;
2589 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2590 PID_LIST[j] = PID_LIST[plist_length];
2591 found = 1;
2592 break;
2596 LeaveCS();
2597 /* -------------------- critical section -------------------- */
2599 if (found)
2600 SignalListChanged();
2602 return found;
2605 static void
2606 win32_no_block_spawn (char *command, char *args[], HANDLE *h, int *pid)
2608 BOOL result;
2609 STARTUPINFO SI;
2610 PROCESS_INFORMATION PI;
2611 SECURITY_ATTRIBUTES SA;
2612 int csize = 1;
2613 char *full_command;
2614 int k;
2616 /* compute the total command line length */
2617 k = 0;
2618 while (args[k])
2620 csize += strlen (args[k]) + 1;
2621 k++;
2624 full_command = (char *) xmalloc (csize);
2626 /* Startup info. */
2627 SI.cb = sizeof (STARTUPINFO);
2628 SI.lpReserved = NULL;
2629 SI.lpReserved2 = NULL;
2630 SI.lpDesktop = NULL;
2631 SI.cbReserved2 = 0;
2632 SI.lpTitle = NULL;
2633 SI.dwFlags = 0;
2634 SI.wShowWindow = SW_HIDE;
2636 /* Security attributes. */
2637 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2638 SA.bInheritHandle = TRUE;
2639 SA.lpSecurityDescriptor = NULL;
2641 /* Prepare the command string. */
2642 strcpy (full_command, command);
2643 strcat (full_command, " ");
2645 k = 1;
2646 while (args[k])
2648 strcat (full_command, args[k]);
2649 strcat (full_command, " ");
2650 k++;
2654 int wsize = csize * 2;
2655 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2657 S2WSC (wcommand, full_command, wsize);
2659 free (full_command);
2661 result = CreateProcess
2662 (NULL, wcommand, &SA, NULL, TRUE,
2663 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2665 free (wcommand);
2668 if (result == TRUE)
2670 CloseHandle (PI.hThread);
2671 *h = PI.hProcess;
2672 *pid = PI.dwProcessId;
2674 else
2676 *h = NULL;
2677 *pid = 0;
2681 static int
2682 win32_wait (int *status)
2684 DWORD exitcode, pid;
2685 HANDLE *hl;
2686 HANDLE h;
2687 int *pidl;
2688 DWORD res;
2689 int hl_len;
2690 int found;
2691 int pos;
2693 START_WAIT:
2695 if (plist_length == 0)
2697 errno = ECHILD;
2698 return -1;
2701 /* -------------------- critical section -------------------- */
2702 EnterCS();
2704 /* ??? We can't wait for more than MAXIMUM_WAIT_OBJECTS due to a Win32
2705 limitation */
2706 if (plist_length < MAXIMUM_WAIT_OBJECTS)
2707 hl_len = plist_length;
2708 else
2710 errno = EINVAL;
2711 return -1;
2714 #ifdef CERT
2715 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2716 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
2717 pidl = (int *) xmalloc (sizeof (int) * hl_len);
2718 memmove (pidl, PID_LIST, sizeof (int) * hl_len);
2719 #else
2720 /* Note that index 0 contains the event handle that is signaled when the
2721 process list has changed */
2722 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * (hl_len + 1));
2723 hl[0] = ProcListEvt;
2724 memmove (&hl[1], HANDLES_LIST, sizeof (HANDLE) * hl_len);
2725 pidl = (int *) xmalloc (sizeof (int) * (hl_len + 1));
2726 memmove (&pidl[1], PID_LIST, sizeof (int) * hl_len);
2727 hl_len++;
2728 #endif
2730 LeaveCS();
2731 /* -------------------- critical section -------------------- */
2733 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2735 /* If there was an error, exit now */
2736 if (res == WAIT_FAILED)
2738 free (hl);
2739 free (pidl);
2740 errno = EINVAL;
2741 return -1;
2744 /* if the ProcListEvt has been signaled then the list of processes has been
2745 updated to add or remove a handle, just loop over */
2747 if (res - WAIT_OBJECT_0 == 0)
2749 free (hl);
2750 free (pidl);
2751 goto START_WAIT;
2754 /* Handle two distinct groups of return codes: finished waits and abandoned
2755 waits */
2757 if (res < WAIT_ABANDONED_0)
2758 pos = res - WAIT_OBJECT_0;
2759 else
2760 pos = res - WAIT_ABANDONED_0;
2762 h = hl[pos];
2763 GetExitCodeProcess (h, &exitcode);
2764 pid = pidl [pos];
2766 found = __gnat_win32_remove_handle (h, -1);
2768 free (hl);
2769 free (pidl);
2771 /* if not found another process waiting has already handled this process */
2773 if (!found)
2775 goto START_WAIT;
2778 *status = (int) exitcode;
2779 return (int) pid;
2782 #endif
2785 __gnat_portable_no_block_spawn (char *args[] ATTRIBUTE_UNUSED)
2788 #if defined (__vxworks) || defined (__PikeOS__)
2789 /* Not supported. */
2790 return -1;
2792 #elif defined(__DJGPP__)
2793 if (spawnvp (P_WAIT, args[0], args) != 0)
2794 return -1;
2795 else
2796 return 0;
2798 #elif defined (_WIN32)
2800 HANDLE h = NULL;
2801 int pid;
2803 win32_no_block_spawn (args[0], args, &h, &pid);
2804 if (h != NULL)
2806 add_handle (h, pid);
2807 return pid;
2809 else
2810 return -1;
2812 #else
2814 int pid = fork ();
2816 if (pid == 0)
2818 /* The child. */
2819 execv (args[0], MAYBE_TO_PTR32 (args));
2821 /* execv() returns only on error */
2822 _exit (1);
2825 return pid;
2827 #endif
2831 __gnat_portable_wait (int *process_status)
2833 int status = 0;
2834 int pid = 0;
2836 #if defined (__vxworks) || defined (__PikeOS__)
2837 /* Not sure what to do here, so do nothing but return zero. */
2839 #elif defined (_WIN32)
2841 pid = win32_wait (&status);
2843 #elif defined (__DJGPP__)
2844 /* Child process has already ended in case of DJGPP.
2845 No need to do anything. Just return success. */
2846 #else
2848 pid = waitpid (-1, &status, 0);
2849 status = status & 0xffff;
2850 #endif
2852 *process_status = status;
2853 return pid;
2857 __gnat_portable_no_block_wait (int *process_status)
2859 int status = 0;
2860 int pid = 0;
2862 #if defined (__vxworks) || defined (__PikeOS__) || defined (_WIN32)
2863 /* Not supported. */
2864 status = -1;
2866 #else
2868 pid = waitpid (-1, &status, WNOHANG);
2869 status = status & 0xffff;
2870 #endif
2872 *process_status = status;
2873 return pid;
2876 void
2877 __gnat_os_exit (int status)
2879 exit (status);
2883 __gnat_current_process_id (void)
2885 #if defined (__vxworks) || defined (__PikeOS__)
2886 return -1;
2888 #elif defined (_WIN32)
2890 return (int)GetCurrentProcessId();
2892 #else
2894 return (int)getpid();
2895 #endif
2898 /* Locate file on path, that matches a predicate */
2900 char *
2901 __gnat_locate_file_with_predicate (char *file_name, char *path_val,
2902 int (*predicate)(char *))
2904 char *ptr;
2905 char *file_path = (char *) alloca (strlen (file_name) + 1);
2906 int absolute;
2908 /* Return immediately if file_name is empty */
2910 if (*file_name == '\0')
2911 return 0;
2913 /* Remove quotes around file_name if present */
2915 ptr = file_name;
2916 if (*ptr == '"')
2917 ptr++;
2919 strcpy (file_path, ptr);
2921 ptr = file_path + strlen (file_path) - 1;
2923 if (*ptr == '"')
2924 *ptr = '\0';
2926 /* Handle absolute pathnames. */
2928 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2930 if (absolute)
2932 if (predicate (file_path))
2933 return xstrdup (file_path);
2935 return 0;
2938 /* If file_name include directory separator(s), try it first as
2939 a path name relative to the current directory */
2940 for (ptr = file_name; *ptr && !IS_DIRECTORY_SEPARATOR(*ptr); ptr++)
2943 if (*ptr != 0)
2945 if (predicate (file_name))
2946 return xstrdup (file_name);
2949 if (path_val == 0)
2950 return 0;
2953 /* The result has to be smaller than path_val + file_name. */
2954 char *file_path =
2955 (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2957 for (;;)
2959 /* Skip the starting quote */
2961 if (*path_val == '"')
2962 path_val++;
2964 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2965 *ptr++ = *path_val++;
2967 /* If directory is empty, it is the current directory*/
2969 if (ptr == file_path)
2971 *ptr = '.';
2973 else
2974 ptr--;
2976 /* Skip the ending quote */
2978 if (*ptr == '"')
2979 ptr--;
2981 if (!IS_DIRECTORY_SEPARATOR(*ptr))
2982 *++ptr = DIR_SEPARATOR;
2984 strcpy (++ptr, file_name);
2986 if (predicate (file_path))
2987 return xstrdup (file_path);
2989 if (*path_val == 0)
2990 return 0;
2992 /* Skip path separator */
2994 path_val++;
2998 return 0;
3001 /* Locate an executable file, give a Path value. */
3003 char *
3004 __gnat_locate_executable_file (char *file_name, char *path_val)
3006 return __gnat_locate_file_with_predicate
3007 (file_name, path_val, &__gnat_is_executable_file);
3010 /* Locate a regular file, give a Path value. */
3012 char *
3013 __gnat_locate_regular_file (char *file_name, char *path_val)
3015 return __gnat_locate_file_with_predicate
3016 (file_name, path_val, &__gnat_is_regular_file);
3019 /* Locate an executable given a Path argument. This routine is only used by
3020 gnatbl and should not be used otherwise. Use locate_exec_on_path
3021 instead. */
3023 char *
3024 __gnat_locate_exec (char *exec_name, char *path_val)
3026 const unsigned int len = strlen (HOST_EXECUTABLE_SUFFIX);
3027 char *ptr;
3029 if (len > 0 && !strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
3031 char *full_exec_name = (char *) alloca (strlen (exec_name) + len + 1);
3033 strcpy (full_exec_name, exec_name);
3034 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
3035 ptr = __gnat_locate_executable_file (full_exec_name, path_val);
3037 if (ptr == 0)
3038 return __gnat_locate_executable_file (exec_name, path_val);
3039 return ptr;
3041 else
3042 return __gnat_locate_executable_file (exec_name, path_val);
3045 /* Locate an executable using the Systems default PATH. */
3047 char *
3048 __gnat_locate_exec_on_path (char *exec_name)
3050 char *apath_val;
3052 #if defined (_WIN32)
3053 TCHAR *wpath_val = _tgetenv (_T("PATH"));
3054 TCHAR *wapath_val;
3055 /* In Win32 systems we expand the PATH as for XP environment
3056 variables are not automatically expanded. We also prepend the
3057 ".;" to the path to match normal NT path search semantics */
3059 #define EXPAND_BUFFER_SIZE 32767
3061 wapath_val = (TCHAR *) alloca (EXPAND_BUFFER_SIZE);
3063 wapath_val [0] = '.';
3064 wapath_val [1] = ';';
3066 DWORD res = ExpandEnvironmentStrings
3067 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
3069 if (!res) wapath_val [0] = _T('\0');
3071 apath_val = (char *) alloca (EXPAND_BUFFER_SIZE);
3073 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
3075 #else
3076 const char *path_val = getenv ("PATH");
3078 /* If PATH is not defined, proceed with __gnat_locate_exec anyway, so we can
3079 find files that contain directory names. */
3081 if (path_val == NULL) path_val = "";
3082 apath_val = (char *) alloca (strlen (path_val) + 1);
3083 strcpy (apath_val, path_val);
3084 #endif
3086 return __gnat_locate_exec (exec_name, apath_val);
3089 /* Dummy functions for Osint import for non-VMS systems.
3090 ??? To be removed. */
3093 __gnat_to_canonical_file_list_init (char *dirspec ATTRIBUTE_UNUSED,
3094 int onlydirs ATTRIBUTE_UNUSED)
3096 return 0;
3099 char *
3100 __gnat_to_canonical_file_list_next (void)
3102 static char empty[] = "";
3103 return empty;
3106 void
3107 __gnat_to_canonical_file_list_free (void)
3111 char *
3112 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3114 return dirspec;
3117 char *
3118 __gnat_to_canonical_file_spec (char *filespec)
3120 return filespec;
3123 char *
3124 __gnat_to_canonical_path_spec (char *pathspec)
3126 return pathspec;
3129 char *
3130 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3132 return dirspec;
3135 char *
3136 __gnat_to_host_file_spec (char *filespec)
3138 return filespec;
3141 void
3142 __gnat_adjust_os_resource_limits (void)
3146 #if defined (__mips_vxworks)
3148 _flush_cache (void)
3150 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3152 #endif
3154 #if defined (_WIN32)
3155 int __gnat_argument_needs_quote = 1;
3156 #else
3157 int __gnat_argument_needs_quote = 0;
3158 #endif
3160 /* This option is used to enable/disable object files handling from the
3161 binder file by the GNAT Project module. For example, this is disabled on
3162 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3163 Stating with GCC 3.4 the shared libraries are not based on mdll
3164 anymore as it uses the GCC's -shared option */
3165 #if defined (_WIN32) \
3166 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3167 int __gnat_prj_add_obj_files = 0;
3168 #else
3169 int __gnat_prj_add_obj_files = 1;
3170 #endif
3172 /* char used as prefix/suffix for environment variables */
3173 #if defined (_WIN32)
3174 char __gnat_environment_char = '%';
3175 #else
3176 char __gnat_environment_char = '$';
3177 #endif
3179 /* This functions copy the file attributes from a source file to a
3180 destination file.
3182 mode = 0 : In this mode copy only the file time stamps (last access and
3183 last modification time stamps).
3185 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3186 copied.
3188 mode = 2 : In this mode, only read/write/execute attributes are copied
3190 Returns 0 if operation was successful and -1 in case of error. */
3193 __gnat_copy_attribs (char *from ATTRIBUTE_UNUSED, char *to ATTRIBUTE_UNUSED,
3194 int mode ATTRIBUTE_UNUSED)
3196 #if (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
3197 return -1;
3199 #elif defined (_WIN32)
3200 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3201 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3202 BOOL res;
3203 FILETIME fct, flat, flwt;
3204 HANDLE hfrom, hto;
3206 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3207 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3209 /* Do we need to copy the timestamp ? */
3211 if (mode != 2) {
3212 /* retrieve from times */
3214 hfrom = CreateFile
3215 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING,
3216 FILE_ATTRIBUTE_NORMAL, NULL);
3218 if (hfrom == INVALID_HANDLE_VALUE)
3219 return -1;
3221 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3223 CloseHandle (hfrom);
3225 if (res == 0)
3226 return -1;
3228 /* retrieve from times */
3230 hto = CreateFile
3231 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
3232 FILE_ATTRIBUTE_NORMAL, NULL);
3234 if (hto == INVALID_HANDLE_VALUE)
3235 return -1;
3237 res = SetFileTime (hto, NULL, &flat, &flwt);
3239 CloseHandle (hto);
3241 if (res == 0)
3242 return -1;
3245 /* Do we need to copy the permissions ? */
3246 /* Set file attributes in full mode. */
3248 if (mode != 0)
3250 DWORD attribs = GetFileAttributes (wfrom);
3252 if (attribs == INVALID_FILE_ATTRIBUTES)
3253 return -1;
3255 res = SetFileAttributes (wto, attribs);
3256 if (res == 0)
3257 return -1;
3260 return 0;
3262 #else
3263 GNAT_STRUCT_STAT fbuf;
3265 if (GNAT_STAT (from, &fbuf) == -1) {
3266 return -1;
3269 #if (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 7)
3271 /* VxWorks prior to 7 only has utime. */
3273 /* Do we need to copy the timestamp ? */
3274 if (mode != 2) {
3275 struct utimbuf tbuf;
3277 tbuf.actime = fbuf.st_atime;
3278 tbuf.modtime = fbuf.st_mtime;
3280 if (utime (to, &tbuf) == -1)
3281 return -1;
3284 #elif _POSIX_C_SOURCE >= 200809L
3285 struct timespec tbuf[2];
3287 if (mode != 2) {
3288 tbuf[0] = fbuf.st_atim;
3289 tbuf[1] = fbuf.st_mtim;
3291 if (utimensat (AT_FDCWD, to, tbuf, 0) == -1) {
3292 return -1;
3296 #else
3297 struct timeval tbuf[2];
3298 /* Do we need to copy timestamp ? */
3300 if (mode != 2) {
3301 tbuf[0].tv_sec = fbuf.st_atime;
3302 tbuf[1].tv_sec = fbuf.st_mtime;
3304 #if defined(st_mtime)
3305 tbuf[0].tv_usec = fbuf.st_atim.tv_nsec / 1000;
3306 tbuf[1].tv_usec = fbuf.st_mtim.tv_nsec / 1000;
3307 #else
3308 tbuf[0].tv_usec = 0;
3309 tbuf[1].tv_usec = 0;
3310 #endif
3312 if (utimes (to, tbuf) == -1) {
3313 return -1;
3316 #endif
3318 /* Do we need to copy file permissions ? */
3319 if (mode != 0 && (chmod (to, fbuf.st_mode) == -1)) {
3320 return -1;
3323 return 0;
3324 #endif
3328 __gnat_lseek (int fd, long offset, int whence)
3330 return (int) lseek (fd, offset, whence);
3333 /* This function returns the major version number of GCC being used. */
3335 get_gcc_version (void)
3337 #ifdef IN_RTS
3338 return __GNUC__;
3339 #else
3340 return (int) (version_string[0] - '0');
3341 #endif
3345 * Set Close_On_Exec as indicated.
3346 * Note: this is used for both GNAT.OS_Lib and GNAT.Sockets.
3350 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3351 int close_on_exec_p ATTRIBUTE_UNUSED)
3353 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3354 int flags = fcntl (fd, F_GETFD, 0);
3355 if (flags < 0)
3356 return flags;
3357 if (close_on_exec_p)
3358 flags |= FD_CLOEXEC;
3359 else
3360 flags &= ~FD_CLOEXEC;
3361 return fcntl (fd, F_SETFD, flags);
3362 #elif defined(_WIN32)
3363 HANDLE h = (HANDLE) _get_osfhandle (fd);
3364 if (h == (HANDLE) -1)
3365 return -1;
3366 if (close_on_exec_p)
3367 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3368 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3369 HANDLE_FLAG_INHERIT);
3370 #else
3371 /* TODO: Unimplemented. */
3372 return -1;
3373 #endif
3376 /* Indicates if platforms supports automatic initialization through the
3377 constructor mechanism */
3379 __gnat_binder_supports_auto_init (void)
3381 return 1;
3384 /* Indicates that Stand-Alone Libraries are automatically initialized through
3385 the constructor mechanism */
3387 __gnat_sals_init_using_constructors (void)
3389 #if defined (__vxworks) || defined (__Lynx__)
3390 return 0;
3391 #else
3392 return 1;
3393 #endif
3396 #if defined (__linux__) || defined (__ANDROID__)
3397 /* There is no function in the glibc to retrieve the LWP of the current
3398 thread. We need to do a system call in order to retrieve this
3399 information. */
3400 #include <sys/syscall.h>
3401 void *
3402 __gnat_lwp_self (void)
3404 return (void *) syscall (__NR_gettid);
3406 #endif
3408 #if defined (__APPLE__)
3409 # if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060
3410 # include <mach/thread_info.h>
3411 # include <mach/mach_init.h>
3412 # include <mach/thread_act.h>
3413 # else
3414 # include <pthread.h>
3415 # endif
3417 /* System-wide thread identifier. Note it could be truncated on 32 bit
3418 hosts.
3419 Previously was: pthread_mach_thread_np (pthread_self ()). */
3420 void *
3421 __gnat_lwp_self (void)
3423 #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060
3424 thread_identifier_info_data_t data;
3425 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
3426 kern_return_t kret;
3428 kret = thread_info (mach_thread_self (), THREAD_IDENTIFIER_INFO,
3429 (thread_info_t) &data, &count);
3430 if (kret == KERN_SUCCESS)
3431 return (void *)(uintptr_t)data.thread_id;
3432 else
3433 return 0;
3434 #else
3435 return (void *)pthread_mach_thread_np (pthread_self ());
3436 #endif
3438 #endif
3440 #if defined (__linux__)
3441 #include <sched.h>
3443 /* glibc versions earlier than 2.7 do not define the routines to handle
3444 dynamically allocated CPU sets. For these targets, we use the static
3445 versions. */
3447 #ifdef CPU_ALLOC
3449 /* Dynamic cpu sets */
3451 cpu_set_t *
3452 __gnat_cpu_alloc (size_t count)
3454 return CPU_ALLOC (count);
3457 size_t
3458 __gnat_cpu_alloc_size (size_t count)
3460 return CPU_ALLOC_SIZE (count);
3463 void
3464 __gnat_cpu_free (cpu_set_t *set)
3466 CPU_FREE (set);
3469 void
3470 __gnat_cpu_zero (size_t count, cpu_set_t *set)
3472 CPU_ZERO_S (count, set);
3475 void
3476 __gnat_cpu_set (int cpu, size_t count, cpu_set_t *set)
3478 /* Ada handles CPU numbers starting from 1, while C identifies the first
3479 CPU by a 0, so we need to adjust. */
3480 CPU_SET_S (cpu - 1, count, set);
3483 #else /* !CPU_ALLOC */
3485 /* Static cpu sets */
3487 cpu_set_t *
3488 __gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED)
3490 return (cpu_set_t *) xmalloc (sizeof (cpu_set_t));
3493 size_t
3494 __gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED)
3496 return sizeof (cpu_set_t);
3499 void
3500 __gnat_cpu_free (cpu_set_t *set)
3502 free (set);
3505 void
3506 __gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3508 CPU_ZERO (set);
3511 void
3512 __gnat_cpu_set (int cpu, size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3514 /* Ada handles CPU numbers starting from 1, while C identifies the first
3515 CPU by a 0, so we need to adjust. */
3516 CPU_SET (cpu - 1, set);
3518 #endif /* !CPU_ALLOC */
3519 #endif /* __linux__ */
3521 /* Return the load address of the executable, or 0 if not known. In the
3522 specific case of error, (void *)-1 can be returned. Beware: this unit may
3523 be in a shared library. As low-level units are needed, we allow #include
3524 here. */
3526 #if defined (__APPLE__)
3527 #include <mach-o/dyld.h>
3528 #elif defined (__linux__)
3529 #include <features.h>
3530 #include <link.h>
3531 #endif
3533 const void *
3534 __gnat_get_executable_load_address (void)
3536 #if defined (__APPLE__)
3537 return _dyld_get_image_header (0);
3539 #elif defined (__linux__) && (defined (__GLIBC__) || defined (__UCLIBC__))
3540 struct link_map *map = _r_debug.r_map;
3541 return (const void *)map->l_addr;
3543 #elif defined (_WIN32)
3544 return GetModuleHandle (NULL);
3546 #else
3547 return NULL;
3548 #endif
3551 void
3552 __gnat_kill (int pid, int sig)
3554 #if defined(_WIN32)
3555 HANDLE h;
3557 switch (sig) {
3558 case 9: // SIGKILL is not declared in Windows headers
3559 case SIGINT:
3560 case SIGBREAK:
3561 case SIGTERM:
3562 case SIGABRT:
3563 h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
3564 if (h != NULL) {
3565 TerminateProcess (h, sig);
3566 CloseHandle (h);
3570 #elif defined (__vxworks)
3571 /* Not implemented */
3572 #else
3573 kill (pid, sig);
3574 #endif
3577 void __gnat_killprocesstree (int pid, int sig_num)
3579 #if defined(_WIN32)
3580 PROCESSENTRY32 pe;
3582 memset(&pe, 0, sizeof(PROCESSENTRY32));
3583 pe.dwSize = sizeof(PROCESSENTRY32);
3585 HANDLE hSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
3587 /* cannot take snapshot, just kill the parent process */
3589 if (hSnap == INVALID_HANDLE_VALUE)
3591 __gnat_kill (pid, sig_num);
3592 return;
3595 if (Process32First(hSnap, &pe))
3597 BOOL bContinue = TRUE;
3599 /* kill child processes first */
3601 while (bContinue)
3603 if (pe.th32ParentProcessID == (DWORD)pid)
3604 __gnat_killprocesstree (pe.th32ProcessID, sig_num);
3606 bContinue = Process32Next (hSnap, &pe);
3610 CloseHandle (hSnap);
3612 /* kill process */
3614 __gnat_kill (pid, sig_num);
3616 #elif defined (__vxworks)
3617 /* not implemented */
3619 #elif defined (__linux__)
3620 DIR *dir;
3621 struct dirent *d;
3623 /* read all processes' pid and ppid */
3625 dir = opendir ("/proc");
3627 /* cannot open proc, just kill the parent process */
3629 if (!dir)
3631 __gnat_kill (pid, sig_num);
3632 return;
3635 /* kill child processes first */
3637 while ((d = readdir (dir)) != NULL)
3639 if ((d->d_type & DT_DIR) == DT_DIR)
3641 char statfile[64];
3642 int _pid, _ppid;
3644 /* read /proc/<PID>/stat */
3646 if (strlen (d->d_name) >= sizeof (statfile) - strlen ("/proc//stat"))
3647 continue;
3648 strcpy (statfile, "/proc/");
3649 strcat (statfile, d->d_name);
3650 strcat (statfile, "/stat");
3652 FILE *fd = fopen (statfile, "r");
3654 if (fd)
3656 const int match = fscanf (fd, "%d %*s %*s %d", &_pid, &_ppid);
3657 fclose (fd);
3659 if (match == 2 && _ppid == pid)
3660 __gnat_killprocesstree (_pid, sig_num);
3665 closedir (dir);
3667 /* kill process */
3669 __gnat_kill (pid, sig_num);
3670 #else
3671 __gnat_kill (pid, sig_num);
3672 #endif
3673 /* Note on Solaris it is possible to read /proc/<PID>/status.
3674 The 5th and 6th words are the pid and the 7th and 8th the ppid.
3675 See: /usr/include/sys/procfs.h (struct pstatus).
3679 #ifdef __cplusplus
3681 #endif