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