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