1 /****************************************************************************
3 * GNAT COMPILER COMPONENTS *
7 * C Implementation File *
9 * Copyright (C) 1992-2020, Free Software Foundation, Inc. *
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. *
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. *
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/>. *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
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. */
47 /* Use 64 bit Large File API */
49 #define _LARGEFILE64_SOURCE 1
50 #elif !defined(_LARGEFILE_SOURCE)
51 #define _LARGEFILE_SOURCE
53 #define _FILE_OFFSET_BITS 64
57 /* No need to redefine exit here. */
60 /* We want to use the POSIX variants of include files. */
65 #if defined (__mips_vxworks)
67 #endif /* __mips_vxworks */
69 /* If SMP, access vxCpuConfiguredGet */
70 #ifdef _WRS_CONFIG_SMP
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. */
78 /* vwModNum.h and dosFsLib.h are needed for the VxWorks 6 rename workaround.
80 #if (_WRS_VXWORKS_MAJOR == 6)
86 #if defined (__APPLE__)
90 #if defined (__hpux__)
91 #include <sys/param.h>
92 #include <sys/pstat.h>
96 #define __BSD_VISIBLE 1
100 #include <sys/syspage.h>
107 #include <sys/types.h>
108 #include <sys/stat.h>
113 /* for CPU_SET/CPU_ZERO */
124 #include <sys/stat.h>
128 #if defined (__vxworks) || defined (__ANDROID__)
129 /* S_IREAD and S_IWRITE are not defined in VxWorks or Android */
131 #define S_IREAD (S_IRUSR | S_IRGRP | S_IROTH)
135 #define S_IWRITE (S_IWUSR)
139 /* We don't have libiberty, so use malloc. */
140 #define xmalloc(S) malloc (S)
141 #define xrealloc(V,S) realloc (V,S)
148 /* limits.h is needed for LLONG_MIN. */
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. */
167 #define ISALPHA isalpha
170 #elif defined (__MINGW32__) || defined (__CYGWIN__)
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. */
186 #define ISALPHA isalpha
189 #elif defined (__Lynx__)
191 /* Lynx utime.h only defines the entities of interest to us if
192 defined (VMOS_DEV), so ... */
201 /* wait.h processing */
204 # include <sys/wait.h>
206 #elif defined (__vxworks) && defined (__RTP__)
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. */
220 #include <sys/wait.h>
223 #if defined (__DJGPP__)
229 #define DIR_SEPARATOR '\\'
231 #elif defined (_WIN32)
236 #include <tlhelp32.h>
239 #define DIR_SEPARATOR '\\'
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
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. */
268 #ifndef HOST_EXECUTABLE_SUFFIX
269 #define HOST_EXECUTABLE_SUFFIX ""
272 #ifndef HOST_OBJECT_SUFFIX
273 #define HOST_OBJECT_SUFFIX ".o"
276 #ifndef PATH_SEPARATOR
277 #define PATH_SEPARATOR ':'
280 #ifndef DIR_SEPARATOR
281 #define DIR_SEPARATOR '/'
282 #define IS_DIRECTORY_SEPARATOR(c) ((c) == DIR_SEPARATOR)
284 #define IS_DIRECTORY_SEPARATOR(c) ((c) == '/' || (c) == DIR_SEPARATOR)
287 /* Check for cross-compilation. */
288 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
290 int __gnat_is_cross_compiler
= 1;
293 int __gnat_is_cross_compiler
= 0;
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
313 * if they are needed but not present, the link
316 * otherwise they are libraries in the system paths and so
317 they are considered part of the system and not checked
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"
328 const char *__gnat_library_template
= GNAT_LIBRARY_TEMPLATE
;
330 #if defined (__vxworks)
331 #define GNAT_MAX_PATH_LEN PATH_MAX
335 #if defined (__MINGW32__)
339 #include <sys/param.h>
343 #include <sys/param.h>
347 #define GNAT_MAX_PATH_LEN MAXPATHLEN
349 #define GNAT_MAX_PATH_LEN 256
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
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
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 */
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
) {
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
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. */
433 /* The sub-seconds are manually set to zero since type time_t lacks the
434 precision necessary for nanoseconds. */
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
)
442 time_t time
= (time_t) *p_time
;
444 res
= gmtime (&time
);
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
;
455 *p_year
= *p_month
= *p_day
= *p_hours
= *p_mins
= *p_secs
= 0;
459 __gnat_to_os_time (OS_Time
*p_time
, int year
, int month
, int day
,
460 int hours
, int mins
, int secs
)
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__)
491 return readlink (path
, buf
, bufsiz
);
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__)
507 return symlink (oldpath
, newpath
);
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
)
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);
548 sprintf (full_path
, "%s%c%s", dir
, DIR_SEPARATOR
, file
);
549 fd
= open (full_path
, O_CREAT
| O_EXCL
, 0600);
561 /* Version using link(), more secure over NFS. */
562 /* See TN 6913-016 for discussion ??? */
565 __gnat_try_lock (char *dir
, char *file
)
569 GNAT_STRUCT_STAT stat_result
;
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);
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
);
590 return stat_result
.st_nlink
== 2;
594 /* Return the maximum file name length. */
597 __gnat_get_maximum_file_name_length (void)
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';
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;
625 file_names_case_sensitive_cache
= 1;
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__)
645 __gnat_get_default_identifier_character_set (void)
650 /* Return the current working directory. */
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
);
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. */
675 *length
= strlen (dir
);
677 if (dir
[*length
- 1] != DIR_SEPARATOR
)
679 dir
[*length
] = DIR_SEPARATOR
;
685 /* Return the suffix for object files. */
688 __gnat_get_object_suffix_ptr (int *len
, const char **value
)
690 *value
= HOST_OBJECT_SUFFIX
;
695 *len
= strlen (*value
);
700 /* Return the suffix for executable files. */
703 __gnat_get_executable_suffix_ptr (int *len
, const char **value
)
705 *value
= HOST_EXECUTABLE_SUFFIX
;
710 *len
= strlen (*value
);
715 /* Return the suffix for debuggable files. Usually this is the same as the
716 executable extension. */
719 __gnat_get_debuggable_suffix_ptr (int *len
, const char **value
)
721 *value
= HOST_EXECUTABLE_SUFFIX
;
726 *len
= strlen (*value
);
731 /* Returns the OS filename and corresponding encoding. */
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
);
745 strcpy (os_name
, filename
);
746 *o_length
= strlen (filename
);
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
);
764 return unlink (path
);
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
))
796 return rename (from
, to
);
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
);
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 */
837 #if defined (_WIN32) || defined (__linux__) || defined (__sun__) \
838 || defined (__FreeBSD__) || defined(__DragonFly__) || defined (__QNX__)
839 #define HAS_TARGET_WCHAR_T
842 #ifdef HAS_TARGET_WCHAR_T
847 __gnat_fputwc(int c
, FILE *stream
)
849 #ifdef HAS_TARGET_WCHAR_T
850 return fputwc ((wchar_t)c
, stream
);
852 return fputc (c
, stream
);
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
];
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
);
870 S2WS (wpath
, path
, GNAT_MAX_PATH_LEN
);
872 return _tfopen (wpath
, wmode
);
875 return GNAT_FOPEN (path
, mode
);
880 __gnat_freopen (char *path
,
883 int encoding ATTRIBUTE_UNUSED
)
885 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
886 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
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
);
896 S2WS (wpath
, path
, GNAT_MAX_PATH_LEN
);
898 return _tfreopen (wpath
, wmode
, stream
);
900 return freopen (path
, mode
, stream
);
905 __gnat_open_read (char *path
, int fmode
)
908 int o_fmode
= O_BINARY
;
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);
923 fd
= GNAT_OPEN (path
, O_RDONLY
| o_fmode
);
926 return fd
< 0 ? -1 : fd
;
929 #if defined (__MINGW32__)
930 #define PERM (S_IREAD | S_IWRITE)
932 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
936 __gnat_open_rw (char *path
, int fmode
)
939 int o_fmode
= O_BINARY
;
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
);
952 fd
= GNAT_OPEN (path
, O_RDWR
| o_fmode
, PERM
);
955 return fd
< 0 ? -1 : fd
;
959 __gnat_open_create (char *path
, int fmode
)
962 int o_fmode
= O_BINARY
;
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
);
975 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| o_fmode
, PERM
);
978 return fd
< 0 ? -1 : fd
;
982 __gnat_create_output_file (char *path
)
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
);
993 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
, PERM
);
996 return fd
< 0 ? -1 : fd
;
1000 __gnat_create_output_file_new (char *path
)
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
);
1011 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
| O_EXCL
, PERM
);
1014 return fd
< 0 ? -1 : fd
;
1018 __gnat_open_append (char *path
, int fmode
)
1021 int o_fmode
= O_BINARY
;
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
);
1034 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_APPEND
| o_fmode
, PERM
);
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
)
1046 int o_fmode
= O_BINARY
;
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
);
1059 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_EXCL
| o_fmode
, PERM
);
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
)
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__)
1082 if (mktemp (path
) == NULL
)
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
)
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
);
1106 fd
= GNAT_OPEN (path
, fmode
, PERM
);
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 ****************************************************************/
1118 __gnat_stat_to_attr (int fd
, char* name
, struct file_attributes
* attr
)
1120 GNAT_STRUCT_STAT statbuf
;
1124 /* GNAT_FSTAT returns -1 and sets errno for failure */
1125 ret
= GNAT_FSTAT (fd
, &statbuf
);
1126 error
= ret
? errno
: 0;
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
1139 if (error
== 0 || error
== ENOENT
)
1142 attr
->error
= error
;
1144 attr
->regular
= (!ret
&& S_ISREG (statbuf
.st_mode
));
1145 attr
->directory
= (!ret
&& S_ISDIR (statbuf
.st_mode
));
1148 attr
->file_length
= 0;
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
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
));
1165 attr
->timestamp
= (OS_Time
)-1;
1167 attr
->timestamp
= (OS_Time
)statbuf
.st_mtime
;
1171 /****************************************************************
1172 ** Return the number of bytes in the specified file
1173 ****************************************************************/
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
;
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
);
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
);
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
1213 __gnat_tmp_name (char *tmp_filename
)
1215 #if defined (__MINGW32__)
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 */
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);
1243 strcpy (tmp_filename
, 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
)
1258 strcpy (tmp_filename
, "/cache/gnat-XXXXXX");
1260 strcpy (tmp_filename
, "/tmp/gnat-XXXXXX");
1263 sprintf (tmp_filename
, "%s/gnat-XXXXXX", tmpdir
);
1265 close (mkstemp(tmp_filename
));
1266 #elif defined (__vxworks) && !defined (VTHREADS)
1270 static ushort_t seed
= 0; /* used to generate unique name */
1272 /* Generate a unique name. */
1273 strcpy (tmp_filename
, "tmp");
1276 savepos
= pos
= tmp_filename
+ strlen (tmp_filename
) + index
;
1284 /* Fill up the name buffer from the last position. */
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");
1298 tmpnam (tmp_filename
);
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
);
1313 return opendir (name
);
1317 /* Read the next entry in a directory. The returned string points somewhere
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
1328 __gnat_readdir (DIR *dirp
, char *buffer
, int *len
)
1330 #if defined (__MINGW32__)
1331 struct _tdirent
*dirent
= _treaddir ((_TDIR
*)dirp
);
1335 WS2SC (buffer
, dirent
->d_name
, GNAT_MAX_PATH_LEN
);
1336 *len
= strlen (buffer
);
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
;
1354 struct dirent
*dirent
= (struct dirent
*) readdir (dirp
);
1358 strcpy (buffer
, dirent
->d_name
);
1359 *len
= strlen (buffer
);
1368 /* Close a directory entry. */
1370 int __gnat_closedir (DIR *dirp
)
1372 #if defined (__MINGW32__)
1373 return _tclosedir ((_TDIR
*)dirp
);
1376 return closedir (dirp
);
1380 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1383 __gnat_readdir_is_thread_safe (void)
1385 #ifdef HAVE_READDIR_R
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
1402 win32_filetime (HANDLE h
)
1407 unsigned long long ull_time
;
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
);
1419 /* As above but starting from a FILETIME. */
1421 f2t (const FILETIME
*ft
, __time64_t
*t
)
1426 unsigned long long ull_time
;
1429 t_write
.ft_time
= *ft
;
1430 *t
= (__time64_t
) (t_write
.ull_time
/ 10000000ULL - w32_epoch_offset
);
1434 /* Return a GNAT time stamp given a file name. */
1437 __gnat_file_time_name_attr (char* name
, struct file_attributes
* attr
)
1439 if (attr
->timestamp
== (OS_Time
)-2) {
1440 #if defined (_WIN32)
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
;
1451 __gnat_stat_to_attr (-1, name
, attr
);
1454 return attr
->timestamp
;
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. */
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
;
1477 __gnat_stat_to_attr (fd
, NULL
, attr
);
1481 return attr
->timestamp
;
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
)
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;
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
;
1514 if (!GetFileAttributesExA(name
, GetFileExInfoStandard
, &fad
)) {
1518 t_write
.ft_time
= fad
.ftLastWriteTime
;
1520 #if defined(__GNUG__) && __GNUG__ <= 4
1521 result
= (t_write
.ll_time
- w32_epoch_offset
) * 100;
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
)) {
1530 if (__builtin_smulll_overflow(result
, 100, &result
)) {
1538 if (stat(name
, &sb
) != 0) {
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
;
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
)) {
1556 if (__builtin_smulll_overflow(result
, 1E9
, &result
)) {
1560 #if defined(st_mtime)
1561 if (__builtin_saddll_overflow(result
, sb
.st_mtim
.tv_nsec
, &result
)) {
1570 /* Set the file time stamp. */
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)
1583 unsigned long long ull_time
;
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
,
1593 if (h
== INVALID_HANDLE_VALUE
)
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
);
1605 struct utimbuf utimbuf
;
1608 /* Set modification time to requested time. */
1609 utimbuf
.modtime
= time_stamp
;
1611 /* Set access time to now in local time. */
1613 utimbuf
.actime
= mktime (localtime (&t
));
1615 utime (name
, &utimbuf
);
1619 /* Get the list of installed standard libraries from the
1620 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1624 __gnat_get_libraries_from_registry (void)
1626 char *result
= (char *) xmalloc (1);
1630 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
1633 DWORD name_size
, value_size
;
1640 /* First open the key. */
1641 res
= RegOpenKeyExA (HKEY_LOCAL_MACHINE
, "SOFTWARE", 0, KEY_READ
, ®_key
);
1643 if (res
== ERROR_SUCCESS
)
1644 res
= RegOpenKeyExA (reg_key
, "Ada Core Technologies", 0,
1645 KEY_READ
, ®_key
);
1647 if (res
== ERROR_SUCCESS
)
1648 res
= RegOpenKeyExA (reg_key
, "GNAT", 0, KEY_READ
, ®_key
);
1650 if (res
== ERROR_SUCCESS
)
1651 res
= RegOpenKeyExA (reg_key
, "Standard Libraries", 0, KEY_READ
, ®_key
);
1653 /* If the key exists, read out all the values in it and concatenate them
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
, ";");
1673 /* Remove the trailing ";". */
1675 result
[strlen (result
) - 1] = 0;
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
)
1688 WIN32_FILE_ATTRIBUTE_DATA fad
;
1689 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
1694 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
1695 name_len
= _tcslen (wname
);
1697 if (name_len
> GNAT_MAX_PATH_LEN
)
1700 ZeroMemory (statbuf
, sizeof(GNAT_STRUCT_STAT
));
1702 res
= GetFileAttributesEx (wname
, GetFileExInfoStandard
, &fad
);
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
;
1717 case ERROR_ACCESS_DENIED
:
1718 case ERROR_SHARING_VIOLATION
:
1719 case ERROR_LOCK_VIOLATION
:
1720 case ERROR_SHARING_BUFFER_EXCEEDED
:
1722 case ERROR_BUFFER_OVERFLOW
:
1723 return ENAMETOOLONG
;
1724 case ERROR_NOT_ENOUGH_MEMORY
:
1731 f2t (&fad
.ftCreationTime
, &statbuf
->st_ctime
);
1732 f2t (&fad
.ftLastWriteTime
, &statbuf
->st_mtime
);
1733 f2t (&fad
.ftLastAccessTime
, &statbuf
->st_atime
);
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
;
1744 statbuf
->st_mode
|= S_IFREG
;
1746 if (!(fad
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
))
1747 statbuf
->st_mode
|= S_IWRITE
;
1752 return GNAT_STAT (name
, statbuf
) == 0 ? 0 : errno
;
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
)
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. */
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] == '/')))
1802 else if (name
[index
] == '/')
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]))
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
)
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
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
);
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('\\'));
1910 /* logical drive \\.\c\dir\file */
1916 _tcscat (p
, _T(":\\"));
1918 return GetDriveType (p
);
1925 /* This MingW section contains code to work with ACL. */
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
;
1937 PSECURITY_DESCRIPTOR pSD
= NULL
;
1940 (wname
, OWNER_SECURITY_INFORMATION
|
1941 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
1944 if ((pSD
= (SECURITY_DESCRIPTOR
*) HeapAlloc
1945 (GetProcessHeap (), HEAP_ZERO_MEMORY
, nLength
)) == NULL
)
1948 /* Obtain the security descriptor. */
1950 if (!GetFileSecurity
1951 (wname
, OWNER_SECURITY_INFORMATION
|
1952 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
1953 pSD
, nLength
, &nLength
))
1956 if (!ImpersonateSelf (SecurityImpersonation
))
1959 if (!OpenThreadToken
1960 (GetCurrentThread(), TOKEN_DUPLICATE
| TOKEN_QUERY
, FALSE
, &hToken
))
1963 /* Undoes the effect of ImpersonateSelf. */
1967 /* We want to test for write permissions. */
1969 dwAccessDesired
= CheckAccessDesired
;
1971 MapGenericMask (&dwAccessDesired
, &CheckGenericMapping
);
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 */
1984 CloseHandle (hToken
);
1985 HeapFree (GetProcessHeap (), 0, pSD
);
1986 return fAccessGranted
;
1990 CloseHandle (hToken
);
1991 HeapFree (GetProcessHeap (), 0, pSD
);
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
;
2004 TCHAR username
[100];
2007 /* Get current user, he will act as the owner */
2009 if (!GetUserName (username
, &unsize
))
2012 if (GetNamedSecurityInfo
2015 DACL_SECURITY_INFORMATION
,
2016 NULL
, NULL
, &pOldDACL
, NULL
, &pSD
) != ERROR_SUCCESS
)
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
)
2030 if (SetEntriesInAcl (1, &ea
, pOldDACL
, &pNewDACL
) != ERROR_SUCCESS
)
2033 if (SetNamedSecurityInfo
2034 (wname
, SE_FILE_OBJECT
,
2035 DACL_SECURITY_INFORMATION
, NULL
, NULL
, pNewDACL
, NULL
) != ERROR_SUCCESS
)
2039 LocalFree (pNewDACL
);
2042 /* Check if it is possible to use ACL for wname, the file must not be on a
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
;
2069 __gnat_check_OWNER_ACL (wname
, FILE_READ_DATA
, GenericMapping
);
2072 attr
->readable
= GetFileAttributes (wname
) != INVALID_FILE_ATTRIBUTES
;
2074 __gnat_stat_to_attr (-1, name
, attr
);
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)
2094 if ((fd
= open (name
, O_RDONLY
, 0)) < 0)
2100 return !access (name
, R_OK
);
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
);
2135 !(GetFileAttributes (wname
) & FILE_ATTRIBUTE_READONLY
);
2138 __gnat_stat_to_attr (-1, name
, attr
);
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)
2167 if ((fd
= open (name
, O_WRONLY
, 0)) < 0)
2173 return !access (name
, W_OK
);
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
;
2194 __gnat_check_OWNER_ACL (wname
, FILE_EXECUTE
, GenericMapping
);
2198 TCHAR
*l
, *last
= _tcsstr(wname
, _T(".exe"));
2200 /* look for last .exe */
2202 while ((l
= _tcsstr(last
+1, _T(".exe"))))
2206 GetFileAttributes (wname
) != INVALID_FILE_ATTRIBUTES
2207 && (last
- wname
) == (int) (_tcslen (wname
) - 4);
2210 __gnat_stat_to_attr (-1, name
, attr
);
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
);
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
);
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
);
2250 /* must match definition in s-os_lib.ads */
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)
2272 statbuf
.st_mode
= statbuf
.st_mode
| S_IXUSR
;
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
);
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
);
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
);
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
);
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
));
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__)
2362 GNAT_STRUCT_STAT statbuf
;
2363 ret
= GNAT_LSTAT (name
, &statbuf
);
2364 attr
->symbolic_link
= (!ret
&& S_ISLNK (statbuf
.st_mode
));
2366 attr
->symbolic_link
= 0;
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. */
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__)
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 */
2410 args
[0] = (char *)args_0
;
2426 __gnat_in_child_after_fork
= 1;
2427 if (execv (args
[0], MAYBE_TO_PTR32 (args
)) != 0)
2432 finished
= waitpid (pid
, &status
, 0);
2434 if (finished
!= pid
|| WIFEXITED (status
) == 0)
2437 return WEXITSTATUS (status
);
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
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
2468 #elif defined (__PikeOS__)
2469 /* Not supported. */
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)
2478 return dup2 (oldfd
, newfd
);
2480 return dup2 (oldfd
, newfd
);
2485 __gnat_number_of_cpus (void)
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 ();
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. */
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) {}
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
);
2553 static HANDLE
*HANDLES_LIST
= NULL
;
2554 static int *PID_LIST
= NULL
, plist_length
= 0, plist_max_length
= 0;
2557 add_handle (HANDLE h
, int pid
)
2559 /* -------------------- critical section -------------------- */
2562 if (plist_length
== plist_max_length
)
2564 plist_max_length
+= 100;
2566 (HANDLE
*) xrealloc (HANDLES_LIST
, sizeof (HANDLE
) * plist_max_length
);
2568 (int *) xrealloc (PID_LIST
, sizeof (int) * plist_max_length
);
2571 HANDLES_LIST
[plist_length
] = h
;
2572 PID_LIST
[plist_length
] = pid
;
2575 SignalListChanged();
2577 /* -------------------- critical section -------------------- */
2581 __gnat_win32_remove_handle (HANDLE h
, int pid
)
2586 /* -------------------- critical section -------------------- */
2589 for (j
= 0; j
< plist_length
; j
++)
2591 if ((HANDLES_LIST
[j
] == h
) || (PID_LIST
[j
] == pid
))
2595 HANDLES_LIST
[j
] = HANDLES_LIST
[plist_length
];
2596 PID_LIST
[j
] = PID_LIST
[plist_length
];
2603 /* -------------------- critical section -------------------- */
2606 SignalListChanged();
2612 win32_no_block_spawn (char *command
, char *args
[], HANDLE
*h
, int *pid
)
2616 PROCESS_INFORMATION PI
;
2617 SECURITY_ATTRIBUTES SA
;
2622 /* compute the total command line length */
2626 csize
+= strlen (args
[k
]) + 1;
2630 full_command
= (char *) xmalloc (csize
);
2633 SI
.cb
= sizeof (STARTUPINFO
);
2634 SI
.lpReserved
= NULL
;
2635 SI
.lpReserved2
= NULL
;
2636 SI
.lpDesktop
= NULL
;
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
, " ");
2654 strcat (full_command
, args
[k
]);
2655 strcat (full_command
, " ");
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
);
2676 CloseHandle (PI
.hThread
);
2678 *pid
= PI
.dwProcessId
;
2688 win32_wait (int *status
)
2690 DWORD exitcode
, pid
;
2701 if (plist_length
== 0)
2707 /* -------------------- critical section -------------------- */
2710 /* ??? We can't wait for more than MAXIMUM_WAIT_OBJECTS due to a Win32
2712 if (plist_length
< MAXIMUM_WAIT_OBJECTS
)
2713 hl_len
= plist_length
;
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
);
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
);
2737 /* -------------------- critical section -------------------- */
2739 res
= WaitForMultipleObjects (hl_len
, hl
, FALSE
, INFINITE
);
2741 /* If there was an error, exit now */
2742 if (res
== WAIT_FAILED
)
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)
2760 /* Handle two distinct groups of return codes: finished waits and abandoned
2763 if (res
< WAIT_ABANDONED_0
)
2764 pos
= res
- WAIT_OBJECT_0
;
2766 pos
= res
- WAIT_ABANDONED_0
;
2769 GetExitCodeProcess (h
, &exitcode
);
2772 found
= __gnat_win32_remove_handle (h
, -1);
2777 /* if not found another process waiting has already handled this process */
2784 *status
= (int) exitcode
;
2791 __gnat_portable_no_block_spawn (char *args
[] ATTRIBUTE_UNUSED
)
2794 #if defined (__vxworks) || defined (__PikeOS__)
2795 /* Not supported. */
2798 #elif defined(__DJGPP__)
2799 if (spawnvp (P_WAIT
, args
[0], args
) != 0)
2804 #elif defined (_WIN32)
2809 win32_no_block_spawn (args
[0], args
, &h
, &pid
);
2812 add_handle (h
, pid
);
2825 if (execv (args
[0], MAYBE_TO_PTR32 (args
)) != 0)
2835 __gnat_portable_wait (int *process_status
)
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. */
2852 pid
= waitpid (-1, &status
, 0);
2853 status
= status
& 0xffff;
2856 *process_status
= status
;
2861 __gnat_portable_no_block_wait (int *process_status
)
2866 #if defined (__vxworks) || defined (__PikeOS__) || defined (_WIN32)
2867 /* Not supported. */
2872 pid
= waitpid (-1, &status
, WNOHANG
);
2873 status
= status
& 0xffff;
2876 *process_status
= status
;
2881 __gnat_os_exit (int status
)
2887 __gnat_current_process_id (void)
2889 #if defined (__vxworks) || defined (__PikeOS__)
2892 #elif defined (_WIN32)
2894 return (int)GetCurrentProcessId();
2898 return (int)getpid();
2902 /* Locate file on path, that matches a predicate */
2905 __gnat_locate_file_with_predicate (char *file_name
, char *path_val
,
2906 int (*predicate
)(char *))
2909 char *file_path
= (char *) alloca (strlen (file_name
) + 1);
2912 /* Return immediately if file_name is empty */
2914 if (*file_name
== '\0')
2917 /* Remove quotes around file_name if present */
2923 strcpy (file_path
, ptr
);
2925 ptr
= file_path
+ strlen (file_path
) - 1;
2930 /* Handle absolute pathnames. */
2932 absolute
= __gnat_is_absolute_path (file_path
, strlen (file_name
));
2936 if (predicate (file_path
))
2937 return xstrdup (file_path
);
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
++)
2949 if (predicate (file_name
))
2950 return xstrdup (file_name
);
2957 /* The result has to be smaller than path_val + file_name. */
2959 (char *) alloca (strlen (path_val
) + strlen (file_name
) + 2);
2963 /* Skip the starting quote */
2965 if (*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
)
2980 /* Skip the ending quote */
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
);
2996 /* Skip path separator */
3005 /* Locate an executable file, give a Path value. */
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. */
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
3028 __gnat_locate_exec (char *exec_name
, char *path_val
)
3030 const unsigned int len
= strlen (HOST_EXECUTABLE_SUFFIX
);
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
);
3042 return __gnat_locate_executable_file (exec_name
, path_val
);
3046 return __gnat_locate_executable_file (exec_name
, path_val
);
3049 /* Locate an executable using the Systems default PATH. */
3052 __gnat_locate_exec_on_path (char *exec_name
)
3056 #if defined (_WIN32)
3057 TCHAR
*wpath_val
= _tgetenv (_T("PATH"));
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
);
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
);
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
)
3104 __gnat_to_canonical_file_list_next (void)
3106 static char empty
[] = "";
3111 __gnat_to_canonical_file_list_free (void)
3116 __gnat_to_canonical_dir_spec (char *dirspec
, int prefixflag ATTRIBUTE_UNUSED
)
3122 __gnat_to_canonical_file_spec (char *filespec
)
3128 __gnat_to_canonical_path_spec (char *pathspec
)
3134 __gnat_to_host_dir_spec (char *dirspec
, int prefixflag ATTRIBUTE_UNUSED
)
3140 __gnat_to_host_file_spec (char *filespec
)
3146 __gnat_adjust_os_resource_limits (void)
3150 #if defined (__mips_vxworks)
3154 CACHE_USER_FLUSH (0, ENTIRE_CACHE
);
3158 #if defined (_WIN32)
3159 int __gnat_argument_needs_quote
= 1;
3161 int __gnat_argument_needs_quote
= 0;
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;
3173 int __gnat_prj_add_obj_files
= 1;
3176 /* char used as prefix/suffix for environment variables */
3177 #if defined (_WIN32)
3178 char __gnat_environment_char
= '%';
3180 char __gnat_environment_char
= '$';
3183 /* This functions copy the file attributes from a source file to a
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
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)
3203 #elif defined (_WIN32)
3204 TCHAR wfrom
[GNAT_MAX_PATH_LEN
+ 2];
3205 TCHAR wto
[GNAT_MAX_PATH_LEN
+ 2];
3207 FILETIME fct
, flat
, flwt
;
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 ? */
3216 /* retrieve from times */
3219 (wfrom
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
3220 FILE_ATTRIBUTE_NORMAL
, NULL
);
3222 if (hfrom
== INVALID_HANDLE_VALUE
)
3225 res
= GetFileTime (hfrom
, &fct
, &flat
, &flwt
);
3227 CloseHandle (hfrom
);
3232 /* retrieve from times */
3235 (wto
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
,
3236 FILE_ATTRIBUTE_NORMAL
, NULL
);
3238 if (hto
== INVALID_HANDLE_VALUE
)
3241 res
= SetFileTime (hto
, NULL
, &flat
, &flwt
);
3249 /* Do we need to copy the permissions ? */
3250 /* Set file attributes in full mode. */
3254 DWORD attribs
= GetFileAttributes (wfrom
);
3256 if (attribs
== INVALID_FILE_ATTRIBUTES
)
3259 res
= SetFileAttributes (wto
, attribs
);
3267 GNAT_STRUCT_STAT fbuf
;
3269 if (GNAT_STAT (from
, &fbuf
) == -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 ? */
3279 struct utimbuf tbuf
;
3281 tbuf
.actime
= fbuf
.st_atime
;
3282 tbuf
.modtime
= fbuf
.st_mtime
;
3284 if (utime (to
, &tbuf
) == -1)
3288 #elif _POSIX_C_SOURCE >= 200809L
3289 struct timespec tbuf
[2];
3292 tbuf
[0] = fbuf
.st_atim
;
3293 tbuf
[1] = fbuf
.st_mtim
;
3295 if (utimensat (AT_FDCWD
, to
, tbuf
, 0) == -1) {
3301 struct timeval tbuf
[2];
3302 /* Do we need to copy timestamp ? */
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;
3312 tbuf
[0].tv_usec
= 0;
3313 tbuf
[1].tv_usec
= 0;
3316 if (utimes (to
, tbuf
) == -1) {
3322 /* Do we need to copy file permissions ? */
3323 if (mode
!= 0 && (chmod (to
, fbuf
.st_mode
) == -1)) {
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)
3344 return (int) (version_string
[0] - '0');
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);
3361 if (close_on_exec_p
)
3362 flags
|= FD_CLOEXEC
;
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)
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
);
3375 /* TODO: Unimplemented. */
3380 /* Indicates if platforms supports automatic initialization through the
3381 constructor mechanism */
3383 __gnat_binder_supports_auto_init (void)
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__)
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
3404 #include <sys/syscall.h>
3406 __gnat_lwp_self (void)
3408 return (void *) syscall (__NR_gettid
);
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>
3418 # include <pthread.h>
3421 /* System-wide thread identifier. Note it could be truncated on 32 bit
3423 Previously was: pthread_mach_thread_np (pthread_self ()). */
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
;
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
;
3439 return (void *)pthread_mach_thread_np (pthread_self ());
3444 #if defined (__linux__)
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
3453 /* Dynamic cpu sets */
3456 __gnat_cpu_alloc (size_t count
)
3458 return CPU_ALLOC (count
);
3462 __gnat_cpu_alloc_size (size_t count
)
3464 return CPU_ALLOC_SIZE (count
);
3468 __gnat_cpu_free (cpu_set_t
*set
)
3474 __gnat_cpu_zero (size_t count
, cpu_set_t
*set
)
3476 CPU_ZERO_S (count
, set
);
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 */
3492 __gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED
)
3494 return (cpu_set_t
*) xmalloc (sizeof (cpu_set_t
));
3498 __gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED
)
3500 return sizeof (cpu_set_t
);
3504 __gnat_cpu_free (cpu_set_t
*set
)
3510 __gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED
, cpu_set_t
*set
)
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
3530 #if defined (__APPLE__)
3531 #include <mach-o/dyld.h>
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
;
3552 __gnat_kill (int pid
, int sig
, int close ATTRIBUTE_UNUSED
)
3555 HANDLE h
= OpenProcess (PROCESS_ALL_ACCESS
, FALSE
, pid
);
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 */
3572 #elif defined (__vxworks)
3573 /* Not implemented */
3579 void __gnat_killprocesstree (int pid
, int sig_num
)
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);
3597 if (Process32First(hSnap
, &pe
))
3599 BOOL bContinue
= TRUE
;
3601 /* kill child processes first */
3605 if (pe
.th32ParentProcessID
== (DWORD
)pid
)
3606 __gnat_killprocesstree (pe
.th32ProcessID
, sig_num
);
3608 bContinue
= Process32Next (hSnap
, &pe
);
3612 CloseHandle (hSnap
);
3616 __gnat_kill (pid
, sig_num
, 1);
3618 #elif defined (__vxworks)
3619 /* not implemented */
3621 #elif defined (__linux__)
3625 /* read all processes' pid and ppid */
3627 dir
= opendir ("/proc");
3629 /* cannot open proc, just kill the parent process */
3633 __gnat_kill (pid
, sig_num
, 1);
3637 /* kill child processes first */
3639 while ((d
= readdir (dir
)) != NULL
)
3641 if ((d
->d_type
& DT_DIR
) == DT_DIR
)
3646 /* read /proc/<PID>/stat */
3648 if (strlen (d
->d_name
) >= sizeof (statfile
) - strlen ("/proc//stat"))
3650 strcpy (statfile
, "/proc/");
3651 strcat (statfile
, d
->d_name
);
3652 strcat (statfile
, "/stat");
3654 FILE *fd
= fopen (statfile
, "r");
3658 const int match
= fscanf (fd
, "%d %*s %*s %d", &_pid
, &_ppid
);
3661 if (match
== 2 && _ppid
== pid
)
3662 __gnat_killprocesstree (_pid
, sig_num
);
3671 __gnat_kill (pid
, sig_num
, 1);
3673 __gnat_kill (pid
, sig_num
, 1);
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).