]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ada/adaint.c
2014-11-20 Vadim Godunko <godunko@adacore.com>
[thirdparty/gcc.git] / gcc / ada / adaint.c
CommitLineData
1fac938e 1/****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
1fac938e 7 * C Implementation File *
8 * *
7cc02797 9 * Copyright (C) 1992-2014, Free Software Foundation, Inc. *
1fac938e 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- *
6bc9506f 13 * ware Foundation; either version 3, or (at your option) any later ver- *
1fac938e 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 *
6bc9506f 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/>. *
1fac938e 26 * *
27 * GNAT was originally developed by the GNAT team at New York University. *
e78e8c8e 28 * Extensive contributions were provided by Ada Core Technologies Inc. *
1fac938e 29 * *
30 ****************************************************************************/
31
f15731c4 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. */
1fac938e 36
360f426f 37/* Ensure access to errno is thread safe. */
543c8be5 38#define _REENTRANT
39#define _THREAD_SAFE
40
1fac938e 41#ifdef __vxworks
f15731c4 42
43/* No need to redefine exit here. */
1fac938e 44#undef exit
f15731c4 45
1fac938e 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
0f4d3df5 54/* If SMP, access vxCpuConfiguredGet */
55#ifdef _WRS_CONFIG_SMP
56#include <vxCpuLib.h>
57#endif /* _WRS_CONFIG_SMP */
58
b07bcda8 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
1fac938e 63#endif /* VxWorks */
64
5641963c 65#if defined (__APPLE__)
90bc406c 66#include <unistd.h>
67#endif
68
69#if defined (__hpux__)
70#include <sys/param.h>
71#include <sys/pstat.h>
72#endif
73
8cb1db0d 74#ifdef __PikeOS__
75#define __BSD_VISIBLE 1
76#endif
77
1fac938e 78#ifdef IN_RTS
79#include "tconfig.h"
80#include "tsystem.h"
81#include <sys/stat.h>
82#include <fcntl.h>
83#include <time.h>
84
b261877a 85#if defined (__vxworks) || defined (__ANDROID__)
86/* S_IREAD and S_IWRITE are not defined in VxWorks or Android */
b07bcda8 87#ifndef S_IREAD
88#define S_IREAD (S_IRUSR | S_IRGRP | S_IROTH)
89#endif
90
91#ifndef S_IWRITE
92#define S_IWRITE (S_IWUSR)
93#endif
94#endif
95
f15731c4 96/* We don't have libiberty, so use malloc. */
1fac938e 97#define xmalloc(S) malloc (S)
f15731c4 98#define xrealloc(V,S) realloc (V,S)
1fac938e 99#else
100#include "config.h"
101#include "system.h"
e2c62f37 102#include "version.h"
1fac938e 103#endif
9dfe12ae 104
e78e02f9 105#ifdef __cplusplus
106extern "C" {
107#endif
108
fa0b5df1 109#if defined (__MINGW32__)
110
e2a33c18 111#if defined (RTX)
112#include <windows.h>
113#include <Rtapi.h>
fa0b5df1 114#else
9dfe12ae 115#include "mingw32.h"
f60cc57d 116
a360a0f7 117/* Current code page and CCS encoding to use, set in initialize.c. */
f60cc57d 118UINT CurrentCodePage;
a360a0f7 119UINT CurrentCCSEncoding;
fa0b5df1 120#endif
121
9dfe12ae 122#include <sys/utime.h>
a4f295eb 123
124/* For isalpha-like tests in the compiler, we're expected to resort to
125 safe-ctype.h/ISALPHA. This isn't available for the runtime library
126 build, so we fallback on ctype.h/isalpha there. */
127
128#ifdef IN_RTS
f0a28ccb 129#include <ctype.h>
a4f295eb 130#define ISALPHA isalpha
131#endif
2359306a 132
133#elif defined (__Lynx__)
134
135/* Lynx utime.h only defines the entities of interest to us if
136 defined (VMOS_DEV), so ... */
137#define VMOS_DEV
138#include <utime.h>
139#undef VMOS_DEV
140
3897a124 141#else
9dfe12ae 142#include <utime.h>
9dfe12ae 143#endif
144
5091bc2f 145/* wait.h processing */
9dfe12ae 146#ifdef __MINGW32__
8cb1db0d 147# if OLD_MINGW
148# include <sys/wait.h>
149# endif
8ffbc401 150#elif defined (__vxworks) && defined (__RTP__)
8cb1db0d 151# include <wait.h>
2359306a 152#elif defined (__Lynx__)
153/* ??? We really need wait.h and it includes resource.h on Lynx. GCC
154 has a resource.h header as well, included instead of the lynx
155 version in our setup, causing lots of errors. We don't really need
156 the lynx contents of this file, so just workaround the issue by
157 preventing the inclusion of the GCC header from doing anything. */
8cb1db0d 158# define GCC_RESOURCE_H
159# include <sys/wait.h>
160#elif defined (__nucleus__) || defined (__PikeOS__)
24d7b9d6 161/* No wait() or waitpid() calls available. */
9dfe12ae 162#else
24d7b9d6 163/* Default case. */
9dfe12ae 164#include <sys/wait.h>
165#endif
1fac938e 166
30592778 167#if defined (_WIN32)
d8dd2062 168
1fac938e 169#include <process.h>
1fac938e 170#include <dir.h>
171#include <windows.h>
7db1ef17 172#include <accctrl.h>
173#include <aclapi.h>
fef772a5 174#undef DIR_SEPARATOR
175#define DIR_SEPARATOR '\\'
3897a124 176
177#else
178#include <utime.h>
1fac938e 179#endif
180
181#include "adaint.h"
182
183/* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
184 defined in the current system. On DOS-like systems these flags control
185 whether the file is opened/created in text-translation mode (CR/LF in
186 external file mapped to LF in internal file), but in Unix-like systems,
187 no text translation is required, so these flags have no effect. */
188
1fac938e 189#ifndef O_BINARY
190#define O_BINARY 0
191#endif
192
193#ifndef O_TEXT
194#define O_TEXT 0
195#endif
196
197#ifndef HOST_EXECUTABLE_SUFFIX
198#define HOST_EXECUTABLE_SUFFIX ""
199#endif
200
201#ifndef HOST_OBJECT_SUFFIX
202#define HOST_OBJECT_SUFFIX ".o"
203#endif
204
205#ifndef PATH_SEPARATOR
206#define PATH_SEPARATOR ':'
207#endif
208
209#ifndef DIR_SEPARATOR
210#define DIR_SEPARATOR '/'
211#endif
212
24d7b9d6 213/* Check for cross-compilation. */
8c7d3bad 214#if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
215#define IS_CROSS 1
a3b0f4f2 216int __gnat_is_cross_compiler = 1;
217#else
8c7d3bad 218#undef IS_CROSS
a3b0f4f2 219int __gnat_is_cross_compiler = 0;
220#endif
221
1fac938e 222char __gnat_dir_separator = DIR_SEPARATOR;
223
224char __gnat_path_separator = PATH_SEPARATOR;
225
226/* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
227 the base filenames that libraries specified with -lsomelib options
228 may have. This is used by GNATMAKE to check whether an executable
229 is up-to-date or not. The syntax is
230
231 library_template ::= { pattern ; } pattern NUL
232 pattern ::= [ prefix ] * [ postfix ]
233
234 These should only specify names of static libraries as it makes
235 no sense to determine at link time if dynamic-link libraries are
236 up to date or not. Any libraries that are not found are supposed
237 to be up-to-date:
238
239 * if they are needed but not present, the link
240 will fail,
241
242 * otherwise they are libraries in the system paths and so
243 they are considered part of the system and not checked
244 for that reason.
245
246 ??? This should be part of a GNAT host-specific compiler
247 file instead of being included in all user applications
f15731c4 248 as well. This is only a temporary work-around for 3.11b. */
1fac938e 249
250#ifndef GNAT_LIBRARY_TEMPLATE
1fac938e 251#define GNAT_LIBRARY_TEMPLATE "lib*.a"
252#endif
1fac938e 253
254const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
255
3897a124 256#if defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
9dfe12ae 257#define GNAT_MAX_PATH_LEN PATH_MAX
258
259#else
260
261#if defined (__MINGW32__)
262#include "mingw32.h"
263
264#if OLD_MINGW
265#include <sys/param.h>
266#endif
e633acdc 267
268#else
269#include <sys/param.h>
9dfe12ae 270#endif
271
8ae72cac 272#ifdef MAXPATHLEN
9dfe12ae 273#define GNAT_MAX_PATH_LEN MAXPATHLEN
8ae72cac 274#else
275#define GNAT_MAX_PATH_LEN 256
276#endif
e633acdc 277
278#endif
279
28a4283c 280/* Used for runtime check that Ada constant File_Attributes_Size is no
281 less than the actual size of struct file_attributes (see Osint
282 initialization). */
becb63f5 283int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
5f93bcbf 284
5f93bcbf 285void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
286
9dfe12ae 287/* The __gnat_max_path_len variable is used to export the maximum
288 length of a path name to Ada code. max_path_len is also provided
289 for compatibility with older GNAT versions, please do not use
290 it. */
291
292int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
293int max_path_len = GNAT_MAX_PATH_LEN;
294
2726b813 295/* Control whether we can use ACL on Windows. */
296
297int __gnat_use_acl = 1;
298
1fac938e 299/* The following macro HAVE_READDIR_R should be defined if the
f15731c4 300 system provides the routine readdir_r. */
1fac938e 301#undef HAVE_READDIR_R
302\f
6d9c3443 303#define MAYBE_TO_PTR32(argv) argv
6d9c3443 304
44fef051 305static const char ATTR_UNSET = 127;
bce992c9 306
77416989 307/* Reset the file attributes as if no system call had been performed */
308
5f93bcbf 309void
24d7b9d6 310__gnat_reset_attributes (struct file_attributes* attr)
5f93bcbf 311{
bce992c9 312 attr->exists = ATTR_UNSET;
28a4283c 313 attr->error = EINVAL;
5f93bcbf 314
bce992c9 315 attr->writable = ATTR_UNSET;
316 attr->readable = ATTR_UNSET;
317 attr->executable = ATTR_UNSET;
5f93bcbf 318
bce992c9 319 attr->regular = ATTR_UNSET;
320 attr->symbolic_link = ATTR_UNSET;
321 attr->directory = ATTR_UNSET;
5f93bcbf 322
323 attr->timestamp = (OS_Time)-2;
324 attr->file_length = -1;
325}
326
28a4283c 327int
328__gnat_error_attributes (struct file_attributes *attr) {
329 return attr->error;
330}
331
1e622f0e 332OS_Time
24d7b9d6 333__gnat_current_time (void)
1e622f0e 334{
335 time_t res = time (NULL);
336 return (OS_Time) res;
337}
338
a17c817e 339/* Return the current local time as a string in the ISO 8601 format of
340 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
341 long. */
342
343void
24d7b9d6 344__gnat_current_time_string (char *result)
a17c817e 345{
346 const char *format = "%Y-%m-%d %H:%M:%S";
347 /* Format string necessary to describe the ISO 8601 format */
348
349 const time_t t_val = time (NULL);
350
351 strftime (result, 22, format, localtime (&t_val));
352 /* Convert the local time into a string following the ISO format, copying
353 at most 22 characters into the result string. */
354
355 result [19] = '.';
356 result [20] = '0';
357 result [21] = '0';
358 /* The sub-seconds are manually set to zero since type time_t lacks the
359 precision necessary for nanoseconds. */
360}
361
1fac938e 362void
24d7b9d6 363__gnat_to_gm_time (OS_Time *p_time, int *p_year, int *p_month, int *p_day,
364 int *p_hours, int *p_mins, int *p_secs)
1fac938e 365{
366 struct tm *res;
9dfe12ae 367 time_t time = (time_t) *p_time;
1fac938e 368
369#ifdef _WIN32
370 /* On Windows systems, the time is sometimes rounded up to the nearest
371 even second, so if the number of seconds is odd, increment it. */
372 if (time & 1)
373 time++;
374#endif
375
376 res = gmtime (&time);
1fac938e 377 if (res)
378 {
379 *p_year = res->tm_year;
380 *p_month = res->tm_mon;
381 *p_day = res->tm_mday;
382 *p_hours = res->tm_hour;
383 *p_mins = res->tm_min;
384 *p_secs = res->tm_sec;
f15731c4 385 }
1fac938e 386 else
387 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
388}
389
2a68b2f5 390void
391__gnat_to_os_time (OS_Time *p_time, int year, int month, int day,
392 int hours, int mins, int secs)
393{
394 struct tm v;
395
396 v.tm_year = year;
397 v.tm_mon = month;
398 v.tm_mday = day;
399 v.tm_hour = hours;
400 v.tm_min = mins;
401 v.tm_sec = secs;
51f09f19 402 v.tm_isdst = -1;
2a68b2f5 403
404 /* returns -1 of failing, this is s-os_lib Invalid_Time */
405
406 *p_time = (OS_Time) mktime (&v);
407}
408
1fac938e 409/* Place the contents of the symbolic link named PATH in the buffer BUF,
410 which has size BUFSIZ. If PATH is a symbolic link, then return the number
5091bc2f 411 of characters of its content in BUF. Otherwise, return -1.
412 For systems not supporting symbolic links, always return -1. */
1fac938e 413
9dfe12ae 414int
f0a28ccb 415__gnat_readlink (char *path ATTRIBUTE_UNUSED,
416 char *buf ATTRIBUTE_UNUSED,
417 size_t bufsiz ATTRIBUTE_UNUSED)
1fac938e 418{
3897a124 419#if defined (_WIN32) \
8cb1db0d 420 || defined(__vxworks) || defined (__nucleus__) || defined (__PikeOS__)
1fac938e 421 return -1;
422#else
423 return readlink (path, buf, bufsiz);
424#endif
425}
426
5091bc2f 427/* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
428 If NEWPATH exists it will NOT be overwritten.
429 For systems not supporting symbolic links, always return -1. */
1fac938e 430
431int
f0a28ccb 432__gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
433 char *newpath ATTRIBUTE_UNUSED)
1fac938e 434{
3897a124 435#if defined (_WIN32) \
8cb1db0d 436 || defined(__vxworks) || defined (__nucleus__) || defined (__PikeOS__)
1fac938e 437 return -1;
438#else
439 return symlink (oldpath, newpath);
440#endif
441}
442
f15731c4 443/* Try to lock a file, return 1 if success. */
1fac938e 444
30592778 445#if defined (__vxworks) || defined (__nucleus__) \
3897a124 446 || defined (_WIN32) || defined (__PikeOS__)
1fac938e 447
448/* Version that does not use link. */
449
450int
9dfe12ae 451__gnat_try_lock (char *dir, char *file)
1fac938e 452{
1fac938e 453 int fd;
3b18b370 454#ifdef __MINGW32__
455 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
456 TCHAR wfile[GNAT_MAX_PATH_LEN];
457 TCHAR wdir[GNAT_MAX_PATH_LEN];
458
f60cc57d 459 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
460 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
3b18b370 461
658ba466 462 /* ??? the code below crash on MingW64 for obscure reasons, a ticket
463 has been opened here:
464
465 https://sourceforge.net/p/mingw-w64/bugs/414/
466
467 As a workaround an equivalent set of code has been put in place below.
468
3b18b370 469 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
658ba466 470 */
471
472 _tcscpy (wfull_path, wdir);
473 _tcscat (wfull_path, L"\\");
474 _tcscat (wfull_path, wfile);
475
3b18b370 476 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
477#else
478 char full_path[256];
1fac938e 479
480 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
481 fd = open (full_path, O_CREAT | O_EXCL, 0600);
3b18b370 482#endif
483
f15731c4 484 if (fd < 0)
1fac938e 485 return 0;
f15731c4 486
1fac938e 487 close (fd);
488 return 1;
489}
490
1fac938e 491#else
f15731c4 492
1fac938e 493/* Version using link(), more secure over NFS. */
9dfe12ae 494/* See TN 6913-016 for discussion ??? */
1fac938e 495
496int
9dfe12ae 497__gnat_try_lock (char *dir, char *file)
1fac938e 498{
f15731c4 499 char full_path[256];
500 char temp_file[256];
8cb516d7 501 GNAT_STRUCT_STAT stat_result;
1fac938e 502 int fd;
503
504 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
4a3f445c 505 sprintf (temp_file, "%s%cTMP-%ld-%ld",
506 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
1fac938e 507
f15731c4 508 /* Create the temporary file and write the process number. */
1fac938e 509 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
510 if (fd < 0)
511 return 0;
512
513 close (fd);
514
f15731c4 515 /* Link it with the new file. */
1fac938e 516 link (temp_file, full_path);
517
518 /* Count the references on the old one. If we have a count of two, then
f15731c4 519 the link did succeed. Remove the temporary file before returning. */
1fac938e 520 __gnat_stat (temp_file, &stat_result);
521 unlink (temp_file);
522 return stat_result.st_nlink == 2;
523}
524#endif
525
526/* Return the maximum file name length. */
527
528int
6f2c2693 529__gnat_get_maximum_file_name_length (void)
1fac938e 530{
1fac938e 531 return -1;
1fac938e 532}
533
1fac938e 534/* Return nonzero if file names are case sensitive. */
535
cda81c7b 536static int file_names_case_sensitive_cache = -1;
537
1fac938e 538int
6f2c2693 539__gnat_get_file_names_case_sensitive (void)
1fac938e 540{
cda81c7b 541 if (file_names_case_sensitive_cache == -1)
542 {
543 const char *sensitive = getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
cd2495b4 544
cda81c7b 545 if (sensitive != NULL
546 && (sensitive[0] == '0' || sensitive[0] == '1')
547 && sensitive[1] == '\0')
548 file_names_case_sensitive_cache = sensitive[0] - '0';
549 else
64f44677 550 {
551 /* By default, we suppose filesystems aren't case sensitive on
552 Windows and Darwin (but they are on arm-darwin). */
553#if defined (WINNT) || (defined (__APPLE__) && !defined (__arm__))
554 file_names_case_sensitive_cache = 0;
1fac938e 555#else
64f44677 556 file_names_case_sensitive_cache = 1;
1fac938e 557#endif
64f44677 558 }
cda81c7b 559 }
560 return file_names_case_sensitive_cache;
1fac938e 561}
562
a027cdc7 563/* Return nonzero if environment variables are case sensitive. */
564
565int
566__gnat_get_env_vars_case_sensitive (void)
567{
3897a124 568#if defined (WINNT)
a027cdc7 569 return 0;
570#else
571 return 1;
572#endif
573}
574
1fac938e 575char
6f2c2693 576__gnat_get_default_identifier_character_set (void)
1fac938e 577{
1fac938e 578 return '1';
1fac938e 579}
580
f15731c4 581/* Return the current working directory. */
1fac938e 582
583void
9dfe12ae 584__gnat_get_current_dir (char *dir, int *length)
1fac938e 585{
3b18b370 586#if defined (__MINGW32__)
587 TCHAR wdir[GNAT_MAX_PATH_LEN];
588
589 _tgetcwd (wdir, *length);
590
f60cc57d 591 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
3b18b370 592
1fac938e 593#else
594 getcwd (dir, *length);
595#endif
596
597 *length = strlen (dir);
598
9dfe12ae 599 if (dir [*length - 1] != DIR_SEPARATOR)
600 {
601 dir [*length] = DIR_SEPARATOR;
602 ++(*length);
603 }
f15731c4 604 dir[*length] = '\0';
1fac938e 605}
606
f15731c4 607/* Return the suffix for object files. */
1fac938e 608
609void
9dfe12ae 610__gnat_get_object_suffix_ptr (int *len, const char **value)
1fac938e 611{
612 *value = HOST_OBJECT_SUFFIX;
613
614 if (*value == 0)
615 *len = 0;
616 else
617 *len = strlen (*value);
618
619 return;
620}
621
f15731c4 622/* Return the suffix for executable files. */
1fac938e 623
624void
9dfe12ae 625__gnat_get_executable_suffix_ptr (int *len, const char **value)
1fac938e 626{
627 *value = HOST_EXECUTABLE_SUFFIX;
628 if (!*value)
629 *len = 0;
630 else
631 *len = strlen (*value);
632
633 return;
634}
635
636/* Return the suffix for debuggable files. Usually this is the same as the
f15731c4 637 executable extension. */
1fac938e 638
639void
9dfe12ae 640__gnat_get_debuggable_suffix_ptr (int *len, const char **value)
1fac938e 641{
1fac938e 642 *value = HOST_EXECUTABLE_SUFFIX;
1fac938e 643
644 if (*value == 0)
645 *len = 0;
646 else
647 *len = strlen (*value);
648
649 return;
650}
651
1aa4b9ce 652/* Returns the OS filename and corresponding encoding. */
653
654void
12e8797f 655__gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
656 char *w_filename ATTRIBUTE_UNUSED,
1aa4b9ce 657 char *os_name, int *o_length,
c62e34a4 658 char *encoding ATTRIBUTE_UNUSED, int *e_length)
1aa4b9ce 659{
8c7d3bad 660#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
7bb7733e 661 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
1aa4b9ce 662 *o_length = strlen (os_name);
663 strcpy (encoding, "encoding=utf8");
664 *e_length = strlen (encoding);
665#else
666 strcpy (os_name, filename);
667 *o_length = strlen (filename);
668 *e_length = 0;
669#endif
670}
671
13320214 672/* Delete a file. */
673
674int
675__gnat_unlink (char *path)
676{
8c7d3bad 677#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
13320214 678 {
679 TCHAR wpath[GNAT_MAX_PATH_LEN];
680
f60cc57d 681 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
13320214 682 return _tunlink (wpath);
683 }
684#else
685 return unlink (path);
686#endif
687}
688
689/* Rename a file. */
690
691int
692__gnat_rename (char *from, char *to)
693{
8c7d3bad 694#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
13320214 695 {
696 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
697
f60cc57d 698 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
699 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
13320214 700 return _trename (wfrom, wto);
701 }
702#else
703 return rename (from, to);
704#endif
705}
706
a8d94a8f 707/* Changing directory. */
708
709int
710__gnat_chdir (char *path)
711{
8c7d3bad 712#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
a8d94a8f 713 {
714 TCHAR wpath[GNAT_MAX_PATH_LEN];
715
f60cc57d 716 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
a8d94a8f 717 return _tchdir (wpath);
718 }
719#else
720 return chdir (path);
721#endif
722}
723
437991c2 724/* Removing a directory. */
725
726int
727__gnat_rmdir (char *path)
728{
8c7d3bad 729#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
437991c2 730 {
731 TCHAR wpath[GNAT_MAX_PATH_LEN];
732
f60cc57d 733 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
437991c2 734 return _trmdir (wpath);
735 }
2db7aef0 736#elif defined (VTHREADS)
737 /* rmdir not available */
738 return -1;
437991c2 739#else
740 return rmdir (path);
741#endif
742}
743
5cf1cbbb 744#if defined (_WIN32) || defined (linux) || defined (sun) \
745 || defined (__FreeBSD__)
746#define HAS_TARGET_WCHAR_T
747#endif
748
749#ifdef HAS_TARGET_WCHAR_T
750#include <wchar.h>
751#endif
752
7601c9a8 753int
754__gnat_fputwc(int c, FILE *stream)
755{
5cf1cbbb 756#ifdef HAS_TARGET_WCHAR_T
7601c9a8 757 return fputwc ((wchar_t)c, stream);
758#else
759 return fputc (c, stream);
760#endif
761}
762
e2c62f37 763FILE *
9c8f71d4 764__gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
e2c62f37 765{
8c7d3bad 766#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
e2c62f37 767 TCHAR wpath[GNAT_MAX_PATH_LEN];
768 TCHAR wmode[10];
769
e2c62f37 770 S2WS (wmode, mode, 10);
1e622f0e 771
f60cc57d 772 if (encoding == Encoding_Unspecified)
773 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
774 else if (encoding == Encoding_UTF8)
1e622f0e 775 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
776 else
777 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
778
e2c62f37 779 return _tfopen (wpath, wmode);
3897a124 780
e2c62f37 781#else
8cb516d7 782 return GNAT_FOPEN (path, mode);
7465a8fe 783#endif
e2c62f37 784}
785
e2c62f37 786FILE *
d9c927cc 787__gnat_freopen (char *path,
788 char *mode,
789 FILE *stream,
9c8f71d4 790 int encoding ATTRIBUTE_UNUSED)
e2c62f37 791{
8c7d3bad 792#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
e2c62f37 793 TCHAR wpath[GNAT_MAX_PATH_LEN];
794 TCHAR wmode[10];
795
e2c62f37 796 S2WS (wmode, mode, 10);
1e622f0e 797
f60cc57d 798 if (encoding == Encoding_Unspecified)
799 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
800 else if (encoding == Encoding_UTF8)
1e622f0e 801 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
802 else
803 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
804
e2c62f37 805 return _tfreopen (wpath, wmode, stream);
806#else
807 return freopen (path, mode, stream);
808#endif
809}
810
1fac938e 811int
9dfe12ae 812__gnat_open_read (char *path, int fmode)
1fac938e 813{
814 int fd;
815 int o_fmode = O_BINARY;
816
817 if (fmode)
818 o_fmode = O_TEXT;
819
3897a124 820#if defined (__vxworks)
1fac938e 821 fd = open (path, O_RDONLY | o_fmode, 0444);
3b18b370 822#elif defined (__MINGW32__)
823 {
824 TCHAR wpath[GNAT_MAX_PATH_LEN];
825
f60cc57d 826 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 827 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
828 }
1fac938e 829#else
781a0dc4 830 fd = GNAT_OPEN (path, O_RDONLY | o_fmode);
1fac938e 831#endif
f15731c4 832
1fac938e 833 return fd < 0 ? -1 : fd;
834}
835
30592778 836#if defined (__MINGW32__)
1fac938e 837#define PERM (S_IREAD | S_IWRITE)
838#else
839#define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
840#endif
841
842int
9dfe12ae 843__gnat_open_rw (char *path, int fmode)
1fac938e 844{
845 int fd;
846 int o_fmode = O_BINARY;
847
848 if (fmode)
849 o_fmode = O_TEXT;
850
3897a124 851#if defined (__MINGW32__)
3b18b370 852 {
853 TCHAR wpath[GNAT_MAX_PATH_LEN];
854
f60cc57d 855 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 856 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
857 }
1fac938e 858#else
781a0dc4 859 fd = GNAT_OPEN (path, O_RDWR | o_fmode, PERM);
1fac938e 860#endif
861
862 return fd < 0 ? -1 : fd;
863}
864
865int
9dfe12ae 866__gnat_open_create (char *path, int fmode)
1fac938e 867{
868 int fd;
869 int o_fmode = O_BINARY;
870
871 if (fmode)
872 o_fmode = O_TEXT;
873
3897a124 874#if defined (__MINGW32__)
3b18b370 875 {
876 TCHAR wpath[GNAT_MAX_PATH_LEN];
877
f60cc57d 878 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 879 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
880 }
1fac938e 881#else
781a0dc4 882 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
1fac938e 883#endif
884
885 return fd < 0 ? -1 : fd;
28ed91d4 886}
887
888int
889__gnat_create_output_file (char *path)
890{
891 int fd;
3897a124 892#if defined (__MINGW32__)
3b18b370 893 {
894 TCHAR wpath[GNAT_MAX_PATH_LEN];
895
f60cc57d 896 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 897 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
898 }
28ed91d4 899#else
781a0dc4 900 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
28ed91d4 901#endif
902
903 return fd < 0 ? -1 : fd;
1fac938e 904}
905
df40eeb0 906int
907__gnat_create_output_file_new (char *path)
908{
909 int fd;
3897a124 910#if defined (__MINGW32__)
df40eeb0 911 {
912 TCHAR wpath[GNAT_MAX_PATH_LEN];
913
914 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
915 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
916 }
917#else
781a0dc4 918 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
df40eeb0 919#endif
920
921 return fd < 0 ? -1 : fd;
922}
923
1fac938e 924int
9dfe12ae 925__gnat_open_append (char *path, int fmode)
1fac938e 926{
927 int fd;
928 int o_fmode = O_BINARY;
929
930 if (fmode)
931 o_fmode = O_TEXT;
932
3897a124 933#if defined (__MINGW32__)
3b18b370 934 {
935 TCHAR wpath[GNAT_MAX_PATH_LEN];
936
f60cc57d 937 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 938 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
939 }
1fac938e 940#else
781a0dc4 941 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
1fac938e 942#endif
943
944 return fd < 0 ? -1 : fd;
945}
946
f15731c4 947/* Open a new file. Return error (-1) if the file already exists. */
1fac938e 948
949int
9dfe12ae 950__gnat_open_new (char *path, int fmode)
1fac938e 951{
952 int fd;
953 int o_fmode = O_BINARY;
954
955 if (fmode)
956 o_fmode = O_TEXT;
957
3897a124 958#if defined (__MINGW32__)
3b18b370 959 {
960 TCHAR wpath[GNAT_MAX_PATH_LEN];
961
f60cc57d 962 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 963 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
964 }
1fac938e 965#else
781a0dc4 966 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1fac938e 967#endif
968
969 return fd < 0 ? -1 : fd;
970}
971
3897a124 972/* Open a new temp file. Return error (-1) if the file already exists. */
1fac938e 973
974int
9dfe12ae 975__gnat_open_new_temp (char *path, int fmode)
1fac938e 976{
977 int fd;
978 int o_fmode = O_BINARY;
979
980 strcpy (path, "GNAT-XXXXXX");
981
e0324ff5 982#if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
9d093602 983 || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
1fac938e 984 return mkstemp (path);
159eb63c 985#elif defined (__Lynx__)
986 mktemp (path);
5091bc2f 987#elif defined (__nucleus__)
988 return -1;
1fac938e 989#else
990 if (mktemp (path) == NULL)
991 return -1;
992#endif
993
994 if (fmode)
995 o_fmode = O_TEXT;
996
781a0dc4 997 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1fac938e 998 return fd < 0 ? -1 : fd;
999}
1000
cdeff474 1001int
1002__gnat_open (char *path, int fmode)
1003{
1004 int fd;
1005
3897a124 1006#if defined (__MINGW32__)
cdeff474 1007 {
1008 TCHAR wpath[GNAT_MAX_PATH_LEN];
1009
1010 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1011 fd = _topen (wpath, fmode, PERM);
1012 }
1013#else
1014 fd = GNAT_OPEN (path, fmode, PERM);
1015#endif
1016
1017 return fd < 0 ? -1 : fd;
1018}
1019
5f93bcbf 1020/****************************************************************
1021 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1022 ** as possible from it, storing the result in a cache for later reuse
1023 ****************************************************************/
1fac938e 1024
5f93bcbf 1025void
1026__gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
1fac938e 1027{
8cb516d7 1028 GNAT_STRUCT_STAT statbuf;
28a4283c 1029 int ret, error;
1fac938e 1030
28a4283c 1031 if (fd != -1) {
1032 /* GNAT_FSTAT returns -1 and sets errno for failure */
5f93bcbf 1033 ret = GNAT_FSTAT (fd, &statbuf);
28a4283c 1034 error = ret ? errno : 0;
1035
1036 } else {
1037 /* __gnat_stat returns errno value directly */
1038 error = __gnat_stat (name, &statbuf);
1039 ret = error ? -1 : 0;
1040 }
1041
1042 /*
1043 * A missing file is reported as an attr structure with error == 0 and
1044 * exists == 0.
1045 */
1046
1047 if (error == 0 || error == ENOENT)
1048 attr->error = 0;
5f93bcbf 1049 else
28a4283c 1050 attr->error = error;
5f93bcbf 1051
1052 attr->regular = (!ret && S_ISREG (statbuf.st_mode));
1053 attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
1fac938e 1054
5f93bcbf 1055 if (!attr->regular)
1056 attr->file_length = 0;
1057 else
1058 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1059 don't return a useful value for files larger than 2 gigabytes in
1060 either case. */
1061 attr->file_length = statbuf.st_size; /* all systems */
1062
5f93bcbf 1063 attr->exists = !ret;
5f93bcbf 1064
1065#if !defined (_WIN32) || defined (RTX)
1066 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1067 attr->readable = (!ret && (statbuf.st_mode & S_IRUSR));
1068 attr->writable = (!ret && (statbuf.st_mode & S_IWUSR));
1069 attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
1070#endif
1071
5f93bcbf 1072 if (ret != 0) {
1073 attr->timestamp = (OS_Time)-1;
1074 } else {
5f93bcbf 1075 attr->timestamp = (OS_Time)statbuf.st_mtime;
5f93bcbf 1076 }
1fac938e 1077}
1078
5f93bcbf 1079/****************************************************************
1080 ** Return the number of bytes in the specified file
1081 ****************************************************************/
d24d7e81 1082
8e28536f 1083__int64
5f93bcbf 1084__gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
d24d7e81 1085{
5f93bcbf 1086 if (attr->file_length == -1) {
1087 __gnat_stat_to_attr (fd, name, attr);
1088 }
d24d7e81 1089
5f93bcbf 1090 return attr->file_length;
1091}
d24d7e81 1092
8e28536f 1093__int64
5f93bcbf 1094__gnat_file_length (int fd)
1095{
1096 struct file_attributes attr;
d2697a05 1097 __gnat_reset_attributes (&attr);
5f93bcbf 1098 return __gnat_file_length_attr (fd, NULL, &attr);
1099}
c85cfca7 1100
26a98730 1101long
1102__gnat_file_length_long (int fd)
1103{
1104 struct file_attributes attr;
1105 __gnat_reset_attributes (&attr);
1106 return (long)__gnat_file_length_attr (fd, NULL, &attr);
1107}
1108
8e28536f 1109__int64
5f93bcbf 1110__gnat_named_file_length (char *name)
1111{
1112 struct file_attributes attr;
d2697a05 1113 __gnat_reset_attributes (&attr);
5f93bcbf 1114 return __gnat_file_length_attr (-1, name, &attr);
d24d7e81 1115}
1116
1fac938e 1117/* Create a temporary filename and put it in string pointed to by
f15731c4 1118 TMP_FILENAME. */
1fac938e 1119
1120void
9dfe12ae 1121__gnat_tmp_name (char *tmp_filename)
1fac938e 1122{
72772d89 1123#ifdef RTX
f5099270 1124 /* Variable used to create a series of unique names */
1125 static int counter = 0;
1126
1127 /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
1128 strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
1129 sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
72772d89 1130
1131#elif defined (__MINGW32__)
1fac938e 1132 {
1133 char *pname;
8db090bd 1134 char prefix[25];
1fac938e 1135
1136 /* tempnam tries to create a temporary file in directory pointed to by
1137 TMP environment variable, in c:\temp if TMP is not set, and in
1138 directory specified by P_tmpdir in stdio.h if c:\temp does not
1139 exist. The filename will be created with the prefix "gnat-". */
1140
8db090bd 1141 sprintf (prefix, "gnat-%d-", (int)getpid());
1142 pname = (char *) _tempnam ("c:\\temp", prefix);
1fac938e 1143
9dfe12ae 1144 /* if pname is NULL, the file was not created properly, the disk is full
1145 or there is no more free temporary files */
1146
1147 if (pname == NULL)
1148 *tmp_filename = '\0';
1149
f15731c4 1150 /* If pname start with a back slash and not path information it means that
1151 the filename is valid for the current working directory. */
1fac938e 1152
9dfe12ae 1153 else if (pname[0] == '\\')
1fac938e 1154 {
1155 strcpy (tmp_filename, ".\\");
1156 strcat (tmp_filename, pname+1);
1157 }
1158 else
1159 strcpy (tmp_filename, pname);
1160
1161 free (pname);
1162 }
f15731c4 1163
e0324ff5 1164#elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
5bfeb3fa 1165 || defined (__OpenBSD__) || defined(__GLIBC__) || defined (__ANDROID__)
9dfe12ae 1166#define MAX_SAFE_PATH 1000
1fac938e 1167 char *tmpdir = getenv ("TMPDIR");
1168
9dfe12ae 1169 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1170 a buffer overflow. */
1171 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
5bfeb3fa 1172#ifdef __ANDROID__
1173 strcpy (tmp_filename, "/cache/gnat-XXXXXX");
1174#else
1fac938e 1175 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
5bfeb3fa 1176#endif
1fac938e 1177 else
9dfe12ae 1178 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1fac938e 1179
1180 close (mkstemp(tmp_filename));
f5688ed4 1181#elif defined (__vxworks) && !(defined (__RTP__) || defined (VTHREADS))
1182 int index;
1183 char * pos;
1184 ushort_t t;
1185 static ushort_t seed = 0; /* used to generate unique name */
1186
1187 /* generate unique name */
1188 strcpy (tmp_filename, "tmp");
1189
1190 /* fill up the name buffer from the last position */
1191 index = 5;
1192 pos = tmp_filename + strlen (tmp_filename) + index;
1193 *pos = '\0';
1194
1195 seed++;
1196 for (t = seed; 0 <= --index; t >>= 3)
1197 *--pos = '0' + (t & 07);
1fac938e 1198#else
1199 tmpnam (tmp_filename);
1200#endif
1201}
1202
3b18b370 1203/* Open directory and returns a DIR pointer. */
1204
1205DIR* __gnat_opendir (char *name)
1206{
e2a33c18 1207#if defined (RTX)
1208 /* Not supported in RTX */
1209
1210 return NULL;
1211
1212#elif defined (__MINGW32__)
3b18b370 1213 TCHAR wname[GNAT_MAX_PATH_LEN];
1214
f60cc57d 1215 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
3b18b370 1216 return (DIR*)_topendir (wname);
1217
1218#else
1219 return opendir (name);
1220#endif
1221}
1222
1fac938e 1223/* Read the next entry in a directory. The returned string points somewhere
1224 in the buffer. */
1225
1226char *
3b18b370 1227__gnat_readdir (DIR *dirp, char *buffer, int *len)
1fac938e 1228{
e2a33c18 1229#if defined (RTX)
1230 /* Not supported in RTX */
1231
1232 return NULL;
8e726ab4 1233
e2a33c18 1234#elif defined (__MINGW32__)
3b18b370 1235 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1236
1237 if (dirent != NULL)
1238 {
f60cc57d 1239 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
3b18b370 1240 *len = strlen (buffer);
1241
1242 return buffer;
1243 }
1244 else
1245 return NULL;
1246
1247#elif defined (HAVE_READDIR_R)
1fac938e 1248 /* If possible, try to use the thread-safe version. */
1fac938e 1249 if (readdir_r (dirp, buffer) != NULL)
1aa4b9ce 1250 {
1251 *len = strlen (((struct dirent*) buffer)->d_name);
1252 return ((struct dirent*) buffer)->d_name;
1253 }
1fac938e 1254 else
1255 return NULL;
1256
1257#else
5b941af6 1258 struct dirent *dirent = (struct dirent *) readdir (dirp);
1fac938e 1259
1260 if (dirent != NULL)
1261 {
1262 strcpy (buffer, dirent->d_name);
3b18b370 1263 *len = strlen (buffer);
1fac938e 1264 return buffer;
1265 }
1266 else
1267 return NULL;
1268
1269#endif
1270}
1271
3b18b370 1272/* Close a directory entry. */
1273
1274int __gnat_closedir (DIR *dirp)
1275{
e2a33c18 1276#if defined (RTX)
1277 /* Not supported in RTX */
1278
1279 return 0;
1280
1281#elif defined (__MINGW32__)
3b18b370 1282 return _tclosedir ((_TDIR*)dirp);
1283
1284#else
1285 return closedir (dirp);
1286#endif
1287}
1288
1fac938e 1289/* Returns 1 if readdir is thread safe, 0 otherwise. */
1290
1291int
6f2c2693 1292__gnat_readdir_is_thread_safe (void)
1fac938e 1293{
1294#ifdef HAVE_READDIR_R
1295 return 1;
1296#else
1297 return 0;
1298#endif
1299}
1300
e2a33c18 1301#if defined (_WIN32) && !defined (RTX)
982e2721 1302/* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1303static const unsigned long long w32_epoch_offset = 11644473600ULL;
1fac938e 1304
1305/* Returns the file modification timestamp using Win32 routines which are
1306 immune against daylight saving time change. It is in fact not possible to
1307 use fstat for this purpose as the DST modify the st_mtime field of the
1308 stat structure. */
1309
1310static time_t
9dfe12ae 1311win32_filetime (HANDLE h)
1fac938e 1312{
982e2721 1313 union
1314 {
1315 FILETIME ft_time;
1316 unsigned long long ull_time;
1317 } t_write;
1fac938e 1318
1319 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1320 since <Jan 1st 1601>. This function must return the number of seconds
1321 since <Jan 1st 1970>. */
1322
982e2721 1323 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
3b18b370 1324 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
982e2721 1325 return (time_t) 0;
1fac938e 1326}
d7c2851f 1327
1328/* As above but starting from a FILETIME. */
7edd5071 1329static void
c8a2d809 1330f2t (const FILETIME *ft, __time64_t *t)
d7c2851f 1331{
1332 union
1333 {
1334 FILETIME ft_time;
1335 unsigned long long ull_time;
1336 } t_write;
1337
1338 t_write.ft_time = *ft;
c8a2d809 1339 *t = (__time64_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
d7c2851f 1340}
1fac938e 1341#endif
1342
1343/* Return a GNAT time stamp given a file name. */
1344
1bbc9831 1345OS_Time
5f93bcbf 1346__gnat_file_time_name_attr (char* name, struct file_attributes* attr)
1fac938e 1347{
5f93bcbf 1348 if (attr->timestamp == (OS_Time)-2) {
30592778 1349#if defined (_WIN32) && !defined (RTX)
7edd5071 1350 BOOL res;
1351 WIN32_FILE_ATTRIBUTE_DATA fad;
c8a2d809 1352 __time64_t ret = -1;
5f93bcbf 1353 TCHAR wname[GNAT_MAX_PATH_LEN];
1354 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
3b18b370 1355
928c11f3 1356 if ((res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad)))
7edd5071 1357 f2t (&fad.ftLastWriteTime, &ret);
5f93bcbf 1358 attr->timestamp = (OS_Time) ret;
1fac938e 1359#else
5f93bcbf 1360 __gnat_stat_to_attr (-1, name, attr);
1fac938e 1361#endif
1bbc9831 1362 }
5f93bcbf 1363 return attr->timestamp;
1364}
1365
1366OS_Time
1367__gnat_file_time_name (char *name)
1368{
1369 struct file_attributes attr;
d2697a05 1370 __gnat_reset_attributes (&attr);
5f93bcbf 1371 return __gnat_file_time_name_attr (name, &attr);
1fac938e 1372}
1373
1374/* Return a GNAT time stamp given a file descriptor. */
1375
1bbc9831 1376OS_Time
5f93bcbf 1377__gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
1fac938e 1378{
5f93bcbf 1379 if (attr->timestamp == (OS_Time)-2) {
30592778 1380#if defined (_WIN32) && !defined (RTX)
5f93bcbf 1381 HANDLE h = (HANDLE) _get_osfhandle (fd);
1382 time_t ret = win32_filetime (h);
1383 attr->timestamp = (OS_Time) ret;
1fac938e 1384
1385#else
5f93bcbf 1386 __gnat_stat_to_attr (fd, NULL, attr);
1fac938e 1387#endif
5f93bcbf 1388 }
1389
1390 return attr->timestamp;
1391}
1392
1393OS_Time
1394__gnat_file_time_fd (int fd)
1395{
1396 struct file_attributes attr;
d2697a05 1397 __gnat_reset_attributes (&attr);
5f93bcbf 1398 return __gnat_file_time_fd_attr (fd, &attr);
1fac938e 1399}
1400
f15731c4 1401/* Set the file time stamp. */
d8dd2062 1402
1403void
9dfe12ae 1404__gnat_set_file_time_name (char *name, time_t time_stamp)
d8dd2062 1405{
30592778 1406#if defined (__vxworks)
71a3e619 1407
f15731c4 1408/* Code to implement __gnat_set_file_time_name for these systems. */
71a3e619 1409
e2a33c18 1410#elif defined (_WIN32) && !defined (RTX)
982e2721 1411 union
1412 {
1413 FILETIME ft_time;
1414 unsigned long long ull_time;
1415 } t_write;
3b18b370 1416 TCHAR wname[GNAT_MAX_PATH_LEN];
fabb7dc5 1417
f60cc57d 1418 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
3b18b370 1419
1420 HANDLE h = CreateFile
1421 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1422 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1423 NULL);
982e2721 1424 if (h == INVALID_HANDLE_VALUE)
1425 return;
1426 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1427 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1428 /* Convert to 100 nanosecond units */
1429 t_write.ull_time *= 10000000ULL;
1430
1431 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1432 CloseHandle (h);
1433 return;
1434
d8dd2062 1435#else
1436 struct utimbuf utimbuf;
1437 time_t t;
1438
f15731c4 1439 /* Set modification time to requested time. */
d8dd2062 1440 utimbuf.modtime = time_stamp;
1441
f15731c4 1442 /* Set access time to now in local time. */
d8dd2062 1443 t = time ((time_t) 0);
1444 utimbuf.actime = mktime (localtime (&t));
1445
1446 utime (name, &utimbuf);
1447#endif
1448}
1449
1fac938e 1450/* Get the list of installed standard libraries from the
1451 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1452 key. */
1453
1454char *
6f2c2693 1455__gnat_get_libraries_from_registry (void)
1fac938e 1456{
69d33a1d 1457 char *result = (char *) xmalloc (1);
1458
1459 result[0] = '\0';
1fac938e 1460
8c7d3bad 1461#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS) \
1462 && ! defined (RTX)
1fac938e 1463
1464 HKEY reg_key;
1465 DWORD name_size, value_size;
1466 char name[256];
1467 char value[256];
1468 DWORD type;
1469 DWORD index;
1470 LONG res;
1471
1472 /* First open the key. */
1473 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1474
1475 if (res == ERROR_SUCCESS)
1476 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1477 KEY_READ, &reg_key);
1478
1479 if (res == ERROR_SUCCESS)
1480 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1481
1482 if (res == ERROR_SUCCESS)
1483 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1484
1485 /* If the key exists, read out all the values in it and concatenate them
1486 into a path. */
1487 for (index = 0; res == ERROR_SUCCESS; index++)
1488 {
1489 value_size = name_size = 256;
2726b813 1490 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
e2c62f37 1491 &type, (LPBYTE)value, &value_size);
1fac938e 1492
1493 if (res == ERROR_SUCCESS && type == REG_SZ)
1494 {
1495 char *old_result = result;
1496
1497 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1498 strcpy (result, old_result);
1499 strcat (result, value);
1500 strcat (result, ";");
69d33a1d 1501 free (old_result);
1fac938e 1502 }
1503 }
1504
1505 /* Remove the trailing ";". */
1506 if (result[0] != 0)
1507 result[strlen (result) - 1] = 0;
2b4d7555 1508
69d33a1d 1509#endif
1fac938e 1510 return result;
1511}
1512
28a4283c 1513/* Query information for the given file NAME and return it in STATBUF.
1514 * Returns 0 for success, or errno value for failure.
1515 */
1fac938e 1516int
8cb516d7 1517__gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1fac938e 1518{
3b18b370 1519#ifdef __MINGW32__
d7c2851f 1520 WIN32_FILE_ATTRIBUTE_DATA fad;
3b18b370 1521 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
d7c2851f 1522 int name_len;
1523 BOOL res;
7d20685d 1524 DWORD error;
3b18b370 1525
f60cc57d 1526 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
3b18b370 1527 name_len = _tcslen (wname);
e7b2d6bc 1528
1529 if (name_len > GNAT_MAX_PATH_LEN)
28a4283c 1530 return EINVAL;
1fac938e 1531
d7c2851f 1532 ZeroMemory (statbuf, sizeof(GNAT_STRUCT_STAT));
1533
1534 res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad);
1535
7d20685d 1536 if (res == FALSE) {
1537 error = GetLastError();
1538
1539 /* Check file existence using GetFileAttributes() which does not fail on
1540 special Windows files like con:, aux:, nul: etc... */
1541
1542 if (GetFileAttributes(wname) != INVALID_FILE_ATTRIBUTES) {
1543 /* Just pretend that it is a regular and readable file */
1544 statbuf->st_mode = S_IFREG | S_IREAD | S_IWRITE;
1545 return 0;
1546 }
1547
1548 switch (error) {
7edd5071 1549 case ERROR_ACCESS_DENIED:
1550 case ERROR_SHARING_VIOLATION:
1551 case ERROR_LOCK_VIOLATION:
1552 case ERROR_SHARING_BUFFER_EXCEEDED:
1553 return EACCES;
1554 case ERROR_BUFFER_OVERFLOW:
1555 return ENAMETOOLONG;
1556 case ERROR_NOT_ENOUGH_MEMORY:
1557 return ENOMEM;
1558 default:
1559 return ENOENT;
1fac938e 1560 }
7d20685d 1561 }
1fac938e 1562
d7c2851f 1563 f2t (&fad.ftCreationTime, &statbuf->st_ctime);
1564 f2t (&fad.ftLastWriteTime, &statbuf->st_mtime);
1565 f2t (&fad.ftLastAccessTime, &statbuf->st_atime);
8234fccd 1566
b6f6bb02 1567 statbuf->st_size =
1568 (__int64)fad.nFileSizeLow | (__int64)fad.nFileSizeHigh << 32;
8234fccd 1569
d7c2851f 1570 /* We do not have the S_IEXEC attribute, but this is not used on GNAT. */
1571 statbuf->st_mode = S_IREAD;
1fac938e 1572
d7c2851f 1573 if (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1574 statbuf->st_mode |= S_IFDIR;
1575 else
1576 statbuf->st_mode |= S_IFREG;
1577
1578 if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1579 statbuf->st_mode |= S_IWRITE;
1580
1581 return 0;
1fac938e 1582
1583#else
28a4283c 1584 return GNAT_STAT (name, statbuf) == 0 ? 0 : errno;
1fac938e 1585#endif
1586}
1587
5f93bcbf 1588/*************************************************************************
1589 ** Check whether a file exists
1590 *************************************************************************/
1591
1fac938e 1592int
5f93bcbf 1593__gnat_file_exists_attr (char* name, struct file_attributes* attr)
1fac938e 1594{
24d7b9d6 1595 if (attr->exists == ATTR_UNSET)
1596 __gnat_stat_to_attr (-1, name, attr);
5f93bcbf 1597
1598 return attr->exists;
1fac938e 1599}
1600
5f93bcbf 1601int
1602__gnat_file_exists (char *name)
1603{
1604 struct file_attributes attr;
d2697a05 1605 __gnat_reset_attributes (&attr);
5f93bcbf 1606 return __gnat_file_exists_attr (name, &attr);
1607}
1608
1609/**********************************************************************
1610 ** Whether name is an absolute path
1611 **********************************************************************/
1612
9dfe12ae 1613int
4a3f445c 1614__gnat_is_absolute_path (char *name, int length)
1fac938e 1615{
8620a406 1616#ifdef __vxworks
1617 /* On VxWorks systems, an absolute path can be represented (depending on
1618 the host platform) as either /dir/file, or device:/dir/file, or
1619 device:drive_letter:/dir/file. */
1620
1621 int index;
1622
1623 if (name[0] == '/')
1624 return 1;
1625
1626 for (index = 0; index < length; index++)
1627 {
1628 if (name[index] == ':' &&
1629 ((name[index + 1] == '/') ||
1630 (isalpha (name[index + 1]) && index + 2 <= length &&
1631 name[index + 2] == '/')))
1632 return 1;
1633
1634 else if (name[index] == '/')
1635 return 0;
1636 }
1637 return 0;
1638#else
4a3f445c 1639 return (length != 0) &&
1640 (*name == '/' || *name == DIR_SEPARATOR
30592778 1641#if defined (WINNT)
a4f295eb 1642 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1fac938e 1643#endif
69d33a1d 1644 );
8620a406 1645#endif
1fac938e 1646}
1647
5f93bcbf 1648int
1649__gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
1650{
24d7b9d6 1651 if (attr->regular == ATTR_UNSET)
1652 __gnat_stat_to_attr (-1, name, attr);
5f93bcbf 1653
1654 return attr->regular;
1655}
1656
1fac938e 1657int
9dfe12ae 1658__gnat_is_regular_file (char *name)
1fac938e 1659{
5f93bcbf 1660 struct file_attributes attr;
24d7b9d6 1661
d2697a05 1662 __gnat_reset_attributes (&attr);
5f93bcbf 1663 return __gnat_is_regular_file_attr (name, &attr);
1664}
1665
12c194d1 1666int
1667__gnat_is_regular_file_fd (int fd)
1668{
1669 int ret;
1670 GNAT_STRUCT_STAT statbuf;
1671
1672 ret = GNAT_FSTAT (fd, &statbuf);
1673 return (!ret && S_ISREG (statbuf.st_mode));
1674}
1675
5f93bcbf 1676int
1677__gnat_is_directory_attr (char* name, struct file_attributes* attr)
1678{
24d7b9d6 1679 if (attr->directory == ATTR_UNSET)
1680 __gnat_stat_to_attr (-1, name, attr);
1fac938e 1681
5f93bcbf 1682 return attr->directory;
1fac938e 1683}
1684
1685int
9dfe12ae 1686__gnat_is_directory (char *name)
1fac938e 1687{
5f93bcbf 1688 struct file_attributes attr;
24d7b9d6 1689
d2697a05 1690 __gnat_reset_attributes (&attr);
5f93bcbf 1691 return __gnat_is_directory_attr (name, &attr);
1fac938e 1692}
1693
7db1ef17 1694#if defined (_WIN32) && !defined (RTX)
57ecb969 1695
1696/* Returns the same constant as GetDriveType but takes a pathname as
1697 argument. */
1698
1699static UINT
1700GetDriveTypeFromPath (TCHAR *wfullpath)
1701{
1702 TCHAR wdrv[MAX_PATH];
1703 TCHAR wpath[MAX_PATH];
1704 TCHAR wfilename[MAX_PATH];
1705 TCHAR wext[MAX_PATH];
1706
1707 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1708
1709 if (_tcslen (wdrv) != 0)
1710 {
1711 /* we have a drive specified. */
1712 _tcscat (wdrv, _T("\\"));
1713 return GetDriveType (wdrv);
1714 }
1715 else
1716 {
1717 /* No drive specified. */
1718
1719 /* Is this a relative path, if so get current drive type. */
1720 if (wpath[0] != _T('\\') ||
24d7b9d6 1721 (_tcslen (wpath) > 2 && wpath[0] == _T('\\')
1722 && wpath[1] != _T('\\')))
69d33a1d 1723 return GetDriveType (NULL);
57ecb969 1724
1725 UINT result = GetDriveType (wpath);
1726
1727 /* Cannot guess the drive type, is this \\.\ ? */
1728
1729 if (result == DRIVE_NO_ROOT_DIR &&
69d33a1d 1730 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1731 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1732 {
1733 if (_tcslen (wpath) == 4)
1734 _tcscat (wpath, wfilename);
57ecb969 1735
69d33a1d 1736 LPTSTR p = &wpath[4];
1737 LPTSTR b = _tcschr (p, _T('\\'));
57ecb969 1738
69d33a1d 1739 if (b != NULL)
24d7b9d6 1740 {
1741 /* logical drive \\.\c\dir\file */
69d33a1d 1742 *b++ = _T(':');
1743 *b++ = _T('\\');
1744 *b = _T('\0');
1745 }
1746 else
1747 _tcscat (p, _T(":\\"));
57ecb969 1748
69d33a1d 1749 return GetDriveType (p);
1750 }
57ecb969 1751
1752 return result;
1753 }
1754}
1755
24d7b9d6 1756/* This MingW section contains code to work with ACL. */
7db1ef17 1757static int
24d7b9d6 1758__gnat_check_OWNER_ACL (TCHAR *wname,
1759 DWORD CheckAccessDesired,
1760 GENERIC_MAPPING CheckGenericMapping)
7db1ef17 1761{
7db1ef17 1762 DWORD dwAccessDesired, dwAccessAllowed;
1763 PRIVILEGE_SET PrivilegeSet;
1764 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1765 BOOL fAccessGranted = FALSE;
f060ec3a 1766 HANDLE hToken = NULL;
1767 DWORD nLength = 0;
c8a2d809 1768 PSECURITY_DESCRIPTOR pSD = NULL;
7db1ef17 1769
7db1ef17 1770 GetFileSecurity
1771 (wname, OWNER_SECURITY_INFORMATION |
1772 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1773 NULL, 0, &nLength);
1774
2b2212d1 1775 if ((pSD = (SECURITY_DESCRIPTOR *) HeapAlloc
7db1ef17 1776 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1777 return 0;
1778
24d7b9d6 1779 /* Obtain the security descriptor. */
7db1ef17 1780
1781 if (!GetFileSecurity
1782 (wname, OWNER_SECURITY_INFORMATION |
1783 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1784 pSD, nLength, &nLength))
f060ec3a 1785 goto error;
7db1ef17 1786
1787 if (!ImpersonateSelf (SecurityImpersonation))
f060ec3a 1788 goto error;
7db1ef17 1789
1790 if (!OpenThreadToken
1791 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
f060ec3a 1792 goto error;
7db1ef17 1793
1794 /* Undoes the effect of ImpersonateSelf. */
1795
1796 RevertToSelf ();
1797
1798 /* We want to test for write permissions. */
1799
1800 dwAccessDesired = CheckAccessDesired;
1801
1802 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1803
1804 if (!AccessCheck
1805 (pSD , /* security descriptor to check */
1806 hToken, /* impersonation token */
1807 dwAccessDesired, /* requested access rights */
1808 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1809 &PrivilegeSet, /* receives privileges used in check */
1810 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1811 &dwAccessAllowed, /* receives mask of allowed access rights */
1812 &fAccessGranted))
f060ec3a 1813 goto error;
7db1ef17 1814
f060ec3a 1815 CloseHandle (hToken);
1816 HeapFree (GetProcessHeap (), 0, pSD);
7db1ef17 1817 return fAccessGranted;
f060ec3a 1818
1819 error:
1820 if (hToken)
1821 CloseHandle (hToken);
1822 HeapFree (GetProcessHeap (), 0, pSD);
1823 return 0;
7db1ef17 1824}
1825
1826static void
24d7b9d6 1827__gnat_set_OWNER_ACL (TCHAR *wname,
c8a2d809 1828 ACCESS_MODE AccessMode,
24d7b9d6 1829 DWORD AccessPermissions)
7db1ef17 1830{
4c4697b8 1831 PACL pOldDACL = NULL;
1832 PACL pNewDACL = NULL;
1833 PSECURITY_DESCRIPTOR pSD = NULL;
7db1ef17 1834 EXPLICIT_ACCESS ea;
1835 TCHAR username [100];
1836 DWORD unsize = 100;
1837
7db1ef17 1838 /* Get current user, he will act as the owner */
1839
1840 if (!GetUserName (username, &unsize))
1841 return;
1842
0b3929a6 1843 if (GetNamedSecurityInfo
1844 (wname,
7db1ef17 1845 SE_FILE_OBJECT,
1846 DACL_SECURITY_INFORMATION,
1847 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1848 return;
1849
0b3929a6 1850 BuildExplicitAccessWithName
2b2212d1 1851 (&ea, username, AccessPermissions, (ACCESS_MODE) AccessMode, NO_INHERITANCE);
7db1ef17 1852
1853 if (AccessMode == SET_ACCESS)
1854 {
1855 /* SET_ACCESS, we want to set an explicte set of permissions, do not
69d33a1d 1856 merge with current DACL. */
7db1ef17 1857 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
69d33a1d 1858 return;
7db1ef17 1859 }
1860 else
1861 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1862 return;
1863
0b3929a6 1864 if (SetNamedSecurityInfo
1865 (wname, SE_FILE_OBJECT,
7db1ef17 1866 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
1867 return;
1868
1869 LocalFree (pSD);
1870 LocalFree (pNewDACL);
7db1ef17 1871}
57ecb969 1872
1873/* Check if it is possible to use ACL for wname, the file must not be on a
1874 network drive. */
1875
1876static int
1877__gnat_can_use_acl (TCHAR *wname)
1878{
1879 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
1880}
1881
7db1ef17 1882#endif /* defined (_WIN32) && !defined (RTX) */
1883
1fac938e 1884int
5f93bcbf 1885__gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
9dfe12ae 1886{
24d7b9d6 1887 if (attr->readable == ATTR_UNSET)
1888 {
7db1ef17 1889#if defined (_WIN32) && !defined (RTX)
24d7b9d6 1890 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1891 GENERIC_MAPPING GenericMapping;
3855c659 1892
24d7b9d6 1893 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
7db1ef17 1894
24d7b9d6 1895 if (__gnat_can_use_acl (wname))
1896 {
1897 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1898 GenericMapping.GenericRead = GENERIC_READ;
1899 attr->readable =
1900 __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
1901 }
1902 else
1903 attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
7db1ef17 1904#else
24d7b9d6 1905 __gnat_stat_to_attr (-1, name, attr);
7db1ef17 1906#endif
24d7b9d6 1907 }
5f93bcbf 1908
1909 return attr->readable;
9dfe12ae 1910}
1911
1912int
5f93bcbf 1913__gnat_is_readable_file (char *name)
1914{
1915 struct file_attributes attr;
24d7b9d6 1916
d2697a05 1917 __gnat_reset_attributes (&attr);
5f93bcbf 1918 return __gnat_is_readable_file_attr (name, &attr);
1919}
1920
1921int
1922__gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
1fac938e 1923{
24d7b9d6 1924 if (attr->writable == ATTR_UNSET)
1925 {
7db1ef17 1926#if defined (_WIN32) && !defined (RTX)
24d7b9d6 1927 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1928 GENERIC_MAPPING GenericMapping;
3855c659 1929
24d7b9d6 1930 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
3855c659 1931
24d7b9d6 1932 if (__gnat_can_use_acl (wname))
1933 {
1934 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1935 GenericMapping.GenericWrite = GENERIC_WRITE;
2726b813 1936
24d7b9d6 1937 attr->writable = __gnat_check_OWNER_ACL
5f93bcbf 1938 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
1939 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
24d7b9d6 1940 }
1941 else
1942 attr->writable =
1943 !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
7db1ef17 1944
7db1ef17 1945#else
24d7b9d6 1946 __gnat_stat_to_attr (-1, name, attr);
7db1ef17 1947#endif
24d7b9d6 1948 }
5f93bcbf 1949
1950 return attr->writable;
7db1ef17 1951}
1952
1953int
5f93bcbf 1954__gnat_is_writable_file (char *name)
7db1ef17 1955{
5f93bcbf 1956 struct file_attributes attr;
24d7b9d6 1957
d2697a05 1958 __gnat_reset_attributes (&attr);
5f93bcbf 1959 return __gnat_is_writable_file_attr (name, &attr);
1960}
1961
1962int
1963__gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
1964{
24d7b9d6 1965 if (attr->executable == ATTR_UNSET)
1966 {
7db1ef17 1967#if defined (_WIN32) && !defined (RTX)
24d7b9d6 1968 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1969 GENERIC_MAPPING GenericMapping;
3855c659 1970
24d7b9d6 1971 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
3855c659 1972
24d7b9d6 1973 if (__gnat_can_use_acl (wname))
1974 {
1975 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1976 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2726b813 1977
24d7b9d6 1978 attr->executable =
1979 __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
1980 }
1981 else
1982 {
1983 TCHAR *l, *last = _tcsstr(wname, _T(".exe"));
278c67dc 1984
24d7b9d6 1985 /* look for last .exe */
1986 if (last)
1987 while ((l = _tcsstr(last+1, _T(".exe"))))
1988 last = l;
278c67dc 1989
24d7b9d6 1990 attr->executable =
1991 GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
1992 && (last - wname) == (int) (_tcslen (wname) - 4);
1993 }
7db1ef17 1994#else
24d7b9d6 1995 __gnat_stat_to_attr (-1, name, attr);
7db1ef17 1996#endif
24d7b9d6 1997 }
5f93bcbf 1998
a5109493 1999 return attr->regular && attr->executable;
5f93bcbf 2000}
2001
2002int
2003__gnat_is_executable_file (char *name)
2004{
2005 struct file_attributes attr;
24d7b9d6 2006
d2697a05 2007 __gnat_reset_attributes (&attr);
5f93bcbf 2008 return __gnat_is_executable_file_attr (name, &attr);
1fac938e 2009}
2010
9dfe12ae 2011void
2012__gnat_set_writable (char *name)
2013{
7db1ef17 2014#if defined (_WIN32) && !defined (RTX)
3855c659 2015 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2016
f60cc57d 2017 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
3855c659 2018
57ecb969 2019 if (__gnat_can_use_acl (wname))
2726b813 2020 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2021
3855c659 2022 SetFileAttributes
2023 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
b07bcda8 2024#elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) && \
2025 ! defined(__nucleus__)
8cb516d7 2026 GNAT_STRUCT_STAT statbuf;
9dfe12ae 2027
8cb516d7 2028 if (GNAT_STAT (name, &statbuf) == 0)
0e9e8338 2029 {
2030 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2031 chmod (name, statbuf.st_mode);
2032 }
9dfe12ae 2033#endif
2034}
2035
c1efebf9 2036/* must match definition in s-os_lib.ads */
2037#define S_OWNER 1
2038#define S_GROUP 2
2039#define S_OTHERS 4
2040
5329ca64 2041void
c8a2d809 2042__gnat_set_executable (char *name, int mode ATTRIBUTE_UNUSED)
5329ca64 2043{
7db1ef17 2044#if defined (_WIN32) && !defined (RTX)
3855c659 2045 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2046
57ecb969 2047 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2048
2049 if (__gnat_can_use_acl (wname))
2050 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
3855c659 2051
b07bcda8 2052#elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) && \
2053 ! defined(__nucleus__)
8cb516d7 2054 GNAT_STRUCT_STAT statbuf;
5329ca64 2055
8cb516d7 2056 if (GNAT_STAT (name, &statbuf) == 0)
0e9e8338 2057 {
c1efebf9 2058 if (mode & S_OWNER)
2059 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2060 if (mode & S_GROUP)
2061 statbuf.st_mode = statbuf.st_mode | S_IXGRP;
2062 if (mode & S_OTHERS)
2063 statbuf.st_mode = statbuf.st_mode | S_IXOTH;
0e9e8338 2064 chmod (name, statbuf.st_mode);
2065 }
5329ca64 2066#endif
2067}
2068
9dfe12ae 2069void
2ab009c7 2070__gnat_set_non_writable (char *name)
9dfe12ae 2071{
7db1ef17 2072#if defined (_WIN32) && !defined (RTX)
3855c659 2073 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2074
f60cc57d 2075 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
3855c659 2076
57ecb969 2077 if (__gnat_can_use_acl (wname))
2726b813 2078 __gnat_set_OWNER_ACL
2079 (wname, DENY_ACCESS,
2080 FILE_WRITE_DATA | FILE_APPEND_DATA |
2081 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2082
3855c659 2083 SetFileAttributes
2084 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
b07bcda8 2085#elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) && \
2086 ! defined(__nucleus__)
8cb516d7 2087 GNAT_STRUCT_STAT statbuf;
9dfe12ae 2088
8cb516d7 2089 if (GNAT_STAT (name, &statbuf) == 0)
0b3929a6 2090 {
2091 statbuf.st_mode = statbuf.st_mode & 07577;
2092 chmod (name, statbuf.st_mode);
2093 }
2094#endif
2095}
2096
2097void
2098__gnat_set_readable (char *name)
2099{
2100#if defined (_WIN32) && !defined (RTX)
2101 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2102
57ecb969 2103 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2104
2105 if (__gnat_can_use_acl (wname))
2106 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
0b3929a6 2107
b07bcda8 2108#elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) && \
2109 ! defined(__nucleus__)
8cb516d7 2110 GNAT_STRUCT_STAT statbuf;
0b3929a6 2111
8cb516d7 2112 if (GNAT_STAT (name, &statbuf) == 0)
0b3929a6 2113 {
2114 chmod (name, statbuf.st_mode | S_IREAD);
2115 }
2116#endif
2117}
2118
2119void
2120__gnat_set_non_readable (char *name)
2121{
2122#if defined (_WIN32) && !defined (RTX)
2123 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2124
57ecb969 2125 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2126
2127 if (__gnat_can_use_acl (wname))
2128 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
0b3929a6 2129
b07bcda8 2130#elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) && \
2131 ! defined(__nucleus__)
8cb516d7 2132 GNAT_STRUCT_STAT statbuf;
0b3929a6 2133
8cb516d7 2134 if (GNAT_STAT (name, &statbuf) == 0)
0b3929a6 2135 {
2136 chmod (name, statbuf.st_mode & (~S_IREAD));
2137 }
9dfe12ae 2138#endif
2139}
2140
2141int
9b52e7a7 2142__gnat_is_symbolic_link_attr (char* name ATTRIBUTE_UNUSED,
2143 struct file_attributes* attr)
9dfe12ae 2144{
24d7b9d6 2145 if (attr->symbolic_link == ATTR_UNSET)
2146 {
5091bc2f 2147#if defined (__vxworks) || defined (__nucleus__)
24d7b9d6 2148 attr->symbolic_link = 0;
9dfe12ae 2149
8e761191 2150#elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
24d7b9d6 2151 int ret;
2152 GNAT_STRUCT_STAT statbuf;
2153 ret = GNAT_LSTAT (name, &statbuf);
2154 attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
9dfe12ae 2155#else
24d7b9d6 2156 attr->symbolic_link = 0;
9dfe12ae 2157#endif
24d7b9d6 2158 }
5f93bcbf 2159 return attr->symbolic_link;
2160}
2161
2162int
2163__gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2164{
2165 struct file_attributes attr;
24d7b9d6 2166
d2697a05 2167 __gnat_reset_attributes (&attr);
5f93bcbf 2168 return __gnat_is_symbolic_link_attr (name, &attr);
9dfe12ae 2169}
2170
1fac938e 2171#if defined (sun) && defined (__SVR4)
2172/* Using fork on Solaris will duplicate all the threads. fork1, which
2173 duplicates only the active thread, must be used instead, or spawning
2174 subprocess from a program with tasking will lead into numerous problems. */
2175#define fork fork1
2176#endif
2177
2178int
8cb1db0d 2179__gnat_portable_spawn (char *args[] ATTRIBUTE_UNUSED)
1fac938e 2180{
8cb1db0d 2181 int status ATTRIBUTE_UNUSED = 0;
f0a28ccb 2182 int finished ATTRIBUTE_UNUSED;
2183 int pid ATTRIBUTE_UNUSED;
1fac938e 2184
8cb1db0d 2185#if defined (__vxworks) || defined(__nucleus__) || defined(RTX) \
2186 || defined(__PikeOS__)
e2a33c18 2187 return -1;
2188
30592778 2189#elif defined (_WIN32)
f270dc82 2190 /* args[0] must be quotes as it could contain a full pathname with spaces */
38750fcd 2191 char *args_0 = args[0];
f270dc82 2192 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2193 strcpy (args[0], "\"");
2194 strcat (args[0], args_0);
2195 strcat (args[0], "\"");
2196
c8a2d809 2197 status = spawnvp (P_WAIT, args_0, (char ** const)args);
f270dc82 2198
2199 /* restore previous value */
2200 free (args[0]);
8e761191 2201 args[0] = (char *)args_0;
f270dc82 2202
1fac938e 2203 if (status < 0)
f15731c4 2204 return -1;
1fac938e 2205 else
2206 return status;
2207
1fac938e 2208#else
2209
1fac938e 2210 pid = fork ();
f15731c4 2211 if (pid < 0)
2212 return -1;
1fac938e 2213
f15731c4 2214 if (pid == 0)
2215 {
2216 /* The child. */
6d9c3443 2217 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
69d33a1d 2218 _exit (1);
f15731c4 2219 }
1fac938e 2220
f15731c4 2221 /* The parent. */
1fac938e 2222 finished = waitpid (pid, &status, 0);
2223
2224 if (finished != pid || WIFEXITED (status) == 0)
f15731c4 2225 return -1;
1fac938e 2226
2227 return WEXITSTATUS (status);
2228#endif
f15731c4 2229
1fac938e 2230 return 0;
2231}
2232
8e761191 2233/* Create a copy of the given file descriptor.
2234 Return -1 if an error occurred. */
2235
2236int
2237__gnat_dup (int oldfd)
2238{
8ffbc401 2239#if defined (__vxworks) && !defined (__RTP__)
2240 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2241 RTPs. */
2242 return -1;
8e761191 2243#else
8ffbc401 2244 return dup (oldfd);
8e761191 2245#endif
2246}
2247
2248/* Make newfd be the copy of oldfd, closing newfd first if necessary.
5e947a95 2249 Return -1 if an error occurred. */
8e761191 2250
2251int
8cb1db0d 2252__gnat_dup2 (int oldfd ATTRIBUTE_UNUSED, int newfd ATTRIBUTE_UNUSED)
8e761191 2253{
8ffbc401 2254#if defined (__vxworks) && !defined (__RTP__)
2255 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2256 RTPs. */
8e761191 2257 return -1;
8cb1db0d 2258#elif defined (__PikeOS__)
2259 /* Not supported. */
2260 return -1;
00234530 2261#elif defined (_WIN32)
2262 /* Special case when oldfd and newfd are identical and are the standard
2263 input, output or error as this makes Windows XP hangs. Note that we
2264 do that only for standard file descriptors that are known to be valid. */
2265 if (oldfd == newfd && newfd >= 0 && newfd <= 2)
2266 return newfd;
2267 else
2268 return dup2 (oldfd, newfd);
8e761191 2269#else
2270 return dup2 (oldfd, newfd);
2271#endif
2272}
2273
ed8e5b83 2274int
2275__gnat_number_of_cpus (void)
2276{
2277 int cores = 1;
2278
126b6848 2279#if defined (linux) || defined (sun) || defined (AIX) || defined (__APPLE__)
f7479d84 2280 cores = (int) sysconf (_SC_NPROCESSORS_ONLN);
90bc406c 2281
90bc406c 2282#elif defined (__hpux__)
f7479d84 2283 struct pst_dynamic psd;
2284 if (pstat_getdynamic (&psd, sizeof (psd), 1, 0) != -1)
2285 cores = (int) psd.psd_proc_cnt;
90bc406c 2286
ee0d6223 2287#elif defined (_WIN32)
2288 SYSTEM_INFO sysinfo;
2289 GetSystemInfo (&sysinfo);
2290 cores = (int) sysinfo.dwNumberOfProcessors;
9b1d6aeb 2291
e423341f 2292#elif defined (_WRS_CONFIG_SMP)
0f4d3df5 2293 unsigned int vxCpuConfiguredGet (void);
2294
2295 cores = vxCpuConfiguredGet ();
2296
ed8e5b83 2297#endif
2298
2299 return cores;
2300}
2301
f15731c4 2302/* WIN32 code to implement a wait call that wait for any child process. */
2303
e2a33c18 2304#if defined (_WIN32) && !defined (RTX)
1fac938e 2305
2306/* Synchronization code, to be thread safe. */
2307
51fa65dc 2308#ifdef CERT
1fac938e 2309
51fa65dc 2310/* For the Cert run times on native Windows we use dummy functions
2311 for locking and unlocking tasks since we do not support multiple
2312 threads on this configuration (Cert run time on native Windows). */
1fac938e 2313
4bdd5344 2314static void EnterCS (void) {}
2315static void LeaveCS (void) {}
2316static void SignalListChanged (void) {}
51fa65dc 2317
2318#else
2319
4bdd5344 2320CRITICAL_SECTION ProcListCS;
2321HANDLE ProcListEvt;
2322
2323static void EnterCS (void)
2324{
2325 EnterCriticalSection(&ProcListCS);
2326}
51fa65dc 2327
4bdd5344 2328static void LeaveCS (void)
2329{
2330 LeaveCriticalSection(&ProcListCS);
2331}
2332
2333static void SignalListChanged (void)
2334{
2335 SetEvent (ProcListEvt);
2336}
51fa65dc 2337
2338#endif
1fac938e 2339
4c4697b8 2340static HANDLE *HANDLES_LIST = NULL;
2341static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
1fac938e 2342
2343static void
14d22a3f 2344add_handle (HANDLE h, int pid)
1fac938e 2345{
1fac938e 2346 /* -------------------- critical section -------------------- */
4bdd5344 2347 EnterCS();
51fa65dc 2348
4c4697b8 2349 if (plist_length == plist_max_length)
2350 {
bb16a9f9 2351 plist_max_length += 100;
4c4697b8 2352 HANDLES_LIST =
c8a2d809 2353 (HANDLE *) xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
4c4697b8 2354 PID_LIST =
2b2212d1 2355 (int *) xrealloc (PID_LIST, sizeof (int) * plist_max_length);
4c4697b8 2356 }
2357
2358 HANDLES_LIST[plist_length] = h;
14d22a3f 2359 PID_LIST[plist_length] = pid;
1fac938e 2360 ++plist_length;
1fac938e 2361
4bdd5344 2362 SignalListChanged();
2363 LeaveCS();
51fa65dc 2364 /* -------------------- critical section -------------------- */
1fac938e 2365}
2366
4bdd5344 2367int
2368__gnat_win32_remove_handle (HANDLE h, int pid)
1fac938e 2369{
4c4697b8 2370 int j;
4bdd5344 2371 int found = 0;
2372
2373 /* -------------------- critical section -------------------- */
2374 EnterCS();
1fac938e 2375
4c4697b8 2376 for (j = 0; j < plist_length; j++)
1fac938e 2377 {
4c4697b8 2378 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
1fac938e 2379 {
4c4697b8 2380 CloseHandle (h);
2381 --plist_length;
2382 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2383 PID_LIST[j] = PID_LIST[plist_length];
4bdd5344 2384 found = 1;
1fac938e 2385 break;
2386 }
1fac938e 2387 }
92c3bf26 2388
4bdd5344 2389 LeaveCS();
92c3bf26 2390 /* -------------------- critical section -------------------- */
92c3bf26 2391
4bdd5344 2392 if (found)
2393 SignalListChanged();
1fac938e 2394
4bdd5344 2395 return found;
1fac938e 2396}
2397
14d22a3f 2398static void
2399win32_no_block_spawn (char *command, char *args[], HANDLE *h, int *pid)
1fac938e 2400{
2401 BOOL result;
2402 STARTUPINFO SI;
2403 PROCESS_INFORMATION PI;
2404 SECURITY_ATTRIBUTES SA;
f15731c4 2405 int csize = 1;
2406 char *full_command;
1fac938e 2407 int k;
2408
f15731c4 2409 /* compute the total command line length */
2410 k = 0;
2411 while (args[k])
2412 {
2413 csize += strlen (args[k]) + 1;
2414 k++;
2415 }
2416
2417 full_command = (char *) xmalloc (csize);
2418
1fac938e 2419 /* Startup info. */
2420 SI.cb = sizeof (STARTUPINFO);
2421 SI.lpReserved = NULL;
2422 SI.lpReserved2 = NULL;
2423 SI.lpDesktop = NULL;
2424 SI.cbReserved2 = 0;
2425 SI.lpTitle = NULL;
2426 SI.dwFlags = 0;
2427 SI.wShowWindow = SW_HIDE;
2428
2429 /* Security attributes. */
2430 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2431 SA.bInheritHandle = TRUE;
2432 SA.lpSecurityDescriptor = NULL;
2433
2434 /* Prepare the command string. */
2435 strcpy (full_command, command);
2436 strcat (full_command, " ");
2437
2438 k = 1;
2439 while (args[k])
2440 {
2441 strcat (full_command, args[k]);
2442 strcat (full_command, " ");
2443 k++;
2444 }
2445
3b18b370 2446 {
2447 int wsize = csize * 2;
2448 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2449
f60cc57d 2450 S2WSC (wcommand, full_command, wsize);
3b18b370 2451
2452 free (full_command);
1fac938e 2453
3b18b370 2454 result = CreateProcess
2455 (NULL, wcommand, &SA, NULL, TRUE,
2456 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2457
2458 free (wcommand);
2459 }
f15731c4 2460
1fac938e 2461 if (result == TRUE)
2462 {
1fac938e 2463 CloseHandle (PI.hThread);
14d22a3f 2464 *h = PI.hProcess;
2465 *pid = PI.dwProcessId;
1fac938e 2466 }
2467 else
14d22a3f 2468 {
2469 *h = NULL;
2470 *pid = 0;
2471 }
1fac938e 2472}
2473
2474static int
9dfe12ae 2475win32_wait (int *status)
1fac938e 2476{
4c4697b8 2477 DWORD exitcode, pid;
1fac938e 2478 HANDLE *hl;
2479 HANDLE h;
4bdd5344 2480 int *pidl;
1fac938e 2481 DWORD res;
e41b023d 2482 int hl_len;
4bdd5344 2483 int found;
1fac938e 2484
4bdd5344 2485 START_WAIT:
92c3bf26 2486
1fac938e 2487 if (plist_length == 0)
2488 {
2489 errno = ECHILD;
2490 return -1;
2491 }
2492
4bdd5344 2493 /* -------------------- critical section -------------------- */
2494 EnterCS();
2495
e41b023d 2496 hl_len = plist_length;
2497
4bdd5344 2498#ifdef CERT
e41b023d 2499 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
4c4697b8 2500 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
4bdd5344 2501 pidl = (int *) xmalloc (sizeof (int) * hl_len);
2502 memmove (pidl, PID_LIST, sizeof (int) * hl_len);
2503#else
2504 /* Note that index 0 contains the event hanlde that is signaled when the
2505 process list has changed */
2506 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len + 1);
2507 hl[0] = ProcListEvt;
2508 memmove (&hl[1], HANDLES_LIST, sizeof (HANDLE) * hl_len);
2509 pidl = (int *) xmalloc (sizeof (int) * hl_len + 1);
2510 memmove (&pidl[1], PID_LIST, sizeof (int) * hl_len);
2511 hl_len++;
2512#endif
2513
2514 LeaveCS();
2515 /* -------------------- critical section -------------------- */
1fac938e 2516
e41b023d 2517 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
1fac938e 2518
4bdd5344 2519 /* if the ProcListEvt has been signaled then the list of processes has been
2520 updated to add or remove a handle, just loop over */
2521
2522 if (res - WAIT_OBJECT_0 == 0)
2523 {
2524 free (hl);
2525 free (pidl);
2526 goto START_WAIT;
2527 }
2528
2529 h = hl[res - WAIT_OBJECT_0];
1fac938e 2530 GetExitCodeProcess (h, &exitcode);
4bdd5344 2531 pid = pidl [res - WAIT_OBJECT_0];
2532
2533 found = __gnat_win32_remove_handle (h, -1);
4c4697b8 2534
2535 free (hl);
4bdd5344 2536 free (pidl);
2537
2538 /* if not found another process waiting has already handled this process */
2539
2540 if (!found)
2541 {
2542 goto START_WAIT;
2543 }
1fac938e 2544
2545 *status = (int) exitcode;
4c4697b8 2546 return (int) pid;
1fac938e 2547}
2548
2549#endif
2550
2551int
8cb1db0d 2552__gnat_portable_no_block_spawn (char *args[] ATTRIBUTE_UNUSED)
1fac938e 2553{
1fac938e 2554
8cb1db0d 2555#if defined (__vxworks) || defined (__nucleus__) || defined (RTX) \
2556 || defined (__PikeOS__)
2557 /* Not supported. */
e2a33c18 2558 return -1;
2559
1fac938e 2560#elif defined (_WIN32)
2561
4c4697b8 2562 HANDLE h = NULL;
14d22a3f 2563 int pid;
4c4697b8 2564
14d22a3f 2565 win32_no_block_spawn (args[0], args, &h, &pid);
4c4697b8 2566 if (h != NULL)
5d56d161 2567 {
14d22a3f 2568 add_handle (h, pid);
2569 return pid;
5d56d161 2570 }
2571 else
2572 return -1;
1fac938e 2573
1fac938e 2574#else
4c4697b8 2575
2576 int pid = fork ();
1fac938e 2577
f15731c4 2578 if (pid == 0)
2579 {
2580 /* The child. */
6d9c3443 2581 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
69d33a1d 2582 _exit (1);
f15731c4 2583 }
2584
1fac938e 2585 return pid;
4c4697b8 2586
2587 #endif
1fac938e 2588}
2589
2590int
9dfe12ae 2591__gnat_portable_wait (int *process_status)
1fac938e 2592{
2593 int status = 0;
2594 int pid = 0;
2595
8cb1db0d 2596#if defined (__vxworks) || defined (__nucleus__) || defined (RTX) \
2597 || defined (__PikeOS__)
30592778 2598 /* Not sure what to do here, so do nothing but return zero. */
e2a33c18 2599
2600#elif defined (_WIN32)
1fac938e 2601
2602 pid = win32_wait (&status);
2603
1fac938e 2604#else
2605
1fac938e 2606 pid = waitpid (-1, &status, 0);
1fac938e 2607 status = status & 0xffff;
2608#endif
2609
2610 *process_status = status;
2611 return pid;
2612}
2613
2614void
9dfe12ae 2615__gnat_os_exit (int status)
1fac938e 2616{
1fac938e 2617 exit (status);
1fac938e 2618}
2619
b860aaec 2620/* Locate file on path, that matches a predicate */
1fac938e 2621
2622char *
24d7b9d6 2623__gnat_locate_file_with_predicate (char *file_name, char *path_val,
2624 int (*predicate)(char *))
1fac938e 2625{
2626 char *ptr;
5703e222 2627 char *file_path = (char *) alloca (strlen (file_name) + 1);
c69ba469 2628 int absolute;
2629
b51bcb1c 2630 /* Return immediately if file_name is empty */
2631
2632 if (*file_name == '\0')
2633 return 0;
2634
c69ba469 2635 /* Remove quotes around file_name if present */
2636
2637 ptr = file_name;
2638 if (*ptr == '"')
2639 ptr++;
2640
2641 strcpy (file_path, ptr);
2642
2643 ptr = file_path + strlen (file_path) - 1;
2644
2645 if (*ptr == '"')
2646 *ptr = '\0';
1fac938e 2647
f15731c4 2648 /* Handle absolute pathnames. */
c69ba469 2649
2650 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2651
9dfe12ae 2652 if (absolute)
2653 {
b860aaec 2654 if (predicate (file_path))
c69ba469 2655 return xstrdup (file_path);
9dfe12ae 2656
2657 return 0;
2658 }
2659
2660 /* If file_name include directory separator(s), try it first as
2661 a path name relative to the current directory */
1fac938e 2662 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2663 ;
2664
9dfe12ae 2665 if (*ptr != 0)
1fac938e 2666 {
b860aaec 2667 if (predicate (file_name))
1fac938e 2668 return xstrdup (file_name);
1fac938e 2669 }
2670
2671 if (path_val == 0)
2672 return 0;
2673
2674 {
2675 /* The result has to be smaller than path_val + file_name. */
d9c927cc 2676 char *file_path =
2677 (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
1fac938e 2678
2679 for (;;)
2680 {
c69ba469 2681 /* Skip the starting quote */
2682
2683 if (*path_val == '"')
69d33a1d 2684 path_val++;
c69ba469 2685
1fac938e 2686 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
69d33a1d 2687 *ptr++ = *path_val++;
1fac938e 2688
5c182b3b 2689 /* If directory is empty, it is the current directory*/
2690
2691 if (ptr == file_path)
2692 {
2693 *ptr = '.';
2694 }
2695 else
2696 ptr--;
c69ba469 2697
2698 /* Skip the ending quote */
2699
2700 if (*ptr == '"')
69d33a1d 2701 ptr--;
c69ba469 2702
1fac938e 2703 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2704 *++ptr = DIR_SEPARATOR;
2705
2706 strcpy (++ptr, file_name);
2707
b860aaec 2708 if (predicate (file_path))
1fac938e 2709 return xstrdup (file_path);
5c182b3b 2710
2711 if (*path_val == 0)
2712 return 0;
2713
2714 /* Skip path separator */
2715
2716 path_val++;
1fac938e 2717 }
2718 }
2719
2720 return 0;
2721}
2722
b860aaec 2723/* Locate an executable file, give a Path value. */
2724
2725char *
2726__gnat_locate_executable_file (char *file_name, char *path_val)
2727{
2728 return __gnat_locate_file_with_predicate
2729 (file_name, path_val, &__gnat_is_executable_file);
2730}
2731
2732/* Locate a regular file, give a Path value. */
2733
2734char *
2735__gnat_locate_regular_file (char *file_name, char *path_val)
2736{
2737 return __gnat_locate_file_with_predicate
2738 (file_name, path_val, &__gnat_is_regular_file);
2739}
2740
1fac938e 2741/* Locate an executable given a Path argument. This routine is only used by
2742 gnatbl and should not be used otherwise. Use locate_exec_on_path
f15731c4 2743 instead. */
1fac938e 2744
2745char *
9dfe12ae 2746__gnat_locate_exec (char *exec_name, char *path_val)
1fac938e 2747{
fb31b465 2748 char *ptr;
1fac938e 2749 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2750 {
d9c927cc 2751 char *full_exec_name =
2752 (char *) alloca
2753 (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
1fac938e 2754
2755 strcpy (full_exec_name, exec_name);
2756 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
b860aaec 2757 ptr = __gnat_locate_executable_file (full_exec_name, path_val);
fb31b465 2758
2759 if (ptr == 0)
b860aaec 2760 return __gnat_locate_executable_file (exec_name, path_val);
fb31b465 2761 return ptr;
1fac938e 2762 }
2763 else
b860aaec 2764 return __gnat_locate_executable_file (exec_name, path_val);
1fac938e 2765}
2766
f15731c4 2767/* Locate an executable using the Systems default PATH. */
1fac938e 2768
2769char *
9dfe12ae 2770__gnat_locate_exec_on_path (char *exec_name)
1fac938e 2771{
9dfe12ae 2772 char *apath_val;
3b18b370 2773
e2a33c18 2774#if defined (_WIN32) && !defined (RTX)
3b18b370 2775 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2776 TCHAR *wapath_val;
9dfe12ae 2777 /* In Win32 systems we expand the PATH as for XP environment
c69ba469 2778 variables are not automatically expanded. We also prepend the
2779 ".;" to the path to match normal NT path search semantics */
9dfe12ae 2780
c69ba469 2781 #define EXPAND_BUFFER_SIZE 32767
9dfe12ae 2782
2b2212d1 2783 wapath_val = (TCHAR *) alloca (EXPAND_BUFFER_SIZE);
c69ba469 2784
3b18b370 2785 wapath_val [0] = '.';
2786 wapath_val [1] = ';';
1fac938e 2787
c69ba469 2788 DWORD res = ExpandEnvironmentStrings
3b18b370 2789 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2790
2791 if (!res) wapath_val [0] = _T('\0');
2792
2b2212d1 2793 apath_val = (char *) alloca (EXPAND_BUFFER_SIZE);
3b18b370 2794
f60cc57d 2795 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
3b18b370 2796 return __gnat_locate_exec (exec_name, apath_val);
c69ba469 2797
3b18b370 2798#else
2799 char *path_val = getenv ("PATH");
3897a124 2800
e2c62f37 2801 if (path_val == NULL) return NULL;
5703e222 2802 apath_val = (char *) alloca (strlen (path_val) + 1);
1fac938e 2803 strcpy (apath_val, path_val);
2804 return __gnat_locate_exec (exec_name, apath_val);
3b18b370 2805#endif
1fac938e 2806}
2807
3897a124 2808/* Dummy functions for Osint import for non-VMS systems.
2809 ??? To be removed. */
1fac938e 2810
2811int
24d7b9d6 2812__gnat_to_canonical_file_list_init (char *dirspec ATTRIBUTE_UNUSED,
2813 int onlydirs ATTRIBUTE_UNUSED)
1fac938e 2814{
2815 return 0;
2816}
2817
2818char *
6f2c2693 2819__gnat_to_canonical_file_list_next (void)
1fac938e 2820{
6b88f2fe 2821 static char empty[] = "";
4c4697b8 2822 return empty;
1fac938e 2823}
2824
2825void
6f2c2693 2826__gnat_to_canonical_file_list_free (void)
1fac938e 2827{
2828}
2829
2830char *
9dfe12ae 2831__gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 2832{
2833 return dirspec;
2834}
2835
2836char *
9dfe12ae 2837__gnat_to_canonical_file_spec (char *filespec)
1fac938e 2838{
2839 return filespec;
2840}
2841
2842char *
9dfe12ae 2843__gnat_to_canonical_path_spec (char *pathspec)
1fac938e 2844{
2845 return pathspec;
2846}
2847
2848char *
9dfe12ae 2849__gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 2850{
2851 return dirspec;
2852}
2853
2854char *
9dfe12ae 2855__gnat_to_host_file_spec (char *filespec)
1fac938e 2856{
2857 return filespec;
2858}
2859
2860void
6f2c2693 2861__gnat_adjust_os_resource_limits (void)
1fac938e 2862{
2863}
2864
1fac938e 2865#if defined (__mips_vxworks)
9dfe12ae 2866int
24d7b9d6 2867_flush_cache (void)
1fac938e 2868{
2869 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2870}
2871#endif
2872
f15731c4 2873#if defined (_WIN32)
2874int __gnat_argument_needs_quote = 1;
2875#else
2876int __gnat_argument_needs_quote = 0;
2877#endif
9dfe12ae 2878
2879/* This option is used to enable/disable object files handling from the
2880 binder file by the GNAT Project module. For example, this is disabled on
e0f42093 2881 Windows (prior to GCC 3.4) as it is already done by the mdll module.
2882 Stating with GCC 3.4 the shared libraries are not based on mdll
2883 anymore as it uses the GCC's -shared option */
2884#if defined (_WIN32) \
2885 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
9dfe12ae 2886int __gnat_prj_add_obj_files = 0;
2887#else
2888int __gnat_prj_add_obj_files = 1;
2889#endif
2890
2891/* char used as prefix/suffix for environment variables */
2892#if defined (_WIN32)
2893char __gnat_environment_char = '%';
2894#else
2895char __gnat_environment_char = '$';
2896#endif
2897
2898/* This functions copy the file attributes from a source file to a
2899 destination file.
2900
2901 mode = 0 : In this mode copy only the file time stamps (last access and
2902 last modification time stamps).
2903
2904 mode = 1 : In this mode, time stamps and read/write/execute attributes are
2905 copied.
2906
2907 Returns 0 if operation was successful and -1 in case of error. */
2908
2909int
75f7f24d 2910__gnat_copy_attribs (char *from ATTRIBUTE_UNUSED, char *to ATTRIBUTE_UNUSED,
2911 int mode ATTRIBUTE_UNUSED)
9dfe12ae 2912{
3897a124 2913#if (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) || \
b07bcda8 2914 defined (__nucleus__)
9dfe12ae 2915 return -1;
6a85c251 2916
2917#elif defined (_WIN32) && !defined (RTX)
2918 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
2919 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
2920 BOOL res;
2921 FILETIME fct, flat, flwt;
2922 HANDLE hfrom, hto;
2923
2924 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
2925 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
2926
2927 /* retrieve from times */
2928
2929 hfrom = CreateFile
2930 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2931
2932 if (hfrom == INVALID_HANDLE_VALUE)
2933 return -1;
2934
2935 res = GetFileTime (hfrom, &fct, &flat, &flwt);
2936
2937 CloseHandle (hfrom);
2938
2939 if (res == 0)
2940 return -1;
2941
2942 /* retrieve from times */
2943
2944 hto = CreateFile
2945 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2946
2947 if (hto == INVALID_HANDLE_VALUE)
2948 return -1;
2949
2950 res = SetFileTime (hto, NULL, &flat, &flwt);
2951
2952 CloseHandle (hto);
2953
2954 if (res == 0)
2955 return -1;
2956
2957 /* Set file attributes in full mode. */
2958
2959 if (mode == 1)
2960 {
2961 DWORD attribs = GetFileAttributes (wfrom);
2962
2963 if (attribs == INVALID_FILE_ATTRIBUTES)
2964 return -1;
2965
2966 res = SetFileAttributes (wto, attribs);
2967 if (res == 0)
2968 return -1;
2969 }
2970
2971 return 0;
2972
9dfe12ae 2973#else
8cb516d7 2974 GNAT_STRUCT_STAT fbuf;
9dfe12ae 2975 struct utimbuf tbuf;
2976
8cb516d7 2977 if (GNAT_STAT (from, &fbuf) == -1)
9dfe12ae 2978 {
2979 return -1;
2980 }
2981
2982 tbuf.actime = fbuf.st_atime;
2983 tbuf.modtime = fbuf.st_mtime;
2984
2985 if (utime (to, &tbuf) == -1)
2986 {
2987 return -1;
2988 }
2989
2990 if (mode == 1)
2991 {
2992 if (chmod (to, fbuf.st_mode) == -1)
2993 {
2994 return -1;
2995 }
2996 }
2997
2998 return 0;
2999#endif
3000}
3001
cf6d853e 3002int
3003__gnat_lseek (int fd, long offset, int whence)
3004{
3005 return (int) lseek (fd, offset, whence);
3006}
0914a918 3007
e2c62f37 3008/* This function returns the major version number of GCC being used. */
0914a918 3009int
3010get_gcc_version (void)
3011{
e2c62f37 3012#ifdef IN_RTS
3013 return __GNUC__;
3014#else
3015 return (int) (version_string[0] - '0');
3016#endif
0914a918 3017}
6d9c3443 3018
b21edad9 3019/*
3020 * Set Close_On_Exec as indicated.
3021 * Note: this is used for both GNAT.OS_Lib and GNAT.Sockets.
3022 */
3023
6d9c3443 3024int
de10c095 3025__gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
0e9e8338 3026 int close_on_exec_p ATTRIBUTE_UNUSED)
6d9c3443 3027{
3028#if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3029 int flags = fcntl (fd, F_GETFD, 0);
3030 if (flags < 0)
3031 return flags;
3032 if (close_on_exec_p)
3033 flags |= FD_CLOEXEC;
3034 else
3035 flags &= ~FD_CLOEXEC;
6fdfe796 3036 return fcntl (fd, F_SETFD, flags);
07f34887 3037#elif defined(_WIN32)
3038 HANDLE h = (HANDLE) _get_osfhandle (fd);
3039 if (h == (HANDLE) -1)
3040 return -1;
3041 if (close_on_exec_p)
3042 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
bcf0a1b1 3043 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
07f34887 3044 HANDLE_FLAG_INHERIT);
6d9c3443 3045#else
07f34887 3046 /* TODO: Unimplemented. */
6d9c3443 3047 return -1;
6d9c3443 3048#endif
3049}
fb31b465 3050
3051/* Indicates if platforms supports automatic initialization through the
3052 constructor mechanism */
3053int
c88e6a4f 3054__gnat_binder_supports_auto_init (void)
fb31b465 3055{
3897a124 3056 return 1;
fb31b465 3057}
3058
3059/* Indicates that Stand-Alone Libraries are automatically initialized through
3060 the constructor mechanism */
3061int
c88e6a4f 3062__gnat_sals_init_using_constructors (void)
fb31b465 3063{
3897a124 3064#if defined (__vxworks) || defined (__Lynx__)
fb31b465 3065 return 0;
3066#else
3067 return 1;
3068#endif
3069}
e2a33c18 3070
8e726ab4 3071#ifdef RTX
3072
e2a33c18 3073/* In RTX mode, the procedure to get the time (as file time) is different
3074 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3075 we introduce an intermediate procedure to link against the corresponding
3076 one in each situation. */
8e726ab4 3077
24d7b9d6 3078extern void GetTimeAsFileTime (LPFILETIME pTime);
e2a33c18 3079
24d7b9d6 3080void GetTimeAsFileTime (LPFILETIME pTime)
e2a33c18 3081{
3082#ifdef RTSS
3083 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3084#else
3085 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3086#endif
3087}
8e726ab4 3088
3089#ifdef RTSS
3090/* Add symbol that is required to link. It would otherwise be taken from
3091 libgcc.a and it would try to use the gcc constructors that are not
3092 supported by Microsoft linker. */
3093
3094extern void __main (void);
3095
24d7b9d6 3096void __main (void)
3097{
3098}
89da8724 3099#endif /* RTSS */
3100#endif /* RTX */
e2a33c18 3101
b261877a 3102#if defined (__ANDROID__)
3103
3104#include <pthread.h>
3105
24d7b9d6 3106void *
3107__gnat_lwp_self (void)
b261877a 3108{
3109 return (void *) pthread_self ();
3110}
3111
3112#elif defined (linux)
a0d9619f 3113/* There is no function in the glibc to retrieve the LWP of the current
3114 thread. We need to do a system call in order to retrieve this
3115 information. */
3116#include <sys/syscall.h>
24d7b9d6 3117void *
3118__gnat_lwp_self (void)
12e8797f 3119{
a0d9619f 3120 return (void *) syscall (__NR_gettid);
3121}
40d4441d 3122
3123#include <sched.h>
3124
38846e90 3125/* glibc versions earlier than 2.7 do not define the routines to handle
3126 dynamically allocated CPU sets. For these targets, we use the static
3127 versions. */
3128
3129#ifdef CPU_ALLOC
3130
3131/* Dynamic cpu sets */
3132
24d7b9d6 3133cpu_set_t *
3134__gnat_cpu_alloc (size_t count)
40d4441d 3135{
91965b95 3136 return CPU_ALLOC (count);
40d4441d 3137}
3138
24d7b9d6 3139size_t
3140__gnat_cpu_alloc_size (size_t count)
91965b95 3141{
3142 return CPU_ALLOC_SIZE (count);
3143}
3144
24d7b9d6 3145void
3146__gnat_cpu_free (cpu_set_t *set)
91965b95 3147{
3148 CPU_FREE (set);
3149}
3150
24d7b9d6 3151void
3152__gnat_cpu_zero (size_t count, cpu_set_t *set)
91965b95 3153{
3154 CPU_ZERO_S (count, set);
3155}
3156
24d7b9d6 3157void
3158__gnat_cpu_set (int cpu, size_t count, cpu_set_t *set)
40d4441d 3159{
3160 /* Ada handles CPU numbers starting from 1, while C identifies the first
3161 CPU by a 0, so we need to adjust. */
91965b95 3162 CPU_SET_S (cpu - 1, count, set);
40d4441d 3163}
38846e90 3164
89da8724 3165#else /* !CPU_ALLOC */
38846e90 3166
3167/* Static cpu sets */
3168
24d7b9d6 3169cpu_set_t *
3170__gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED)
38846e90 3171{
3172 return (cpu_set_t *) xmalloc (sizeof (cpu_set_t));
3173}
3174
24d7b9d6 3175size_t
3176__gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED)
38846e90 3177{
3178 return sizeof (cpu_set_t);
3179}
3180
24d7b9d6 3181void
3182__gnat_cpu_free (cpu_set_t *set)
38846e90 3183{
3184 free (set);
3185}
3186
24d7b9d6 3187void
3188__gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
38846e90 3189{
3190 CPU_ZERO (set);
3191}
3192
24d7b9d6 3193void
3194__gnat_cpu_set (int cpu, size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
38846e90 3195{
3196 /* Ada handles CPU numbers starting from 1, while C identifies the first
3197 CPU by a 0, so we need to adjust. */
3198 CPU_SET (cpu - 1, set);
3199}
89da8724 3200#endif /* !CPU_ALLOC */
3201#endif /* linux */
3202
3203/* Return the load address of the executable, or 0 if not known. In the
3204 specific case of error, (void *)-1 can be returned. Beware: this unit may
3205 be in a shared library. As low-level units are needed, we allow #include
3206 here. */
3207
3208#if defined (__APPLE__)
3209#include <mach-o/dyld.h>
7d6851fb 3210#elif 0 && defined (__linux__)
89da8724 3211#include <link.h>
a0d9619f 3212#endif
89da8724 3213
3214const void *
3215__gnat_get_executable_load_address (void)
3216{
3217#if defined (__APPLE__)
3218 return _dyld_get_image_header (0);
3219
94e053cd 3220#elif 0 && defined (__linux__)
3221 /* Currently disabled as it needs at least -ldl. */
89da8724 3222 struct link_map *map = _r_debug.r_map;
3223
3224 return (const void *)map->l_addr;
3225
89da8724 3226#else
3227 return NULL;
63b63ca2 3228#endif
89da8724 3229}
becb63f5 3230
3231#ifdef __cplusplus
3232}
3233#endif