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