Change of behavior of Ada.Directories.Start_Search and Full_Name

I’ve discovered a change of behavior for the Ada.Directories.Start_Search and the associated Full_Name function. With a simple directory search with a relative path ".", you will get a relative path with GNAT 12 and an absolute path with GNAT 10.

package AD renames Ada.Directories;
...
Dir_Filter  : constant AD.Filter_Type := (AD.Ordinary_File => True,
                                          AD.Directory     => True,
                                          others           => False);
Ent    : AD.Directory_Entry_Type;
Search : AD.Search_Type;
begin
AD.Start_Search (Search, Directory => ".",
                 Pattern => "*", Filter => Dir_Filter);
while AD.More_Entries (Search) loop
   AD.Get_Next_Entry (Search, Ent);
   declare
     Full_Path : constant String := AD.Full_Name (Ent);
   begin
      Ada.Text_IO.Put_Line (Full_Path);
   end;
end loop;

In other words, Full_Name (Directory_Entry) does not normalize the path anymore as does the Full_Name (String) version.

We can get the old behavior by calling Full_Name (String) again on the return value, that is:

Full_Path : constant String := AD.Full_Name (AD.Full_Name (Ent));

There is nothing wrong with both implementations (the ARM says this is implementation defined), but, this change of behavior can give some surprises…

1 Like

out of curiosity are you able to call Full_Name on the string returned from that version and get the absolute path that way?

Yes, AD.Full_Name (AD.Full_Name (Ent)) gives you the absolute path.

It’s weird they decided to change that. If you are a customer of AdaCore, maybe toss them an email and see what the thinking was? If not, maybe an issue up on the ARG github can spark a convo on it (since the AARM indicates it is implementation defined…why?)

This looks like a GNAT bug to me. The Ada RM is pretty clear:

RM A.16(47/2) says:

The full name of an external file is a full specification of the name of the file. If the external environment allows alternative specifications of the name (for example, abbreviations), the full name should not use such alternatives. A full name typically will include the names of all of the directories that contain the item.

and then RM A.16(115/2-116/2) says:

function Full_Name (Directory_Entry : in Directory_Entry_Type)
return String;

Returns the full external name of the external file (including directories) represented by Directory_Entry. …

This seems to imply that the string returned by Full_Name(Directory_Entry) should include the name starting at the root of the file system. So I think GNAT is wrong here.

1 Like

I don’t disagree with you, but I think the confusion comes from the following sentence not in your quoted part:
RM A.16(116/2): The format of the name returned is implementation defined.

That word “format” really isn’t explained or qualified, so one could interpret that to mean either relative or absolute is ok for this version of Full_Name. I personally don’t think it affects that, but I don’t know for sure and that sentence casts doubt.

I suppose “format” in (116) might mean Windows (with disk:/share:) vs Unix.

But in any case you’d think that (47.a), (72.a) and (116) would be consistent. Could the latter two refer to the first?

I think the statement that the “format is implementation defined” is simply stating that the directory separator character, the drive letter, the initial character, etc., are all up to the implementation. I don’t think the implementor should ignore the requirement that if multiple representations are possible, the “full” name is the one that gives the “full” story!

2 Likes