OSDN Git Service

* config/stormy16/stormy16-lib2.c (__ucmpsi2): Fix thinko.
[pf3gnuchains/gcc-fork.git] / gcc / ada / adaint.c
index c3405da..54b3223 100644 (file)
@@ -324,6 +324,12 @@ const int __gnat_vmsp = 0;
 
 #endif
 
+/* Used for Ada bindings */
+const int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
+
+/* Reset the file attributes as if no system call had been performed */
+void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
+
 /* The __gnat_max_path_len variable is used to export the maximum
    length of a path name to Ada code. max_path_len is also provided
    for compatibility with older GNAT versions, please do not use
@@ -371,6 +377,26 @@ to_ptr32 (char **ptr64)
 #define MAYBE_TO_PTR32(argv) argv
 #endif
 
+const char ATTR_UNSET = 127;
+
+void
+__gnat_reset_attributes
+  (struct file_attributes* attr)
+{
+  attr->exists     = ATTR_UNSET;
+
+  attr->writable   = ATTR_UNSET;
+  attr->readable   = ATTR_UNSET;
+  attr->executable = ATTR_UNSET;
+
+  attr->regular    = ATTR_UNSET;
+  attr->symbolic_link = ATTR_UNSET;
+  attr->directory = ATTR_UNSET;
+
+  attr->timestamp = (OS_Time)-2;
+  attr->file_length = -1;
+}
+
 OS_Time
 __gnat_current_time
   (void)
@@ -673,7 +699,7 @@ __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
                    char *encoding ATTRIBUTE_UNUSED, int *e_length)
 {
 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
-  WS2SC (os_name, (TCHAR *)w_filename, (DWORD)o_length);
+  WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
   *o_length = strlen (os_name);
   strcpy (encoding, "encoding=utf8");
   *e_length = strlen (encoding);
@@ -923,6 +949,28 @@ __gnat_create_output_file (char *path)
 }
 
 int
+__gnat_create_output_file_new (char *path)
+{
+  int fd;
+#if defined (VMS)
+  fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM,
+             "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
+             "shr=del,get,put,upd");
+#elif defined (__MINGW32__)
+  {
+    TCHAR wpath[GNAT_MAX_PATH_LEN];
+
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
+    fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
+  }
+#else
+  fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
+#endif
+
+  return fd < 0 ? -1 : fd;
+}
+
+int
 __gnat_open_append (char *path, int fmode)
 {
   int fd;
@@ -1014,42 +1062,89 @@ __gnat_open_new_temp (char *path, int fmode)
   return fd < 0 ? -1 : fd;
 }
 
-/* Return the number of bytes in the specified file.  */
+/****************************************************************
+ ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
+ ** as possible from it, storing the result in a cache for later reuse
+ ****************************************************************/
 
-long
-__gnat_file_length (int fd)
+void
+__gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
 {
-  int ret;
   GNAT_STRUCT_STAT statbuf;
+  int ret;
 
-  ret = GNAT_FSTAT (fd, &statbuf);
-  if (ret || !S_ISREG (statbuf.st_mode))
-    return 0;
+  if (fd != -1)
+    ret = GNAT_FSTAT (fd, &statbuf);
+  else
+    ret = __gnat_stat (name, &statbuf);
+
+  attr->regular   = (!ret && S_ISREG (statbuf.st_mode));
+  attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
 
-  /* st_size may be 32 bits, or 64 bits which is converted to long. We
-     don't return a useful value for files larger than 2 gigabytes in
-     either case. */
+  if (!attr->regular)
+    attr->file_length = 0;
+  else
+    /* st_size may be 32 bits, or 64 bits which is converted to long. We
+       don't return a useful value for files larger than 2 gigabytes in
+       either case. */
+    attr->file_length = statbuf.st_size;  /* all systems */
+
+#ifndef __MINGW32__
+  /* on Windows requires extra system call, see comment in __gnat_file_exists_attr */
+  attr->exists = !ret;
+#endif
+
+#if !defined (_WIN32) || defined (RTX)
+  /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
+  attr->readable   = (!ret && (statbuf.st_mode & S_IRUSR));
+  attr->writable   = (!ret && (statbuf.st_mode & S_IWUSR));
+  attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
+#endif
+
+#if !defined (__EMX__) && !defined (MSDOS) && (!defined (_WIN32) || defined (RTX))
+  /* on Windows requires extra system call, see __gnat_file_time_name_attr */
+  if (ret != 0) {
+     attr->timestamp = (OS_Time)-1;
+  } else {
+#ifdef VMS
+     /* VMS has file versioning.  */
+     attr->timestamp = (OS_Time)statbuf.st_ctime;
+#else
+     attr->timestamp = (OS_Time)statbuf.st_mtime;
+#endif
+  }
+#endif
 
-  return (statbuf.st_size);
 }
 
-/* Return the number of bytes in the specified named file.  */
+/****************************************************************
+ ** Return the number of bytes in the specified file
+ ****************************************************************/
 
 long
-__gnat_named_file_length (char *name)
+__gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
 {
-  int ret;
-  GNAT_STRUCT_STAT statbuf;
+  if (attr->file_length == -1) {
+    __gnat_stat_to_attr (fd, name, attr);
+  }
 
-  ret = __gnat_stat (name, &statbuf);
-  if (ret || !S_ISREG (statbuf.st_mode))
-    return 0;
+  return attr->file_length;
+}
 
-  /* st_size may be 32 bits, or 64 bits which is converted to long. We
-     don't return a useful value for files larger than 2 gigabytes in
-     either case. */
+long
+__gnat_file_length (int fd)
+{
+  struct file_attributes attr;
+  __gnat_reset_attributes (&attr);
+  return __gnat_file_length_attr (fd, NULL, &attr);
+}
 
-  return (statbuf.st_size);
+long
+__gnat_named_file_length (char *name)
+{
+  struct file_attributes attr;
+  __gnat_reset_attributes (&attr);
+  return __gnat_file_length_attr (-1, name, &attr);
 }
 
 /* Create a temporary filename and put it in string pointed to by
@@ -1244,137 +1339,136 @@ win32_filetime (HANDLE h)
 /* Return a GNAT time stamp given a file name.  */
 
 OS_Time
-__gnat_file_time_name (char *name)
+__gnat_file_time_name_attr (char* name, struct file_attributes* attr)
 {
-
+   if (attr->timestamp == (OS_Time)-2) {
 #if defined (__EMX__) || defined (MSDOS)
-  int fd = open (name, O_RDONLY | O_BINARY);
-  time_t ret = __gnat_file_time_fd (fd);
-  close (fd);
-  return (OS_Time)ret;
+      int fd = open (name, O_RDONLY | O_BINARY);
+      time_t ret = __gnat_file_time_fd (fd);
+      close (fd);
+      attr->timestamp = (OS_Time)ret;
 
 #elif defined (_WIN32) && !defined (RTX)
-  time_t ret = -1;
-  TCHAR wname[GNAT_MAX_PATH_LEN];
+      time_t ret = -1;
+      TCHAR wname[GNAT_MAX_PATH_LEN];
+      S2WSC (wname, name, GNAT_MAX_PATH_LEN);
 
-  S2WSC (wname, name, GNAT_MAX_PATH_LEN);
-
-  HANDLE h = CreateFile
-    (wname, GENERIC_READ, FILE_SHARE_READ, 0,
-     OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+      HANDLE h = CreateFile
+        (wname, GENERIC_READ, FILE_SHARE_READ, 0,
+         OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
 
-  if (h != INVALID_HANDLE_VALUE)
-    {
-      ret = win32_filetime (h);
-      CloseHandle (h);
-    }
-  return (OS_Time) ret;
-#else
-  GNAT_STRUCT_STAT statbuf;
-  if (__gnat_stat (name, &statbuf) != 0) {
-     return (OS_Time)-1;
-  } else {
-#ifdef VMS
-     /* VMS has file versioning.  */
-     return (OS_Time)statbuf.st_ctime;
+      if (h != INVALID_HANDLE_VALUE) {
+         ret = win32_filetime (h);
+         CloseHandle (h);
+      }
+      attr->timestamp = (OS_Time) ret;
 #else
-     return (OS_Time)statbuf.st_mtime;
+      __gnat_stat_to_attr (-1, name, attr);
 #endif
   }
-#endif
+  return attr->timestamp;
+}
+
+OS_Time
+__gnat_file_time_name (char *name)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_file_time_name_attr (name, &attr);
 }
 
 /* Return a GNAT time stamp given a file descriptor.  */
 
 OS_Time
-__gnat_file_time_fd (int fd)
+__gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
 {
-  /* The following workaround code is due to the fact that under EMX and
-     DJGPP fstat attempts to convert time values to GMT rather than keep the
-     actual OS timestamp of the file. By using the OS2/DOS functions directly
-     the GNAT timestamp are independent of this behavior, which is desired to
-     facilitate the distribution of GNAT compiled libraries.  */
+   if (attr->timestamp == (OS_Time)-2) {
+     /* The following workaround code is due to the fact that under EMX and
+        DJGPP fstat attempts to convert time values to GMT rather than keep the
+        actual OS timestamp of the file. By using the OS2/DOS functions directly
+        the GNAT timestamp are independent of this behavior, which is desired to
+        facilitate the distribution of GNAT compiled libraries.  */
 
 #if defined (__EMX__) || defined (MSDOS)
 #ifdef __EMX__
 
-  FILESTATUS fs;
-  int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
-                                sizeof (FILESTATUS));
+     FILESTATUS fs;
+     int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
+                                   sizeof (FILESTATUS));
 
-  unsigned file_year  = fs.fdateLastWrite.year;
-  unsigned file_month = fs.fdateLastWrite.month;
-  unsigned file_day   = fs.fdateLastWrite.day;
-  unsigned file_hour  = fs.ftimeLastWrite.hours;
-  unsigned file_min   = fs.ftimeLastWrite.minutes;
-  unsigned file_tsec  = fs.ftimeLastWrite.twosecs;
+     unsigned file_year  = fs.fdateLastWrite.year;
+     unsigned file_month = fs.fdateLastWrite.month;
+     unsigned file_day   = fs.fdateLastWrite.day;
+     unsigned file_hour  = fs.ftimeLastWrite.hours;
+     unsigned file_min   = fs.ftimeLastWrite.minutes;
+     unsigned file_tsec  = fs.ftimeLastWrite.twosecs;
 
 #else
-  struct ftime fs;
-  int ret = getftime (fd, &fs);
+     struct ftime fs;
+     int ret = getftime (fd, &fs);
 
-  unsigned file_year  = fs.ft_year;
-  unsigned file_month = fs.ft_month;
-  unsigned file_day   = fs.ft_day;
-  unsigned file_hour  = fs.ft_hour;
-  unsigned file_min   = fs.ft_min;
-  unsigned file_tsec  = fs.ft_tsec;
+     unsigned file_year  = fs.ft_year;
+     unsigned file_month = fs.ft_month;
+     unsigned file_day   = fs.ft_day;
+     unsigned file_hour  = fs.ft_hour;
+     unsigned file_min   = fs.ft_min;
+     unsigned file_tsec  = fs.ft_tsec;
 #endif
 
-  /* Calculate the seconds since epoch from the time components. First count
-     the whole days passed.  The value for years returned by the DOS and OS2
-     functions count years from 1980, so to compensate for the UNIX epoch which
-     begins in 1970 start with 10 years worth of days and add days for each
-     four year period since then.  */
+     /* Calculate the seconds since epoch from the time components. First count
+        the whole days passed.  The value for years returned by the DOS and OS2
+        functions count years from 1980, so to compensate for the UNIX epoch which
+        begins in 1970 start with 10 years worth of days and add days for each
+        four year period since then.  */
 
-  time_t tot_secs;
-  int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
-  int days_passed = 3652 + (file_year / 4) * 1461;
-  int years_since_leap = file_year % 4;
+     time_t tot_secs;
+     int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+     int days_passed = 3652 + (file_year / 4) * 1461;
+     int years_since_leap = file_year % 4;
 
-  if (years_since_leap == 1)
-    days_passed += 366;
-  else if (years_since_leap == 2)
-    days_passed += 731;
-  else if (years_since_leap == 3)
-    days_passed += 1096;
+     if (years_since_leap == 1)
+       days_passed += 366;
+     else if (years_since_leap == 2)
+       days_passed += 731;
+     else if (years_since_leap == 3)
+       days_passed += 1096;
 
-  if (file_year > 20)
-    days_passed -= 1;
+     if (file_year > 20)
+       days_passed -= 1;
 
-  days_passed += cum_days[file_month - 1];
-  if (years_since_leap == 0 && file_year != 20 && file_month > 2)
-    days_passed++;
+     days_passed += cum_days[file_month - 1];
+     if (years_since_leap == 0 && file_year != 20 && file_month > 2)
+       days_passed++;
 
-  days_passed += file_day - 1;
+     days_passed += file_day - 1;
 
-  /* OK - have whole days.  Multiply -- then add in other parts.  */
+     /* OK - have whole days.  Multiply -- then add in other parts.  */
 
-  tot_secs  = days_passed * 86400;
-  tot_secs += file_hour * 3600;
-  tot_secs += file_min * 60;
-  tot_secs += file_tsec * 2;
-  return (OS_Time) tot_secs;
+     tot_secs  = days_passed * 86400;
+     tot_secs += file_hour * 3600;
+     tot_secs += file_min * 60;
+     tot_secs += file_tsec * 2;
+     attr->timestamp = (OS_Time) tot_secs;
 
 #elif defined (_WIN32) && !defined (RTX)
-  HANDLE h = (HANDLE) _get_osfhandle (fd);
-  time_t ret = win32_filetime (h);
-  return (OS_Time) ret;
+     HANDLE h = (HANDLE) _get_osfhandle (fd);
+     time_t ret = win32_filetime (h);
+     attr->timestamp = (OS_Time) ret;
 
 #else
-  GNAT_STRUCT_STAT statbuf;
-
-  if (GNAT_FSTAT (fd, &statbuf) != 0) {
-     return (OS_Time) -1;
-  } else {
-#ifdef VMS
-     /* VMS has file versioning.  */
-     return (OS_Time) statbuf.st_ctime;
-#else
-     return (OS_Time) statbuf.st_mtime;
-#endif
-  }
+     __gnat_stat_to_attr (fd, NULL, attr);
 #endif
+   }
+
+   return attr->timestamp;
+}
+
+OS_Time
+__gnat_file_time_fd (int fd)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_file_time_fd_attr (fd, &attr);
 }
 
 /* Set the file time stamp.  */
@@ -1700,24 +1794,41 @@ __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
 #endif
 }
 
+/*************************************************************************
+ ** Check whether a file exists
+ *************************************************************************/
+
 int
-__gnat_file_exists (char *name)
+__gnat_file_exists_attr (char* name, struct file_attributes* attr)
 {
+   if (attr->exists == ATTR_UNSET) {
 #ifdef __MINGW32__
-  /*  On Windows do not use __gnat_stat() because a bug in Microsoft
-  _stat() routine. When the system time-zone is set with a negative
-  offset the _stat() routine fails on specific files like CON:  */
-  TCHAR wname [GNAT_MAX_PATH_LEN + 2];
-
-  S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
-  return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
+      /*  On Windows do not use __gnat_stat() because of a bug in Microsoft
+         _stat() routine. When the system time-zone is set with a negative
+         offset the _stat() routine fails on specific files like CON:  */
+      TCHAR wname [GNAT_MAX_PATH_LEN + 2];
+      S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
+      attr->exists = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
 #else
-  GNAT_STRUCT_STAT statbuf;
-
-  return !__gnat_stat (name, &statbuf);
+      __gnat_stat_to_attr (-1, name, attr);
 #endif
+   }
+
+   return attr->exists;
+}
+
+int
+__gnat_file_exists (char *name)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_file_exists_attr (name, &attr);
 }
 
+/**********************************************************************
+ ** Whether name is an absolute path
+ **********************************************************************/
+
 int
 __gnat_is_absolute_path (char *name, int length)
 {
@@ -1754,23 +1865,39 @@ __gnat_is_absolute_path (char *name, int length)
 }
 
 int
+__gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
+{
+   if (attr->regular == ATTR_UNSET) {
+      __gnat_stat_to_attr (-1, name, attr);
+   }
+
+   return attr->regular;
+}
+
+int
 __gnat_is_regular_file (char *name)
 {
-  int ret;
-  GNAT_STRUCT_STAT statbuf;
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_regular_file_attr (name, &attr);
+}
 
-  ret = __gnat_stat (name, &statbuf);
-  return (!ret && S_ISREG (statbuf.st_mode));
+int
+__gnat_is_directory_attr (char* name, struct file_attributes* attr)
+{
+   if (attr->directory == ATTR_UNSET) {
+      __gnat_stat_to_attr (-1, name, attr);
+   }
+
+   return attr->directory;
 }
 
 int
 __gnat_is_directory (char *name)
 {
-  int ret;
-  GNAT_STRUCT_STAT statbuf;
-
-  ret = __gnat_stat (name, &statbuf);
-  return (!ret && S_ISDIR (statbuf.st_mode));
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_directory_attr (name, &attr);
 }
 
 #if defined (_WIN32) && !defined (RTX)
@@ -1964,95 +2091,111 @@ __gnat_can_use_acl (TCHAR *wname)
 #endif /* defined (_WIN32) && !defined (RTX) */
 
 int
-__gnat_is_readable_file (char *name)
+__gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
 {
+   if (attr->readable == ATTR_UNSET) {
 #if defined (_WIN32) && !defined (RTX)
-  TCHAR wname [GNAT_MAX_PATH_LEN + 2];
-  GENERIC_MAPPING GenericMapping;
-
-  S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
-
-  if (__gnat_can_use_acl (wname))
-    {
-      ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
-      GenericMapping.GenericRead = GENERIC_READ;
+     TCHAR wname [GNAT_MAX_PATH_LEN + 2];
+     GENERIC_MAPPING GenericMapping;
 
-      return __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
-    }
-  else
-    return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
+     S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
 
+     if (__gnat_can_use_acl (wname))
+     {
+        ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
+        GenericMapping.GenericRead = GENERIC_READ;
+        attr->readable = __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
+     }
+     else
+        attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
 #else
-  int ret;
-  int mode;
-  GNAT_STRUCT_STAT statbuf;
-
-  ret = GNAT_STAT (name, &statbuf);
-  mode = statbuf.st_mode & S_IRUSR;
-  return (!ret && mode);
+     __gnat_stat_to_attr (-1, name, attr);
 #endif
+   }
+
+   return attr->readable;
 }
 
 int
-__gnat_is_writable_file (char *name)
+__gnat_is_readable_file (char *name)
 {
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_readable_file_attr (name, &attr);
+}
+
+int
+__gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
+{
+   if (attr->writable == ATTR_UNSET) {
 #if defined (_WIN32) && !defined (RTX)
-  TCHAR wname [GNAT_MAX_PATH_LEN + 2];
-  GENERIC_MAPPING GenericMapping;
+     TCHAR wname [GNAT_MAX_PATH_LEN + 2];
+     GENERIC_MAPPING GenericMapping;
 
-  S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
+     S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
 
-  if (__gnat_can_use_acl (wname))
-    {
-      ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
-      GenericMapping.GenericWrite = GENERIC_WRITE;
+     if (__gnat_can_use_acl (wname))
+       {
+         ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
+         GenericMapping.GenericWrite = GENERIC_WRITE;
 
-      return __gnat_check_OWNER_ACL
-       (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
-       && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
-    }
-  else
-    return !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
+         attr->writable = __gnat_check_OWNER_ACL
+            (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
+            && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
+       }
+     else
+       attr->writable = !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
 
 #else
-  int ret;
-  int mode;
-  GNAT_STRUCT_STAT statbuf;
-
-  ret = GNAT_STAT (name, &statbuf);
-  mode = statbuf.st_mode & S_IWUSR;
-  return (!ret && mode);
+     __gnat_stat_to_attr (-1, name, attr);
 #endif
+   }
+
+   return attr->writable;
 }
 
 int
-__gnat_is_executable_file (char *name)
+__gnat_is_writable_file (char *name)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_writable_file_attr (name, &attr);
+}
+
+int
+__gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
 {
+   if (attr->executable == ATTR_UNSET) {
 #if defined (_WIN32) && !defined (RTX)
-  TCHAR wname [GNAT_MAX_PATH_LEN + 2];
-  GENERIC_MAPPING GenericMapping;
+     TCHAR wname [GNAT_MAX_PATH_LEN + 2];
+     GENERIC_MAPPING GenericMapping;
 
-  S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
+     S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
 
-  if (__gnat_can_use_acl (wname))
-    {
-      ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
-      GenericMapping.GenericExecute = GENERIC_EXECUTE;
+     if (__gnat_can_use_acl (wname))
+       {
+         ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
+         GenericMapping.GenericExecute = GENERIC_EXECUTE;
 
-      return __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
-    }
-  else
-    return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
-      && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
+         attr->executable = __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
+       }
+     else
+       attr->executable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
+         && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
 #else
-  int ret;
-  int mode;
-  GNAT_STRUCT_STAT statbuf;
-
-  ret = GNAT_STAT (name, &statbuf);
-  mode = statbuf.st_mode & S_IXUSR;
-  return (!ret && mode);
+     __gnat_stat_to_attr (-1, name, attr);
 #endif
+   }
+
+   return attr->executable;
+}
+
+int
+__gnat_is_executable_file (char *name)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_executable_file_attr (name, &attr);
 }
 
 void
@@ -2171,21 +2314,31 @@ __gnat_set_non_readable (char *name)
 }
 
 int
-__gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
+__gnat_is_symbolic_link_attr (char* name, struct file_attributes* attr)
 {
+   if (attr->symbolic_link == ATTR_UNSET) {
 #if defined (__vxworks) || defined (__nucleus__)
-  return 0;
+      attr->symbolic_link = 0;
 
 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
-  int ret;
-  GNAT_STRUCT_STAT statbuf;
-
-  ret = GNAT_LSTAT (name, &statbuf);
-  return (!ret && S_ISLNK (statbuf.st_mode));
-
+      int ret;
+      GNAT_STRUCT_STAT statbuf;
+      ret = GNAT_LSTAT (name, &statbuf);
+      attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
 #else
-  return 0;
+      attr->symbolic_link = 0;
 #endif
+   }
+   return attr->symbolic_link;
+}
+
+int
+__gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_symbolic_link_attr (name, &attr);
+
 }
 
 #if defined (sun) && defined (__SVR4)