File::create should not also open the file


#1

I find it too surprising for the fs::File::create function to also open the file. Worse still, it also opens it in write-only mode. Can we limit it to merely create the file, as the name suggests.


#2

I can’t imagine a good counter argument


#3

Posix creates files with the open() system-call, which returns a file-handle. Windows creates files with the CreateFile system call, which returns a file-handle.

Creating and opening a file should be a single atomic operation at the system level, because otherwise you could be subject to race conditions when you first create the file, then later open it, what if someone swapped a new file in place between the two calls (create and open) and you aren’t actually writing to the file you intended to? Attacks like this are common.

I can’t think of an API that separates create from open… And in almost all cases, the open will return the file-handle with write-permissions enabled.


#4

Its purpose is to open a file, and the “method” of doing so is create/overwrite.


#5

Are you saying that you want to create a file without opening a File object for writing to it? If so that is a stupid idea.

Are you saying that File::create should error if the file already exists? If so, this is a valid point. I already brought up the option of creating a file without overwriting an existing file during the fs reform.


#6

If there is no use-case for creating a file without a need to write to it, then this function should be removed from the API. One can easily do a File open that also truncates. That way, things are more explicit.


#7

I wasn’t thinking of that, but it’s a great point. It really should complain (and panic) if the file already exits.


#8

Definitely there should be an equivalent to POSIX open with O_EXCL and O_CREAT which I cannot find in stdlib. Or is that on purpose because some systems does not offer such semantics?


#9

Why panic? It already returns a Result so you can just return an error for when the file already exists.


#10

But there is a use case for File::create. Whenever people want to create a file and write to it, they use File::create. If you don’t like that it restricts you to write only and want more control there is OpenOptions which lets you have very fine grained control over the behavior in a cross platform manner, and even in a platform specific manner through OpenOptionsExt.


#11

The use-case I was talking about: creating a file without opening it.

I talked to someone, who says the one use-case they can think of is creating lock files.


#13

Here is your create_file that creates a file and immediately drops the handle. This is how your proposal would effectively be implemented since there is no way to create a file without opening a handle to it on Windows or Posix.

fn create_file<P: AsPath + ?Sized>(path: &P) -> Result<()> {
    File::create(path).map(|| ())
}

#14

Is it fair to say that your objection is more to the name of the function (create) not fully expressing the behavior (create_and_open) than it is to the actual behavior of the function as defined? So that, if the function were renamed create_and_open without having the behavior change, that would address your concern?

I’m sympathetic to this. Perhaps a better name is open_new? But I can’t think of any reason that we’d want a function with the behavior that a file be created without returning a handle to write the file.


#15

Yeah, that would work.

A use-case is creating a lock file.


#16

A use-case is creating a lock file.

Operating system already returns opened handle so there is no use in function that closes it for you. You can easily close it ourself. Other systems programming languages has this kind of API for ages so it would be more confusing for experienced low-level programmers to not behave in similar manner.