diff -uNr a/vtools/manifest b/vtools/manifest --- a/vtools/manifest f0dd63123a8745028d31cb4db9674994382318cbdc7c613d9886bf55c1ceacd8b22a7a4d9573fcf09ef53363caf0942ce2bcb3183e04abd09be6981a38208b32 +++ b/vtools/manifest 330fa25a9dc07c74d18d1b5489b17b8234ff442d0e3cb527263bea3183d41c5323867175a48a86c55c081c1225d90bb00236cbfe9549474ef77afb85b6b6544b @@ -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-25 bvt +Standalone temporary file generation code; creates temporary files in the vpatch work directory. 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 4747969b6df8aa268419f3259a757d1fee33b8b4a7d440b8adfe07c7f6335060b533791908ff1f5022ecfb51708277a59b0876812c4343e17df1f3f0de0ea767 @@ -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 94160eed9e9d4daf0b80dea4cc22b8060554e972e84b072ef7b5227dbcde4f5b0367c0706a6885a00f1151a59039a94db196370dfcbe941e352ac8838ea3a03e @@ -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 548d5a8f4f97e8cbfe84822335672c485b6e713e0e1620f706464090e75a1850c059e681c0d35edd23c444cac55d8ecd5180a53f6b570c46c632c4c34a7bee99 +++ b/vtools/src/vpatch.adb 2698cfb2456be817451e0e79abb76d94adf9f5a0befad34a52ed91d15342cd57e229b0f2a76f5f1da8b7f8824bedb7ef42d1832aaea71e2405d012f6e344da7e @@ -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 => "vpatch-", Seed => To_F_Name); case Op is when Op_Create => Has_Input_File := False;