diff -uNr a/vtools/manifest b/vtools/manifest --- a/vtools/manifest bb7b5cb38ad1749d191b26362c637e55b9abc4a4b689885ececc5c7eea142d86ef56278874b665bb0c14f73819f2857e33f888bcfdc2bde3f3401f241fa566a4 +++ b/vtools/manifest 6e0728447dd05a8e1d4dd21a9647ac87e1e66b16e1cb15dca1a9e775907767fcae8b4db6be152aba863bee3bf15cfb665512a45f001593bfd990b43e4087d3ef @@ -7,3 +7,4 @@ 517100 phf vtools_fixes_static_tohex Fixes for xalloc's use of static inline courtesy of spyked, fix broken ToHex implementation 517100 phf vtools_vpatch_newline Vpatch tool support for "No newline at end of file" directive. 543200 phf vtools_ksum Ksum standalone keccak hasher +547300 bvt vtools_tempfile_standalone_notmp 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 23dcf3c0eff5d5ca20ce1c5091e4dc9b739d2d98630208aa16dec1298a13c28962089c0311e8e50af9801c026e79f003fe8b9ce9341c351cb4e4556347d14734 +++ b/vtools/src/vpatch.adb 11c17fedc3c0442c3ca93589a47f5fdc4b9ab3bab4361a96cbff4bbb15e031d44bfeceed59e5ea6942f552fca67214c3fc9d956779f77b8a0e7432ca609f779f @@ -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;