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