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