Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tempname: add parent and cleanup arguments #33090

Merged
merged 3 commits into from
Aug 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ New library functions
---------------------

* The `splitpath` function now accepts any `AbstractString` whereas previously it only accepted paths of type `String` ([#33012]).
* The `tempname` function now takes an optional `parent::AbstractString` argument to give it a directory in which to attempt to produce a temporary path name ([#33090]).
* The `tempname` function now takes a `cleanup::Bool` keyword argument defaulting to `true`, which causes the process to try to ensure that any file or directory at the path returned by `tempname` is deleted upon process exit ([#33090]).


Standard library changes
Expand Down
38 changes: 30 additions & 8 deletions base/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -500,29 +500,32 @@ function mktemp(parent::AbstractString=tempdir(); cleanup::Bool=true)
return (filename, Base.open(filename, "r+"))
end

function tempname()
parent = tempdir()
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)
StefanKarpinski marked this conversation as resolved.
Show resolved Hide resolved
cleanup && temp_cleanup_later(filename)
return filename
end
seed += 1
end
end

else # !windows

# Obtain a temporary filename.
function tempname()
d = tempdir() # tempnam ignores TMPDIR on darwin
p = ccall(:tempnam, Cstring, (Cstring, Cstring), d, temp_prefix)
function tempname(parent::AbstractString=tempdir(); cleanup::Bool=true)
isdir(parent) || throw(ArgumentError("$(repr(parent)) is not a directory"))
p = ccall(:tempnam, Cstring, (Cstring, Cstring), parent, temp_prefix)
systemerror(:tempnam, p == C_NULL)
s = unsafe_string(p)
Libc.free(p)
cleanup && temp_cleanup_later(s)
return s
end

Expand All @@ -540,16 +543,35 @@ end # os-test


"""
tempname()
tempname(parent=tempdir(); cleanup=true) -> String

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.
created. The path is likely to be unique, but this cannot be guaranteed due to
the very remote posibility of two simultaneous calls to `tempname` generating
the same file name. The name is guaranteed to differ from all files already
existing at the time of the call to `tempname`.

When called with no arguments, the temporary name will be an absolute path to a
temporary name in the system temporary directory as given by `tempdir()`. If a
`parent` directory argument is given, the temporary path will be in that
directory instead.

The `cleanup` option controls whether the process attempts to delete the
returned path automatically when the process exits. Note that the `tempname`
function does not create any file or directory at the returned location, so
there is nothing to cleanup unless you create a file or directory there. If
you do and `clean` is `true` it will be deleted upon process termination.

!!! compat "Julia 1.4"
The `parent` and `cleanup` arguments were added in 1.4. Prior to Julia 1.4
the path `tempname` would never be cleaned up at process termination.

!!! warning

This can lead to security holes if another process obtains the same
file name and creates the file before you are able to. Open the file with
`JL_O_EXCL` if this is a concern. Using [`mktemp()`](@ref) is also recommended instead.
`JL_O_EXCL` if this is a concern. Using [`mktemp()`](@ref) is also
recommended instead.
"""
tempname()

Expand Down
20 changes: 20 additions & 0 deletions test/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ if !Sys.iswindows()
cd(pwd_)
end

using Random

@testset "tempname with parent" begin
t = tempname()
@test dirname(t) == tempdir()
mktempdir() do d
t = tempname(d)
@test dirname(t) == d
end
@test_throws ArgumentError tempname(randstring())
end

child_eval(code::String) = eval(Meta.parse(readchomp(`$(Base.julia_cmd()) -E $code`)))

@testset "mktemp/dir basic cleanup" begin
Expand All @@ -67,6 +79,14 @@ child_eval(code::String) = eval(Meta.parse(readchomp(`$(Base.julia_cmd()) -E $co
# mktempdir with cleanup
t = child_eval("t = mktempdir(); touch(joinpath(t, \"file.txt\")); t")
@test !ispath(t)
# tempname without cleanup
t = child_eval("t = tempname(cleanup=false); touch(t); t")
@test isfile(t)
rm(t, force=true)
@test !ispath(t)
# tempname with cleanup
t = child_eval("t = tempname(); touch(t); t")
@test !ispath(t)
end

import Base.Filesystem: TEMP_CLEANUP_MIN, TEMP_CLEANUP_MAX, TEMP_CLEANUP
Expand Down