#load "install.fsx" open System open System.IO open System.IO.Compression open System.Security.Cryptography open Install let root = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")) let destination = root + "/plugins" let bytes = use buffer = new MemoryStream() use zip = new ZipArchive(buffer, ZipArchiveMode.Create, true) for name, content, mode in [ "plugin.json", "synthetic manifest", 0o100644; "rcon_linux_amd64", "synthetic backend", 0o100755 ] do let entry = zip.CreateEntry("quorate-rcon-app/" + name) entry.ExternalAttributes <- mode <<< 16 use writer = new StreamWriter(entry.Open()) writer.Write(content: string) zip.Dispose() buffer.ToArray() let expected = SHA256.HashData bytes |> Convert.ToHexString |> _.ToLowerInvariant() let input () = new MemoryStream(bytes) let snapshot () = Directory.GetFiles(destination, "*", SearchOption.AllDirectories) |> Array.map (fun path -> path, File.ReadAllBytes path, File.GetUnixFileMode path) try use first = input () unpack expected first destination let files = snapshot () assert (File.GetUnixFileMode(destination + "/quorate-rcon-app/plugin.json") = enum 0o644) assert (File.GetUnixFileMode(destination + "/quorate-rcon-app/rcon_linux_amd64") = enum 0o755) use second = input () unpack expected second destination assert (files = snapshot ()) let mutable rejected = false use changed = input () try unpack (String.replicate 64 "0") changed destination with :? InvalidOperationException -> rejected <- true assert rejected assert (files = snapshot ()) printfn "PASS: repeat installation, executable modes and checksum rejection before writes" finally Directory.Delete(root, true)