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