1 /****************************************************************************
3 * GNAT COMPILER COMPONENTS *
7 * C Implementation File *
9 * Copyright (C) 1992-2009, Free Software Foundation, Inc. *
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. *
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. *
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/>. *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
30 ****************************************************************************/
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. */
39 /* No need to redefine exit here. */
42 /* We want to use the POSIX variants of include files. */
46 #if defined (__mips_vxworks)
48 #endif /* __mips_vxworks */
54 #define HOST_EXECUTABLE_SUFFIX ".exe"
55 #define HOST_OBJECT_SUFFIX ".obj"
69 /* We don't have libiberty, so use malloc. */
70 #define xmalloc(S) malloc (S)
71 #define xrealloc(V,S) realloc (V,S)
78 #if defined (__MINGW32__)
86 /* Current code page to use, set in initialize.c. */
90 #include <sys/utime.h>
92 /* For isalpha-like tests in the compiler, we're expected to resort to
93 safe-ctype.h/ISALPHA. This isn't available for the runtime library
94 build, so we fallback on ctype.h/isalpha there. */
98 #define ISALPHA isalpha
101 #elif defined (__Lynx__)
103 /* Lynx utime.h only defines the entities of interest to us if
104 defined (VMOS_DEV), so ... */
113 /* wait.h processing */
116 #include <sys/wait.h>
118 #elif defined (__vxworks) && defined (__RTP__)
120 #elif defined (__Lynx__)
121 /* ??? We really need wait.h and it includes resource.h on Lynx. GCC
122 has a resource.h header as well, included instead of the lynx
123 version in our setup, causing lots of errors. We don't really need
124 the lynx contents of this file, so just workaround the issue by
125 preventing the inclusion of the GCC header from doing anything. */
126 #define GCC_RESOURCE_H
127 #include <sys/wait.h>
128 #elif defined (__nucleus__)
129 /* No wait() or waitpid() calls available */
132 #include <sys/wait.h>
135 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
138 /* Header files and definitions for __gnat_set_file_time_name. */
140 #define __NEW_STARLET 1
142 #include <vms/atrdef.h>
143 #include <vms/fibdef.h>
144 #include <vms/stsdef.h>
145 #include <vms/iodef.h>
147 #include <vms/descrip.h>
151 /* Use native 64-bit arithmetic. */
152 #define unix_time_to_vms(X,Y) \
153 { unsigned long long reftime, tmptime = (X); \
154 $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
155 SYS$BINTIM (&unixtime, &reftime); \
156 Y = tmptime * 10000000 + reftime; }
158 /* descrip.h doesn't have everything ... */
159 typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
160 struct dsc$descriptor_fib
162 unsigned int fib$l_len;
163 __fibdef_ptr32 fib$l_addr;
166 /* I/O Status Block. */
169 unsigned short status, count;
173 static char *tryfile;
175 /* Variable length string. */
179 char string[NAM$C_MAXRSS+1];
186 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
197 #define DIR_SEPARATOR '\\'
202 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
203 defined in the current system. On DOS-like systems these flags control
204 whether the file is opened/created in text-translation mode (CR/LF in
205 external file mapped to LF in internal file), but in Unix-like systems,
206 no text translation is required, so these flags have no effect. */
208 #if defined (__EMX__)
224 #ifndef HOST_EXECUTABLE_SUFFIX
225 #define HOST_EXECUTABLE_SUFFIX ""
228 #ifndef HOST_OBJECT_SUFFIX
229 #define HOST_OBJECT_SUFFIX ".o"
232 #ifndef PATH_SEPARATOR
233 #define PATH_SEPARATOR ':'
236 #ifndef DIR_SEPARATOR
237 #define DIR_SEPARATOR '/'
240 /* Check for cross-compilation */
241 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
243 int __gnat_is_cross_compiler = 1;
246 int __gnat_is_cross_compiler = 0;
249 char __gnat_dir_separator = DIR_SEPARATOR;
251 char __gnat_path_separator = PATH_SEPARATOR;
253 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
254 the base filenames that libraries specified with -lsomelib options
255 may have. This is used by GNATMAKE to check whether an executable
256 is up-to-date or not. The syntax is
258 library_template ::= { pattern ; } pattern NUL
259 pattern ::= [ prefix ] * [ postfix ]
261 These should only specify names of static libraries as it makes
262 no sense to determine at link time if dynamic-link libraries are
263 up to date or not. Any libraries that are not found are supposed
266 * if they are needed but not present, the link
269 * otherwise they are libraries in the system paths and so
270 they are considered part of the system and not checked
273 ??? This should be part of a GNAT host-specific compiler
274 file instead of being included in all user applications
275 as well. This is only a temporary work-around for 3.11b. */
277 #ifndef GNAT_LIBRARY_TEMPLATE
278 #if defined (__EMX__)
279 #define GNAT_LIBRARY_TEMPLATE "*.a"
281 #define GNAT_LIBRARY_TEMPLATE "*.olb"
283 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
287 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
289 /* This variable is used in hostparm.ads to say whether the host is a VMS
292 const int __gnat_vmsp = 1;
294 const int __gnat_vmsp = 0;
298 #define GNAT_MAX_PATH_LEN MAX_PATH
301 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
303 #elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
304 #define GNAT_MAX_PATH_LEN PATH_MAX
308 #if defined (__MINGW32__)
312 #include <sys/param.h>
316 #include <sys/param.h>
320 #define GNAT_MAX_PATH_LEN MAXPATHLEN
322 #define GNAT_MAX_PATH_LEN 256
327 /* The __gnat_max_path_len variable is used to export the maximum
328 length of a path name to Ada code. max_path_len is also provided
329 for compatibility with older GNAT versions, please do not use
332 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
333 int max_path_len = GNAT_MAX_PATH_LEN;
335 /* Control whether we can use ACL on Windows. */
337 int __gnat_use_acl = 1;
339 /* The following macro HAVE_READDIR_R should be defined if the
340 system provides the routine readdir_r. */
341 #undef HAVE_READDIR_R
343 #if defined(VMS) && defined (__LONG_POINTERS)
345 /* Return a 32 bit pointer to an array of 32 bit pointers
346 given a 64 bit pointer to an array of 64 bit pointers */
348 typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
350 static __char_ptr_char_ptr32
351 to_ptr32 (char **ptr64)
354 __char_ptr_char_ptr32 short_argv;
356 for (argc=0; ptr64[argc]; argc++);
358 /* Reallocate argv with 32 bit pointers. */
359 short_argv = (__char_ptr_char_ptr32) decc$malloc
360 (sizeof (__char_ptr32) * (argc + 1));
362 for (argc=0; ptr64[argc]; argc++)
363 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
365 short_argv[argc] = (__char_ptr32) 0;
369 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
371 #define MAYBE_TO_PTR32(argv) argv
378 time_t res = time (NULL);
379 return (OS_Time) res;
382 /* Return the current local time as a string in the ISO 8601 format of
383 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
387 __gnat_current_time_string
390 const char *format = "%Y-%m-%d %H:%M:%S";
391 /* Format string necessary to describe the ISO 8601 format */
393 const time_t t_val = time (NULL);
395 strftime (result, 22, format, localtime (&t_val));
396 /* Convert the local time into a string following the ISO format, copying
397 at most 22 characters into the result string. */
402 /* The sub-seconds are manually set to zero since type time_t lacks the
403 precision necessary for nanoseconds. */
417 time_t time = (time_t) *p_time;
420 /* On Windows systems, the time is sometimes rounded up to the nearest
421 even second, so if the number of seconds is odd, increment it. */
427 res = localtime (&time);
429 res = gmtime (&time);
434 *p_year = res->tm_year;
435 *p_month = res->tm_mon;
436 *p_day = res->tm_mday;
437 *p_hours = res->tm_hour;
438 *p_mins = res->tm_min;
439 *p_secs = res->tm_sec;
442 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
445 /* Place the contents of the symbolic link named PATH in the buffer BUF,
446 which has size BUFSIZ. If PATH is a symbolic link, then return the number
447 of characters of its content in BUF. Otherwise, return -1.
448 For systems not supporting symbolic links, always return -1. */
451 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
452 char *buf ATTRIBUTE_UNUSED,
453 size_t bufsiz ATTRIBUTE_UNUSED)
455 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
456 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
459 return readlink (path, buf, bufsiz);
463 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
464 If NEWPATH exists it will NOT be overwritten.
465 For systems not supporting symbolic links, always return -1. */
468 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
469 char *newpath ATTRIBUTE_UNUSED)
471 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
472 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
475 return symlink (oldpath, newpath);
479 /* Try to lock a file, return 1 if success. */
481 #if defined (__vxworks) || defined (__nucleus__) || defined (MSDOS) \
482 || defined (_WIN32) || defined (__EMX__) || defined (VMS)
484 /* Version that does not use link. */
487 __gnat_try_lock (char *dir, char *file)
491 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
492 TCHAR wfile[GNAT_MAX_PATH_LEN];
493 TCHAR wdir[GNAT_MAX_PATH_LEN];
495 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
496 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
498 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
499 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
503 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
504 fd = open (full_path, O_CREAT | O_EXCL, 0600);
516 /* Version using link(), more secure over NFS. */
517 /* See TN 6913-016 for discussion ??? */
520 __gnat_try_lock (char *dir, char *file)
524 GNAT_STRUCT_STAT stat_result;
527 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
528 sprintf (temp_file, "%s%cTMP-%ld-%ld",
529 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
531 /* Create the temporary file and write the process number. */
532 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
538 /* Link it with the new file. */
539 link (temp_file, full_path);
541 /* Count the references on the old one. If we have a count of two, then
542 the link did succeed. Remove the temporary file before returning. */
543 __gnat_stat (temp_file, &stat_result);
545 return stat_result.st_nlink == 2;
549 /* Return the maximum file name length. */
552 __gnat_get_maximum_file_name_length (void)
557 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
566 /* Return nonzero if file names are case sensitive. */
569 __gnat_get_file_names_case_sensitive (void)
571 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
579 __gnat_get_default_identifier_character_set (void)
581 #if defined (__EMX__) || defined (MSDOS)
588 /* Return the current working directory. */
591 __gnat_get_current_dir (char *dir, int *length)
593 #if defined (__MINGW32__)
594 TCHAR wdir[GNAT_MAX_PATH_LEN];
596 _tgetcwd (wdir, *length);
598 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
601 /* Force Unix style, which is what GNAT uses internally. */
602 getcwd (dir, *length, 0);
604 getcwd (dir, *length);
607 *length = strlen (dir);
609 if (dir [*length - 1] != DIR_SEPARATOR)
611 dir [*length] = DIR_SEPARATOR;
617 /* Return the suffix for object files. */
620 __gnat_get_object_suffix_ptr (int *len, const char **value)
622 *value = HOST_OBJECT_SUFFIX;
627 *len = strlen (*value);
632 /* Return the suffix for executable files. */
635 __gnat_get_executable_suffix_ptr (int *len, const char **value)
637 *value = HOST_EXECUTABLE_SUFFIX;
641 *len = strlen (*value);
646 /* Return the suffix for debuggable files. Usually this is the same as the
647 executable extension. */
650 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
653 *value = HOST_EXECUTABLE_SUFFIX;
655 /* On DOS, the extensionless COFF file is what gdb likes. */
662 *len = strlen (*value);
667 /* Returns the OS filename and corresponding encoding. */
670 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
671 char *w_filename ATTRIBUTE_UNUSED,
672 char *os_name, int *o_length,
673 char *encoding ATTRIBUTE_UNUSED, int *e_length)
675 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
676 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)o_length);
677 *o_length = strlen (os_name);
678 strcpy (encoding, "encoding=utf8");
679 *e_length = strlen (encoding);
681 strcpy (os_name, filename);
682 *o_length = strlen (filename);
690 __gnat_unlink (char *path)
692 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
694 TCHAR wpath[GNAT_MAX_PATH_LEN];
696 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
697 return _tunlink (wpath);
700 return unlink (path);
707 __gnat_rename (char *from, char *to)
709 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
711 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
713 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
714 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
715 return _trename (wfrom, wto);
718 return rename (from, to);
722 /* Changing directory. */
725 __gnat_chdir (char *path)
727 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
729 TCHAR wpath[GNAT_MAX_PATH_LEN];
731 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
732 return _tchdir (wpath);
739 /* Removing a directory. */
742 __gnat_rmdir (char *path)
744 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
746 TCHAR wpath[GNAT_MAX_PATH_LEN];
748 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
749 return _trmdir (wpath);
751 #elif defined (VTHREADS)
752 /* rmdir not available */
760 __gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
762 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
763 TCHAR wpath[GNAT_MAX_PATH_LEN];
766 S2WS (wmode, mode, 10);
768 if (encoding == Encoding_Unspecified)
769 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
770 else if (encoding == Encoding_UTF8)
771 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
773 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
775 return _tfopen (wpath, wmode);
777 return decc$fopen (path, mode);
779 return GNAT_FOPEN (path, mode);
784 __gnat_freopen (char *path, char *mode, FILE *stream, int encoding ATTRIBUTE_UNUSED)
786 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
787 TCHAR wpath[GNAT_MAX_PATH_LEN];
790 S2WS (wmode, mode, 10);
792 if (encoding == Encoding_Unspecified)
793 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
794 else if (encoding == Encoding_UTF8)
795 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
797 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
799 return _tfreopen (wpath, wmode, stream);
801 return decc$freopen (path, mode, stream);
803 return freopen (path, mode, stream);
808 __gnat_open_read (char *path, int fmode)
811 int o_fmode = O_BINARY;
817 /* Optional arguments mbc,deq,fop increase read performance. */
818 fd = open (path, O_RDONLY | o_fmode, 0444,
819 "mbc=16", "deq=64", "fop=tef");
820 #elif defined (__vxworks)
821 fd = open (path, O_RDONLY | o_fmode, 0444);
822 #elif defined (__MINGW32__)
824 TCHAR wpath[GNAT_MAX_PATH_LEN];
826 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
827 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
830 fd = open (path, O_RDONLY | o_fmode);
833 return fd < 0 ? -1 : fd;
836 #if defined (__EMX__) || defined (__MINGW32__)
837 #define PERM (S_IREAD | S_IWRITE)
839 /* Excerpt from DECC C RTL Reference Manual:
840 To create files with OpenVMS RMS default protections using the UNIX
841 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
842 and open with a file-protection mode argument of 0777 in a program
843 that never specifically calls umask. These default protections include
844 correctly establishing protections based on ACLs, previous versions of
848 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
852 __gnat_open_rw (char *path, int fmode)
855 int o_fmode = O_BINARY;
861 fd = open (path, O_RDWR | o_fmode, PERM,
862 "mbc=16", "deq=64", "fop=tef");
863 #elif defined (__MINGW32__)
865 TCHAR wpath[GNAT_MAX_PATH_LEN];
867 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
868 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
871 fd = open (path, O_RDWR | o_fmode, PERM);
874 return fd < 0 ? -1 : fd;
878 __gnat_open_create (char *path, int fmode)
881 int o_fmode = O_BINARY;
887 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
888 "mbc=16", "deq=64", "fop=tef");
889 #elif defined (__MINGW32__)
891 TCHAR wpath[GNAT_MAX_PATH_LEN];
893 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
894 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
897 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
900 return fd < 0 ? -1 : fd;
904 __gnat_create_output_file (char *path)
908 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
909 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
910 "shr=del,get,put,upd");
911 #elif defined (__MINGW32__)
913 TCHAR wpath[GNAT_MAX_PATH_LEN];
915 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
916 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
919 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
922 return fd < 0 ? -1 : fd;
926 __gnat_open_append (char *path, int fmode)
929 int o_fmode = O_BINARY;
935 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
936 "mbc=16", "deq=64", "fop=tef");
937 #elif defined (__MINGW32__)
939 TCHAR wpath[GNAT_MAX_PATH_LEN];
941 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
942 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
945 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
948 return fd < 0 ? -1 : fd;
951 /* Open a new file. Return error (-1) if the file already exists. */
954 __gnat_open_new (char *path, int fmode)
957 int o_fmode = O_BINARY;
963 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
964 "mbc=16", "deq=64", "fop=tef");
965 #elif defined (__MINGW32__)
967 TCHAR wpath[GNAT_MAX_PATH_LEN];
969 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
970 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
973 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
976 return fd < 0 ? -1 : fd;
979 /* Open a new temp file. Return error (-1) if the file already exists.
980 Special options for VMS allow the file to be shared between parent and child
981 processes, however they really slow down output. Used in gnatchop. */
984 __gnat_open_new_temp (char *path, int fmode)
987 int o_fmode = O_BINARY;
989 strcpy (path, "GNAT-XXXXXX");
991 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
992 || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
993 return mkstemp (path);
994 #elif defined (__Lynx__)
996 #elif defined (__nucleus__)
999 if (mktemp (path) == NULL)
1007 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1008 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
1009 "mbc=16", "deq=64", "fop=tef");
1011 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1014 return fd < 0 ? -1 : fd;
1017 /* Return the number of bytes in the specified file. */
1020 __gnat_file_length (int fd)
1023 GNAT_STRUCT_STAT statbuf;
1025 ret = GNAT_FSTAT (fd, &statbuf);
1026 if (ret || !S_ISREG (statbuf.st_mode))
1029 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1030 don't return a useful value for files larger than 2 gigabytes in
1033 return (statbuf.st_size);
1036 /* Return the number of bytes in the specified named file. */
1039 __gnat_named_file_length (char *name)
1042 GNAT_STRUCT_STAT statbuf;
1044 ret = __gnat_stat (name, &statbuf);
1045 if (ret || !S_ISREG (statbuf.st_mode))
1048 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1049 don't return a useful value for files larger than 2 gigabytes in
1052 return (statbuf.st_size);
1055 /* Create a temporary filename and put it in string pointed to by
1059 __gnat_tmp_name (char *tmp_filename)
1062 /* Variable used to create a series of unique names */
1063 static int counter = 0;
1065 /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
1066 strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
1067 sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
1069 #elif defined (__MINGW32__)
1073 /* tempnam tries to create a temporary file in directory pointed to by
1074 TMP environment variable, in c:\temp if TMP is not set, and in
1075 directory specified by P_tmpdir in stdio.h if c:\temp does not
1076 exist. The filename will be created with the prefix "gnat-". */
1078 pname = (char *) tempnam ("c:\\temp", "gnat-");
1080 /* if pname is NULL, the file was not created properly, the disk is full
1081 or there is no more free temporary files */
1084 *tmp_filename = '\0';
1086 /* If pname start with a back slash and not path information it means that
1087 the filename is valid for the current working directory. */
1089 else if (pname[0] == '\\')
1091 strcpy (tmp_filename, ".\\");
1092 strcat (tmp_filename, pname+1);
1095 strcpy (tmp_filename, pname);
1100 #elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
1101 || defined (__OpenBSD__) || defined(__GLIBC__)
1102 #define MAX_SAFE_PATH 1000
1103 char *tmpdir = getenv ("TMPDIR");
1105 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1106 a buffer overflow. */
1107 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1108 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1110 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1112 close (mkstemp(tmp_filename));
1114 tmpnam (tmp_filename);
1118 /* Open directory and returns a DIR pointer. */
1120 DIR* __gnat_opendir (char *name)
1123 /* Not supported in RTX */
1127 #elif defined (__MINGW32__)
1128 TCHAR wname[GNAT_MAX_PATH_LEN];
1130 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1131 return (DIR*)_topendir (wname);
1134 return opendir (name);
1138 /* Read the next entry in a directory. The returned string points somewhere
1142 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1145 /* Not supported in RTX */
1149 #elif defined (__MINGW32__)
1150 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1154 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1155 *len = strlen (buffer);
1162 #elif defined (HAVE_READDIR_R)
1163 /* If possible, try to use the thread-safe version. */
1164 if (readdir_r (dirp, buffer) != NULL)
1166 *len = strlen (((struct dirent*) buffer)->d_name);
1167 return ((struct dirent*) buffer)->d_name;
1173 struct dirent *dirent = (struct dirent *) readdir (dirp);
1177 strcpy (buffer, dirent->d_name);
1178 *len = strlen (buffer);
1187 /* Close a directory entry. */
1189 int __gnat_closedir (DIR *dirp)
1192 /* Not supported in RTX */
1196 #elif defined (__MINGW32__)
1197 return _tclosedir ((_TDIR*)dirp);
1200 return closedir (dirp);
1204 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1207 __gnat_readdir_is_thread_safe (void)
1209 #ifdef HAVE_READDIR_R
1216 #if defined (_WIN32) && !defined (RTX)
1217 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1218 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1220 /* Returns the file modification timestamp using Win32 routines which are
1221 immune against daylight saving time change. It is in fact not possible to
1222 use fstat for this purpose as the DST modify the st_mtime field of the
1226 win32_filetime (HANDLE h)
1231 unsigned long long ull_time;
1234 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1235 since <Jan 1st 1601>. This function must return the number of seconds
1236 since <Jan 1st 1970>. */
1238 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1239 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1244 /* Return a GNAT time stamp given a file name. */
1247 __gnat_file_time_name (char *name)
1250 #if defined (__EMX__) || defined (MSDOS)
1251 int fd = open (name, O_RDONLY | O_BINARY);
1252 time_t ret = __gnat_file_time_fd (fd);
1254 return (OS_Time)ret;
1256 #elif defined (_WIN32) && !defined (RTX)
1258 TCHAR wname[GNAT_MAX_PATH_LEN];
1260 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1262 HANDLE h = CreateFile
1263 (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1264 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
1266 if (h != INVALID_HANDLE_VALUE)
1268 ret = win32_filetime (h);
1271 return (OS_Time) ret;
1273 GNAT_STRUCT_STAT statbuf;
1274 if (__gnat_stat (name, &statbuf) != 0) {
1278 /* VMS has file versioning. */
1279 return (OS_Time)statbuf.st_ctime;
1281 return (OS_Time)statbuf.st_mtime;
1287 /* Return a GNAT time stamp given a file descriptor. */
1290 __gnat_file_time_fd (int fd)
1292 /* The following workaround code is due to the fact that under EMX and
1293 DJGPP fstat attempts to convert time values to GMT rather than keep the
1294 actual OS timestamp of the file. By using the OS2/DOS functions directly
1295 the GNAT timestamp are independent of this behavior, which is desired to
1296 facilitate the distribution of GNAT compiled libraries. */
1298 #if defined (__EMX__) || defined (MSDOS)
1302 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
1303 sizeof (FILESTATUS));
1305 unsigned file_year = fs.fdateLastWrite.year;
1306 unsigned file_month = fs.fdateLastWrite.month;
1307 unsigned file_day = fs.fdateLastWrite.day;
1308 unsigned file_hour = fs.ftimeLastWrite.hours;
1309 unsigned file_min = fs.ftimeLastWrite.minutes;
1310 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
1314 int ret = getftime (fd, &fs);
1316 unsigned file_year = fs.ft_year;
1317 unsigned file_month = fs.ft_month;
1318 unsigned file_day = fs.ft_day;
1319 unsigned file_hour = fs.ft_hour;
1320 unsigned file_min = fs.ft_min;
1321 unsigned file_tsec = fs.ft_tsec;
1324 /* Calculate the seconds since epoch from the time components. First count
1325 the whole days passed. The value for years returned by the DOS and OS2
1326 functions count years from 1980, so to compensate for the UNIX epoch which
1327 begins in 1970 start with 10 years worth of days and add days for each
1328 four year period since then. */
1331 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1332 int days_passed = 3652 + (file_year / 4) * 1461;
1333 int years_since_leap = file_year % 4;
1335 if (years_since_leap == 1)
1337 else if (years_since_leap == 2)
1339 else if (years_since_leap == 3)
1340 days_passed += 1096;
1345 days_passed += cum_days[file_month - 1];
1346 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
1349 days_passed += file_day - 1;
1351 /* OK - have whole days. Multiply -- then add in other parts. */
1353 tot_secs = days_passed * 86400;
1354 tot_secs += file_hour * 3600;
1355 tot_secs += file_min * 60;
1356 tot_secs += file_tsec * 2;
1357 return (OS_Time) tot_secs;
1359 #elif defined (_WIN32) && !defined (RTX)
1360 HANDLE h = (HANDLE) _get_osfhandle (fd);
1361 time_t ret = win32_filetime (h);
1362 return (OS_Time) ret;
1365 GNAT_STRUCT_STAT statbuf;
1367 if (GNAT_FSTAT (fd, &statbuf) != 0) {
1368 return (OS_Time) -1;
1371 /* VMS has file versioning. */
1372 return (OS_Time) statbuf.st_ctime;
1374 return (OS_Time) statbuf.st_mtime;
1380 /* Set the file time stamp. */
1383 __gnat_set_file_time_name (char *name, time_t time_stamp)
1385 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1387 /* Code to implement __gnat_set_file_time_name for these systems. */
1389 #elif defined (_WIN32) && !defined (RTX)
1393 unsigned long long ull_time;
1395 TCHAR wname[GNAT_MAX_PATH_LEN];
1397 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1399 HANDLE h = CreateFile
1400 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1401 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1403 if (h == INVALID_HANDLE_VALUE)
1405 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1406 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1407 /* Convert to 100 nanosecond units */
1408 t_write.ull_time *= 10000000ULL;
1410 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1420 unsigned long long backup, create, expire, revise;
1424 unsigned short value;
1427 unsigned system : 4;
1433 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1437 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1438 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1439 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1440 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
1441 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
1442 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1447 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1451 unsigned long long newtime;
1452 unsigned long long revtime;
1456 struct vstring file;
1457 struct dsc$descriptor_s filedsc
1458 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1459 struct vstring device;
1460 struct dsc$descriptor_s devicedsc
1461 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1462 struct vstring timev;
1463 struct dsc$descriptor_s timedsc
1464 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1465 struct vstring result;
1466 struct dsc$descriptor_s resultdsc
1467 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1469 /* Convert parameter name (a file spec) to host file form. Note that this
1470 is needed on VMS to prepare for subsequent calls to VMS RMS library
1471 routines. Note that it would not work to call __gnat_to_host_dir_spec
1472 as was done in a previous version, since this fails silently unless
1473 the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1474 (directory not found) condition is signalled. */
1475 tryfile = (char *) __gnat_to_host_file_spec (name);
1477 /* Allocate and initialize a FAB and NAM structures. */
1481 nam.nam$l_esa = file.string;
1482 nam.nam$b_ess = NAM$C_MAXRSS;
1483 nam.nam$l_rsa = result.string;
1484 nam.nam$b_rss = NAM$C_MAXRSS;
1485 fab.fab$l_fna = tryfile;
1486 fab.fab$b_fns = strlen (tryfile);
1487 fab.fab$l_nam = &nam;
1489 /* Validate filespec syntax and device existence. */
1490 status = SYS$PARSE (&fab, 0, 0);
1491 if ((status & 1) != 1)
1492 LIB$SIGNAL (status);
1494 file.string[nam.nam$b_esl] = 0;
1496 /* Find matching filespec. */
1497 status = SYS$SEARCH (&fab, 0, 0);
1498 if ((status & 1) != 1)
1499 LIB$SIGNAL (status);
1501 file.string[nam.nam$b_esl] = 0;
1502 result.string[result.length=nam.nam$b_rsl] = 0;
1504 /* Get the device name and assign an IO channel. */
1505 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1506 devicedsc.dsc$w_length = nam.nam$b_dev;
1508 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1509 if ((status & 1) != 1)
1510 LIB$SIGNAL (status);
1512 /* Initialize the FIB and fill in the directory id field. */
1513 memset (&fib, 0, sizeof (fib));
1514 fib.fib$w_did[0] = nam.nam$w_did[0];
1515 fib.fib$w_did[1] = nam.nam$w_did[1];
1516 fib.fib$w_did[2] = nam.nam$w_did[2];
1517 fib.fib$l_acctl = 0;
1519 strcpy (file.string, (strrchr (result.string, ']') + 1));
1520 filedsc.dsc$w_length = strlen (file.string);
1521 result.string[result.length = 0] = 0;
1523 /* Open and close the file to fill in the attributes. */
1525 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1526 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1527 if ((status & 1) != 1)
1528 LIB$SIGNAL (status);
1529 if ((iosb.status & 1) != 1)
1530 LIB$SIGNAL (iosb.status);
1532 result.string[result.length] = 0;
1533 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1535 if ((status & 1) != 1)
1536 LIB$SIGNAL (status);
1537 if ((iosb.status & 1) != 1)
1538 LIB$SIGNAL (iosb.status);
1543 /* Set creation time to requested time. */
1544 unix_time_to_vms (time_stamp, newtime);
1546 t = time ((time_t) 0);
1548 /* Set revision time to now in local time. */
1549 unix_time_to_vms (t, revtime);
1552 /* Reopen the file, modify the times and then close. */
1553 fib.fib$l_acctl = FIB$M_WRITE;
1555 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1556 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1557 if ((status & 1) != 1)
1558 LIB$SIGNAL (status);
1559 if ((iosb.status & 1) != 1)
1560 LIB$SIGNAL (iosb.status);
1562 Fat.create = newtime;
1563 Fat.revise = revtime;
1565 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1566 &fibdsc, 0, 0, 0, &atrlst, 0);
1567 if ((status & 1) != 1)
1568 LIB$SIGNAL (status);
1569 if ((iosb.status & 1) != 1)
1570 LIB$SIGNAL (iosb.status);
1572 /* Deassign the channel and exit. */
1573 status = SYS$DASSGN (chan);
1574 if ((status & 1) != 1)
1575 LIB$SIGNAL (status);
1577 struct utimbuf utimbuf;
1580 /* Set modification time to requested time. */
1581 utimbuf.modtime = time_stamp;
1583 /* Set access time to now in local time. */
1584 t = time ((time_t) 0);
1585 utimbuf.actime = mktime (localtime (&t));
1587 utime (name, &utimbuf);
1591 /* Get the list of installed standard libraries from the
1592 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1596 __gnat_get_libraries_from_registry (void)
1598 char *result = (char *) xmalloc (1);
1602 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS) \
1606 DWORD name_size, value_size;
1613 /* First open the key. */
1614 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, ®_key);
1616 if (res == ERROR_SUCCESS)
1617 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1618 KEY_READ, ®_key);
1620 if (res == ERROR_SUCCESS)
1621 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, ®_key);
1623 if (res == ERROR_SUCCESS)
1624 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, ®_key);
1626 /* If the key exists, read out all the values in it and concatenate them
1628 for (index = 0; res == ERROR_SUCCESS; index++)
1630 value_size = name_size = 256;
1631 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
1632 &type, (LPBYTE)value, &value_size);
1634 if (res == ERROR_SUCCESS && type == REG_SZ)
1636 char *old_result = result;
1638 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1639 strcpy (result, old_result);
1640 strcat (result, value);
1641 strcat (result, ";");
1646 /* Remove the trailing ";". */
1648 result[strlen (result) - 1] = 0;
1655 __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1658 /* Under Windows the directory name for the stat function must not be
1659 terminated by a directory separator except if just after a drive name
1660 or with UNC path without directory (only the name of the shared
1661 resource), for example: \\computer\share\ */
1663 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1666 int dirsep_count = 0;
1668 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1669 name_len = _tcslen (wname);
1671 if (name_len > GNAT_MAX_PATH_LEN)
1674 last_char = wname[name_len - 1];
1676 while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1678 wname[name_len - 1] = _T('\0');
1680 last_char = wname[name_len - 1];
1683 /* Count back-slashes. */
1685 for (k=0; k<name_len; k++)
1686 if (wname[k] == _T('\\') || wname[k] == _T('/'))
1689 /* Only a drive letter followed by ':', we must add a directory separator
1690 for the stat routine to work properly. */
1691 if ((name_len == 2 && wname[1] == _T(':'))
1692 || (name_len > 3 && wname[0] == _T('\\') && wname[1] == _T('\\')
1693 && dirsep_count == 3))
1694 _tcscat (wname, _T("\\"));
1696 return _tstat (wname, (struct _stat *)statbuf);
1699 return GNAT_STAT (name, statbuf);
1704 __gnat_file_exists (char *name)
1707 /* On Windows do not use __gnat_stat() because a bug in Microsoft
1708 _stat() routine. When the system time-zone is set with a negative
1709 offset the _stat() routine fails on specific files like CON: */
1710 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1712 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1713 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1715 GNAT_STRUCT_STAT statbuf;
1717 return !__gnat_stat (name, &statbuf);
1722 __gnat_is_absolute_path (char *name, int length)
1725 /* On VxWorks systems, an absolute path can be represented (depending on
1726 the host platform) as either /dir/file, or device:/dir/file, or
1727 device:drive_letter:/dir/file. */
1734 for (index = 0; index < length; index++)
1736 if (name[index] == ':' &&
1737 ((name[index + 1] == '/') ||
1738 (isalpha (name[index + 1]) && index + 2 <= length &&
1739 name[index + 2] == '/')))
1742 else if (name[index] == '/')
1747 return (length != 0) &&
1748 (*name == '/' || *name == DIR_SEPARATOR
1749 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1750 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1757 __gnat_is_regular_file (char *name)
1760 GNAT_STRUCT_STAT statbuf;
1762 ret = __gnat_stat (name, &statbuf);
1763 return (!ret && S_ISREG (statbuf.st_mode));
1767 __gnat_is_directory (char *name)
1770 GNAT_STRUCT_STAT statbuf;
1772 ret = __gnat_stat (name, &statbuf);
1773 return (!ret && S_ISDIR (statbuf.st_mode));
1776 #if defined (_WIN32) && !defined (RTX)
1778 /* Returns the same constant as GetDriveType but takes a pathname as
1782 GetDriveTypeFromPath (TCHAR *wfullpath)
1784 TCHAR wdrv[MAX_PATH];
1785 TCHAR wpath[MAX_PATH];
1786 TCHAR wfilename[MAX_PATH];
1787 TCHAR wext[MAX_PATH];
1789 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1791 if (_tcslen (wdrv) != 0)
1793 /* we have a drive specified. */
1794 _tcscat (wdrv, _T("\\"));
1795 return GetDriveType (wdrv);
1799 /* No drive specified. */
1801 /* Is this a relative path, if so get current drive type. */
1802 if (wpath[0] != _T('\\') ||
1803 (_tcslen (wpath) > 2 && wpath[0] == _T('\\') && wpath[1] != _T('\\')))
1804 return GetDriveType (NULL);
1806 UINT result = GetDriveType (wpath);
1808 /* Cannot guess the drive type, is this \\.\ ? */
1810 if (result == DRIVE_NO_ROOT_DIR &&
1811 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1812 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1814 if (_tcslen (wpath) == 4)
1815 _tcscat (wpath, wfilename);
1817 LPTSTR p = &wpath[4];
1818 LPTSTR b = _tcschr (p, _T('\\'));
1821 { /* logical drive \\.\c\dir\file */
1827 _tcscat (p, _T(":\\"));
1829 return GetDriveType (p);
1836 /* This MingW section contains code to work with ACL. */
1838 __gnat_check_OWNER_ACL
1840 DWORD CheckAccessDesired,
1841 GENERIC_MAPPING CheckGenericMapping)
1843 DWORD dwAccessDesired, dwAccessAllowed;
1844 PRIVILEGE_SET PrivilegeSet;
1845 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1846 BOOL fAccessGranted = FALSE;
1847 HANDLE hToken = NULL;
1849 SECURITY_DESCRIPTOR* pSD = NULL;
1852 (wname, OWNER_SECURITY_INFORMATION |
1853 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1856 if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
1857 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1860 /* Obtain the security descriptor. */
1862 if (!GetFileSecurity
1863 (wname, OWNER_SECURITY_INFORMATION |
1864 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1865 pSD, nLength, &nLength))
1868 if (!ImpersonateSelf (SecurityImpersonation))
1871 if (!OpenThreadToken
1872 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1875 /* Undoes the effect of ImpersonateSelf. */
1879 /* We want to test for write permissions. */
1881 dwAccessDesired = CheckAccessDesired;
1883 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1886 (pSD , /* security descriptor to check */
1887 hToken, /* impersonation token */
1888 dwAccessDesired, /* requested access rights */
1889 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1890 &PrivilegeSet, /* receives privileges used in check */
1891 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1892 &dwAccessAllowed, /* receives mask of allowed access rights */
1896 CloseHandle (hToken);
1897 HeapFree (GetProcessHeap (), 0, pSD);
1898 return fAccessGranted;
1902 CloseHandle (hToken);
1903 HeapFree (GetProcessHeap (), 0, pSD);
1908 __gnat_set_OWNER_ACL
1911 DWORD AccessPermissions)
1913 PACL pOldDACL = NULL;
1914 PACL pNewDACL = NULL;
1915 PSECURITY_DESCRIPTOR pSD = NULL;
1917 TCHAR username [100];
1920 /* Get current user, he will act as the owner */
1922 if (!GetUserName (username, &unsize))
1925 if (GetNamedSecurityInfo
1928 DACL_SECURITY_INFORMATION,
1929 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1932 BuildExplicitAccessWithName
1933 (&ea, username, AccessPermissions, AccessMode, NO_INHERITANCE);
1935 if (AccessMode == SET_ACCESS)
1937 /* SET_ACCESS, we want to set an explicte set of permissions, do not
1938 merge with current DACL. */
1939 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
1943 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1946 if (SetNamedSecurityInfo
1947 (wname, SE_FILE_OBJECT,
1948 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
1952 LocalFree (pNewDACL);
1955 /* Check if it is possible to use ACL for wname, the file must not be on a
1959 __gnat_can_use_acl (TCHAR *wname)
1961 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
1964 #endif /* defined (_WIN32) && !defined (RTX) */
1967 __gnat_is_readable_file (char *name)
1969 #if defined (_WIN32) && !defined (RTX)
1970 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1971 GENERIC_MAPPING GenericMapping;
1973 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1975 if (__gnat_can_use_acl (wname))
1977 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1978 GenericMapping.GenericRead = GENERIC_READ;
1980 return __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
1983 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1988 GNAT_STRUCT_STAT statbuf;
1990 ret = GNAT_STAT (name, &statbuf);
1991 mode = statbuf.st_mode & S_IRUSR;
1992 return (!ret && mode);
1997 __gnat_is_writable_file (char *name)
1999 #if defined (_WIN32) && !defined (RTX)
2000 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2001 GENERIC_MAPPING GenericMapping;
2003 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2005 if (__gnat_can_use_acl (wname))
2007 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2008 GenericMapping.GenericWrite = GENERIC_WRITE;
2010 return __gnat_check_OWNER_ACL
2011 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
2012 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2015 return !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2020 GNAT_STRUCT_STAT statbuf;
2022 ret = GNAT_STAT (name, &statbuf);
2023 mode = statbuf.st_mode & S_IWUSR;
2024 return (!ret && mode);
2029 __gnat_is_executable_file (char *name)
2031 #if defined (_WIN32) && !defined (RTX)
2032 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2033 GENERIC_MAPPING GenericMapping;
2035 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2037 if (__gnat_can_use_acl (wname))
2039 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2040 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2042 return __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2045 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2046 && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
2050 GNAT_STRUCT_STAT statbuf;
2052 ret = GNAT_STAT (name, &statbuf);
2053 mode = statbuf.st_mode & S_IXUSR;
2054 return (!ret && mode);
2059 __gnat_set_writable (char *name)
2061 #if defined (_WIN32) && !defined (RTX)
2062 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2064 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2066 if (__gnat_can_use_acl (wname))
2067 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2070 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
2071 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2072 GNAT_STRUCT_STAT statbuf;
2074 if (GNAT_STAT (name, &statbuf) == 0)
2076 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2077 chmod (name, statbuf.st_mode);
2083 __gnat_set_executable (char *name)
2085 #if defined (_WIN32) && !defined (RTX)
2086 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2088 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2090 if (__gnat_can_use_acl (wname))
2091 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
2093 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2094 GNAT_STRUCT_STAT statbuf;
2096 if (GNAT_STAT (name, &statbuf) == 0)
2098 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2099 chmod (name, statbuf.st_mode);
2105 __gnat_set_non_writable (char *name)
2107 #if defined (_WIN32) && !defined (RTX)
2108 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2110 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2112 if (__gnat_can_use_acl (wname))
2113 __gnat_set_OWNER_ACL
2114 (wname, DENY_ACCESS,
2115 FILE_WRITE_DATA | FILE_APPEND_DATA |
2116 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2119 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
2120 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2121 GNAT_STRUCT_STAT statbuf;
2123 if (GNAT_STAT (name, &statbuf) == 0)
2125 statbuf.st_mode = statbuf.st_mode & 07577;
2126 chmod (name, statbuf.st_mode);
2132 __gnat_set_readable (char *name)
2134 #if defined (_WIN32) && !defined (RTX)
2135 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2137 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2139 if (__gnat_can_use_acl (wname))
2140 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
2142 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2143 GNAT_STRUCT_STAT statbuf;
2145 if (GNAT_STAT (name, &statbuf) == 0)
2147 chmod (name, statbuf.st_mode | S_IREAD);
2153 __gnat_set_non_readable (char *name)
2155 #if defined (_WIN32) && !defined (RTX)
2156 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2158 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2160 if (__gnat_can_use_acl (wname))
2161 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
2163 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2164 GNAT_STRUCT_STAT statbuf;
2166 if (GNAT_STAT (name, &statbuf) == 0)
2168 chmod (name, statbuf.st_mode & (~S_IREAD));
2174 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2176 #if defined (__vxworks) || defined (__nucleus__)
2179 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2181 GNAT_STRUCT_STAT statbuf;
2183 ret = GNAT_LSTAT (name, &statbuf);
2184 return (!ret && S_ISLNK (statbuf.st_mode));
2191 #if defined (sun) && defined (__SVR4)
2192 /* Using fork on Solaris will duplicate all the threads. fork1, which
2193 duplicates only the active thread, must be used instead, or spawning
2194 subprocess from a program with tasking will lead into numerous problems. */
2199 __gnat_portable_spawn (char *args[])
2202 int finished ATTRIBUTE_UNUSED;
2203 int pid ATTRIBUTE_UNUSED;
2205 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
2208 #elif defined (MSDOS) || defined (_WIN32)
2209 /* args[0] must be quotes as it could contain a full pathname with spaces */
2210 char *args_0 = args[0];
2211 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2212 strcpy (args[0], "\"");
2213 strcat (args[0], args_0);
2214 strcat (args[0], "\"");
2216 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
2218 /* restore previous value */
2220 args[0] = (char *)args_0;
2230 pid = spawnvp (P_NOWAIT, args[0], args);
2242 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2244 return -1; /* execv is in parent context on VMS. */
2252 finished = waitpid (pid, &status, 0);
2254 if (finished != pid || WIFEXITED (status) == 0)
2257 return WEXITSTATUS (status);
2263 /* Create a copy of the given file descriptor.
2264 Return -1 if an error occurred. */
2267 __gnat_dup (int oldfd)
2269 #if defined (__vxworks) && !defined (__RTP__)
2270 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2278 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2279 Return -1 if an error occurred. */
2282 __gnat_dup2 (int oldfd, int newfd)
2284 #if defined (__vxworks) && !defined (__RTP__)
2285 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2289 return dup2 (oldfd, newfd);
2293 /* WIN32 code to implement a wait call that wait for any child process. */
2295 #if defined (_WIN32) && !defined (RTX)
2297 /* Synchronization code, to be thread safe. */
2301 /* For the Cert run times on native Windows we use dummy functions
2302 for locking and unlocking tasks since we do not support multiple
2303 threads on this configuration (Cert run time on native Windows). */
2305 void dummy (void) {}
2307 void (*Lock_Task) () = &dummy;
2308 void (*Unlock_Task) () = &dummy;
2312 #define Lock_Task system__soft_links__lock_task
2313 extern void (*Lock_Task) (void);
2315 #define Unlock_Task system__soft_links__unlock_task
2316 extern void (*Unlock_Task) (void);
2320 static HANDLE *HANDLES_LIST = NULL;
2321 static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
2324 add_handle (HANDLE h)
2327 /* -------------------- critical section -------------------- */
2330 if (plist_length == plist_max_length)
2332 plist_max_length += 1000;
2334 xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2336 xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2339 HANDLES_LIST[plist_length] = h;
2340 PID_LIST[plist_length] = GetProcessId (h);
2344 /* -------------------- critical section -------------------- */
2348 __gnat_win32_remove_handle (HANDLE h, int pid)
2352 /* -------------------- critical section -------------------- */
2355 for (j = 0; j < plist_length; j++)
2357 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
2361 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2362 PID_LIST[j] = PID_LIST[plist_length];
2368 /* -------------------- critical section -------------------- */
2372 win32_no_block_spawn (char *command, char *args[])
2376 PROCESS_INFORMATION PI;
2377 SECURITY_ATTRIBUTES SA;
2382 /* compute the total command line length */
2386 csize += strlen (args[k]) + 1;
2390 full_command = (char *) xmalloc (csize);
2393 SI.cb = sizeof (STARTUPINFO);
2394 SI.lpReserved = NULL;
2395 SI.lpReserved2 = NULL;
2396 SI.lpDesktop = NULL;
2400 SI.wShowWindow = SW_HIDE;
2402 /* Security attributes. */
2403 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2404 SA.bInheritHandle = TRUE;
2405 SA.lpSecurityDescriptor = NULL;
2407 /* Prepare the command string. */
2408 strcpy (full_command, command);
2409 strcat (full_command, " ");
2414 strcat (full_command, args[k]);
2415 strcat (full_command, " ");
2420 int wsize = csize * 2;
2421 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2423 S2WSC (wcommand, full_command, wsize);
2425 free (full_command);
2427 result = CreateProcess
2428 (NULL, wcommand, &SA, NULL, TRUE,
2429 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2436 CloseHandle (PI.hThread);
2444 win32_wait (int *status)
2446 DWORD exitcode, pid;
2453 if (plist_length == 0)
2461 /* -------------------- critical section -------------------- */
2464 hl_len = plist_length;
2466 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2468 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
2471 /* -------------------- critical section -------------------- */
2473 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2474 h = hl[res - WAIT_OBJECT_0];
2476 GetExitCodeProcess (h, &exitcode);
2477 pid = GetProcessId (h);
2478 __gnat_win32_remove_handle (h, -1);
2482 *status = (int) exitcode;
2489 __gnat_portable_no_block_spawn (char *args[])
2492 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2495 #elif defined (__EMX__) || defined (MSDOS)
2497 /* ??? For PC machines I (Franco) don't know the system calls to implement
2498 this routine. So I'll fake it as follows. This routine will behave
2499 exactly like the blocking portable_spawn and will systematically return
2500 a pid of 0 unless the spawned task did not complete successfully, in
2501 which case we return a pid of -1. To synchronize with this the
2502 portable_wait below systematically returns a pid of 0 and reports that
2503 the subprocess terminated successfully. */
2505 if (spawnvp (P_WAIT, args[0], args) != 0)
2508 #elif defined (_WIN32)
2512 h = win32_no_block_spawn (args[0], args);
2516 return GetProcessId (h);
2528 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2530 return -1; /* execv is in parent context on VMS. */
2542 __gnat_portable_wait (int *process_status)
2547 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2548 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2551 #elif defined (_WIN32)
2553 pid = win32_wait (&status);
2555 #elif defined (__EMX__) || defined (MSDOS)
2556 /* ??? See corresponding comment in portable_no_block_spawn. */
2560 pid = waitpid (-1, &status, 0);
2561 status = status & 0xffff;
2564 *process_status = status;
2569 __gnat_os_exit (int status)
2574 /* Locate a regular file, give a Path value. */
2577 __gnat_locate_regular_file (char *file_name, char *path_val)
2580 char *file_path = (char *) alloca (strlen (file_name) + 1);
2583 /* Return immediately if file_name is empty */
2585 if (*file_name == '\0')
2588 /* Remove quotes around file_name if present */
2594 strcpy (file_path, ptr);
2596 ptr = file_path + strlen (file_path) - 1;
2601 /* Handle absolute pathnames. */
2603 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2607 if (__gnat_is_regular_file (file_path))
2608 return xstrdup (file_path);
2613 /* If file_name include directory separator(s), try it first as
2614 a path name relative to the current directory */
2615 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2620 if (__gnat_is_regular_file (file_name))
2621 return xstrdup (file_name);
2628 /* The result has to be smaller than path_val + file_name. */
2629 char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2633 for (; *path_val == PATH_SEPARATOR; path_val++)
2639 /* Skip the starting quote */
2641 if (*path_val == '"')
2644 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2645 *ptr++ = *path_val++;
2649 /* Skip the ending quote */
2654 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2655 *++ptr = DIR_SEPARATOR;
2657 strcpy (++ptr, file_name);
2659 if (__gnat_is_regular_file (file_path))
2660 return xstrdup (file_path);
2667 /* Locate an executable given a Path argument. This routine is only used by
2668 gnatbl and should not be used otherwise. Use locate_exec_on_path
2672 __gnat_locate_exec (char *exec_name, char *path_val)
2675 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2677 char *full_exec_name
2678 = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2680 strcpy (full_exec_name, exec_name);
2681 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2682 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2685 return __gnat_locate_regular_file (exec_name, path_val);
2689 return __gnat_locate_regular_file (exec_name, path_val);
2692 /* Locate an executable using the Systems default PATH. */
2695 __gnat_locate_exec_on_path (char *exec_name)
2699 #if defined (_WIN32) && !defined (RTX)
2700 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2702 /* In Win32 systems we expand the PATH as for XP environment
2703 variables are not automatically expanded. We also prepend the
2704 ".;" to the path to match normal NT path search semantics */
2706 #define EXPAND_BUFFER_SIZE 32767
2708 wapath_val = alloca (EXPAND_BUFFER_SIZE);
2710 wapath_val [0] = '.';
2711 wapath_val [1] = ';';
2713 DWORD res = ExpandEnvironmentStrings
2714 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2716 if (!res) wapath_val [0] = _T('\0');
2718 apath_val = alloca (EXPAND_BUFFER_SIZE);
2720 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2721 return __gnat_locate_exec (exec_name, apath_val);
2726 char *path_val = "/VAXC$PATH";
2728 char *path_val = getenv ("PATH");
2730 if (path_val == NULL) return NULL;
2731 apath_val = (char *) alloca (strlen (path_val) + 1);
2732 strcpy (apath_val, path_val);
2733 return __gnat_locate_exec (exec_name, apath_val);
2739 /* These functions are used to translate to and from VMS and Unix syntax
2740 file, directory and path specifications. */
2743 #define MAXNAMES 256
2744 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2746 static char new_canonical_dirspec [MAXPATH];
2747 static char new_canonical_filespec [MAXPATH];
2748 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2749 static unsigned new_canonical_filelist_index;
2750 static unsigned new_canonical_filelist_in_use;
2751 static unsigned new_canonical_filelist_allocated;
2752 static char **new_canonical_filelist;
2753 static char new_host_pathspec [MAXNAMES*MAXPATH];
2754 static char new_host_dirspec [MAXPATH];
2755 static char new_host_filespec [MAXPATH];
2757 /* Routine is called repeatedly by decc$from_vms via
2758 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2762 wildcard_translate_unix (char *name)
2765 char buff [MAXPATH];
2767 strncpy (buff, name, MAXPATH);
2768 buff [MAXPATH - 1] = (char) 0;
2769 ver = strrchr (buff, '.');
2771 /* Chop off the version. */
2775 /* Dynamically extend the allocation by the increment. */
2776 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2778 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2779 new_canonical_filelist = (char **) xrealloc
2780 (new_canonical_filelist,
2781 new_canonical_filelist_allocated * sizeof (char *));
2784 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2789 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2790 full translation and copy the results into a list (_init), then return them
2791 one at a time (_next). If onlydirs set, only expand directory files. */
2794 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2797 char buff [MAXPATH];
2799 len = strlen (filespec);
2800 strncpy (buff, filespec, MAXPATH);
2802 /* Only look for directories */
2803 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2804 strncat (buff, "*.dir", MAXPATH);
2806 buff [MAXPATH - 1] = (char) 0;
2808 decc$from_vms (buff, wildcard_translate_unix, 1);
2810 /* Remove the .dir extension. */
2816 for (i = 0; i < new_canonical_filelist_in_use; i++)
2818 ext = strstr (new_canonical_filelist[i], ".dir");
2824 return new_canonical_filelist_in_use;
2827 /* Return the next filespec in the list. */
2830 __gnat_to_canonical_file_list_next ()
2832 return new_canonical_filelist[new_canonical_filelist_index++];
2835 /* Free storage used in the wildcard expansion. */
2838 __gnat_to_canonical_file_list_free ()
2842 for (i = 0; i < new_canonical_filelist_in_use; i++)
2843 free (new_canonical_filelist[i]);
2845 free (new_canonical_filelist);
2847 new_canonical_filelist_in_use = 0;
2848 new_canonical_filelist_allocated = 0;
2849 new_canonical_filelist_index = 0;
2850 new_canonical_filelist = 0;
2853 /* The functional equivalent of decc$translate_vms routine.
2854 Designed to produce the same output, but is protected against
2855 malformed paths (original version ACCVIOs in this case) and
2856 does not require VMS-specific DECC RTL */
2858 #define NAM$C_MAXRSS 1024
2861 __gnat_translate_vms (char *src)
2863 static char retbuf [NAM$C_MAXRSS+1];
2864 char *srcendpos, *pos1, *pos2, *retpos;
2865 int disp, path_present = 0;
2867 if (!src) return NULL;
2869 srcendpos = strchr (src, '\0');
2872 /* Look for the node and/or device in front of the path */
2874 pos2 = strchr (pos1, ':');
2876 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2877 /* There is a node name. "node_name::" becomes "node_name!" */
2879 strncpy (retbuf, pos1, disp);
2880 retpos [disp] = '!';
2881 retpos = retpos + disp + 1;
2883 pos2 = strchr (pos1, ':');
2887 /* There is a device name. "dev_name:" becomes "/dev_name/" */
2890 strncpy (retpos, pos1, disp);
2891 retpos = retpos + disp;
2896 /* No explicit device; we must look ahead and prepend /sys$disk/ if
2897 the path is absolute */
2898 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2899 && !strchr (".-]>", *(pos1 + 1))) {
2900 strncpy (retpos, "/sys$disk/", 10);
2904 /* Process the path part */
2905 while (*pos1 == '[' || *pos1 == '<') {
2908 if (*pos1 == ']' || *pos1 == '>') {
2909 /* Special case, [] translates to '.' */
2914 /* '[000000' means root dir. It can be present in the middle of
2915 the path due to expansion of logical devices, in which case
2917 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
2918 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
2920 if (*pos1 == '.') pos1++;
2922 else if (*pos1 == '.') {
2927 /* There is a qualified path */
2928 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
2931 /* '.' is used to separate directories. Replace it with '/' but
2932 only if there isn't already '/' just before */
2933 if (*(retpos - 1) != '/') *(retpos++) = '/';
2935 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
2936 /* ellipsis refers to entire subtree; replace with '**' */
2937 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
2942 /* When after '.' '[' '<' is equivalent to Unix ".." but there
2943 may be several in a row */
2944 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
2945 *(pos1 - 1) == '<') {
2946 while (*pos1 == '-') {
2948 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
2953 /* otherwise fall through to default */
2955 *(retpos++) = *(pos1++);
2962 if (pos1 < srcendpos) {
2963 /* Now add the actual file name, until the version suffix if any */
2964 if (path_present) *(retpos++) = '/';
2965 pos2 = strchr (pos1, ';');
2966 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
2967 strncpy (retpos, pos1, disp);
2969 if (pos2 && pos2 < srcendpos) {
2970 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
2972 disp = srcendpos - pos2 - 1;
2973 strncpy (retpos, pos2 + 1, disp);
2984 /* Translate a VMS syntax directory specification in to Unix syntax. If
2985 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2986 found, return input string. Also translate a dirname that contains no
2987 slashes, in case it's a logical name. */
2990 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2994 strcpy (new_canonical_dirspec, "");
2995 if (strlen (dirspec))
2999 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
3001 strncpy (new_canonical_dirspec,
3002 __gnat_translate_vms (dirspec),
3005 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
3007 strncpy (new_canonical_dirspec,
3008 __gnat_translate_vms (dirspec1),
3013 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
3017 len = strlen (new_canonical_dirspec);
3018 if (prefixflag && new_canonical_dirspec [len-1] != '/')
3019 strncat (new_canonical_dirspec, "/", MAXPATH);
3021 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
3023 return new_canonical_dirspec;
3027 /* Translate a VMS syntax file specification into Unix syntax.
3028 If no indicators of VMS syntax found, check if it's an uppercase
3029 alphanumeric_ name and if so try it out as an environment
3030 variable (logical name). If all else fails return the
3034 __gnat_to_canonical_file_spec (char *filespec)
3038 strncpy (new_canonical_filespec, "", MAXPATH);
3040 if (strchr (filespec, ']') || strchr (filespec, ':'))
3042 char *tspec = (char *) __gnat_translate_vms (filespec);
3044 if (tspec != (char *) -1)
3045 strncpy (new_canonical_filespec, tspec, MAXPATH);
3047 else if ((strlen (filespec) == strspn (filespec,
3048 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
3049 && (filespec1 = getenv (filespec)))
3051 char *tspec = (char *) __gnat_translate_vms (filespec1);
3053 if (tspec != (char *) -1)
3054 strncpy (new_canonical_filespec, tspec, MAXPATH);
3058 strncpy (new_canonical_filespec, filespec, MAXPATH);
3061 new_canonical_filespec [MAXPATH - 1] = (char) 0;
3063 return new_canonical_filespec;
3066 /* Translate a VMS syntax path specification into Unix syntax.
3067 If no indicators of VMS syntax found, return input string. */
3070 __gnat_to_canonical_path_spec (char *pathspec)
3072 char *curr, *next, buff [MAXPATH];
3077 /* If there are /'s, assume it's a Unix path spec and return. */
3078 if (strchr (pathspec, '/'))
3081 new_canonical_pathspec[0] = 0;
3086 next = strchr (curr, ',');
3088 next = strchr (curr, 0);
3090 strncpy (buff, curr, next - curr);
3091 buff[next - curr] = 0;
3093 /* Check for wildcards and expand if present. */
3094 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
3098 dirs = __gnat_to_canonical_file_list_init (buff, 1);
3099 for (i = 0; i < dirs; i++)
3103 next_dir = __gnat_to_canonical_file_list_next ();
3104 strncat (new_canonical_pathspec, next_dir, MAXPATH);
3106 /* Don't append the separator after the last expansion. */
3108 strncat (new_canonical_pathspec, ":", MAXPATH);
3111 __gnat_to_canonical_file_list_free ();
3114 strncat (new_canonical_pathspec,
3115 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
3120 strncat (new_canonical_pathspec, ":", MAXPATH);
3124 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
3126 return new_canonical_pathspec;
3129 static char filename_buff [MAXPATH];
3132 translate_unix (char *name, int type)
3134 strncpy (filename_buff, name, MAXPATH);
3135 filename_buff [MAXPATH - 1] = (char) 0;
3139 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
3143 to_host_path_spec (char *pathspec)
3145 char *curr, *next, buff [MAXPATH];
3150 /* Can't very well test for colons, since that's the Unix separator! */
3151 if (strchr (pathspec, ']') || strchr (pathspec, ','))
3154 new_host_pathspec[0] = 0;
3159 next = strchr (curr, ':');
3161 next = strchr (curr, 0);
3163 strncpy (buff, curr, next - curr);
3164 buff[next - curr] = 0;
3166 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
3169 strncat (new_host_pathspec, ",", MAXPATH);
3173 new_host_pathspec [MAXPATH - 1] = (char) 0;
3175 return new_host_pathspec;
3178 /* Translate a Unix syntax directory specification into VMS syntax. The
3179 PREFIXFLAG has no effect, but is kept for symmetry with
3180 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3184 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3186 int len = strlen (dirspec);
3188 strncpy (new_host_dirspec, dirspec, MAXPATH);
3189 new_host_dirspec [MAXPATH - 1] = (char) 0;
3191 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3192 return new_host_dirspec;
3194 while (len > 1 && new_host_dirspec[len - 1] == '/')
3196 new_host_dirspec[len - 1] = 0;
3200 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
3201 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3202 new_host_dirspec [MAXPATH - 1] = (char) 0;
3204 return new_host_dirspec;
3207 /* Translate a Unix syntax file specification into VMS syntax.
3208 If indicators of VMS syntax found, return input string. */
3211 __gnat_to_host_file_spec (char *filespec)
3213 strncpy (new_host_filespec, "", MAXPATH);
3214 if (strchr (filespec, ']') || strchr (filespec, ':'))
3216 strncpy (new_host_filespec, filespec, MAXPATH);
3220 decc$to_vms (filespec, translate_unix, 1, 1);
3221 strncpy (new_host_filespec, filename_buff, MAXPATH);
3224 new_host_filespec [MAXPATH - 1] = (char) 0;
3226 return new_host_filespec;
3230 __gnat_adjust_os_resource_limits ()
3232 SYS$ADJWSL (131072, 0);
3237 /* Dummy functions for Osint import for non-VMS systems. */
3240 __gnat_to_canonical_file_list_init
3241 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
3247 __gnat_to_canonical_file_list_next (void)
3249 static char *empty = "";
3254 __gnat_to_canonical_file_list_free (void)
3259 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3265 __gnat_to_canonical_file_spec (char *filespec)
3271 __gnat_to_canonical_path_spec (char *pathspec)
3277 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3283 __gnat_to_host_file_spec (char *filespec)
3289 __gnat_adjust_os_resource_limits (void)
3295 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
3296 to coordinate this with the EMX distribution. Consequently, we put the
3297 definition of dummy which is used for exception handling, here. */
3299 #if defined (__EMX__)
3303 #if defined (__mips_vxworks)
3307 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3311 #if defined (IS_CROSS) \
3312 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3313 && defined (__SVR4)) \
3314 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
3315 && ! (defined (linux) && defined (__ia64__)) \
3316 && ! (defined (linux) && defined (powerpc)) \
3317 && ! defined (__FreeBSD__) \
3318 && ! defined (__Lynx__) \
3319 && ! defined (__hpux__) \
3320 && ! defined (__APPLE__) \
3321 && ! defined (_AIX) \
3322 && ! (defined (__alpha__) && defined (__osf__)) \
3323 && ! defined (VMS) \
3324 && ! defined (__MINGW32__) \
3325 && ! (defined (__mips) && defined (__sgi)))
3327 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3328 just above for a list of native platforms that provide a non-dummy
3329 version of this procedure in libaddr2line.a. */
3332 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3333 void *addrs ATTRIBUTE_UNUSED,
3334 int n_addr ATTRIBUTE_UNUSED,
3335 void *buf ATTRIBUTE_UNUSED,
3336 int *len ATTRIBUTE_UNUSED)
3342 #if defined (_WIN32)
3343 int __gnat_argument_needs_quote = 1;
3345 int __gnat_argument_needs_quote = 0;
3348 /* This option is used to enable/disable object files handling from the
3349 binder file by the GNAT Project module. For example, this is disabled on
3350 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3351 Stating with GCC 3.4 the shared libraries are not based on mdll
3352 anymore as it uses the GCC's -shared option */
3353 #if defined (_WIN32) \
3354 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3355 int __gnat_prj_add_obj_files = 0;
3357 int __gnat_prj_add_obj_files = 1;
3360 /* char used as prefix/suffix for environment variables */
3361 #if defined (_WIN32)
3362 char __gnat_environment_char = '%';
3364 char __gnat_environment_char = '$';
3367 /* This functions copy the file attributes from a source file to a
3370 mode = 0 : In this mode copy only the file time stamps (last access and
3371 last modification time stamps).
3373 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3376 Returns 0 if operation was successful and -1 in case of error. */
3379 __gnat_copy_attribs (char *from, char *to, int mode)
3381 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
3384 #elif defined (_WIN32) && !defined (RTX)
3385 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3386 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3388 FILETIME fct, flat, flwt;
3391 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3392 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3394 /* retrieve from times */
3397 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3399 if (hfrom == INVALID_HANDLE_VALUE)
3402 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3404 CloseHandle (hfrom);
3409 /* retrieve from times */
3412 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3414 if (hto == INVALID_HANDLE_VALUE)
3417 res = SetFileTime (hto, NULL, &flat, &flwt);
3424 /* Set file attributes in full mode. */
3428 DWORD attribs = GetFileAttributes (wfrom);
3430 if (attribs == INVALID_FILE_ATTRIBUTES)
3433 res = SetFileAttributes (wto, attribs);
3441 GNAT_STRUCT_STAT fbuf;
3442 struct utimbuf tbuf;
3444 if (GNAT_STAT (from, &fbuf) == -1)
3449 tbuf.actime = fbuf.st_atime;
3450 tbuf.modtime = fbuf.st_mtime;
3452 if (utime (to, &tbuf) == -1)
3459 if (chmod (to, fbuf.st_mode) == -1)
3470 __gnat_lseek (int fd, long offset, int whence)
3472 return (int) lseek (fd, offset, whence);
3475 /* This function returns the major version number of GCC being used. */
3477 get_gcc_version (void)
3482 return (int) (version_string[0] - '0');
3487 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3488 int close_on_exec_p ATTRIBUTE_UNUSED)
3490 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3491 int flags = fcntl (fd, F_GETFD, 0);
3494 if (close_on_exec_p)
3495 flags |= FD_CLOEXEC;
3497 flags &= ~FD_CLOEXEC;
3498 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
3499 #elif defined(_WIN32)
3500 HANDLE h = (HANDLE) _get_osfhandle (fd);
3501 if (h == (HANDLE) -1)
3503 if (close_on_exec_p)
3504 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3505 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3506 HANDLE_FLAG_INHERIT);
3508 /* TODO: Unimplemented. */
3513 /* Indicates if platforms supports automatic initialization through the
3514 constructor mechanism */
3516 __gnat_binder_supports_auto_init (void)
3525 /* Indicates that Stand-Alone Libraries are automatically initialized through
3526 the constructor mechanism */
3528 __gnat_sals_init_using_constructors (void)
3530 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3539 /* In RTX mode, the procedure to get the time (as file time) is different
3540 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3541 we introduce an intermediate procedure to link against the corresponding
3542 one in each situation. */
3544 extern void GetTimeAsFileTime(LPFILETIME pTime);
3546 void GetTimeAsFileTime(LPFILETIME pTime)
3549 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3551 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3556 /* Add symbol that is required to link. It would otherwise be taken from
3557 libgcc.a and it would try to use the gcc constructors that are not
3558 supported by Microsoft linker. */
3560 extern void __main (void);
3562 void __main (void) {}
3566 #if defined (linux) || defined(__GLIBC__)
3567 /* pthread affinity support */
3569 int __gnat_pthread_setaffinity_np (pthread_t th,
3571 const void *cpuset);
3574 #include <pthread.h>
3576 __gnat_pthread_setaffinity_np (pthread_t th,
3578 const cpu_set_t *cpuset)
3580 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3584 __gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3585 size_t cpusetsize ATTRIBUTE_UNUSED,
3586 const void *cpuset ATTRIBUTE_UNUSED)
3594 /* There is no function in the glibc to retrieve the LWP of the current
3595 thread. We need to do a system call in order to retrieve this
3597 #include <sys/syscall.h>
3598 void *__gnat_lwp_self (void)
3600 return (void *) syscall (__NR_gettid);