1 /****************************************************************************
3 * GNAT COMPILER COMPONENTS *
7 * C Implementation File *
9 * Copyright (C) 1992-2018, 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. */
41 /* Use 64 bit Large File API */
42 #ifndef _LARGEFILE_SOURCE
43 #define _LARGEFILE_SOURCE
45 #define _FILE_OFFSET_BITS 64
49 /* No need to redefine exit here. */
52 /* We want to use the POSIX variants of include files. */
56 #if defined (__mips_vxworks)
58 #endif /* __mips_vxworks */
60 /* If SMP, access vxCpuConfiguredGet */
61 #ifdef _WRS_CONFIG_SMP
63 #endif /* _WRS_CONFIG_SMP */
65 /* We need to know the VxWorks version because some file operations
66 (such as chmod) are only available on VxWorks 6. */
71 #if defined (__APPLE__)
75 #if defined (__hpux__)
76 #include <sys/param.h>
77 #include <sys/pstat.h>
81 #define __BSD_VISIBLE 1
85 #define _LARGEFILE64_SOURCE 1
95 #if defined (__vxworks) || defined (__ANDROID__)
96 /* S_IREAD and S_IWRITE are not defined in VxWorks or Android */
98 #define S_IREAD (S_IRUSR | S_IRGRP | S_IROTH)
102 #define S_IWRITE (S_IWUSR)
106 /* We don't have libiberty, so use malloc. */
107 #define xmalloc(S) malloc (S)
108 #define xrealloc(V,S) realloc (V,S)
119 #if defined (__DJGPP__)
121 /* For isalpha-like tests in the compiler, we're expected to resort to
122 safe-ctype.h/ISALPHA. This isn't available for the runtime library
123 build, so we fallback on ctype.h/isalpha there. */
127 #define ISALPHA isalpha
130 #elif defined (__MINGW32__) || defined (__CYGWIN__)
134 /* Current code page and CCS encoding to use, set in initialize.c. */
135 UINT __gnat_current_codepage
;
136 UINT __gnat_current_ccs_encoding
;
138 #include <sys/utime.h>
140 /* For isalpha-like tests in the compiler, we're expected to resort to
141 safe-ctype.h/ISALPHA. This isn't available for the runtime library
142 build, so we fallback on ctype.h/isalpha there. */
146 #define ISALPHA isalpha
149 #elif defined (__Lynx__)
151 /* Lynx utime.h only defines the entities of interest to us if
152 defined (VMOS_DEV), so ... */
161 /* wait.h processing */
164 # include <sys/wait.h>
166 #elif defined (__vxworks) && defined (__RTP__)
168 #elif defined (__Lynx__)
169 /* ??? We really need wait.h and it includes resource.h on Lynx. GCC
170 has a resource.h header as well, included instead of the lynx
171 version in our setup, causing lots of errors. We don't really need
172 the lynx contents of this file, so just workaround the issue by
173 preventing the inclusion of the GCC header from doing anything. */
174 # define GCC_RESOURCE_H
175 # include <sys/wait.h>
176 #elif defined (__PikeOS__)
177 /* No wait() or waitpid() calls available. */
180 #include <sys/wait.h>
183 #if defined (__DJGPP__)
189 #define DIR_SEPARATOR '\\'
191 #elif defined (_WIN32)
196 #include <tlhelp32.h>
199 #define DIR_SEPARATOR '\\'
207 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
208 defined in the current system. On DOS-like systems these flags control
209 whether the file is opened/created in text-translation mode (CR/LF in
210 external file mapped to LF in internal file), but in Unix-like systems,
211 no text translation is required, so these flags have no effect. */
221 #ifndef HOST_EXECUTABLE_SUFFIX
222 #define HOST_EXECUTABLE_SUFFIX ""
225 #ifndef HOST_OBJECT_SUFFIX
226 #define HOST_OBJECT_SUFFIX ".o"
229 #ifndef PATH_SEPARATOR
230 #define PATH_SEPARATOR ':'
233 #ifndef DIR_SEPARATOR
234 #define DIR_SEPARATOR '/'
237 /* Check for cross-compilation. */
238 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
240 int __gnat_is_cross_compiler
= 1;
243 int __gnat_is_cross_compiler
= 0;
246 char __gnat_dir_separator
= DIR_SEPARATOR
;
248 char __gnat_path_separator
= PATH_SEPARATOR
;
250 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
251 the base filenames that libraries specified with -lsomelib options
252 may have. This is used by GNATMAKE to check whether an executable
253 is up-to-date or not. The syntax is
255 library_template ::= { pattern ; } pattern NUL
256 pattern ::= [ prefix ] * [ postfix ]
258 These should only specify names of static libraries as it makes
259 no sense to determine at link time if dynamic-link libraries are
260 up to date or not. Any libraries that are not found are supposed
263 * if they are needed but not present, the link
266 * otherwise they are libraries in the system paths and so
267 they are considered part of the system and not checked
270 ??? This should be part of a GNAT host-specific compiler
271 file instead of being included in all user applications
272 as well. This is only a temporary work-around for 3.11b. */
274 #ifndef GNAT_LIBRARY_TEMPLATE
275 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
278 const char *__gnat_library_template
= GNAT_LIBRARY_TEMPLATE
;
280 #if defined (__vxworks)
281 #define GNAT_MAX_PATH_LEN PATH_MAX
285 #if defined (__MINGW32__)
289 #include <sys/param.h>
293 #include <sys/param.h>
297 #define GNAT_MAX_PATH_LEN MAXPATHLEN
299 #define GNAT_MAX_PATH_LEN 256
304 /* Used for runtime check that Ada constant File_Attributes_Size is no
305 less than the actual size of struct file_attributes (see Osint
307 int __gnat_size_of_file_attributes
= sizeof (struct file_attributes
);
309 void __gnat_stat_to_attr (int fd
, char* name
, struct file_attributes
* attr
);
311 /* The __gnat_max_path_len variable is used to export the maximum
312 length of a path name to Ada code. max_path_len is also provided
313 for compatibility with older GNAT versions, please do not use
316 int __gnat_max_path_len
= GNAT_MAX_PATH_LEN
;
317 int max_path_len
= GNAT_MAX_PATH_LEN
;
319 /* Control whether we can use ACL on Windows. */
321 int __gnat_use_acl
= 1;
323 /* The following macro HAVE_READDIR_R should be defined if the
324 system provides the routine readdir_r.
325 ... but we never define it anywhere??? */
326 #undef HAVE_READDIR_R
328 #define MAYBE_TO_PTR32(argv) argv
330 static const char ATTR_UNSET
= 127;
332 /* Reset the file attributes as if no system call had been performed */
335 __gnat_reset_attributes (struct file_attributes
* attr
)
337 attr
->exists
= ATTR_UNSET
;
338 attr
->error
= EINVAL
;
340 attr
->writable
= ATTR_UNSET
;
341 attr
->readable
= ATTR_UNSET
;
342 attr
->executable
= ATTR_UNSET
;
344 attr
->regular
= ATTR_UNSET
;
345 attr
->symbolic_link
= ATTR_UNSET
;
346 attr
->directory
= ATTR_UNSET
;
348 attr
->timestamp
= (OS_Time
)-2;
349 attr
->file_length
= -1;
353 __gnat_error_attributes (struct file_attributes
*attr
) {
358 __gnat_current_time (void)
360 time_t res
= time (NULL
);
361 return (OS_Time
) res
;
364 /* Return the current local time as a string in the ISO 8601 format of
365 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
369 __gnat_current_time_string (char *result
)
371 const char *format
= "%Y-%m-%d %H:%M:%S";
372 /* Format string necessary to describe the ISO 8601 format */
374 const time_t t_val
= time (NULL
);
376 strftime (result
, 22, format
, localtime (&t_val
));
377 /* Convert the local time into a string following the ISO format, copying
378 at most 22 characters into the result string. */
383 /* The sub-seconds are manually set to zero since type time_t lacks the
384 precision necessary for nanoseconds. */
388 __gnat_to_gm_time (OS_Time
*p_time
, int *p_year
, int *p_month
, int *p_day
,
389 int *p_hours
, int *p_mins
, int *p_secs
)
392 time_t time
= (time_t) *p_time
;
395 /* On Windows systems, the time is sometimes rounded up to the nearest
396 even second, so if the number of seconds is odd, increment it. */
401 res
= gmtime (&time
);
404 *p_year
= res
->tm_year
;
405 *p_month
= res
->tm_mon
;
406 *p_day
= res
->tm_mday
;
407 *p_hours
= res
->tm_hour
;
408 *p_mins
= res
->tm_min
;
409 *p_secs
= res
->tm_sec
;
412 *p_year
= *p_month
= *p_day
= *p_hours
= *p_mins
= *p_secs
= 0;
416 __gnat_to_os_time (OS_Time
*p_time
, int year
, int month
, int day
,
417 int hours
, int mins
, int secs
)
429 /* returns -1 of failing, this is s-os_lib Invalid_Time */
431 *p_time
= (OS_Time
) mktime (&v
);
434 /* Place the contents of the symbolic link named PATH in the buffer BUF,
435 which has size BUFSIZ. If PATH is a symbolic link, then return the number
436 of characters of its content in BUF. Otherwise, return -1.
437 For systems not supporting symbolic links, always return -1. */
440 __gnat_readlink (char *path ATTRIBUTE_UNUSED
,
441 char *buf ATTRIBUTE_UNUSED
,
442 size_t bufsiz ATTRIBUTE_UNUSED
)
444 #if defined (_WIN32) \
445 || defined(__vxworks) || defined (__PikeOS__)
448 return readlink (path
, buf
, bufsiz
);
452 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
453 If NEWPATH exists it will NOT be overwritten.
454 For systems not supporting symbolic links, always return -1. */
457 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED
,
458 char *newpath ATTRIBUTE_UNUSED
)
460 #if defined (_WIN32) \
461 || defined(__vxworks) || defined (__PikeOS__)
464 return symlink (oldpath
, newpath
);
468 /* Try to lock a file, return 1 if success. */
470 #if defined (__vxworks) \
471 || defined (_WIN32) || defined (__PikeOS__)
473 /* Version that does not use link. */
476 __gnat_try_lock (char *dir
, char *file
)
480 TCHAR wfull_path
[GNAT_MAX_PATH_LEN
];
481 TCHAR wfile
[GNAT_MAX_PATH_LEN
];
482 TCHAR wdir
[GNAT_MAX_PATH_LEN
];
484 S2WSC (wdir
, dir
, GNAT_MAX_PATH_LEN
);
485 S2WSC (wfile
, file
, GNAT_MAX_PATH_LEN
);
487 /* ??? the code below crash on MingW64 for obscure reasons, a ticket
488 has been opened here:
490 https://sourceforge.net/p/mingw-w64/bugs/414/
492 As a workaround an equivalent set of code has been put in place below.
494 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
497 _tcscpy (wfull_path
, wdir
);
498 _tcscat (wfull_path
, L
"\\");
499 _tcscat (wfull_path
, wfile
);
501 fd
= _topen (wfull_path
, O_CREAT
| O_EXCL
, 0600);
505 sprintf (full_path
, "%s%c%s", dir
, DIR_SEPARATOR
, file
);
506 fd
= open (full_path
, O_CREAT
| O_EXCL
, 0600);
518 /* Version using link(), more secure over NFS. */
519 /* See TN 6913-016 for discussion ??? */
522 __gnat_try_lock (char *dir
, char *file
)
526 GNAT_STRUCT_STAT stat_result
;
529 sprintf (full_path
, "%s%c%s", dir
, DIR_SEPARATOR
, file
);
530 sprintf (temp_file
, "%s%cTMP-%ld-%ld",
531 dir
, DIR_SEPARATOR
, (long)getpid(), (long)getppid ());
533 /* Create the temporary file and write the process number. */
534 fd
= open (temp_file
, O_CREAT
| O_WRONLY
, 0600);
540 /* Link it with the new file. */
541 link (temp_file
, full_path
);
543 /* Count the references on the old one. If we have a count of two, then
544 the link did succeed. Remove the temporary file before returning. */
545 __gnat_stat (temp_file
, &stat_result
);
547 return stat_result
.st_nlink
== 2;
551 /* Return the maximum file name length. */
554 __gnat_get_maximum_file_name_length (void)
559 /* Return nonzero if file names are case sensitive. */
561 static int file_names_case_sensitive_cache
= -1;
564 __gnat_get_file_names_case_sensitive (void)
566 if (file_names_case_sensitive_cache
== -1)
568 const char *sensitive
= getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
570 if (sensitive
!= NULL
571 && (sensitive
[0] == '0' || sensitive
[0] == '1')
572 && sensitive
[1] == '\0')
573 file_names_case_sensitive_cache
= sensitive
[0] - '0';
576 /* By default, we suppose filesystems aren't case sensitive on
577 Windows and Darwin (but they are on arm-darwin). */
578 #if defined (WINNT) || defined (__DJGPP__) \
579 || (defined (__APPLE__) && !(defined (__arm__) || defined (__arm64__)))
580 file_names_case_sensitive_cache
= 0;
582 file_names_case_sensitive_cache
= 1;
586 return file_names_case_sensitive_cache
;
589 /* Return nonzero if environment variables are case sensitive. */
592 __gnat_get_env_vars_case_sensitive (void)
594 #if defined (WINNT) || defined (__DJGPP__)
602 __gnat_get_default_identifier_character_set (void)
607 /* Return the current working directory. */
610 __gnat_get_current_dir (char *dir
, int *length
)
612 #if defined (__MINGW32__)
613 TCHAR wdir
[GNAT_MAX_PATH_LEN
];
615 _tgetcwd (wdir
, *length
);
617 WS2SC (dir
, wdir
, GNAT_MAX_PATH_LEN
);
620 char* result
= getcwd (dir
, *length
);
621 /* If the current directory does not exist, set length = 0
622 to indicate error. That can't happen on windows, where
623 you can't delete a directory if it is the current
624 directory of some process. */
632 *length
= strlen (dir
);
634 if (dir
[*length
- 1] != DIR_SEPARATOR
)
636 dir
[*length
] = DIR_SEPARATOR
;
642 /* Return the suffix for object files. */
645 __gnat_get_object_suffix_ptr (int *len
, const char **value
)
647 *value
= HOST_OBJECT_SUFFIX
;
652 *len
= strlen (*value
);
657 /* Return the suffix for executable files. */
660 __gnat_get_executable_suffix_ptr (int *len
, const char **value
)
662 *value
= HOST_EXECUTABLE_SUFFIX
;
666 *len
= strlen (*value
);
671 /* Return the suffix for debuggable files. Usually this is the same as the
672 executable extension. */
675 __gnat_get_debuggable_suffix_ptr (int *len
, const char **value
)
677 *value
= HOST_EXECUTABLE_SUFFIX
;
682 *len
= strlen (*value
);
687 /* Returns the OS filename and corresponding encoding. */
690 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED
,
691 char *w_filename ATTRIBUTE_UNUSED
,
692 char *os_name
, int *o_length
,
693 char *encoding ATTRIBUTE_UNUSED
, int *e_length
)
695 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
696 WS2SC (os_name
, (TCHAR
*)w_filename
, (DWORD
)*o_length
);
697 *o_length
= strlen (os_name
);
698 strcpy (encoding
, "encoding=utf8");
699 *e_length
= strlen (encoding
);
701 strcpy (os_name
, filename
);
702 *o_length
= strlen (filename
);
710 __gnat_unlink (char *path
)
712 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
714 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
716 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
717 return _tunlink (wpath
);
720 return unlink (path
);
727 __gnat_rename (char *from
, char *to
)
729 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
731 TCHAR wfrom
[GNAT_MAX_PATH_LEN
], wto
[GNAT_MAX_PATH_LEN
];
733 S2WSC (wfrom
, from
, GNAT_MAX_PATH_LEN
);
734 S2WSC (wto
, to
, GNAT_MAX_PATH_LEN
);
735 return _trename (wfrom
, wto
);
738 return rename (from
, to
);
742 /* Changing directory. */
745 __gnat_chdir (char *path
)
747 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
749 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
751 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
752 return _tchdir (wpath
);
759 /* Removing a directory. */
762 __gnat_rmdir (char *path
)
764 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
766 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
768 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
769 return _trmdir (wpath
);
771 #elif defined (VTHREADS)
772 /* rmdir not available */
779 #if defined (_WIN32) || defined (__linux__) || defined (__sun__) \
780 || defined (__FreeBSD__) || defined(__DragonFly__) || defined (__QNX__)
781 #define HAS_TARGET_WCHAR_T
784 #ifdef HAS_TARGET_WCHAR_T
789 __gnat_fputwc(int c
, FILE *stream
)
791 #ifdef HAS_TARGET_WCHAR_T
792 return fputwc ((wchar_t)c
, stream
);
794 return fputc (c
, stream
);
799 __gnat_fopen (char *path
, char *mode
, int encoding ATTRIBUTE_UNUSED
)
801 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
802 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
805 S2WS (wmode
, mode
, 10);
807 if (encoding
== Encoding_Unspecified
)
808 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
809 else if (encoding
== Encoding_UTF8
)
810 S2WSU (wpath
, path
, GNAT_MAX_PATH_LEN
);
812 S2WS (wpath
, path
, GNAT_MAX_PATH_LEN
);
814 return _tfopen (wpath
, wmode
);
817 return GNAT_FOPEN (path
, mode
);
822 __gnat_freopen (char *path
,
825 int encoding ATTRIBUTE_UNUSED
)
827 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
828 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
831 S2WS (wmode
, mode
, 10);
833 if (encoding
== Encoding_Unspecified
)
834 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
835 else if (encoding
== Encoding_UTF8
)
836 S2WSU (wpath
, path
, GNAT_MAX_PATH_LEN
);
838 S2WS (wpath
, path
, GNAT_MAX_PATH_LEN
);
840 return _tfreopen (wpath
, wmode
, stream
);
842 return freopen (path
, mode
, stream
);
847 __gnat_open_read (char *path
, int fmode
)
850 int o_fmode
= O_BINARY
;
855 #if defined (__vxworks)
856 fd
= open (path
, O_RDONLY
| o_fmode
, 0444);
857 #elif defined (__MINGW32__)
859 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
861 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
862 fd
= _topen (wpath
, O_RDONLY
| o_fmode
, 0444);
865 fd
= GNAT_OPEN (path
, O_RDONLY
| o_fmode
);
868 return fd
< 0 ? -1 : fd
;
871 #if defined (__MINGW32__)
872 #define PERM (S_IREAD | S_IWRITE)
874 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
878 __gnat_open_rw (char *path
, int fmode
)
881 int o_fmode
= O_BINARY
;
886 #if defined (__MINGW32__)
888 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
890 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
891 fd
= _topen (wpath
, O_RDWR
| o_fmode
, PERM
);
894 fd
= GNAT_OPEN (path
, O_RDWR
| o_fmode
, PERM
);
897 return fd
< 0 ? -1 : fd
;
901 __gnat_open_create (char *path
, int fmode
)
904 int o_fmode
= O_BINARY
;
909 #if defined (__MINGW32__)
911 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
913 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
914 fd
= _topen (wpath
, O_WRONLY
| O_CREAT
| O_TRUNC
| o_fmode
, PERM
);
917 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| o_fmode
, PERM
);
920 return fd
< 0 ? -1 : fd
;
924 __gnat_create_output_file (char *path
)
927 #if defined (__MINGW32__)
929 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
931 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
932 fd
= _topen (wpath
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
, PERM
);
935 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
, PERM
);
938 return fd
< 0 ? -1 : fd
;
942 __gnat_create_output_file_new (char *path
)
945 #if defined (__MINGW32__)
947 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
949 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
950 fd
= _topen (wpath
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
| O_EXCL
, PERM
);
953 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
| O_EXCL
, PERM
);
956 return fd
< 0 ? -1 : fd
;
960 __gnat_open_append (char *path
, int fmode
)
963 int o_fmode
= O_BINARY
;
968 #if defined (__MINGW32__)
970 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
972 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
973 fd
= _topen (wpath
, O_WRONLY
| O_CREAT
| O_APPEND
| o_fmode
, PERM
);
976 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_APPEND
| o_fmode
, PERM
);
979 return fd
< 0 ? -1 : fd
;
982 /* Open a new file. Return error (-1) if the file already exists. */
985 __gnat_open_new (char *path
, int fmode
)
988 int o_fmode
= O_BINARY
;
993 #if defined (__MINGW32__)
995 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
997 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
998 fd
= _topen (wpath
, O_WRONLY
| O_CREAT
| O_EXCL
| o_fmode
, PERM
);
1001 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_EXCL
| o_fmode
, PERM
);
1004 return fd
< 0 ? -1 : fd
;
1007 /* Open a new temp file. Return error (-1) if the file already exists. */
1010 __gnat_open_new_temp (char *path
, int fmode
)
1013 int o_fmode
= O_BINARY
;
1015 strcpy (path
, "GNAT-XXXXXX");
1017 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
1018 || defined (__linux__) || defined (__GLIBC__) || defined (__ANDROID__) \
1019 || defined (__DragonFly__) || defined (__QNX__)) && !defined (__vxworks)
1020 return mkstemp (path
);
1021 #elif defined (__Lynx__)
1024 if (mktemp (path
) == NULL
)
1031 fd
= GNAT_OPEN (path
, O_WRONLY
| O_CREAT
| O_EXCL
| o_fmode
, PERM
);
1032 return fd
< 0 ? -1 : fd
;
1036 __gnat_open (char *path
, int fmode
)
1040 #if defined (__MINGW32__)
1042 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
1044 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
1045 fd
= _topen (wpath
, fmode
, PERM
);
1048 fd
= GNAT_OPEN (path
, fmode
, PERM
);
1051 return fd
< 0 ? -1 : fd
;
1054 /****************************************************************
1055 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1056 ** as possible from it, storing the result in a cache for later reuse
1057 ****************************************************************/
1060 __gnat_stat_to_attr (int fd
, char* name
, struct file_attributes
* attr
)
1062 GNAT_STRUCT_STAT statbuf
;
1066 /* GNAT_FSTAT returns -1 and sets errno for failure */
1067 ret
= GNAT_FSTAT (fd
, &statbuf
);
1068 error
= ret
? errno
: 0;
1071 /* __gnat_stat returns errno value directly */
1072 error
= __gnat_stat (name
, &statbuf
);
1073 ret
= error
? -1 : 0;
1077 * A missing file is reported as an attr structure with error == 0 and
1081 if (error
== 0 || error
== ENOENT
)
1084 attr
->error
= error
;
1086 attr
->regular
= (!ret
&& S_ISREG (statbuf
.st_mode
));
1087 attr
->directory
= (!ret
&& S_ISDIR (statbuf
.st_mode
));
1090 attr
->file_length
= 0;
1092 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1093 don't return a useful value for files larger than 2 gigabytes in
1095 attr
->file_length
= statbuf
.st_size
; /* all systems */
1097 attr
->exists
= !ret
;
1099 #if !defined (_WIN32)
1100 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1101 attr
->readable
= (!ret
&& (statbuf
.st_mode
& S_IRUSR
));
1102 attr
->writable
= (!ret
&& (statbuf
.st_mode
& S_IWUSR
));
1103 attr
->executable
= (!ret
&& (statbuf
.st_mode
& S_IXUSR
));
1107 attr
->timestamp
= (OS_Time
)-1;
1109 attr
->timestamp
= (OS_Time
)statbuf
.st_mtime
;
1113 /****************************************************************
1114 ** Return the number of bytes in the specified file
1115 ****************************************************************/
1118 __gnat_file_length_attr (int fd
, char* name
, struct file_attributes
* attr
)
1120 if (attr
->file_length
== -1) {
1121 __gnat_stat_to_attr (fd
, name
, attr
);
1124 return attr
->file_length
;
1128 __gnat_file_length (int fd
)
1130 struct file_attributes attr
;
1131 __gnat_reset_attributes (&attr
);
1132 return __gnat_file_length_attr (fd
, NULL
, &attr
);
1136 __gnat_file_length_long (int fd
)
1138 struct file_attributes attr
;
1139 __gnat_reset_attributes (&attr
);
1140 return (long)__gnat_file_length_attr (fd
, NULL
, &attr
);
1144 __gnat_named_file_length (char *name
)
1146 struct file_attributes attr
;
1147 __gnat_reset_attributes (&attr
);
1148 return __gnat_file_length_attr (-1, name
, &attr
);
1151 /* Create a temporary filename and put it in string pointed to by
1155 __gnat_tmp_name (char *tmp_filename
)
1157 #if defined (__MINGW32__)
1162 /* tempnam tries to create a temporary file in directory pointed to by
1163 TMP environment variable, in c:\temp if TMP is not set, and in
1164 directory specified by P_tmpdir in stdio.h if c:\temp does not
1165 exist. The filename will be created with the prefix "gnat-". */
1167 sprintf (prefix
, "gnat-%d-", (int)getpid());
1168 pname
= (char *) _tempnam ("c:\\temp", prefix
);
1170 /* if pname is NULL, the file was not created properly, the disk is full
1171 or there is no more free temporary files */
1174 *tmp_filename
= '\0';
1176 /* If pname start with a back slash and not path information it means that
1177 the filename is valid for the current working directory. */
1179 else if (pname
[0] == '\\')
1181 strcpy (tmp_filename
, ".\\");
1182 strcat (tmp_filename
, pname
+1);
1185 strcpy (tmp_filename
, pname
);
1190 #elif defined (__linux__) || defined (__FreeBSD__) || defined (__NetBSD__) \
1191 || defined (__OpenBSD__) || defined (__GLIBC__) || defined (__ANDROID__) \
1192 || defined (__DragonFly__) || defined (__QNX__)
1193 #define MAX_SAFE_PATH 1000
1194 char *tmpdir
= getenv ("TMPDIR");
1196 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1197 a buffer overflow. */
1198 if (tmpdir
== NULL
|| strlen (tmpdir
) > MAX_SAFE_PATH
)
1200 strcpy (tmp_filename
, "/cache/gnat-XXXXXX");
1202 strcpy (tmp_filename
, "/tmp/gnat-XXXXXX");
1205 sprintf (tmp_filename
, "%s/gnat-XXXXXX", tmpdir
);
1207 close (mkstemp(tmp_filename
));
1208 #elif defined (__vxworks) && !defined (VTHREADS)
1212 static ushort_t seed
= 0; /* used to generate unique name */
1214 /* Generate a unique name. */
1215 strcpy (tmp_filename
, "tmp");
1218 savepos
= pos
= tmp_filename
+ strlen (tmp_filename
) + index
;
1226 /* Fill up the name buffer from the last position. */
1228 for (t
= seed
; --index
>= 0; t
>>= 3)
1229 *--pos
= '0' + (t
& 07);
1231 /* Check to see if its unique, if not bump the seed and try again. */
1232 f
= fopen (tmp_filename
, "r");
1240 tmpnam (tmp_filename
);
1244 /* Open directory and returns a DIR pointer. */
1246 DIR* __gnat_opendir (char *name
)
1248 #if defined (__MINGW32__)
1249 TCHAR wname
[GNAT_MAX_PATH_LEN
];
1251 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
);
1252 return (DIR*)_topendir (wname
);
1255 return opendir (name
);
1259 /* Read the next entry in a directory. The returned string points somewhere
1262 #if defined (__sun__)
1263 /* For Solaris, be sure to use the 64-bit version, otherwise NFS reads may
1264 fail with EOVERFLOW if the server uses 64-bit cookies. */
1265 #define dirent dirent64
1266 #define readdir readdir64
1270 __gnat_readdir (DIR *dirp
, char *buffer
, int *len
)
1272 #if defined (__MINGW32__)
1273 struct _tdirent
*dirent
= _treaddir ((_TDIR
*)dirp
);
1277 WS2SC (buffer
, dirent
->d_name
, GNAT_MAX_PATH_LEN
);
1278 *len
= strlen (buffer
);
1285 #elif defined (HAVE_READDIR_R)
1286 /* If possible, try to use the thread-safe version. */
1287 if (readdir_r (dirp
, buffer
) != NULL
)
1289 *len
= strlen (((struct dirent
*) buffer
)->d_name
);
1290 return ((struct dirent
*) buffer
)->d_name
;
1296 struct dirent
*dirent
= (struct dirent
*) readdir (dirp
);
1300 strcpy (buffer
, dirent
->d_name
);
1301 *len
= strlen (buffer
);
1310 /* Close a directory entry. */
1312 int __gnat_closedir (DIR *dirp
)
1314 #if defined (__MINGW32__)
1315 return _tclosedir ((_TDIR
*)dirp
);
1318 return closedir (dirp
);
1322 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1325 __gnat_readdir_is_thread_safe (void)
1327 #ifdef HAVE_READDIR_R
1334 #if defined (_WIN32)
1335 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1336 static const unsigned long long w32_epoch_offset
= 11644473600ULL;
1338 /* Returns the file modification timestamp using Win32 routines which are
1339 immune against daylight saving time change. It is in fact not possible to
1340 use fstat for this purpose as the DST modify the st_mtime field of the
1344 win32_filetime (HANDLE h
)
1349 unsigned long long ull_time
;
1352 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1353 since <Jan 1st 1601>. This function must return the number of seconds
1354 since <Jan 1st 1970>. */
1356 if (GetFileTime (h
, NULL
, NULL
, &t_write
.ft_time
))
1357 return (time_t) (t_write
.ull_time
/ 10000000ULL - w32_epoch_offset
);
1361 /* As above but starting from a FILETIME. */
1363 f2t (const FILETIME
*ft
, __time64_t
*t
)
1368 unsigned long long ull_time
;
1371 t_write
.ft_time
= *ft
;
1372 *t
= (__time64_t
) (t_write
.ull_time
/ 10000000ULL - w32_epoch_offset
);
1376 /* Return a GNAT time stamp given a file name. */
1379 __gnat_file_time_name_attr (char* name
, struct file_attributes
* attr
)
1381 if (attr
->timestamp
== (OS_Time
)-2) {
1382 #if defined (_WIN32)
1384 WIN32_FILE_ATTRIBUTE_DATA fad
;
1385 __time64_t ret
= -1;
1386 TCHAR wname
[GNAT_MAX_PATH_LEN
];
1387 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
);
1389 if ((res
= GetFileAttributesEx (wname
, GetFileExInfoStandard
, &fad
)))
1390 f2t (&fad
.ftLastWriteTime
, &ret
);
1391 attr
->timestamp
= (OS_Time
) ret
;
1393 __gnat_stat_to_attr (-1, name
, attr
);
1396 return attr
->timestamp
;
1400 __gnat_file_time_name (char *name
)
1402 struct file_attributes attr
;
1403 __gnat_reset_attributes (&attr
);
1404 return __gnat_file_time_name_attr (name
, &attr
);
1407 /* Return a GNAT time stamp given a file descriptor. */
1410 __gnat_file_time_fd_attr (int fd
, struct file_attributes
* attr
)
1412 if (attr
->timestamp
== (OS_Time
)-2) {
1413 #if defined (_WIN32)
1414 HANDLE h
= (HANDLE
) _get_osfhandle (fd
);
1415 time_t ret
= win32_filetime (h
);
1416 attr
->timestamp
= (OS_Time
) ret
;
1419 __gnat_stat_to_attr (fd
, NULL
, attr
);
1423 return attr
->timestamp
;
1427 __gnat_file_time_fd (int fd
)
1429 struct file_attributes attr
;
1430 __gnat_reset_attributes (&attr
);
1431 return __gnat_file_time_fd_attr (fd
, &attr
);
1434 /* Set the file time stamp. */
1437 __gnat_set_file_time_name (char *name
, time_t time_stamp
)
1439 #if defined (__vxworks)
1441 /* Code to implement __gnat_set_file_time_name for these systems. */
1443 #elif defined (_WIN32)
1447 unsigned long long ull_time
;
1449 TCHAR wname
[GNAT_MAX_PATH_LEN
];
1451 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
);
1453 HANDLE h
= CreateFile
1454 (wname
, GENERIC_WRITE
, FILE_SHARE_WRITE
, NULL
,
1455 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
,
1457 if (h
== INVALID_HANDLE_VALUE
)
1459 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1460 t_write
.ull_time
= ((unsigned long long)time_stamp
+ w32_epoch_offset
);
1461 /* Convert to 100 nanosecond units */
1462 t_write
.ull_time
*= 10000000ULL;
1464 SetFileTime(h
, NULL
, NULL
, &t_write
.ft_time
);
1469 struct utimbuf utimbuf
;
1472 /* Set modification time to requested time. */
1473 utimbuf
.modtime
= time_stamp
;
1475 /* Set access time to now in local time. */
1476 t
= time ((time_t) 0);
1477 utimbuf
.actime
= mktime (localtime (&t
));
1479 utime (name
, &utimbuf
);
1483 /* Get the list of installed standard libraries from the
1484 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1488 __gnat_get_libraries_from_registry (void)
1490 char *result
= (char *) xmalloc (1);
1494 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
1497 DWORD name_size
, value_size
;
1504 /* First open the key. */
1505 res
= RegOpenKeyExA (HKEY_LOCAL_MACHINE
, "SOFTWARE", 0, KEY_READ
, ®_key
);
1507 if (res
== ERROR_SUCCESS
)
1508 res
= RegOpenKeyExA (reg_key
, "Ada Core Technologies", 0,
1509 KEY_READ
, ®_key
);
1511 if (res
== ERROR_SUCCESS
)
1512 res
= RegOpenKeyExA (reg_key
, "GNAT", 0, KEY_READ
, ®_key
);
1514 if (res
== ERROR_SUCCESS
)
1515 res
= RegOpenKeyExA (reg_key
, "Standard Libraries", 0, KEY_READ
, ®_key
);
1517 /* If the key exists, read out all the values in it and concatenate them
1519 for (index
= 0; res
== ERROR_SUCCESS
; index
++)
1521 value_size
= name_size
= 256;
1522 res
= RegEnumValueA (reg_key
, index
, name
, &name_size
, 0,
1523 &type
, (LPBYTE
)value
, &value_size
);
1525 if (res
== ERROR_SUCCESS
&& type
== REG_SZ
)
1527 char *old_result
= result
;
1529 result
= (char *) xmalloc (strlen (old_result
) + value_size
+ 2);
1530 strcpy (result
, old_result
);
1531 strcat (result
, value
);
1532 strcat (result
, ";");
1537 /* Remove the trailing ";". */
1539 result
[strlen (result
) - 1] = 0;
1545 /* Query information for the given file NAME and return it in STATBUF.
1546 * Returns 0 for success, or errno value for failure.
1549 __gnat_stat (char *name
, GNAT_STRUCT_STAT
*statbuf
)
1552 WIN32_FILE_ATTRIBUTE_DATA fad
;
1553 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
1558 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
1559 name_len
= _tcslen (wname
);
1561 if (name_len
> GNAT_MAX_PATH_LEN
)
1564 ZeroMemory (statbuf
, sizeof(GNAT_STRUCT_STAT
));
1566 res
= GetFileAttributesEx (wname
, GetFileExInfoStandard
, &fad
);
1569 error
= GetLastError();
1571 /* Check file existence using GetFileAttributes() which does not fail on
1572 special Windows files like con:, aux:, nul: etc... */
1574 if (GetFileAttributes(wname
) != INVALID_FILE_ATTRIBUTES
) {
1575 /* Just pretend that it is a regular and readable file */
1576 statbuf
->st_mode
= S_IFREG
| S_IREAD
| S_IWRITE
;
1581 case ERROR_ACCESS_DENIED
:
1582 case ERROR_SHARING_VIOLATION
:
1583 case ERROR_LOCK_VIOLATION
:
1584 case ERROR_SHARING_BUFFER_EXCEEDED
:
1586 case ERROR_BUFFER_OVERFLOW
:
1587 return ENAMETOOLONG
;
1588 case ERROR_NOT_ENOUGH_MEMORY
:
1595 f2t (&fad
.ftCreationTime
, &statbuf
->st_ctime
);
1596 f2t (&fad
.ftLastWriteTime
, &statbuf
->st_mtime
);
1597 f2t (&fad
.ftLastAccessTime
, &statbuf
->st_atime
);
1600 (__int64
)fad
.nFileSizeLow
| (__int64
)fad
.nFileSizeHigh
<< 32;
1602 /* We do not have the S_IEXEC attribute, but this is not used on GNAT. */
1603 statbuf
->st_mode
= S_IREAD
;
1605 if (fad
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1606 statbuf
->st_mode
|= S_IFDIR
;
1608 statbuf
->st_mode
|= S_IFREG
;
1610 if (!(fad
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
))
1611 statbuf
->st_mode
|= S_IWRITE
;
1616 return GNAT_STAT (name
, statbuf
) == 0 ? 0 : errno
;
1620 /*************************************************************************
1621 ** Check whether a file exists
1622 *************************************************************************/
1625 __gnat_file_exists_attr (char* name
, struct file_attributes
* attr
)
1627 if (attr
->exists
== ATTR_UNSET
)
1628 __gnat_stat_to_attr (-1, name
, attr
);
1630 return attr
->exists
;
1634 __gnat_file_exists (char *name
)
1636 struct file_attributes attr
;
1637 __gnat_reset_attributes (&attr
);
1638 return __gnat_file_exists_attr (name
, &attr
);
1641 /**********************************************************************
1642 ** Whether name is an absolute path
1643 **********************************************************************/
1646 __gnat_is_absolute_path (char *name
, int length
)
1649 /* On VxWorks systems, an absolute path can be represented (depending on
1650 the host platform) as either /dir/file, or device:/dir/file, or
1651 device:drive_letter:/dir/file. */
1658 for (index
= 0; index
< length
; index
++)
1660 if (name
[index
] == ':' &&
1661 ((name
[index
+ 1] == '/') ||
1662 (isalpha (name
[index
+ 1]) && index
+ 2 <= length
&&
1663 name
[index
+ 2] == '/')))
1666 else if (name
[index
] == '/')
1671 return (length
!= 0) &&
1672 (*name
== '/' || *name
== DIR_SEPARATOR
1673 #if defined (WINNT) || defined(__DJGPP__)
1674 || (length
> 1 && ISALPHA (name
[0]) && name
[1] == ':')
1681 __gnat_is_regular_file_attr (char* name
, struct file_attributes
* attr
)
1683 if (attr
->regular
== ATTR_UNSET
)
1684 __gnat_stat_to_attr (-1, name
, attr
);
1686 return attr
->regular
;
1690 __gnat_is_regular_file (char *name
)
1692 struct file_attributes attr
;
1694 __gnat_reset_attributes (&attr
);
1695 return __gnat_is_regular_file_attr (name
, &attr
);
1699 __gnat_is_regular_file_fd (int fd
)
1702 GNAT_STRUCT_STAT statbuf
;
1704 ret
= GNAT_FSTAT (fd
, &statbuf
);
1705 return (!ret
&& S_ISREG (statbuf
.st_mode
));
1709 __gnat_is_directory_attr (char* name
, struct file_attributes
* attr
)
1711 if (attr
->directory
== ATTR_UNSET
)
1712 __gnat_stat_to_attr (-1, name
, attr
);
1714 return attr
->directory
;
1718 __gnat_is_directory (char *name
)
1720 struct file_attributes attr
;
1722 __gnat_reset_attributes (&attr
);
1723 return __gnat_is_directory_attr (name
, &attr
);
1726 #if defined (_WIN32)
1728 /* Returns the same constant as GetDriveType but takes a pathname as
1732 GetDriveTypeFromPath (TCHAR
*wfullpath
)
1734 TCHAR wdrv
[MAX_PATH
];
1735 TCHAR wpath
[MAX_PATH
];
1736 TCHAR wfilename
[MAX_PATH
];
1737 TCHAR wext
[MAX_PATH
];
1739 _tsplitpath (wfullpath
, wdrv
, wpath
, wfilename
, wext
);
1741 if (_tcslen (wdrv
) != 0)
1743 /* we have a drive specified. */
1744 _tcscat (wdrv
, _T("\\"));
1745 return GetDriveType (wdrv
);
1749 /* No drive specified. */
1751 /* Is this a relative path, if so get current drive type. */
1752 if (wpath
[0] != _T('\\') ||
1753 (_tcslen (wpath
) > 2 && wpath
[0] == _T('\\')
1754 && wpath
[1] != _T('\\')))
1755 return GetDriveType (NULL
);
1757 UINT result
= GetDriveType (wpath
);
1759 /* Cannot guess the drive type, is this \\.\ ? */
1761 if (result
== DRIVE_NO_ROOT_DIR
&&
1762 _tcslen (wpath
) >= 4 && wpath
[0] == _T('\\') && wpath
[1] == _T('\\')
1763 && wpath
[2] == _T('.') && wpath
[3] == _T('\\'))
1765 if (_tcslen (wpath
) == 4)
1766 _tcscat (wpath
, wfilename
);
1768 LPTSTR p
= &wpath
[4];
1769 LPTSTR b
= _tcschr (p
, _T('\\'));
1773 /* logical drive \\.\c\dir\file */
1779 _tcscat (p
, _T(":\\"));
1781 return GetDriveType (p
);
1788 /* This MingW section contains code to work with ACL. */
1790 __gnat_check_OWNER_ACL (TCHAR
*wname
,
1791 DWORD CheckAccessDesired
,
1792 GENERIC_MAPPING CheckGenericMapping
)
1794 DWORD dwAccessDesired
, dwAccessAllowed
;
1795 PRIVILEGE_SET PrivilegeSet
;
1796 DWORD dwPrivSetSize
= sizeof (PRIVILEGE_SET
);
1797 BOOL fAccessGranted
= FALSE
;
1798 HANDLE hToken
= NULL
;
1800 PSECURITY_DESCRIPTOR pSD
= NULL
;
1803 (wname
, OWNER_SECURITY_INFORMATION
|
1804 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
1807 if ((pSD
= (SECURITY_DESCRIPTOR
*) HeapAlloc
1808 (GetProcessHeap (), HEAP_ZERO_MEMORY
, nLength
)) == NULL
)
1811 /* Obtain the security descriptor. */
1813 if (!GetFileSecurity
1814 (wname
, OWNER_SECURITY_INFORMATION
|
1815 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
1816 pSD
, nLength
, &nLength
))
1819 if (!ImpersonateSelf (SecurityImpersonation
))
1822 if (!OpenThreadToken
1823 (GetCurrentThread(), TOKEN_DUPLICATE
| TOKEN_QUERY
, FALSE
, &hToken
))
1826 /* Undoes the effect of ImpersonateSelf. */
1830 /* We want to test for write permissions. */
1832 dwAccessDesired
= CheckAccessDesired
;
1834 MapGenericMask (&dwAccessDesired
, &CheckGenericMapping
);
1837 (pSD
, /* security descriptor to check */
1838 hToken
, /* impersonation token */
1839 dwAccessDesired
, /* requested access rights */
1840 &CheckGenericMapping
, /* pointer to GENERIC_MAPPING */
1841 &PrivilegeSet
, /* receives privileges used in check */
1842 &dwPrivSetSize
, /* size of PrivilegeSet buffer */
1843 &dwAccessAllowed
, /* receives mask of allowed access rights */
1847 CloseHandle (hToken
);
1848 HeapFree (GetProcessHeap (), 0, pSD
);
1849 return fAccessGranted
;
1853 CloseHandle (hToken
);
1854 HeapFree (GetProcessHeap (), 0, pSD
);
1859 __gnat_set_OWNER_ACL (TCHAR
*wname
,
1860 ACCESS_MODE AccessMode
,
1861 DWORD AccessPermissions
)
1863 PACL pOldDACL
= NULL
;
1864 PACL pNewDACL
= NULL
;
1865 PSECURITY_DESCRIPTOR pSD
= NULL
;
1867 TCHAR username
[100];
1870 /* Get current user, he will act as the owner */
1872 if (!GetUserName (username
, &unsize
))
1875 if (GetNamedSecurityInfo
1878 DACL_SECURITY_INFORMATION
,
1879 NULL
, NULL
, &pOldDACL
, NULL
, &pSD
) != ERROR_SUCCESS
)
1882 BuildExplicitAccessWithName
1883 (&ea
, username
, AccessPermissions
, (ACCESS_MODE
) AccessMode
, NO_INHERITANCE
);
1885 if (AccessMode
== SET_ACCESS
)
1887 /* SET_ACCESS, we want to set an explicte set of permissions, do not
1888 merge with current DACL. */
1889 if (SetEntriesInAcl (1, &ea
, NULL
, &pNewDACL
) != ERROR_SUCCESS
)
1893 if (SetEntriesInAcl (1, &ea
, pOldDACL
, &pNewDACL
) != ERROR_SUCCESS
)
1896 if (SetNamedSecurityInfo
1897 (wname
, SE_FILE_OBJECT
,
1898 DACL_SECURITY_INFORMATION
, NULL
, NULL
, pNewDACL
, NULL
) != ERROR_SUCCESS
)
1902 LocalFree (pNewDACL
);
1905 /* Check if it is possible to use ACL for wname, the file must not be on a
1909 __gnat_can_use_acl (TCHAR
*wname
)
1911 return __gnat_use_acl
&& GetDriveTypeFromPath (wname
) != DRIVE_REMOTE
;
1914 #endif /* defined (_WIN32) */
1917 __gnat_is_readable_file_attr (char* name
, struct file_attributes
* attr
)
1919 if (attr
->readable
== ATTR_UNSET
)
1921 #if defined (_WIN32)
1922 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
1923 GENERIC_MAPPING GenericMapping
;
1925 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
1927 if (__gnat_can_use_acl (wname
))
1929 ZeroMemory (&GenericMapping
, sizeof (GENERIC_MAPPING
));
1930 GenericMapping
.GenericRead
= GENERIC_READ
;
1932 __gnat_check_OWNER_ACL (wname
, FILE_READ_DATA
, GenericMapping
);
1935 attr
->readable
= GetFileAttributes (wname
) != INVALID_FILE_ATTRIBUTES
;
1937 __gnat_stat_to_attr (-1, name
, attr
);
1941 return attr
->readable
;
1945 __gnat_is_read_accessible_file (char *name
)
1947 #if defined (_WIN32)
1948 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
1950 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
1952 return !_waccess (wname
, 4);
1954 #elif defined (__vxworks)
1957 if ((fd
= open (name
, O_RDONLY
, 0)) < 0)
1963 return !access (name
, R_OK
);
1968 __gnat_is_readable_file (char *name
)
1970 struct file_attributes attr
;
1972 __gnat_reset_attributes (&attr
);
1973 return __gnat_is_readable_file_attr (name
, &attr
);
1977 __gnat_is_writable_file_attr (char* name
, struct file_attributes
* attr
)
1979 if (attr
->writable
== ATTR_UNSET
)
1981 #if defined (_WIN32)
1982 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
1983 GENERIC_MAPPING GenericMapping
;
1985 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
1987 if (__gnat_can_use_acl (wname
))
1989 ZeroMemory (&GenericMapping
, sizeof (GENERIC_MAPPING
));
1990 GenericMapping
.GenericWrite
= GENERIC_WRITE
;
1992 attr
->writable
= __gnat_check_OWNER_ACL
1993 (wname
, FILE_WRITE_DATA
| FILE_APPEND_DATA
, GenericMapping
)
1994 && !(GetFileAttributes (wname
) & FILE_ATTRIBUTE_READONLY
);
1998 !(GetFileAttributes (wname
) & FILE_ATTRIBUTE_READONLY
);
2001 __gnat_stat_to_attr (-1, name
, attr
);
2005 return attr
->writable
;
2009 __gnat_is_writable_file (char *name
)
2011 struct file_attributes attr
;
2013 __gnat_reset_attributes (&attr
);
2014 return __gnat_is_writable_file_attr (name
, &attr
);
2018 __gnat_is_write_accessible_file (char *name
)
2020 #if defined (_WIN32)
2021 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2023 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2025 return !_waccess (wname
, 2);
2027 #elif defined (__vxworks)
2030 if ((fd
= open (name
, O_WRONLY
, 0)) < 0)
2036 return !access (name
, W_OK
);
2041 __gnat_is_executable_file_attr (char* name
, struct file_attributes
* attr
)
2043 if (attr
->executable
== ATTR_UNSET
)
2045 #if defined (_WIN32)
2046 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2047 GENERIC_MAPPING GenericMapping
;
2049 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2051 if (__gnat_can_use_acl (wname
))
2053 ZeroMemory (&GenericMapping
, sizeof (GENERIC_MAPPING
));
2054 GenericMapping
.GenericExecute
= GENERIC_EXECUTE
;
2057 __gnat_check_OWNER_ACL (wname
, FILE_EXECUTE
, GenericMapping
);
2061 TCHAR
*l
, *last
= _tcsstr(wname
, _T(".exe"));
2063 /* look for last .exe */
2065 while ((l
= _tcsstr(last
+1, _T(".exe"))))
2069 GetFileAttributes (wname
) != INVALID_FILE_ATTRIBUTES
2070 && (last
- wname
) == (int) (_tcslen (wname
) - 4);
2073 __gnat_stat_to_attr (-1, name
, attr
);
2077 return attr
->regular
&& attr
->executable
;
2081 __gnat_is_executable_file (char *name
)
2083 struct file_attributes attr
;
2085 __gnat_reset_attributes (&attr
);
2086 return __gnat_is_executable_file_attr (name
, &attr
);
2090 __gnat_set_writable (char *name
)
2092 #if defined (_WIN32)
2093 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2095 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2097 if (__gnat_can_use_acl (wname
))
2098 __gnat_set_OWNER_ACL (wname
, GRANT_ACCESS
, FILE_GENERIC_WRITE
);
2101 (wname
, GetFileAttributes (wname
) & ~FILE_ATTRIBUTE_READONLY
);
2102 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2103 GNAT_STRUCT_STAT statbuf
;
2105 if (GNAT_STAT (name
, &statbuf
) == 0)
2107 statbuf
.st_mode
= statbuf
.st_mode
| S_IWUSR
;
2108 chmod (name
, statbuf
.st_mode
);
2113 /* must match definition in s-os_lib.ads */
2119 __gnat_set_executable (char *name
, int mode ATTRIBUTE_UNUSED
)
2121 #if defined (_WIN32)
2122 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2124 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2126 if (__gnat_can_use_acl (wname
))
2127 __gnat_set_OWNER_ACL (wname
, GRANT_ACCESS
, FILE_GENERIC_EXECUTE
);
2129 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2130 GNAT_STRUCT_STAT statbuf
;
2132 if (GNAT_STAT (name
, &statbuf
) == 0)
2135 statbuf
.st_mode
= statbuf
.st_mode
| S_IXUSR
;
2137 statbuf
.st_mode
= statbuf
.st_mode
| S_IXGRP
;
2138 if (mode
& S_OTHERS
)
2139 statbuf
.st_mode
= statbuf
.st_mode
| S_IXOTH
;
2140 chmod (name
, statbuf
.st_mode
);
2146 __gnat_set_non_writable (char *name
)
2148 #if defined (_WIN32)
2149 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2151 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2153 if (__gnat_can_use_acl (wname
))
2154 __gnat_set_OWNER_ACL
2155 (wname
, DENY_ACCESS
,
2156 FILE_WRITE_DATA
| FILE_APPEND_DATA
|
2157 FILE_WRITE_EA
| FILE_WRITE_ATTRIBUTES
);
2160 (wname
, GetFileAttributes (wname
) | FILE_ATTRIBUTE_READONLY
);
2161 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2162 GNAT_STRUCT_STAT statbuf
;
2164 if (GNAT_STAT (name
, &statbuf
) == 0)
2166 statbuf
.st_mode
= statbuf
.st_mode
& 07577;
2167 chmod (name
, statbuf
.st_mode
);
2173 __gnat_set_readable (char *name
)
2175 #if defined (_WIN32)
2176 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2178 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2180 if (__gnat_can_use_acl (wname
))
2181 __gnat_set_OWNER_ACL (wname
, GRANT_ACCESS
, FILE_GENERIC_READ
);
2183 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2184 GNAT_STRUCT_STAT statbuf
;
2186 if (GNAT_STAT (name
, &statbuf
) == 0)
2188 chmod (name
, statbuf
.st_mode
| S_IREAD
);
2194 __gnat_set_non_readable (char *name
)
2196 #if defined (_WIN32)
2197 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2199 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2201 if (__gnat_can_use_acl (wname
))
2202 __gnat_set_OWNER_ACL (wname
, DENY_ACCESS
, FILE_GENERIC_READ
);
2204 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2205 GNAT_STRUCT_STAT statbuf
;
2207 if (GNAT_STAT (name
, &statbuf
) == 0)
2209 chmod (name
, statbuf
.st_mode
& (~S_IREAD
));
2215 __gnat_is_symbolic_link_attr (char* name ATTRIBUTE_UNUSED
,
2216 struct file_attributes
* attr
)
2218 if (attr
->symbolic_link
== ATTR_UNSET
)
2220 #if defined (__vxworks)
2221 attr
->symbolic_link
= 0;
2223 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2225 GNAT_STRUCT_STAT statbuf
;
2226 ret
= GNAT_LSTAT (name
, &statbuf
);
2227 attr
->symbolic_link
= (!ret
&& S_ISLNK (statbuf
.st_mode
));
2229 attr
->symbolic_link
= 0;
2232 return attr
->symbolic_link
;
2236 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED
)
2238 struct file_attributes attr
;
2240 __gnat_reset_attributes (&attr
);
2241 return __gnat_is_symbolic_link_attr (name
, &attr
);
2244 #if defined (__sun__)
2245 /* Using fork on Solaris will duplicate all the threads. fork1, which
2246 duplicates only the active thread, must be used instead, or spawning
2247 subprocess from a program with tasking will lead into numerous problems. */
2252 __gnat_portable_spawn (char *args
[] ATTRIBUTE_UNUSED
)
2254 int status ATTRIBUTE_UNUSED
= 0;
2255 int finished ATTRIBUTE_UNUSED
;
2256 int pid ATTRIBUTE_UNUSED
;
2258 #if defined (__vxworks) || defined(__PikeOS__)
2261 #elif defined (__DJGPP__) || defined (_WIN32)
2262 /* args[0] must be quotes as it could contain a full pathname with spaces */
2263 char *args_0
= args
[0];
2264 args
[0] = (char *)xmalloc (strlen (args_0
) + 3);
2265 strcpy (args
[0], "\"");
2266 strcat (args
[0], args_0
);
2267 strcat (args
[0], "\"");
2269 status
= spawnvp (P_WAIT
, args_0
, (char ** const)args
);
2271 /* restore previous value */
2273 args
[0] = (char *)args_0
;
2289 if (execv (args
[0], MAYBE_TO_PTR32 (args
)) != 0)
2294 finished
= waitpid (pid
, &status
, 0);
2296 if (finished
!= pid
|| WIFEXITED (status
) == 0)
2299 return WEXITSTATUS (status
);
2305 /* Create a copy of the given file descriptor.
2306 Return -1 if an error occurred. */
2309 __gnat_dup (int oldfd
)
2311 #if defined (__vxworks) && !defined (__RTP__)
2312 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2320 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2321 Return -1 if an error occurred. */
2324 __gnat_dup2 (int oldfd ATTRIBUTE_UNUSED
, int newfd ATTRIBUTE_UNUSED
)
2326 #if defined (__vxworks) && !defined (__RTP__)
2327 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2330 #elif defined (__PikeOS__)
2331 /* Not supported. */
2333 #elif defined (_WIN32)
2334 /* Special case when oldfd and newfd are identical and are the standard
2335 input, output or error as this makes Windows XP hangs. Note that we
2336 do that only for standard file descriptors that are known to be valid. */
2337 if (oldfd
== newfd
&& newfd
>= 0 && newfd
<= 2)
2340 return dup2 (oldfd
, newfd
);
2342 return dup2 (oldfd
, newfd
);
2347 __gnat_number_of_cpus (void)
2351 #if defined (__linux__) || defined (__sun__) || defined (_AIX) \
2352 || defined (__APPLE__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
2353 || defined (__DragonFly__) || defined (__NetBSD__) || defined (__QNX__)
2354 cores
= (int) sysconf (_SC_NPROCESSORS_ONLN
);
2356 #elif defined (__hpux__)
2357 struct pst_dynamic psd
;
2358 if (pstat_getdynamic (&psd
, sizeof (psd
), 1, 0) != -1)
2359 cores
= (int) psd
.psd_proc_cnt
;
2361 #elif defined (_WIN32)
2362 SYSTEM_INFO sysinfo
;
2363 GetSystemInfo (&sysinfo
);
2364 cores
= (int) sysinfo
.dwNumberOfProcessors
;
2366 #elif defined (_WRS_CONFIG_SMP)
2367 unsigned int vxCpuConfiguredGet (void);
2369 cores
= vxCpuConfiguredGet ();
2376 /* WIN32 code to implement a wait call that wait for any child process. */
2378 #if defined (_WIN32)
2380 /* Synchronization code, to be thread safe. */
2384 /* For the Cert run times on native Windows we use dummy functions
2385 for locking and unlocking tasks since we do not support multiple
2386 threads on this configuration (Cert run time on native Windows). */
2388 static void EnterCS (void) {}
2389 static void LeaveCS (void) {}
2390 static void SignalListChanged (void) {}
2394 CRITICAL_SECTION ProcListCS
;
2395 HANDLE ProcListEvt
= NULL
;
2397 static void EnterCS (void)
2399 EnterCriticalSection(&ProcListCS
);
2402 static void LeaveCS (void)
2404 LeaveCriticalSection(&ProcListCS
);
2407 static void SignalListChanged (void)
2409 SetEvent (ProcListEvt
);
2414 static HANDLE
*HANDLES_LIST
= NULL
;
2415 static int *PID_LIST
= NULL
, plist_length
= 0, plist_max_length
= 0;
2418 add_handle (HANDLE h
, int pid
)
2420 /* -------------------- critical section -------------------- */
2423 if (plist_length
== plist_max_length
)
2425 plist_max_length
+= 100;
2427 (HANDLE
*) xrealloc (HANDLES_LIST
, sizeof (HANDLE
) * plist_max_length
);
2429 (int *) xrealloc (PID_LIST
, sizeof (int) * plist_max_length
);
2432 HANDLES_LIST
[plist_length
] = h
;
2433 PID_LIST
[plist_length
] = pid
;
2436 SignalListChanged();
2438 /* -------------------- critical section -------------------- */
2442 __gnat_win32_remove_handle (HANDLE h
, int pid
)
2447 /* -------------------- critical section -------------------- */
2450 for (j
= 0; j
< plist_length
; j
++)
2452 if ((HANDLES_LIST
[j
] == h
) || (PID_LIST
[j
] == pid
))
2456 HANDLES_LIST
[j
] = HANDLES_LIST
[plist_length
];
2457 PID_LIST
[j
] = PID_LIST
[plist_length
];
2464 /* -------------------- critical section -------------------- */
2467 SignalListChanged();
2473 win32_no_block_spawn (char *command
, char *args
[], HANDLE
*h
, int *pid
)
2477 PROCESS_INFORMATION PI
;
2478 SECURITY_ATTRIBUTES SA
;
2483 /* compute the total command line length */
2487 csize
+= strlen (args
[k
]) + 1;
2491 full_command
= (char *) xmalloc (csize
);
2494 SI
.cb
= sizeof (STARTUPINFO
);
2495 SI
.lpReserved
= NULL
;
2496 SI
.lpReserved2
= NULL
;
2497 SI
.lpDesktop
= NULL
;
2501 SI
.wShowWindow
= SW_HIDE
;
2503 /* Security attributes. */
2504 SA
.nLength
= sizeof (SECURITY_ATTRIBUTES
);
2505 SA
.bInheritHandle
= TRUE
;
2506 SA
.lpSecurityDescriptor
= NULL
;
2508 /* Prepare the command string. */
2509 strcpy (full_command
, command
);
2510 strcat (full_command
, " ");
2515 strcat (full_command
, args
[k
]);
2516 strcat (full_command
, " ");
2521 int wsize
= csize
* 2;
2522 TCHAR
*wcommand
= (TCHAR
*) xmalloc (wsize
);
2524 S2WSC (wcommand
, full_command
, wsize
);
2526 free (full_command
);
2528 result
= CreateProcess
2529 (NULL
, wcommand
, &SA
, NULL
, TRUE
,
2530 GetPriorityClass (GetCurrentProcess()), NULL
, NULL
, &SI
, &PI
);
2537 CloseHandle (PI
.hThread
);
2539 *pid
= PI
.dwProcessId
;
2549 win32_wait (int *status
)
2551 DWORD exitcode
, pid
;
2562 if (plist_length
== 0)
2568 /* -------------------- critical section -------------------- */
2571 /* ??? We can't wait for more than MAXIMUM_WAIT_OBJECTS due to a Win32
2573 if (plist_length
< MAXIMUM_WAIT_OBJECTS
)
2574 hl_len
= plist_length
;
2582 hl
= (HANDLE
*) xmalloc (sizeof (HANDLE
) * hl_len
);
2583 memmove (hl
, HANDLES_LIST
, sizeof (HANDLE
) * hl_len
);
2584 pidl
= (int *) xmalloc (sizeof (int) * hl_len
);
2585 memmove (pidl
, PID_LIST
, sizeof (int) * hl_len
);
2587 /* Note that index 0 contains the event handle that is signaled when the
2588 process list has changed */
2589 hl
= (HANDLE
*) xmalloc (sizeof (HANDLE
) * hl_len
+ 1);
2590 hl
[0] = ProcListEvt
;
2591 memmove (&hl
[1], HANDLES_LIST
, sizeof (HANDLE
) * hl_len
);
2592 pidl
= (int *) xmalloc (sizeof (int) * hl_len
+ 1);
2593 memmove (&pidl
[1], PID_LIST
, sizeof (int) * hl_len
);
2598 /* -------------------- critical section -------------------- */
2600 res
= WaitForMultipleObjects (hl_len
, hl
, FALSE
, INFINITE
);
2602 /* If there was an error, exit now */
2603 if (res
== WAIT_FAILED
)
2609 /* if the ProcListEvt has been signaled then the list of processes has been
2610 updated to add or remove a handle, just loop over */
2612 if (res
- WAIT_OBJECT_0
== 0)
2619 /* Handle two distinct groups of return codes: finished waits and abandoned
2622 if (res
< WAIT_ABANDONED_0
)
2623 pos
= res
- WAIT_OBJECT_0
;
2625 pos
= res
- WAIT_ABANDONED_0
;
2628 GetExitCodeProcess (h
, &exitcode
);
2631 found
= __gnat_win32_remove_handle (h
, -1);
2636 /* if not found another process waiting has already handled this process */
2643 *status
= (int) exitcode
;
2650 __gnat_portable_no_block_spawn (char *args
[] ATTRIBUTE_UNUSED
)
2653 #if defined (__vxworks) || defined (__PikeOS__)
2654 /* Not supported. */
2657 #elif defined(__DJGPP__)
2658 if (spawnvp (P_WAIT
, args
[0], args
) != 0)
2663 #elif defined (_WIN32)
2668 win32_no_block_spawn (args
[0], args
, &h
, &pid
);
2671 add_handle (h
, pid
);
2684 if (execv (args
[0], MAYBE_TO_PTR32 (args
)) != 0)
2694 __gnat_portable_wait (int *process_status
)
2699 #if defined (__vxworks) || defined (__PikeOS__)
2700 /* Not sure what to do here, so do nothing but return zero. */
2702 #elif defined (_WIN32)
2704 pid
= win32_wait (&status
);
2706 #elif defined (__DJGPP__)
2707 /* Child process has already ended in case of DJGPP.
2708 No need to do anything. Just return success. */
2711 pid
= waitpid (-1, &status
, 0);
2712 status
= status
& 0xffff;
2715 *process_status
= status
;
2720 __gnat_portable_no_block_wait (int *process_status
)
2725 #if defined (__vxworks) || defined (__PikeOS__) || defined (_WIN32)
2726 /* Not supported. */
2731 pid
= waitpid (-1, &status
, WNOHANG
);
2732 status
= status
& 0xffff;
2735 *process_status
= status
;
2740 __gnat_os_exit (int status
)
2746 __gnat_current_process_id (void)
2748 #if defined (__vxworks) || defined (__PikeOS__)
2751 #elif defined (_WIN32)
2753 return (int)GetCurrentProcessId();
2757 return (int)getpid();
2761 /* Locate file on path, that matches a predicate */
2764 __gnat_locate_file_with_predicate (char *file_name
, char *path_val
,
2765 int (*predicate
)(char *))
2768 char *file_path
= (char *) alloca (strlen (file_name
) + 1);
2771 /* Return immediately if file_name is empty */
2773 if (*file_name
== '\0')
2776 /* Remove quotes around file_name if present */
2782 strcpy (file_path
, ptr
);
2784 ptr
= file_path
+ strlen (file_path
) - 1;
2789 /* Handle absolute pathnames. */
2791 absolute
= __gnat_is_absolute_path (file_path
, strlen (file_name
));
2795 if (predicate (file_path
))
2796 return xstrdup (file_path
);
2801 /* If file_name include directory separator(s), try it first as
2802 a path name relative to the current directory */
2803 for (ptr
= file_name
; *ptr
&& *ptr
!= '/' && *ptr
!= DIR_SEPARATOR
; ptr
++)
2808 if (predicate (file_name
))
2809 return xstrdup (file_name
);
2816 /* The result has to be smaller than path_val + file_name. */
2818 (char *) alloca (strlen (path_val
) + strlen (file_name
) + 2);
2822 /* Skip the starting quote */
2824 if (*path_val
== '"')
2827 for (ptr
= file_path
; *path_val
&& *path_val
!= PATH_SEPARATOR
; )
2828 *ptr
++ = *path_val
++;
2830 /* If directory is empty, it is the current directory*/
2832 if (ptr
== file_path
)
2839 /* Skip the ending quote */
2844 if (*ptr
!= '/' && *ptr
!= DIR_SEPARATOR
)
2845 *++ptr
= DIR_SEPARATOR
;
2847 strcpy (++ptr
, file_name
);
2849 if (predicate (file_path
))
2850 return xstrdup (file_path
);
2855 /* Skip path separator */
2864 /* Locate an executable file, give a Path value. */
2867 __gnat_locate_executable_file (char *file_name
, char *path_val
)
2869 return __gnat_locate_file_with_predicate
2870 (file_name
, path_val
, &__gnat_is_executable_file
);
2873 /* Locate a regular file, give a Path value. */
2876 __gnat_locate_regular_file (char *file_name
, char *path_val
)
2878 return __gnat_locate_file_with_predicate
2879 (file_name
, path_val
, &__gnat_is_regular_file
);
2882 /* Locate an executable given a Path argument. This routine is only used by
2883 gnatbl and should not be used otherwise. Use locate_exec_on_path
2887 __gnat_locate_exec (char *exec_name
, char *path_val
)
2890 if (!strstr (exec_name
, HOST_EXECUTABLE_SUFFIX
))
2892 char *full_exec_name
=
2894 (strlen (exec_name
) + strlen (HOST_EXECUTABLE_SUFFIX
) + 1);
2896 strcpy (full_exec_name
, exec_name
);
2897 strcat (full_exec_name
, HOST_EXECUTABLE_SUFFIX
);
2898 ptr
= __gnat_locate_executable_file (full_exec_name
, path_val
);
2901 return __gnat_locate_executable_file (exec_name
, path_val
);
2905 return __gnat_locate_executable_file (exec_name
, path_val
);
2908 /* Locate an executable using the Systems default PATH. */
2911 __gnat_locate_exec_on_path (char *exec_name
)
2915 #if defined (_WIN32)
2916 TCHAR
*wpath_val
= _tgetenv (_T("PATH"));
2918 /* In Win32 systems we expand the PATH as for XP environment
2919 variables are not automatically expanded. We also prepend the
2920 ".;" to the path to match normal NT path search semantics */
2922 #define EXPAND_BUFFER_SIZE 32767
2924 wapath_val
= (TCHAR
*) alloca (EXPAND_BUFFER_SIZE
);
2926 wapath_val
[0] = '.';
2927 wapath_val
[1] = ';';
2929 DWORD res
= ExpandEnvironmentStrings
2930 (wpath_val
, &wapath_val
[2], EXPAND_BUFFER_SIZE
- 2);
2932 if (!res
) wapath_val
[0] = _T('\0');
2934 apath_val
= (char *) alloca (EXPAND_BUFFER_SIZE
);
2936 WS2SC (apath_val
, wapath_val
, EXPAND_BUFFER_SIZE
);
2939 const char *path_val
= getenv ("PATH");
2941 /* If PATH is not defined, proceed with __gnat_locate_exec anyway, so we can
2942 find files that contain directory names. */
2944 if (path_val
== NULL
) path_val
= "";
2945 apath_val
= (char *) alloca (strlen (path_val
) + 1);
2946 strcpy (apath_val
, path_val
);
2949 return __gnat_locate_exec (exec_name
, apath_val
);
2952 /* Dummy functions for Osint import for non-VMS systems.
2953 ??? To be removed. */
2956 __gnat_to_canonical_file_list_init (char *dirspec ATTRIBUTE_UNUSED
,
2957 int onlydirs ATTRIBUTE_UNUSED
)
2963 __gnat_to_canonical_file_list_next (void)
2965 static char empty
[] = "";
2970 __gnat_to_canonical_file_list_free (void)
2975 __gnat_to_canonical_dir_spec (char *dirspec
, int prefixflag ATTRIBUTE_UNUSED
)
2981 __gnat_to_canonical_file_spec (char *filespec
)
2987 __gnat_to_canonical_path_spec (char *pathspec
)
2993 __gnat_to_host_dir_spec (char *dirspec
, int prefixflag ATTRIBUTE_UNUSED
)
2999 __gnat_to_host_file_spec (char *filespec
)
3005 __gnat_adjust_os_resource_limits (void)
3009 #if defined (__mips_vxworks)
3013 CACHE_USER_FLUSH (0, ENTIRE_CACHE
);
3017 #if defined (_WIN32)
3018 int __gnat_argument_needs_quote
= 1;
3020 int __gnat_argument_needs_quote
= 0;
3023 /* This option is used to enable/disable object files handling from the
3024 binder file by the GNAT Project module. For example, this is disabled on
3025 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3026 Stating with GCC 3.4 the shared libraries are not based on mdll
3027 anymore as it uses the GCC's -shared option */
3028 #if defined (_WIN32) \
3029 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3030 int __gnat_prj_add_obj_files
= 0;
3032 int __gnat_prj_add_obj_files
= 1;
3035 /* char used as prefix/suffix for environment variables */
3036 #if defined (_WIN32)
3037 char __gnat_environment_char
= '%';
3039 char __gnat_environment_char
= '$';
3042 /* This functions copy the file attributes from a source file to a
3045 mode = 0 : In this mode copy only the file time stamps (last access and
3046 last modification time stamps).
3048 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3051 mode = 2 : In this mode, only read/write/execute attributes are copied
3053 Returns 0 if operation was successful and -1 in case of error. */
3056 __gnat_copy_attribs (char *from ATTRIBUTE_UNUSED
, char *to ATTRIBUTE_UNUSED
,
3057 int mode ATTRIBUTE_UNUSED
)
3059 #if (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
3062 #elif defined (_WIN32)
3063 TCHAR wfrom
[GNAT_MAX_PATH_LEN
+ 2];
3064 TCHAR wto
[GNAT_MAX_PATH_LEN
+ 2];
3066 FILETIME fct
, flat
, flwt
;
3069 S2WSC (wfrom
, from
, GNAT_MAX_PATH_LEN
+ 2);
3070 S2WSC (wto
, to
, GNAT_MAX_PATH_LEN
+ 2);
3072 /* Do we need to copy the timestamp ? */
3075 /* retrieve from times */
3078 (wfrom
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
3079 FILE_ATTRIBUTE_NORMAL
, NULL
);
3081 if (hfrom
== INVALID_HANDLE_VALUE
)
3084 res
= GetFileTime (hfrom
, &fct
, &flat
, &flwt
);
3086 CloseHandle (hfrom
);
3091 /* retrieve from times */
3094 (wto
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
,
3095 FILE_ATTRIBUTE_NORMAL
, NULL
);
3097 if (hto
== INVALID_HANDLE_VALUE
)
3100 res
= SetFileTime (hto
, NULL
, &flat
, &flwt
);
3108 /* Do we need to copy the permissions ? */
3109 /* Set file attributes in full mode. */
3113 DWORD attribs
= GetFileAttributes (wfrom
);
3115 if (attribs
== INVALID_FILE_ATTRIBUTES
)
3118 res
= SetFileAttributes (wto
, attribs
);
3126 GNAT_STRUCT_STAT fbuf
;
3127 struct utimbuf tbuf
;
3129 if (GNAT_STAT (from
, &fbuf
) == -1) {
3133 /* Do we need to copy timestamp ? */
3135 tbuf
.actime
= fbuf
.st_atime
;
3136 tbuf
.modtime
= fbuf
.st_mtime
;
3138 if (utime (to
, &tbuf
) == -1) {
3143 /* Do we need to copy file permissions ? */
3144 if (mode
!= 0 && (chmod (to
, fbuf
.st_mode
) == -1)) {
3153 __gnat_lseek (int fd
, long offset
, int whence
)
3155 return (int) lseek (fd
, offset
, whence
);
3158 /* This function returns the major version number of GCC being used. */
3160 get_gcc_version (void)
3165 return (int) (version_string
[0] - '0');
3170 * Set Close_On_Exec as indicated.
3171 * Note: this is used for both GNAT.OS_Lib and GNAT.Sockets.
3175 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED
,
3176 int close_on_exec_p ATTRIBUTE_UNUSED
)
3178 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3179 int flags
= fcntl (fd
, F_GETFD
, 0);
3182 if (close_on_exec_p
)
3183 flags
|= FD_CLOEXEC
;
3185 flags
&= ~FD_CLOEXEC
;
3186 return fcntl (fd
, F_SETFD
, flags
);
3187 #elif defined(_WIN32)
3188 HANDLE h
= (HANDLE
) _get_osfhandle (fd
);
3189 if (h
== (HANDLE
) -1)
3191 if (close_on_exec_p
)
3192 return ! SetHandleInformation (h
, HANDLE_FLAG_INHERIT
, 0);
3193 return ! SetHandleInformation (h
, HANDLE_FLAG_INHERIT
,
3194 HANDLE_FLAG_INHERIT
);
3196 /* TODO: Unimplemented. */
3201 /* Indicates if platforms supports automatic initialization through the
3202 constructor mechanism */
3204 __gnat_binder_supports_auto_init (void)
3209 /* Indicates that Stand-Alone Libraries are automatically initialized through
3210 the constructor mechanism */
3212 __gnat_sals_init_using_constructors (void)
3214 #if defined (__vxworks) || defined (__Lynx__)
3221 #if defined (__linux__) || defined (__ANDROID__)
3222 /* There is no function in the glibc to retrieve the LWP of the current
3223 thread. We need to do a system call in order to retrieve this
3225 #include <sys/syscall.h>
3227 __gnat_lwp_self (void)
3229 return (void *) syscall (__NR_gettid
);
3233 #if defined (__APPLE__)
3234 #include <mach/thread_info.h>
3235 #include <mach/mach_init.h>
3236 #include <mach/thread_act.h>
3238 /* System-wide thread identifier. Note it could be truncated on 32 bit
3240 Previously was: pthread_mach_thread_np (pthread_self ()). */
3242 __gnat_lwp_self (void)
3244 thread_identifier_info_data_t data
;
3245 mach_msg_type_number_t count
= THREAD_IDENTIFIER_INFO_COUNT
;
3248 kret
= thread_info (mach_thread_self (), THREAD_IDENTIFIER_INFO
,
3249 (thread_info_t
) &data
, &count
);
3250 if (kret
== KERN_SUCCESS
)
3251 return (void *)(uintptr_t)data
.thread_id
;
3257 #if defined (__linux__)
3260 /* glibc versions earlier than 2.7 do not define the routines to handle
3261 dynamically allocated CPU sets. For these targets, we use the static
3266 /* Dynamic cpu sets */
3269 __gnat_cpu_alloc (size_t count
)
3271 return CPU_ALLOC (count
);
3275 __gnat_cpu_alloc_size (size_t count
)
3277 return CPU_ALLOC_SIZE (count
);
3281 __gnat_cpu_free (cpu_set_t
*set
)
3287 __gnat_cpu_zero (size_t count
, cpu_set_t
*set
)
3289 CPU_ZERO_S (count
, set
);
3293 __gnat_cpu_set (int cpu
, size_t count
, cpu_set_t
*set
)
3295 /* Ada handles CPU numbers starting from 1, while C identifies the first
3296 CPU by a 0, so we need to adjust. */
3297 CPU_SET_S (cpu
- 1, count
, set
);
3300 #else /* !CPU_ALLOC */
3302 /* Static cpu sets */
3305 __gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED
)
3307 return (cpu_set_t
*) xmalloc (sizeof (cpu_set_t
));
3311 __gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED
)
3313 return sizeof (cpu_set_t
);
3317 __gnat_cpu_free (cpu_set_t
*set
)
3323 __gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED
, cpu_set_t
*set
)
3329 __gnat_cpu_set (int cpu
, size_t count ATTRIBUTE_UNUSED
, cpu_set_t
*set
)
3331 /* Ada handles CPU numbers starting from 1, while C identifies the first
3332 CPU by a 0, so we need to adjust. */
3333 CPU_SET (cpu
- 1, set
);
3335 #endif /* !CPU_ALLOC */
3336 #endif /* __linux__ */
3338 /* Return the load address of the executable, or 0 if not known. In the
3339 specific case of error, (void *)-1 can be returned. Beware: this unit may
3340 be in a shared library. As low-level units are needed, we allow #include
3343 #if defined (__APPLE__)
3344 #include <mach-o/dyld.h>
3348 __gnat_get_executable_load_address (void)
3350 #if defined (__APPLE__)
3351 return _dyld_get_image_header (0);
3353 #elif 0 && defined (__linux__)
3354 /* Currently disabled as it needs at least -ldl. */
3355 struct link_map
*map
= _r_debug
.r_map
;
3357 return (const void *)map
->l_addr
;
3365 __gnat_kill (int pid
, int sig
, int close ATTRIBUTE_UNUSED
)
3368 HANDLE h
= OpenProcess (PROCESS_ALL_ACCESS
, FALSE
, pid
);
3373 TerminateProcess (h
, 1);
3375 else if (sig
== SIGINT
)
3376 GenerateConsoleCtrlEvent (CTRL_C_EVENT
, pid
);
3377 else if (sig
== SIGBREAK
)
3378 GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT
, pid
);
3379 /* ??? The last two alternatives don't really work. SIGBREAK requires setting
3380 up process groups at start time which we don't do; treating SIGINT is just
3381 not possible apparently. So we really only support signal 9. Fortunately
3382 that's all we use in GNAT.Expect */
3385 #elif defined (__vxworks)
3386 /* Not implemented */
3392 void __gnat_killprocesstree (int pid
, int sig_num
)
3397 memset(&pe
, 0, sizeof(PROCESSENTRY32
));
3398 pe
.dwSize
= sizeof(PROCESSENTRY32
);
3400 HANDLE hSnap
= CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS
, 0);
3402 /* cannot take snapshot, just kill the parent process */
3404 if (hSnap
== INVALID_HANDLE_VALUE
)
3406 __gnat_kill (pid
, sig_num
, 1);
3410 if (Process32First(hSnap
, &pe
))
3412 BOOL bContinue
= TRUE
;
3414 /* kill child processes first */
3418 if (pe
.th32ParentProcessID
== (DWORD
)pid
)
3419 __gnat_killprocesstree (pe
.th32ProcessID
, sig_num
);
3421 bContinue
= Process32Next (hSnap
, &pe
);
3425 CloseHandle (hSnap
);
3429 __gnat_kill (pid
, sig_num
, 1);
3431 #elif defined (__vxworks)
3432 /* not implemented */
3434 #elif defined (__linux__)
3438 /* read all processes' pid and ppid */
3440 dir
= opendir ("/proc");
3442 /* cannot open proc, just kill the parent process */
3446 __gnat_kill (pid
, sig_num
, 1);
3450 /* kill child processes first */
3452 while ((d
= readdir (dir
)) != NULL
)
3454 if ((d
->d_type
& DT_DIR
) == DT_DIR
)
3459 /* read /proc/<PID>/stat */
3461 if (strlen (d
->d_name
) >= sizeof (statfile
) - strlen ("/proc//stat"))
3463 strcpy (statfile
, "/proc/");
3464 strcat (statfile
, d
->d_name
);
3465 strcat (statfile
, "/stat");
3467 FILE *fd
= fopen (statfile
, "r");
3471 const int match
= fscanf (fd
, "%d %*s %*s %d", &_pid
, &_ppid
);
3474 if (match
== 2 && _ppid
== pid
)
3475 __gnat_killprocesstree (_pid
, sig_num
);
3484 __gnat_kill (pid
, sig_num
, 1);
3486 __gnat_kill (pid
, sig_num
, 1);
3488 /* Note on Solaris it is possible to read /proc/<PID>/status.
3489 The 5th and 6th words are the pid and the 7th and 8th the ppid.
3490 See: /usr/include/sys/procfs.h (struct pstatus).