diff --git a/base/file.jl b/base/file.jl index 094327922dcc5..6d4fca5fda8c5 100644 --- a/base/file.jl +++ b/base/file.jl @@ -517,20 +517,27 @@ function mktemp(parent::AbstractString=tempdir(); cleanup::Bool=true) return (filename, Base.open(filename, "r+")) end +# generate a random string from random bytes +function _rand_string() + nchars = 10 + A = Vector{UInt8}(undef, nchars) + ccall((:SystemFunction036, :Advapi32), stdcall, UInt8, (Ptr{Cvoid}, UInt32), A, sizeof(A)) + + slug = Base.StringVector(10) + chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + for i = 1:nchars + slug[i] = chars[(A[i] % length(chars)) + 1] + end + return name = String(slug) +end + function tempname(parent::AbstractString=tempdir(); cleanup::Bool=true) isdir(parent) || throw(ArgumentError("$(repr(parent)) is not a directory")) - seed::UInt32 = rand(UInt32) - while true - if (seed & typemax(UInt16)) == 0 - seed += 1 - end - filename = _win_tempname(parent, seed) - if !ispath(filename) - cleanup && temp_cleanup_later(filename) - return filename - end - seed += 1 - end + name = _rand_string() + filename = joinpath(parent, temp_prefix * name) + @assert !ispath(filename) + cleanup && temp_cleanup_later(filename) + return filename end else # !windows diff --git a/test/file.jl b/test/file.jl index e15807c0adccb..ae3ce717060e0 100644 --- a/test/file.jl +++ b/test/file.jl @@ -50,6 +50,18 @@ end using Random +@testset "that temp names are actually unique" begin + temps = [tempname(cleanup=false) for _ = 1:100] + @test allunique(temps) + temps = map(1:100) do _ + path, io = mktemp(cleanup=false) + close(io) + rm(path, force=true) + return path + end + @test allunique(temps) +end + @testset "tempname with parent" begin t = tempname() @test dirname(t) == tempdir()