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