Skip to content

fs::rename fails when dest exists only on windows #31301

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

Closed
brson opened this issue Jan 30, 2016 · 6 comments
Closed

fs::rename fails when dest exists only on windows #31301

brson opened this issue Jan 30, 2016 · 6 comments
Labels
O-windows Operating system: Windows

Comments

@brson
Copy link
Contributor

brson commented Jan 30, 2016

This code fails on windows, not on linux:

use std::fs;

fn main() {
    let src = "testdir1";
    let dest = "testdir2";
    fs::create_dir(src).unwrap();
    fs::create_dir(dest).unwrap();
    fs::rename(src, dest).unwrap();
}

with

thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 5, message: "Access is denied." } }', ../src/libcore\result.rs:741
@brson brson added I-wrong O-windows Operating system: Windows labels Jan 30, 2016
@alexcrichton
Copy link
Member

I opened this awhile ago as #15836 and closed that as "not a bug" because we're just exporting the system's behavior. I'm personally inclined to say that this is something we shouldn't handle in the standard library (but may wish to document)

@nodakai
Copy link
Contributor

nodakai commented Jan 30, 2016

FYI, Java 7 introduced java.nio.file.Files.move() rather than fixing an decades-old API java.io.File.renameTo()

@retep998
Copy link
Member

Interestingly, the option MOVEFILE_REPLACE_EXISTING states This value cannot be used if lpNewFileName or lpExistingFileName names a directory. so even with that you wouldn't be able to overwrite an existing directory. That said since RemoveDirectory only works on empty directories, a really easy way to workaround this is if the first move fails, attempt to remove the directory and if that succeeds then attempt the move again.

@alexcrichton
Copy link
Member

I'd be wary of making a core operation like this do more than one I/O operation as it'd be tough to ensure that it remains "transactional".

We already attempt to make Windows/Unix behave the same by passing the flag @retep998 mentioned, and the remaining behavior is something I'd prefer to just document.

@retep998
Copy link
Member

I'm not suggesting that the standard library do that, documenting the current behavior should be sufficient. It's just a workaround that users can easily use right now if they do want that sort of behavior on Windows.

@barosl
Copy link
Contributor

barosl commented Feb 29, 2016

I tested MoveFileEx with MOVEFILE_REPLACE_EXISTING on Windows, and the explanation on MSDN seems to be a bit different from the actual implementation. lpNewFileName must not be a directory, yes, but lpExistingFileName can be a directory. So replacing a file with a directory using MoveFileEx is entirely possible (!). Note that the rename POSIX API demands both from and to are of the same type, which prevents such renaming/replacing.

barosl added a commit to barosl/rust that referenced this issue Apr 12, 2016
bors added a commit that referenced this issue Apr 12, 2016
Describe more platform-specific behaviors of `std::fs::rename`

I did some tests myself regarding the situation when both `from` and `to` exist, and the results were:

On Linux:

`from` | `to` | Result
---- | ---- | ----
Directory | Directory | Ok
Directory | File | Error
File | Directory | Error
File | File | Ok

On Windows:

`from` | `to` | Result
---- | ---- | ----
Directory | Directory | Error
Directory | File | Ok
File | Directory | Error
File | File | Ok

This is a bit against the official MSDN documentation, which says "(`MOVEFILE_REPLACE_EXISTING`) cannot be used if `lpNewFileName` or `lpExistingFileName` names a directory." As evidenced above, `lpExistingFileName` *can* be a directory.

I also mentioned the atomicity of the operation.

Fixes #31301.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
O-windows Operating system: Windows
Projects
None yet
Development

No branches or pull requests

5 participants