Vpatch: support for files in vtree root

August 8th, 2019

While doing a test trying to create and press a vpatch with Linux kernel source, I discovered that vpatch cannot handle files in the press root directory1. The reason for this lies in the Path_Prefix function:

function Path_Prefix(Pathname: String;
                     Suffix: Positive) return String is
   Pos: Natural := Pathname'Last;
begin
   for I in 1..Suffix loop
      Pos := Ada.Strings.Fixed.Index(Pathname, "/",
                                     From => Pos,
                                     Going => Ada.Strings.Backward);
      if Pos = 0 then
         return Pathname;
      end if;
      Pos := Pos - 1;
   end loop;
   return Pathname(Pathname'First .. Pos);
end;

The function is written in such a way that when Suffix argument is greater then the number of slash-delimited components in the path, it will incorrectly return the unmodified Pathname argument2. Even though vpatch calls Path_Prefix with Suffix of 1 only, this still triggers the failure case with files in the press directory, forcing creation of directories with the intended names of the files instead:

if Has_Input_File then
   Close(In_F);
   Dirs.Delete_File(To_F_Name);
else
   if not Dirs.Exists(Path_Prefix(To_F_Name, 1)) then
      Dirs.Create_Path(Path_Prefix(To_F_Name, 1));
   end if;
end if;

My vpatch simplifies code a bit, replacing Path_Prefix with Directory_Name (after unix dirname(1)), which correctly handles the case of missing directory components of the path:

function Directory_Name(Pathname: String) return String is
   Pos: Natural := Pathname'Last;
begin
   Pos := Ada.Strings.Fixed.Index(Pathname, "/",
                                  From => Pos,
                                  Going => Ada.Strings.Backward);
   if Pos = 0 then
      return Dirs.Current_Directory;
   end if;
   return Pathname(Pathname'First .. Pos);
end;

Additionally, I fixed a bug with handling of empty vpatches - a cryptic error was thrown on reading them before:

@@ -651,6 +647,7 @@
 begin
 Read_Loop:
     loop
+       exit Read_Loop when End_Of_File;
        declare
           S: String := Get_Line;
        begin
@@ -659,7 +656,6 @@
                 H: Header := Get_Header;
              begin
                 Process_Hunks_For_Header(H);
-                exit Read_Loop when End_Of_File;
              end;
           else
              Put_Line("Prelude: " & S);

With the fix, empty vpatch files are silently ignored. If you wish to have an explicit error in this case, please write in.

The vpatch and seal are available here:

curl 'http://bvt-trace.net/vpatches/vtools_fixes_rootdir_files.vpatch' > vtools_fixes_rootdir_files.vpatch
curl 'http://bvt-trace.net/vpatches/vtools_fixes_rootdir_files.vpatch.bvt.sig' > vtools_fixes_rootdir_files.vpatch.bvt.sig
  1. Initially misdiagnosed as problems with dotfiles. []
  2. Instead of press root directory, for example. Though what is the meaning of removing e.g. 5 last elements, when only 1 is available? []