From 5e2ff127f861ead7b08ce782b830069d77c97f2f Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 15 Jan 2018 12:38:08 -0500 Subject: [PATCH] make `tempname` on windows match unix behavior. fixes #9053 (#25530) also deprecate `tempname(::UInt32)` and add a warning to the docs. --- NEWS.md | 5 ++++- base/deprecated.jl | 7 +++++++ base/file.jl | 32 +++++++++++++++++++++++++++----- base/pkg/entry.jl | 16 +++++----------- test/file.jl | 8 ++++---- test/replcompletions.jl | 1 + 6 files changed, 48 insertions(+), 21 deletions(-) diff --git a/NEWS.md b/NEWS.md index 57548f1a86be7..a66404e1cf104 100644 --- a/NEWS.md +++ b/NEWS.md @@ -385,6 +385,9 @@ This section lists changes that do not have deprecation warnings. to get the old behavior (only "space" characters are considered as word separators), use the keyword `wordsep=isspace`. + * The `tempname` function used to create a file on Windows but not on other + platforms. It now never creates a file ([#9053]). + Library improvements -------------------- @@ -1194,4 +1197,4 @@ Command-line option changes [#25231]: https://github.com/JuliaLang/julia/issues/25231 [#25365]: https://github.com/JuliaLang/julia/issues/25365 [#25424]: https://github.com/JuliaLang/julia/issues/25424 -[#25532]: https://github.com/JuliaLang/julia/issues/25532 \ No newline at end of file +[#25532]: https://github.com/JuliaLang/julia/issues/25532 diff --git a/base/deprecated.jl b/base/deprecated.jl index 63db8ccadd23a..93e97f884d544 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -2789,6 +2789,13 @@ end @deprecate findn(x::AbstractMatrix) (I = find(!iszero, x); (getindex.(I, 1), getindex.(I, 2))) @deprecate findn(a::AbstractArray{T, N}) where {T, N} (I = find(!iszero, x); ntuple(i -> getindex.(I, i), N)) +# issue #9053 +if Sys.iswindows() +function Filesystem.tempname(uunique::UInt32) + error("`tempname(::UInt32)` is discontinued.") +end +end + # END 0.7 deprecations # BEGIN 1.0 deprecations diff --git a/base/file.jl b/base/file.jl index a38275a23ef4f..104e8cc411d2d 100644 --- a/base/file.jl +++ b/base/file.jl @@ -265,9 +265,9 @@ function tempdir() resize!(temppath,lentemppath) return transcode(String, temppath) end -tempname(uunique::UInt32=UInt32(0)) = tempname(tempdir(), uunique) + const temp_prefix = cwstring("jl_") -function tempname(temppath::AbstractString,uunique::UInt32) +function _win_tempname(temppath::AbstractString, uunique::UInt32) tempp = cwstring(temppath) tname = Vector{UInt16}(uninitialized, 32767) uunique = ccall(:GetTempFileNameW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32,Ptr{UInt16}), tempp,temp_prefix,uunique,tname) @@ -280,7 +280,7 @@ function tempname(temppath::AbstractString,uunique::UInt32) end function mktemp(parent=tempdir()) - filename = tempname(parent, UInt32(0)) + filename = _win_tempname(parent, UInt32(0)) return (filename, Base.open(filename, "r+")) end @@ -290,7 +290,7 @@ function mktempdir(parent=tempdir()) if (seed & typemax(UInt16)) == 0 seed += 1 end - filename = tempname(parent, seed) + filename = _win_tempname(parent, seed) ret = ccall(:_wmkdir, Int32, (Ptr{UInt16},), cwstring(filename)) if ret == 0 return filename @@ -300,6 +300,21 @@ function mktempdir(parent=tempdir()) end end +function tempname() + parent = tempdir() + seed::UInt32 = rand(UInt32) + while true + if (seed & typemax(UInt16)) == 0 + seed += 1 + end + filename = _win_tempname(parent, seed) + if !ispath(filename) + return filename + end + seed += 1 + end +end + else # !windows # Obtain a temporary filename. function tempname() @@ -343,7 +358,14 @@ tempdir() """ tempname() -Generate a unique temporary file path. +Generate a temporary file path. This function only returns a path; no file is +created. The path is likely to be unique, but this cannot be guaranteed. + +!!! warning + + This can lead to race conditions if another process obtains the same + file name and creates the file before you are able to. + Using [`mktemp()`](@ref) is recommended instead. """ tempname() diff --git a/base/pkg/entry.jl b/base/pkg/entry.jl index 758a8b2f7bc2b..f52f7674f4851 100644 --- a/base/pkg/entry.jl +++ b/base/pkg/entry.jl @@ -633,19 +633,13 @@ function build!(pkgs::Vector, seen::Set, errfile::AbstractString) end function build!(pkgs::Vector, errs::Dict, seen::Set=Set()) - errfile = tempname() - touch(errfile) # create empty file - try + mktemp() do errfile, f build!(pkgs, seen, errfile) - open(errfile, "r") do f - while !eof(f) - pkg = deserialize(f) - err = deserialize(f) - errs[pkg] = err - end + while !eof(f) + pkg = deserialize(f) + err = deserialize(f) + errs[pkg] = err end - finally - isfile(errfile) && Base.rm(errfile) end end diff --git a/test/file.jl b/test/file.jl index 4c51cf2616b55..ceae11b6f3996 100644 --- a/test/file.jl +++ b/test/file.jl @@ -218,10 +218,10 @@ close(s) my_tempdir = tempdir() @test isdir(my_tempdir) == true -path = tempname() -# Issue #9053. -@test ispath(path) == Sys.iswindows() -ispath(path) && rm(path) +let path = tempname() + # issue #9053 + @test !ispath(path) +end (p, f) = mktemp() print(f, "Here is some text") diff --git a/test/replcompletions.jl b/test/replcompletions.jl index 66feeada0ba96..acc076d7b92dc 100644 --- a/test/replcompletions.jl +++ b/test/replcompletions.jl @@ -776,6 +776,7 @@ end if Sys.iswindows() tmp = tempname() + touch(tmp) path = dirname(tmp) file = basename(tmp) temp_name = basename(path)