async-rs / async-rs/async-std

Fix docs for `fs::rename()`

Open
#1,053 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
4.1k
Forks
339
PR merge metrics
No merged PRs in 30d

Description

Found another minor documentation error. Yay :)
Maybe I'm missing something, but [`fs::rename()`](https://docs.rs/async-std/latest/async_std/fs/fn.rename.html)'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()`](https://doc.rust-lang.org/std/fs/fn.rename.html) [internally](https://docs.rs/async-std/latest/src/async_std/fs/rename.rs.html#39), which currently MAY return an error if `to` exists:

>replacing the original **_file_** if to already exists.

>[**Platform-specific behavior**](https://doc.rust-lang.org/std/fs/fn.rename.html#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:

```rust
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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.