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