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