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