Skip to content

Add exclusive flag to open() keywords (issue #33947) #33949

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Add exclusive flag to open() keywords (issue #33947) #33949

wants to merge 1 commit into from

Conversation

anaveragehuman
Copy link
Contributor

Fixes: #33947

julia> open("/tmp/aaaaa"; create = true, write = true) do f
       write(f, "aaa")
       end
3

julia> open("/tmp/aaaaa"; create = true, write = true, exclusive = true) do f
       write(f, "aaa")
       end
ERROR: SystemError: opening file "/tmp/aaaaa": File exists
Stacktrace:
 [1] systemerror(::String, ::Int32; extrainfo::Nothing) at ./error.jl:168
 [2] #systemerror#44 at ./error.jl:167 [inlined]
 [3] systemerror at ./error.jl:167 [inlined]
 [4] open(::String; read::Nothing, write::Bool, create::Bool, truncate::Nothing, append::Nothing, exclusive::Bool) at ./iostream.jl:257
 [5] open(::var"#11#12", ::String; kwargs::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol,Symbol,Symbol},NamedTuple{(:create, :write, :exclusive),Tuple{Bool,Bool,Bool}}}) at ./io.jl:299
 [6] top-level scope at REPL[4]:1

@stevengj stevengj added the filesystem Underlying file system and functions that use it label Nov 26, 2019
@stevengj
Copy link
Member

stevengj commented Nov 26, 2019

Looks like test/iostream.jl:85 (the test of Base.open_flags) needs to be updated.

Also needs a test.

@stevengj stevengj added the needs tests Unit tests are required for this change label Nov 26, 2019
@ararslan ararslan added the needs compat annotation Add !!! compat "Julia x.y" to the docstring label Nov 26, 2019
@StefanKarpinski
Copy link
Member

This needs some thought as to how it interacts with other boolean flag defaults. It seems like exclusive by itself should imply write and create? @vtjnash, are there other combinations that might make sense or is that the only one?

@anaveragehuman
Copy link
Contributor Author

anaveragehuman commented Nov 26, 2019

The manpage for O_EXCL says that "In general, the behavior of O_EXCL is undefined if it is used without O_CREAT". So from the C perspective, exclusive does not imply write or create.

@StefanKarpinski
Copy link
Member

That reads like exclusive should imply create by default. Does exclusive and read mean anything useful?

@anaveragehuman
Copy link
Contributor Author

Sorry, I should have included more of the manpage:

Ensure that this call creates the file: if this flag is specified in conjunction with O_CREAT, and pathname already exists, then open() fails with the error EEXIST.
When these two flags are specified, symbolic links are not followed: if pathname is a symbolic link, then open() fails regardless of where the symbolic link points.
In general, the behavior of O_EXCL is undefined if it is used without O_CREAT.

exclusive only makes sense in the context of create, and only applies if create is true. So we can:

  • have exclusive = true imply create = true as well.
  • have exclusive = true without create = true be an error.

While the first choice seems like a nice shortcut, the second is more explicit in saying what it does.

@stevengj
Copy link
Member

Could exclusive and read imply F_RDLCK? Maybe it could be called lock instead of exclusive?

@StefanKarpinski
Copy link
Member

I'm not so sure that this API should be squeezed into the open function, to be honest...

@garborg
Copy link
Contributor

garborg commented Jun 4, 2020

Assuming the set of imports below is the right place to reach in the meantime, I'd appreciate having the functionality somewhere (would never have patched myself it together without the link to Pidfile.jl in #33947):

    using Base: IOError, UV_EEXIST
    using Base.Filesystem: JL_O_CREAT, JL_O_EXCL, JL_O_WRONLY, JL_O_RDWR

    function tryopen_exclusive(f, path::String, mode::String="w"; modes::Integer = 0o444)
        flag = if mode == "w+"
            JL_O_RDWR
        elseif mode == "w"
            JL_O_WRONLY
        else
            throw(ArgumentError("`mode` can be \"w\" or \"w+\""))
        end

        try
            io = Base.Filesystem.open(path, flag | JL_O_CREAT | JL_O_EXCL, modes)
            try
                f(io)
            finally
                close(io)
            end
        catch ex
            (isa(ex, IOError) && ex.code == UV_EEXIST) || rethrow(ex)
            return false
        end
        return true
    end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
filesystem Underlying file system and functions that use it needs compat annotation Add !!! compat "Julia x.y" to the docstring needs tests Unit tests are required for this change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

wanted: open(create=true, exclusive=true) dead or alive
5 participants