diff --git a/base/file.jl b/base/file.jl index 54f7323987860..0d5d09fbf819b 100644 --- a/base/file.jl +++ b/base/file.jl @@ -424,18 +424,34 @@ function touch(path::AbstractString) path end -const temp_prefix = "jl_" - -if Sys.iswindows() +""" + tempdir() +Gets the path of the temporary directory. On Windows, `tempdir()` uses the first environment +variable found in the ordered list `TMP`, `TEMP`, `USERPROFILE`. On all other operating +systems, `tempdir()` uses the first environment variable found in the ordered list `TMPDIR`, +`TMP`, `TEMP`, and `TEMPDIR`. If none of these are found, the path `"/tmp"` is used. +""" function tempdir() - temppath = Vector{UInt16}(undef, 32767) - lentemppath = ccall(:GetTempPathW, stdcall, UInt32, (UInt32, Ptr{UInt16}), length(temppath), temppath) - windowserror("GetTempPath", lentemppath >= length(temppath) || lentemppath == 0) - resize!(temppath, lentemppath) - return transcode(String, temppath) + buf = Base.StringVector(AVG_PATH - 1) # space for null-terminator implied by StringVector + sz = RefValue{Csize_t}(length(buf) + 1) # total buffer size including null + while true + rc = ccall(:uv_os_tmpdir, Cint, (Ptr{UInt8}, Ptr{Csize_t}), buf, sz) + if rc == 0 + resize!(buf, sz[]) + return String(buf) + elseif rc == Base.UV_ENOBUFS + resize!(buf, sz[] - 1) # space for null-terminator implied by StringVector + else + uv_error(:tmpdir, rc) + end + end end +const temp_prefix = "jl_" + +if Sys.iswindows() + function _win_tempname(temppath::AbstractString, uunique::UInt32) tempp = cwstring(temppath) temppfx = cwstring(temp_prefix) @@ -481,9 +497,6 @@ function tempname() return s end -# Obtain a temporary directory's path. -tempdir() = dirname(tempname()) - # Create and return the name of a temporary file along with an IOStream function mktemp(parent=tempdir()) b = joinpath(parent, temp_prefix * "XXXXXX") @@ -496,13 +509,6 @@ end end # os-test -""" - tempdir() - -Obtain the path of a temporary directory (possibly shared with other processes). -""" -tempdir() - """ tempname() diff --git a/test/file.jl b/test/file.jl index eec6bcf79d3a5..c711a9571a326 100644 --- a/test/file.jl +++ b/test/file.jl @@ -244,8 +244,39 @@ close(s) end end -my_tempdir = tempdir() -@test isdir(my_tempdir) == true +@testset "tempdir" begin + my_tempdir = tempdir() + @test isdir(my_tempdir) + @test my_tempdir[end] != '/' + @test my_tempdir[end] != '\\' + + var = Sys.iswindows() ? "TMP" : "TMPDIR" + PATH_PREFIX = Sys.iswindows() ? "C:\\" : "/tmp/" + # Warning: On Windows uv_os_tmpdir internally calls GetTempPathW. The max string length for + # GetTempPathW is 261 (including the implied trailing backslash), not the typical length 259. + # We thus use 260 (with implied trailing slash backlash this then gives 261 chars) and + # subtract 9 to account for i = 0:9. + MAX_PATH = (Sys.iswindows() ? 260-9 : 1024) - length(PATH_PREFIX) + for i = 0:8 + local tmp = PATH_PREFIX * "x"^MAX_PATH * "123456789"[1:i] + @test withenv(var => tmp) do + tempdir() + end == (tmp) + end + for i = 9 + local tmp = PATH_PREFIX * "x"^MAX_PATH * "123456789"[1:i] + if Sys.iswindows() + # libuv bug + @test_broken withenv(var => tmp) do + tempdir() + end == tmp + else + @test withenv(var => tmp) do + tempdir() + end == tmp + end + end +end let path = tempname() # issue #9053