diff -uNr a/vtools/manifest b/vtools/manifest --- a/vtools/manifest e4eeb1ec44378d9c6c597a02d7330c220d6ee39d50dd64221091b8124216fbddb1466aee1492e8ad61b8569107bf2fa4e842a66ddb516cf03c3955e58a14efa3 +++ b/vtools/manifest ea86b6861e5be39fcaef55d0934b74255793e20bbf642125552fa25c5a37c423b77d45ecb60fe34bdc79e579a64ea0352c36a1747be6b7e5d0dda1e4c36d1881 @@ -16,3 +16,5 @@ Vpatch tool support for "No newline at end of file" directive. 2018-09-26 phf Ksum standalone keccak hasher +2018-10-23 bvt +Standalone temporary file generation code. diff -uNr a/vtools/src/temporary_file.adb b/vtools/src/temporary_file.adb --- a/vtools/src/temporary_file.adb false +++ b/vtools/src/temporary_file.adb d8cdd79c8b612a176e955323a470ddeb2634741b8c13d93d9818d85f46492bcceee02f9e994077794a9fdbbd754cfeab472109231741aa70bb86e05a1ae62753 @@ -0,0 +1,71 @@ +with Bits; use Bits; +with System; use System; +with SMG_Keccak; use SMG_Keccak; + +package body Temporary_File is + -- Create a new file or exit when the file with specified name exists. + -- Use fopen(3) with "x" mode to create the file or error out if it + -- already exists. + subtype File_Ptr is System.Address; + subtype C_String is System.Address; + + function fopen (Path: C_String; + Mode: C_String) return File_Ptr; + pragma Import (C, fopen); + + procedure fclose (Stream: File_Ptr); + pragma Import (C, fclose); + + function Create_File_Exclusive(Path: String) return Boolean is + Fptr: File_Ptr; + begin + declare + XP : aliased String := Path & ASCII.NUL; + XM : aliased String := "wx" & ASCII.NUL; + begin + Fptr := fopen(XP'Address, XM'Address); + end; + if Fptr = System.Null_Address then + return False; + end if; + fclose(Fptr); + return True; + end Create_File_Exclusive; + + -- Create a temporary file with a randomly generated name; + -- if the file with random component F exists, retry with + -- H(F) as a new random component. + Function Temporary_File(Path_Prefix: String; + Seed: Bitstream) return String is + Hash: Bitstream(1..64*8); + Name_Ctx: Keccak_Context; + + procedure Hash_Bitstream(Input: Bitstream) is + begin + KeccakBegin(Name_Ctx); + KeccakHash(Name_Ctx, Input); + KeccakEnd(Name_Ctx, Hash); + end Hash_Bitstream; + begin + Hash_Bitstream(Seed); + loop + declare + File_Name: String := Path_Prefix & ToHex(Hash); + begin + if Create_File_Exclusive(File_Name) then + return File_Name; + end if; + end; + Hash_Bitstream(Hash); + end loop; + end Temporary_File; + + function Temporary_File(Path_Prefix: String; + Seed: String) return String is + B: Bitstream(1..Seed'Length*8); + begin + ToBitstream(Seed, B); + return Temporary_File(Path_Prefix, B); + end Temporary_File; + +end Temporary_File; diff -uNr a/vtools/src/temporary_file.ads b/vtools/src/temporary_file.ads --- a/vtools/src/temporary_file.ads false +++ b/vtools/src/temporary_file.ads 578a4cb8c15c05b72d4558b4fc8cea70f53dba64bb8c447a72dd2eafdc790390f590c7dc6fc3a8f1cf053f283e5a9edb8aa97b051fb821c4b13e30819c2d0065 @@ -0,0 +1,3 @@ +package Temporary_File is + function Temporary_File(Path_Prefix: String; Seed: String) return String; +end Temporary_File; diff -uNr a/vtools/src/vpatch.adb b/vtools/src/vpatch.adb --- a/vtools/src/vpatch.adb 7fda2219570280da2045c9e7fcd4d122447580ab2a2d235a9789ae04581edd8e992a26da1dd4a2a454a2c94ff1c000eaa1b1c132a773f1d617b7def2731f7fd9 +++ b/vtools/src/vpatch.adb 8991e0b8fcb99f98e5154475a005c10cb4402a93f7afbd0067b053c7a92631711554c8f29cd054aff4945b6cfe3067269d37b121fb827162a215f6d579cb2086 @@ -1,6 +1,4 @@ with Bits; use Bits; -with Interfaces.C; -with Interfaces.C.Strings; with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; with Character_IO; use Character_IO; @@ -11,6 +9,7 @@ with Ada.Characters.Latin_1; with Ada.Sequential_IO; with SMG_Keccak; use SMG_Keccak; +with Temporary_File; use Temporary_File; procedure VPatch is package Latin_1 renames Ada.Characters.Latin_1; @@ -59,36 +58,22 @@ -- Temporary File - procedure MkTemp(Template: Interfaces.C.Strings.Chars_Ptr); - pragma Import(C, mktemp); - - function Temp_File_Name(Template: String) return String is - X: Interfaces.C.Strings.Chars_Ptr - := Interfaces.C.Strings.New_String(Template); - begin - MkTemp(X); - declare - Result: String := Interfaces.C.Strings.Value(X); - begin - Interfaces.C.Strings.Free(X); - return Result; - end; - end; - procedure Create_Temp(File : in out File_Type; Mode : in File_Mode := Out_File; - Template : in String := "vpatch.XXX"; + Prefix : in String; + Seed : in String := ""; Form : in String := "") is - Name: String := Temp_File_Name(Template); + Name: String := Temporary_File.Temporary_File(Prefix, Seed); begin Create(File, Mode, Name, Form); end; procedure Create_Temp(File : in out CIO.File_Type; Mode : in CIO.File_Mode := CIO.Out_File; - Template : in String := "vpatch.XXX"; + Prefix : in String; + Seed : in String := ""; Form : in String := "") is - Name: String := Temp_File_Name(Template); + Name: String := Temporary_File.Temporary_File(Prefix, Seed); begin Create(File, Mode, Name, Form); end; @@ -466,7 +451,7 @@ -- prepare keccak and open files KeccakBegin(To_Ctx); - Create_Temp(To_F, Template => "tmp.XXX"); + Create_Temp(To_F, Prefix => "/tmp/vpatch-", Seed => To_F_Name); case Op is when Op_Create => Has_Input_File := False; @@ -644,10 +629,11 @@ end if; case Op is when Op_Create | Op_Patch => - Dirs.Rename(Tmp_Name, To_F_Name); + Dirs.Copy_File(Tmp_Name, To_F_Name); when Op_Delete => - Dirs.Delete_File(Tmp_Name); + null; end case; + Dirs.Delete_File(Tmp_Name); end; exception