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