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