async-rs / async-std

Async version of the Rust standard library

Home Page:https://async.rs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Fix docs for `fs::rename()`

riveroon opened this issue · comments

Found another minor documentation error. Yay :)
Maybe I'm missing something, but fs::rename()'s docs also have the wrong behavior documented:

If a file or directory already exists at the target location, it will be overwritten by this operation.

However, async-std's rename() uses std's rename() internally, which currently MAY return an error if to exists:

replacing the original file if to already exists.

Platform-specific behavior

This function currently corresponds to the rename function on Unix and the MoveFileEx function with the MOVEFILE_REPLACE_EXISTING flag on Windows.

Because of this, the behavior when both from and to exist differs. On Unix, if from is a directory, to must also be an (empty) directory. If from is not a directory, to must also be not a directory. In contrast, on Windows, from can be anything, but to must not be a directory.

Therefore, the simple statement

If a file or directory already exists at the target location, it will be overwritten by this operation.

does not cover the cases where it WILL return an error, which is:

Unix (and Linux):

  • from and to is an existing directory and a file, or a file and a directory respectively.
  • from and to are both directories, but to is not empty.

Windows

  • from is a existing directory.

This behavior can be demonstrated with the following code:

fn main() -> io::Result<()> {
    async_std::task::block_on(async {
        let from = Path::new("./foo");

        //Create some directories...
        fs::create_dir_all(from).await?;
        fs::create_dir_all("./bar/baz").await?;

        //This should work... or does it?
        fs::rename(from, "./bar").await
    })
}

(Note that this uses fs::create_dir_all() to avoid returning an error if the directories already exist, see #1051)

Running the above code prints

Error: Custom { kind: PermissionDenied, error: VerboseError { source: Os { code: 5, kind: PermissionDenied, message: "Access is denied." }, message: "could not rename `./foo` to `./bar`" } }

for Windows, and

Error: Custom { kind: DirectoryNotEmpty, error: VerboseError { source: Os { code: 39, kind: DirectoryNotEmpty, message: "Directory not empty" }, message: "could not rename `./foo` to `./bar`" } }

for Linux.