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