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;