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

fs::rename behavior differs on windows #15836

Closed
alexcrichton opened this issue Jul 20, 2014 · 9 comments
Closed

fs::rename behavior differs on windows #15836

alexcrichton opened this issue Jul 20, 2014 · 9 comments
Labels
O-windows Operating system: Windows

Comments

@alexcrichton
Copy link
Member

This program will succeed on unix but fail to succeed on windows. The unix behavior is surprising to me!

use std::io::{fs, UserRWX};

fn main() {
    fs::mkdir(&Path::new("test"), UserRWX).unwrap();
    fs::mkdir(&Path::new("test2"), UserRWX).unwrap();
    fs::rename(&Path::new("test"), &Path::new("test2")).unwrap();
}
@abonander
Copy link
Contributor

Actually, looking at the sources, the Windows implementation is surprising to me.

The Windows implementation of fs::rename in libnative/io/file_win32.rs:

pub fn rename(old: &CString, new: &CString) -> IoResult<()> {
    let old = try!(to_utf16(old));
    let new = try!(to_utf16(new));
    super::mkerr_winbool(unsafe {
        libc::MoveFileExW(old.as_ptr(), new.as_ptr(),
        libc::MOVEFILE_REPLACE_EXISTING)
    })
}

And the documentation of MoveFileEx (MoveFileExW is the variant that accepts Unicode filenames):

MOVEFILE_REPLACE_EXISTING

If a file named lpNewFileName exists, the function replaces its contents with the contents of the lpExistingFileName file, provided that security requirements regarding access control lists (ACLs) are met. For more information, see the Remarks section of this topic.

This value cannot be used if lpNewFileName or lpExistingFileName names a directory.

MoveFile can be used on directories, but it cannot overwrite an existing directory, empty or not.

The Unix implementation succeeds because the target directory can be overwritten if it is empty:
http://www.gnu.org/software/libc/manual/html_node/Renaming-Files.html

So fs::rename shouldn't work on directories at all on Windows currently, and the platform-dependent behavior would definitely be frustrating. It should be fixed for Windows, but we'd still have disjoint behavior between platforms. Maybe that part could be fixed with a documentation update.

@brson
Copy link
Contributor

brson commented Aug 27, 2014

The equivalent python and Java programs succeed on Linux, so perhaps success is the correct result.

@brson
Copy link
Contributor

brson commented Aug 27, 2014

The 'only if the directory is empty' rule is pretty bizarre. Is that really the cross-platform rule we want?

@alexcrichton
Copy link
Member Author

I've been rethinking the modification to unlink to unify windows/unix due to the non-atomicity of the operation, I'm not sure if we'd want to add more non-atomicity to either windows or unix, so this may just be an unfortunate fact of life.

@brson
Copy link
Contributor

brson commented Sep 12, 2014

It seems like there's a lot of precedent for unifying I/O semantics from other languages though.

@untitaker
Copy link
Contributor

FWIW Python's rename fails on Windows if the destination path exists: https://docs.python.org/2/library/os.html#os.rename

@alexcrichton
Copy link
Member Author

With the I/O reform having happened since this was opened, I'm going to close this as "not a bug"

@untitaker
Copy link
Contributor

What is the behavior now?

@alexcrichton
Copy link
Member Author

We just shell out to the system call and reexport that behavior.

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

4 participants