Skip to content

Commit 2b08860

Browse files
musmararslan
authored andcommitted
Use libuv for tempdir function (#31434)
Fixes the Windows tempdir function returning a path with the trailing slash.
1 parent f7f482b commit 2b08860

File tree

2 files changed

+57
-20
lines changed

2 files changed

+57
-20
lines changed

base/file.jl

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -424,18 +424,34 @@ function touch(path::AbstractString)
424424
path
425425
end
426426

427-
const temp_prefix = "jl_"
428-
429-
if Sys.iswindows()
427+
"""
428+
tempdir()
430429
430+
Gets the path of the temporary directory. On Windows, `tempdir()` uses the first environment
431+
variable found in the ordered list `TMP`, `TEMP`, `USERPROFILE`. On all other operating
432+
systems, `tempdir()` uses the first environment variable found in the ordered list `TMPDIR`,
433+
`TMP`, `TEMP`, and `TEMPDIR`. If none of these are found, the path `"/tmp"` is used.
434+
"""
431435
function tempdir()
432-
temppath = Vector{UInt16}(undef, 32767)
433-
lentemppath = ccall(:GetTempPathW, stdcall, UInt32, (UInt32, Ptr{UInt16}), length(temppath), temppath)
434-
windowserror("GetTempPath", lentemppath >= length(temppath) || lentemppath == 0)
435-
resize!(temppath, lentemppath)
436-
return transcode(String, temppath)
436+
buf = Base.StringVector(AVG_PATH - 1) # space for null-terminator implied by StringVector
437+
sz = RefValue{Csize_t}(length(buf) + 1) # total buffer size including null
438+
while true
439+
rc = ccall(:uv_os_tmpdir, Cint, (Ptr{UInt8}, Ptr{Csize_t}), buf, sz)
440+
if rc == 0
441+
resize!(buf, sz[])
442+
return String(buf)
443+
elseif rc == Base.UV_ENOBUFS
444+
resize!(buf, sz[] - 1) # space for null-terminator implied by StringVector
445+
else
446+
uv_error(:tmpdir, rc)
447+
end
448+
end
437449
end
438450

451+
const temp_prefix = "jl_"
452+
453+
if Sys.iswindows()
454+
439455
function _win_tempname(temppath::AbstractString, uunique::UInt32)
440456
tempp = cwstring(temppath)
441457
temppfx = cwstring(temp_prefix)
@@ -481,9 +497,6 @@ function tempname()
481497
return s
482498
end
483499

484-
# Obtain a temporary directory's path.
485-
tempdir() = dirname(tempname())
486-
487500
# Create and return the name of a temporary file along with an IOStream
488501
function mktemp(parent=tempdir())
489502
b = joinpath(parent, temp_prefix * "XXXXXX")
@@ -496,13 +509,6 @@ end
496509
end # os-test
497510

498511

499-
"""
500-
tempdir()
501-
502-
Obtain the path of a temporary directory (possibly shared with other processes).
503-
"""
504-
tempdir()
505-
506512
"""
507513
tempname()
508514

test/file.jl

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,39 @@ close(s)
244244
end
245245
end
246246

247-
my_tempdir = tempdir()
248-
@test isdir(my_tempdir) == true
247+
@testset "tempdir" begin
248+
my_tempdir = tempdir()
249+
@test isdir(my_tempdir)
250+
@test my_tempdir[end] != '/'
251+
@test my_tempdir[end] != '\\'
252+
253+
var = Sys.iswindows() ? "TMP" : "TMPDIR"
254+
PATH_PREFIX = Sys.iswindows() ? "C:\\" : "/tmp/"
255+
# Warning: On Windows uv_os_tmpdir internally calls GetTempPathW. The max string length for
256+
# GetTempPathW is 261 (including the implied trailing backslash), not the typical length 259.
257+
# We thus use 260 (with implied trailing slash backlash this then gives 261 chars) and
258+
# subtract 9 to account for i = 0:9.
259+
MAX_PATH = (Sys.iswindows() ? 260-9 : 1024) - length(PATH_PREFIX)
260+
for i = 0:8
261+
local tmp = PATH_PREFIX * "x"^MAX_PATH * "123456789"[1:i]
262+
@test withenv(var => tmp) do
263+
tempdir()
264+
end == (tmp)
265+
end
266+
for i = 9
267+
local tmp = PATH_PREFIX * "x"^MAX_PATH * "123456789"[1:i]
268+
if Sys.iswindows()
269+
# libuv bug
270+
@test_broken withenv(var => tmp) do
271+
tempdir()
272+
end == tmp
273+
else
274+
@test withenv(var => tmp) do
275+
tempdir()
276+
end == tmp
277+
end
278+
end
279+
end
249280

250281
let path = tempname()
251282
# issue #9053

0 commit comments

Comments
 (0)