diff mbox

[Ada] Improve error handling in Ada.Directories search system

Message ID 20140224165213.GA27045@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Feb. 24, 2014, 4:52 p.m. UTC
This change ensures that when iterating on directory entries using
Ada.Directories, and some parent of the searched directory is not accessable,
Use_Error is appropriately raised (instead of just yielding no entries).

The following program must raise USE_ERROR when run in a directory
whose parent is not accessable by the running user:

with Ada.Directories; use Ada.Directories;
with Ada.Text_IO; use Ada.Text_IO;
procedure LSD is
   S : Search_Type;
   E : Directory_Entry_Type;
begin
   Start_Search (S, ".", "*");
   while More_Entries (S) loop
      Get_Next_Entry (S, E);
      Put_Line (Kind (E)'Img & ": " & Simple_Name (E));
   end loop;
end LSD;

Tested on x86_64-pc-linux-gnu, committed on trunk

2014-02-24  Thomas Quinot  <quinot@adacore.com>

	* adaint.h (struct file_attributes): New component "error"
	(__gnat_error_attributes): Accessor for the above.
	* adaint.c (__gnat_error_attributes): New subprogram
	(__gnat_stat): Fix returned value (expect errno value)
	(__gnat_stat_to_attr): Add management of error component (set to
	stat errno value, except for missing files where it is set to 0,
	and exists is set to 0).
	* osint.ads (File_Attributes_Size): Update per change above,
	also clarify documentation.
	* s-filatt.ads: New file, binding to file attributes related
	functions.
	* Makefile.rtl (s-filatt): New runtime unit.
	* s-crtl.ads (strlen): Expose binding to GCC builtin (falls back
	to library function if not available on target).
	* s-os_lib.ads, s-os_lib.adb (Errno_Message): New subprogram.
	* s-oscons-tmplt.c (SIZEOF_struct_file_attributes,
	SIZEOF_struct_dirent_alloc): New constants.
	* Make-generated.in (s-oscons.ads): Now requires adaint.h.
	* a-direct.adb (Fetch_Next_Entry): Fix incorrect buffer sizes.
	Perform appropriate error checking if stat fails (do not just
	ignore existing files if stat fails)
	* gcc-interface/Make-lang.in (GNAT_ADA_OBJS, GNATBIND_OBJS): Update
	dependencies.
diff mbox

Patch

Index: a-direct.adb
===================================================================
--- a-direct.adb	(revision 208067)
+++ a-direct.adb	(working copy)
@@ -6,7 +6,7 @@ 
@@ -36,21 +36,18 @@ 
 with Ada.Strings.Fixed;
 with Ada.Strings.Maps;           use Ada.Strings.Maps;
 with Ada.Strings.Unbounded;      use Ada.Strings.Unbounded;
-with Ada.Unchecked_Conversion;
 with Ada.Unchecked_Deallocation;
 
-with System;              use System;
-with System.CRTL;         use System.CRTL;
-with System.File_IO;      use System.File_IO;
-with System.OS_Constants; use System.OS_Constants;
-with System.OS_Lib;       use System.OS_Lib;
-with System.Regexp;       use System.Regexp;
+with System;                 use System;
+with System.CRTL;            use System.CRTL;
+with System.File_Attributes; use System.File_Attributes;
+with System.File_IO;         use System.File_IO;
+with System.OS_Constants;    use System.OS_Constants;
+with System.OS_Lib;          use System.OS_Lib;
+with System.Regexp;          use System.Regexp;
 
 package body Ada.Directories is
 
-   Filename_Max : constant Integer := 1024;
-   --  1024 is the value of FILENAME_MAX in stdio.h
-
    type Dir_Type_Value is new Address;
    --  This is the low-level address directory structure as returned by the C
    --  opendir routine.
@@ -708,7 +705,7 @@ 
    ----------------------
 
    procedure Fetch_Next_Entry (Search : Search_Type) is
-      Name : String (1 .. 255);
+      Name : String (1 .. NAME_MAX);
       Last : Natural;
 
       Kind : File_Kind := Ordinary_File;
@@ -717,9 +714,7 @@ 
       Filename_Addr : Address;
       Filename_Len  : aliased Integer;
 
-      Buffer : array (0 .. Filename_Max + 12) of Character;
-      --  12 is the size of the dirent structure (see dirent.h), without the
-      --  field for the filename.
+      Buffer : array (1 .. SIZEOF_struct_dirent_alloc) of Character;
 
       function readdir_gnat
         (Directory : Address;
@@ -744,43 +739,60 @@ 
             exit;
          end if;
 
+         if Filename_Len > Name'Length then
+            raise Use_Error with "file name too long";
+         end if;
+
          declare
-            subtype Path_String is String (1 .. Filename_Len);
-            type    Path_String_Access is access Path_String;
+            subtype Name_String is String (1 .. Filename_Len);
+            Dent_Name : Name_String;
+            for Dent_Name'Address use Filename_Addr;
+            pragma Import (Ada, Dent_Name);
 
-            function Address_To_Access is new
-              Ada.Unchecked_Conversion
-                (Source => Address,
-                 Target => Path_String_Access);
-
-            Path_Access : constant Path_String_Access :=
-              Address_To_Access (Filename_Addr);
-
          begin
             Last := Filename_Len;
-            Name (1 .. Last) := Path_Access.all;
+            Name (1 .. Last) := Dent_Name;
          end;
 
          --  Check if the entry matches the pattern
 
          if Match (Name (1 .. Last), Search.Value.Pattern) then
             declare
-               Full_Name : constant String :=
-                 Compose (To_String (Search.Value.Name), Name (1 .. Last));
-               Found     : Boolean := False;
+               C_Full_Name : constant String :=
+                 Compose (To_String (Search.Value.Name), Name (1 .. Last))
+                   & ASCII.NUL;
+               Full_Name   : String renames C_Full_Name
+                               (C_Full_Name'First .. C_Full_Name'Last - 1);
+               Found       : Boolean := False;
+               Attr        : aliased File_Attributes;
+               Exists      : Integer;
+               Error       : Integer;
 
             begin
-               if File_Exists (Full_Name) then
+               Reset_Attributes (Attr'Access);
+               Exists := File_Exists_Attr (C_Full_Name'Address, Attr'Access);
+               Error  := Error_Attributes (Attr'Access);
 
+               if Error /= 0 then
+                  raise Use_Error
+                    with Full_Name & ": " & Errno_Message (Err => Error);
+               end if;
+
+               if Exists = 1 then
+
                   --  Now check if the file kind matches the filter
 
-                  if Is_Regular_File (Full_Name) then
+                  if Is_Regular_File_Attr
+                       (C_Full_Name'Address, Attr'Access) = 1
+                  then
                      if Search.Value.Filter (Ordinary_File) then
                         Kind := Ordinary_File;
                         Found := True;
                      end if;
 
-                  elsif Is_Directory (Full_Name) then
+                  elsif Is_Directory_Attr
+                          (C_Full_Name'Address, Attr'Access) = 1
+                  then
                      if Search.Value.Filter (Directory) then
                         Kind := Directory;
                         Found := True;
@@ -821,7 +833,7 @@ 
    begin
       C_Name (1 .. Name'Length) := Name;
       C_Name (C_Name'Last) := ASCII.NUL;
-      return C_File_Exists (C_Name (1)'Address) = 1;
+      return C_File_Exists (C_Name'Address) = 1;
    end File_Exists;
 
    --------------
Index: s-crtl.ads
===================================================================
--- s-crtl.ads	(revision 208067)
+++ s-crtl.ads	(working copy)
@@ -70,6 +70,11 @@ 
    function atoi (A : System.Address) return Integer;
    pragma Import (C, atoi, "atoi");
 
+   function strlen (A : System.Address) return size_t;
+   pragma Import (Intrinsic, strlen, "strlen");
+   --  Import with convention Intrinsic so that we take advantage of the GCC
+   --  builtin where available (and fall back to the library function if not).
+
    procedure clearerr (stream : FILEs);
    pragma Import (C, clearerr, "clearerr");
 
Index: s-filatt.ads
===================================================================
--- s-filatt.ads	(revision 0)
+++ s-filatt.ads	(revision 0)
@@ -0,0 +1,67 @@ 
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT RUN-TIME COMPONENTS                         --
+--                                                                          --
+--                S Y S T E M . F I L E _ A T T R I B U T E S               --
+--                                                                          --
+--                                 S p e c                                  --
+--                                                                          --
+--             Copyright (C) 2014, Free Software Foundation, Inc.           --
+--                                                                          --
+-- GNAT is free software;  you can  redistribute it  and/or modify it under --
+-- terms of the  GNU General Public License as published  by the Free Soft- --
+-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
+-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
+--                                                                          --
+-- As a special exception under Section 7 of GPL version 3, you are granted --
+-- additional permissions described in the GCC Runtime Library Exception,   --
+-- version 3.1, as published by the Free Software Foundation.               --
+--                                                                          --
+-- You should have received a copy of the GNU General Public License and    --
+-- a copy of the GCC Runtime Library Exception along with this program;     --
+-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
+-- <http://www.gnu.org/licenses/>.                                          --
+--                                                                          --
+-- GNAT was originally developed  by the GNAT team at  New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc.      --
+--                                                                          --
+------------------------------------------------------------------------------
+
+--  This package provides a binding to the GNAT file attribute query functions
+
+with System.OS_Constants;
+with System.Storage_Elements;
+
+package System.File_Attributes is
+
+   type File_Attributes is private;
+
+   procedure Reset_Attributes (A : access File_Attributes);
+   function Error_Attributes (A : access File_Attributes) return Integer;
+   function File_Exists_Attr
+     (N : System.Address;
+      A : access File_Attributes) return Integer;
+   function Is_Regular_File_Attr
+     (N : System.Address;
+      A : access File_Attributes) return Integer;
+   function Is_Directory_Attr
+     (N : System.Address;
+      A : access File_Attributes) return Integer;
+
+private
+
+   package SOSC renames System.OS_Constants;
+
+   type File_Attributes is new System.Storage_Elements.Storage_Array
+     (1 .. SOSC.SIZEOF_struct_file_attributes);
+   for File_Attributes'Alignment use Standard'Maximum_Alignment;
+
+   pragma Import (C, Reset_Attributes,     "__gnat_reset_attributes");
+   pragma Import (C, Error_Attributes,     "__gnat_error_attributes");
+   pragma Import (C, File_Exists_Attr,     "__gnat_file_exists_attr");
+   pragma Import (C, Is_Regular_File_Attr, "__gnat_is_regular_file_attr");
+   pragma Import (C, Is_Directory_Attr,    "__gnat_is_directory_attr");
+
+end System.File_Attributes;
Index: s-oscons-tmplt.c
===================================================================
--- s-oscons-tmplt.c	(revision 208067)
+++ s-oscons-tmplt.c	(working copy)
@@ -89,6 +89,7 @@ 
 /* Include gsocket.h before any system header so it can redefine FD_SETSIZE */
 
 #include "gsocket.h"
+#include "adaint.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -310,6 +311,16 @@ 
 #endif
 CND(IOV_MAX, "Maximum writev iovcnt")
 
+#ifndef NAME_MAX
+# define NAME_MAX 255
+#endif
+CND(NAME_MAX, "Maximum file name length")
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+CND(FILENAME_MAX, "Maximum file path length")
+
 /*
 
    ---------------------
@@ -1319,20 +1330,44 @@ 
 CND(SIZEOF_sockaddr_in6, "struct sockaddr_in6")
 
 #define SIZEOF_fd_set (sizeof (fd_set))
-CND(SIZEOF_fd_set, "fd_set");
-CND(FD_SETSIZE, "Max fd value");
+CND(SIZEOF_fd_set, "fd_set")
+CND(FD_SETSIZE, "Max fd value")
 
 #define SIZEOF_struct_hostent (sizeof (struct hostent))
-CND(SIZEOF_struct_hostent, "struct hostent");
+CND(SIZEOF_struct_hostent, "struct hostent")
 
 #define SIZEOF_struct_servent (sizeof (struct servent))
-CND(SIZEOF_struct_servent, "struct servent");
+CND(SIZEOF_struct_servent, "struct servent")
 
 #if defined (__linux__)
 #define SIZEOF_sigset (sizeof (sigset_t))
-CND(SIZEOF_sigset, "sigset");
+CND(SIZEOF_sigset, "sigset")
 #endif
 
+/**
+ ** Note: this constant can be used in the GNAT runtime library. In compiler
+ ** units on the other hand, System.OS_Constants is not available, so we
+ ** declare an Ada constant (Osint.File_Attributes_Size) independently, which
+ ** is at least as large as sizeof (struct file_attributes), and we have an
+ ** assertion at initialization of Osint checking that the size is indeed at
+ ** least sufficient.
+ **/
+#define SIZEOF_struct_file_attributes (sizeof (struct file_attributes))
+CND(SIZEOF_struct_file_attributes, "struct file_attributes")
+
+/**
+ ** Maximal size of buffer for struct dirent. Note: Since POSIX.1 does not
+ ** specify the size of the d_name field, and other nonstandard fields may
+ ** precede that field within the dirent structure, we must make a conservative
+ ** computation.
+ **/
+{
+  struct dirent dent;
+#define SIZEOF_struct_dirent_alloc \
+  ((char*) &dent.d_name - (char*) &dent) + NAME_MAX + 1
+CND(SIZEOF_struct_dirent_alloc, "struct dirent allocation")
+}
+
 /*
 
    --  Fields of struct msghdr
Index: Makefile.rtl
===================================================================
--- Makefile.rtl	(revision 208067)
+++ Makefile.rtl	(working copy)
@@ -535,6 +535,7 @@ 
   s-fatllf$(objext) \
   s-fatsfl$(objext) \
   s-ficobl$(objext) \
+  s-filatt$(objext) \
   s-fileio$(objext) \
   s-filofl$(objext) \
   s-finmas$(objext) \
Index: adaint.c
===================================================================
--- adaint.c	(revision 208067)
+++ adaint.c	(working copy)
@@ -350,7 +350,9 @@ 
 
 #endif
 
-/* Used for Ada bindings */
+/* Used for runtime check that Ada constant File_Attributes_Size is no
+   less than the actual size of struct file_attributes (see Osint
+   initialization). */
 int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
 
 void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
@@ -411,6 +413,7 @@ 
 __gnat_reset_attributes (struct file_attributes* attr)
 {
   attr->exists     = ATTR_UNSET;
+  attr->error      = EINVAL;
 
   attr->writable   = ATTR_UNSET;
   attr->readable   = ATTR_UNSET;
@@ -424,6 +427,11 @@ 
   attr->file_length = -1;
 }
 
+int
+__gnat_error_attributes (struct file_attributes *attr) {
+  return attr->error;
+}
+
 OS_Time
 __gnat_current_time (void)
 {
@@ -1170,12 +1178,28 @@ 
 __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
 {
   GNAT_STRUCT_STAT statbuf;
-  int ret;
+  int ret, error;
 
-  if (fd != -1)
+  if (fd != -1) {
+    /* GNAT_FSTAT returns -1 and sets errno for failure */
     ret = GNAT_FSTAT (fd, &statbuf);
+    error = ret ? errno : 0;
+
+  } else {
+    /* __gnat_stat returns errno value directly */
+    error = __gnat_stat (name, &statbuf);
+    ret = error ? -1 : 0;
+  }
+
+  /*
+   * A missing file is reported as an attr structure with error == 0 and
+   * exists == 0.
+   */
+
+  if (error == 0 || error == ENOENT)
+    attr->error = 0;
   else
-    ret = __gnat_stat (name, &statbuf);
+    attr->error = error;
 
   attr->regular   = (!ret && S_ISREG (statbuf.st_mode));
   attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
@@ -1793,6 +1817,9 @@ 
   return result;
 }
 
+/* Query information for the given file NAME and return it in STATBUF.
+ * Returns 0 for success, or errno value for failure.
+ */
 int
 __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
 {
@@ -1807,7 +1834,7 @@ 
   name_len = _tcslen (wname);
 
   if (name_len > GNAT_MAX_PATH_LEN)
-    return -1;
+    return EINVAL;
 
   ZeroMemory (statbuf, sizeof(GNAT_STRUCT_STAT));
 
@@ -1860,7 +1887,7 @@ 
   return 0;
 
 #else
-  return GNAT_STAT (name, statbuf);
+  return GNAT_STAT (name, statbuf) == 0 ? 0 : errno;
 #endif
 }
 
Index: adaint.h
===================================================================
--- adaint.h	(revision 208067)
+++ adaint.h	(working copy)
@@ -78,6 +78,11 @@ 
 */
 
 struct file_attributes {
+  int           error;
+  /* Errno value returned by stat()/fstat(). If non-zero, other fields should
+   * be considered as invalid.
+   */
+
   unsigned char exists;
 
   unsigned char writable;
@@ -163,7 +168,8 @@ 
 extern int    __gnat_is_readable_file		   (char *name);
 extern int    __gnat_is_executable_file      (char *name);
 
-extern void __gnat_reset_attributes (struct file_attributes* attr);
+extern void   __gnat_reset_attributes (struct file_attributes *);
+extern int    __gnat_error_attributes (struct file_attributes *);
 extern long   __gnat_file_length_attr        (int, char *, struct file_attributes *);
 extern OS_Time __gnat_file_time_name_attr    (char *, struct file_attributes *);
 extern OS_Time __gnat_file_time_fd_attr      (int,    struct file_attributes *);
Index: osint.ads
===================================================================
--- osint.ads	(revision 208067)
+++ osint.ads	(working copy)
@@ -758,13 +758,14 @@ 
    --  detected, the file being written is deleted, and a fatal error is
    --  signalled.
 
-   File_Attributes_Size : constant Natural := 24;
+   File_Attributes_Size : constant Natural := 32;
    --  This should be big enough to fit a "struct file_attributes" on any
    --  system. It doesn't cause any malfunction if it is too big (which avoids
    --  the need for either mapping the struct exactly or importing the sizeof
    --  from C, which would result in dynamic code). However, it does waste
    --  space (e.g. when a component of this type appears in a record, if it is
-   --  unnecessarily large).
+   --  unnecessarily large). Note: for runtime units, use System.OS_Constants.
+   --  SIZEOF_struct_file_attributes instead, which has the exact value.
 
    type File_Attributes is
      array (1 .. File_Attributes_Size)
Index: Make-generated.in
===================================================================
--- Make-generated.in	(revision 208067)
+++ Make-generated.in	(working copy)
@@ -84,7 +84,7 @@ 
 #  ld -o s-oscons-tmplt.exe s-oscons-tmplt.obj; \
 #  ./s-oscons-tmplt.exe > s-oscons-tmplt.s
 
-$(ADA_GEN_SUBDIR)/s-oscons.ads : $(ADA_GEN_SUBDIR)/s-oscons-tmplt.c $(ADA_GEN_SUBDIR)/gsocket.h $(ADA_GEN_SUBDIR)/xoscons.adb $(ADA_GEN_SUBDIR)/xutil.ads $(ADA_GEN_SUBDIR)/xutil.adb
+$(ADA_GEN_SUBDIR)/s-oscons.ads : $(ADA_GEN_SUBDIR)/s-oscons-tmplt.c $(ADA_GEN_SUBDIR)/gsocket.h $(ADA_GEN_SUBDIR)/adaint.h $(ADA_GEN_SUBDIR)/xoscons.adb $(ADA_GEN_SUBDIR)/xutil.ads $(ADA_GEN_SUBDIR)/xutil.adb
 	-$(MKDIR) $(ADA_GEN_SUBDIR)/bldtools/oscons
 	$(RM) $(addprefix $(ADA_GEN_SUBDIR)/bldtools/oscons/,$(notdir $^))
 	$(CP) $^ $(ADA_GEN_SUBDIR)/bldtools/oscons
Index: s-os_lib.adb
===================================================================
--- s-os_lib.adb	(revision 208067)
+++ s-os_lib.adb	(working copy)
@@ -88,8 +88,8 @@ 
    --  parameters are as in Create_Temp_File.
 
    function C_String_Length (S : Address) return Integer;
-   --  Returns the length of a C string. Does check for null address
-   --  (returns 0).
+   --  Returns the length of C (null-terminated) string at S, or 0 for
+   --  Null_Address.
 
    procedure Spawn_Internal
      (Program_Name : String;
@@ -252,13 +252,11 @@ 
    ---------------------
 
    function C_String_Length (S : Address) return Integer is
-      function Strlen (S : Address) return Integer;
-      pragma Import (C, Strlen, "strlen");
    begin
       if S = Null_Address then
          return 0;
       else
-         return Strlen (S);
+         return Integer (CRTL.strlen (S));
       end if;
    end C_String_Length;
 
@@ -912,6 +910,38 @@ 
       Delete_File (C_Name'Address, Success);
    end Delete_File;
 
+   -------------------
+   -- Errno_Message --
+   -------------------
+
+   function Errno_Message
+     (Err     : Integer := Errno;
+      Default : String  := "") return String
+   is
+      function strerror (errnum : Integer) return System.Address;
+      pragma Import (C, strerror, "strerror");
+
+      C_Msg : constant System.Address := strerror (Err);
+
+   begin
+      if C_Msg = Null_Address then
+         if Default /= "" then
+            return Default;
+         else
+            return "errno =" & Err'Img;
+         end if;
+
+      else
+         declare
+            Msg : String (1 .. Integer (CRTL.strlen (C_Msg)));
+            for Msg'Address use C_Msg;
+            pragma Import (Ada, Msg);
+         begin
+            return Msg;
+         end;
+      end if;
+   end Errno_Message;
+
    ---------------------
    -- File_Time_Stamp --
    ---------------------
@@ -1028,14 +1058,11 @@ 
       procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
       pragma Import (C, Strncpy, "strncpy");
 
-      function Strlen (Cstring : Address) return Integer;
-      pragma Import (C, Strlen, "strlen");
-
       Suffix_Length : Integer;
       Result        : String_Access;
 
    begin
-      Suffix_Length := Strlen (Target_Exec_Ext_Ptr);
+      Suffix_Length := Integer (CRTL.strlen (Target_Exec_Ext_Ptr));
       Result := new String (1 .. Suffix_Length);
 
       if Suffix_Length > 0 then
@@ -1057,14 +1084,11 @@ 
       procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
       pragma Import (C, Strncpy, "strncpy");
 
-      function Strlen (Cstring : Address) return Integer;
-      pragma Import (C, Strlen, "strlen");
-
       Suffix_Length : Integer;
       Result        : String_Access;
 
    begin
-      Suffix_Length := Strlen (Target_Exec_Ext_Ptr);
+      Suffix_Length := Integer (CRTL.strlen (Target_Exec_Ext_Ptr));
       Result := new String (1 .. Suffix_Length);
 
       if Suffix_Length > 0 then
@@ -1086,14 +1110,11 @@ 
       procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
       pragma Import (C, Strncpy, "strncpy");
 
-      function Strlen (Cstring : Address) return Integer;
-      pragma Import (C, Strlen, "strlen");
-
       Suffix_Length : Integer;
       Result        : String_Access;
 
    begin
-      Suffix_Length := Strlen (Target_Object_Ext_Ptr);
+      Suffix_Length := Integer (CRTL.strlen (Target_Object_Ext_Ptr));
       Result := new String (1 .. Suffix_Length);
 
       if Suffix_Length > 0 then
@@ -1792,9 +1813,6 @@ 
       Canonical_File_Addr : System.Address;
       Canonical_File_Len  : Integer;
 
-      function Strlen (S : System.Address) return Integer;
-      pragma Import (C, Strlen, "strlen");
-
       function Final_Value (S : String) return String;
       --  Make final adjustment to the returned string. This function strips
       --  trailing directory separators, and folds returned string to lower
@@ -1926,7 +1944,7 @@ 
          The_Name (The_Name'Last) := ASCII.NUL;
 
          Canonical_File_Addr := To_Canonical_File_Spec (The_Name'Address);
-         Canonical_File_Len  := Strlen (Canonical_File_Addr);
+         Canonical_File_Len  := Integer (CRTL.strlen (Canonical_File_Addr));
 
          --  If VMS syntax conversion has failed, return an empty string
          --  to indicate the failure.
@@ -1937,17 +1955,12 @@ 
 
          declare
             subtype Path_String is String (1 .. Canonical_File_Len);
-            type    Path_String_Access is access Path_String;
+            Canonical_File : Path_String;
+            for Canonical_File'Address use Canonical_File_Addr;
+            pragma Import (Ada, Canonical_File);
 
-            function Address_To_Access is new
-               Ada.Unchecked_Conversion (Source => Address,
-                                     Target => Path_String_Access);
-
-            Path_Access : constant Path_String_Access :=
-                            Address_To_Access (Canonical_File_Addr);
-
          begin
-            Path_Buffer (1 .. Canonical_File_Len) := Path_Access.all;
+            Path_Buffer (1 .. Canonical_File_Len) := Canonical_File;
             End_Path := Canonical_File_Len;
             Last := 1;
          end;
Index: s-os_lib.ads
===================================================================
--- s-os_lib.ads	(revision 208067)
+++ s-os_lib.ads	(working copy)
@@ -962,6 +962,13 @@ 
    pragma Import (C, Set_Errno, "__set_errno");
    --  Set the task-safe error number
 
+   function Errno_Message
+     (Err     : Integer := Errno;
+      Default : String  := "") return String;
+   --  Return a message describing the given Errno value. If none is provided
+   --  by the system, return Default if not empty, else return a generic
+   --  message indicating the numeric errno value.
+
    Directory_Separator : constant Character;
    --  The character that is used to separate parts of a pathname
 
Index: gcc-interface/Make-lang.in
===================================================================
--- gcc-interface/Make-lang.in	(revision 208067)
+++ gcc-interface/Make-lang.in	(working copy)
@@ -350,6 +350,7 @@ 
  ada/s-htable.o	\
  ada/s-imenne.o	\
  ada/s-imgenu.o	\
+ ada/s-imgint.o \
  ada/s-mastop.o	\
  ada/s-memory.o	\
  ada/s-os_lib.o	\
@@ -457,27 +458,16 @@ 
 GNAT1_OBJS = $(GNAT1_C_OBJS) $(GNAT1_ADA_OBJS) ada/b_gnat1.o
 
 GNATBIND_OBJS = \
- ada/adaint.o     \
- ada/argv.o       \
- ada/cio.o        \
- ada/cstreams.o   \
- ada/env.o        \
- ada/exit.o       \
- ada/final.o      \
- ada/init.o       \
- ada/initialize.o \
- ada/link.o       \
- ada/raise.o      \
- ada/seh_init.o   \
- ada/targext.o    \
- ada/ada.o        \
  ada/a-clrefi.o   \
  ada/a-comlin.o   \
  ada/a-elchha.o   \
  ada/a-except.o   \
+ ada/ada.o        \
+ ada/adaint.o     \
  ada/ali-util.o   \
  ada/ali.o        \
  ada/alloc.o      \
+ ada/argv.o       \
  ada/aspects.o    \
  ada/atree.o      \
  ada/bcheck.o     \
@@ -487,34 +477,41 @@ 
  ada/bindusg.o    \
  ada/butil.o      \
  ada/casing.o     \
+ ada/cio.o        \
  ada/csets.o      \
+ ada/cstreams.o   \
  ada/debug.o      \
  ada/einfo.o      \
  ada/elists.o     \
+ ada/env.o        \
  ada/err_vars.o   \
  ada/errout.o     \
  ada/erroutc.o    \
+ ada/exit.o       \
+ ada/final.o      \
  ada/fmap.o       \
+ ada/fname-uf.o   \
  ada/fname.o      \
- ada/fname-uf.o   \
  ada/g-byorma.o   \
  ada/g-hesora.o   \
  ada/g-htable.o   \
- ada/s-os_lib.o   \
- ada/s-string.o   \
  ada/gnat.o       \
  ada/gnatbind.o   \
  ada/gnatvsn.o    \
  ada/hostparm.o   \
+ ada/init.o       \
+ ada/initialize.o \
  ada/interfac.o   \
  ada/krunch.o     \
  ada/lib.o        \
+ ada/link.o       \
  ada/namet.o      \
  ada/nlists.o     \
  ada/opt.o        \
  ada/osint-b.o    \
  ada/osint.o      \
  ada/output.o     \
+ ada/raise.o      \
  ada/restrict.o   \
  ada/rident.o     \
  ada/s-addope.o   \
@@ -537,8 +534,10 @@ 
  ada/s-htable.o   \
  ada/s-imenne.o   \
  ada/s-imgenu.o   \
+ ada/s-imgint.o   \
  ada/s-mastop.o   \
  ada/s-memory.o   \
+ ada/s-os_lib.o   \
  ada/s-parame.o   \
  ada/s-restri.o   \
  ada/s-secsta.o   \
@@ -550,6 +549,7 @@ 
  ada/s-stalib.o   \
  ada/s-stoele.o   \
  ada/s-strhas.o   \
+ ada/s-string.o   \
  ada/s-strops.o   \
  ada/s-traent.o   \
  ada/s-unstyp.o   \
@@ -557,24 +557,26 @@ 
  ada/s-wchcnv.o   \
  ada/s-wchcon.o   \
  ada/s-wchjis.o   \
- ada/scng.o       \
  ada/scans.o      \
  ada/scil_ll.o    \
+ ada/scng.o       \
  ada/sdefault.o   \
+ ada/seh_init.o   \
  ada/sem_aux.o    \
  ada/sinfo.o      \
+ ada/sinput-c.o   \
  ada/sinput.o     \
- ada/sinput-c.o   \
  ada/snames.o     \
  ada/stand.o      \
  ada/stringt.o    \
- ada/switch-b.o   \
- ada/switch.o     \
  ada/style.o      \
  ada/styleg.o     \
  ada/stylesw.o    \
+ ada/switch-b.o   \
+ ada/switch.o     \
  ada/system.o     \
  ada/table.o      \
+ ada/targext.o    \
  ada/targparm.o   \
  ada/tree_io.o    \
  ada/types.o      \