Skip to content

xfs support in test_rename_directory_to_non_empty_directory#156762

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
ferrocene:hoverbear/xfs-test-fix
Jun 8, 2026
Merged

xfs support in test_rename_directory_to_non_empty_directory#156762
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
ferrocene:hoverbear/xfs-test-fix

Conversation

@Hoverbear

@Hoverbear Hoverbear commented May 19, 2026

Copy link
Copy Markdown
Contributor

While running Ferrocene's test suite we use a variety of filesystems, including XFS. Those systems caught a failing test in a recent upstream pull.

The test failing:

#[test]
#[cfg_attr(target_vendor = "win7", ignore = "Unsupported under Windows 7.")]
fn test_rename_directory_to_non_empty_directory() {
// Renaming a directory over a non-empty existing directory should fail.
let tmpdir: TempDir = tmpdir();
let source_path = tmpdir.join("source_directory");
let target_path = tmpdir.join("target_directory");
fs::create_dir(&source_path).unwrap();
fs::create_dir(&target_path).unwrap();
fs::write(target_path.join("target_file.txt"), b"target hello world").unwrap();
let err = fs::rename(source_path, target_path).unwrap_err();
assert_eq!(err.kind(), ErrorKind::DirectoryNotEmpty);
}

It was recently removed from being Windows-only in: a0298aa#diff-0ec4075fea7f5f4cc82c306e975ae7638b1fc500d30c11a83f337a69ef1dfd65L2177

Seemingly on XFS only, the AlreadyExists variant is returned instead.

This workaround allows both possible errors. I am unsure at this time if it is a signal of incorrectness in Rust somewhere, but on Python a similar failure can be noted:

ana@autonoma ~/git/ferrocene/scratch
❯ mkdir blap flap
ana@autonoma ~/git/ferrocene/scratch
❯ touch flap/zap
ana@autonoma ~/git/ferrocene/scratch
❯ python
Python 3.13.13 (main, May 15 2026, 12:38:54) [GCC 15.2.1 20260214] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.rename("blap", "flap")
Traceback (most recent call last):
  File "<python-input-3>", line 1, in <module>
    os.rename("blap", "flap")
    ~~~~~~~~~^^^^^^^^^^^^^^^^
FileExistsError: [Errno 17] File exists: 'blap' -> 'flap'
ana@autonoma ~/git/ferrocene/scratch
❯ cd /tmp/
ana@autonoma /tmp
❯ mkdir blap flap
ana@autonoma /tmp
❯ touch flap/zap
ana@autonoma /tmp
❯ python
Python 3.13.13 (main, May 15 2026, 12:38:54) [GCC 15.2.1 20260214] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.rename("blap", "flap")
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    os.rename("blap", "flap")
    ~~~~~~~~~^^^^^^^^^^^^^^^^
OSError: [Errno 39] Directory not empty: 'blap' -> 'flap'

I tested on ext4, tmpfs, overlayfs, btrfs, and xfs. Only XFS seems to display this error.

Reproduction

On Linux hosts:

use clap::Parser;

struct Args {
    /// Destination to try
    #[arg()]
    path: std::path::PathBuf,
}

fn main() {
    let args = Args::parse();

    // Renaming a directory over a non-empty existing directory should fail.
    let tmpdir = std::path::Path::new(&args.path);
    std::fs::create_dir_all(tmpdir).unwrap();

    let source_path = tmpdir.join("source_directory");
    let target_path = tmpdir.join("target_directory");

    std::fs::create_dir(&source_path).unwrap();
    std::fs::create_dir(&target_path).unwrap();

    let target_path_file = target_path.join("target_file.txt");
    std::fs::write(target_path.join("target_file.txt"), b"target hello world").unwrap();
    println!("wrote {target_path_file:?}");

    println!("{source_path:?} -> {target_path:?}");
    let err = std::fs::rename(source_path, target_path).unwrap_err();
    assert_eq!(err.kind(), std::io::ErrorKind::DirectoryNotEmpty);
}
XFS_BLOCK=image-xfs
truncate -s 512M image-xfs
mkfs.xfs -q image-xfs
mkdir mnt-xfs
sudo mount -o loop image-xfs mnt-xfs
sudo chmod 777 mnt-xfs
cargo run -- mnt-xfs/

Output:

wrote "mnt-xfs/target_directory/target_file.txt"
"mnt-xfs/source_directory" -> "mnt-xfs/target_directory"

thread 'main' (267220) panicked at src/main.rs:30:5:
assertion `left == right` failed
  left: AlreadyExists
 right: DirectoryNotEmpty
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

You can run this test directly:

./x.py --stage 2 test library/std --target x86_64-unknown-linux-gnu -- fs::tests::test_rename_directory_to_non_empty_directory --nocapture

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 19, 2026
@rustbot

rustbot commented May 19, 2026

Copy link
Copy Markdown
Collaborator

r? @Mark-Simulacrum

rustbot has assigned @Mark-Simulacrum.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 8 candidates

@rust-log-analyzer

This comment has been minimized.

@Hoverbear Hoverbear force-pushed the hoverbear/xfs-test-fix branch from 06a46ea to c7a9cdc Compare May 19, 2026 22:27
Comment thread library/std/src/fs/tests.rs Outdated
@the8472

the8472 commented May 20, 2026

Copy link
Copy Markdown
Member

This workaround allows both possible errors. I am unsure at this time if it is a signal of incorrectness in Rust somewhere

The linux rename(2) manpage says

 ENOTEMPTY or EEXIST
        newpath is a nonempty directory, that is, contains entries other than "." and "..".

So this looks correct.

@Mark-Simulacrum

Copy link
Copy Markdown
Member

r=me with commits squashed.

Thanks!

@Mark-Simulacrum

Copy link
Copy Markdown
Member

@bors squash

Actually I'll just go via our squash tooling.

@rust-bors

rust-bors Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

🔑 The Allow edits by maintainers option is not enabled on this PR. It is required for squashing to work.

@Mark-Simulacrum

Copy link
Copy Markdown
Member

Ah, ok. @rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 7, 2026
@rustbot

rustbot commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

Seemingly on XFS only, the `AlreadyExists` variant is returned.

Reproducible on Linux hosts:

```rust
use clap::Parser;

struct Args {
    /// Destination to try
    #[arg()]
    path: std::path::PathBuf,
}

fn main() {
    let args = Args::parse();

    // Renaming a directory over a non-empty existing directory should fail.
    let tmpdir = std::path::Path::new(&args.path);
    std::fs::create_dir_all(tmpdir).unwrap();

    let source_path = tmpdir.join("source_directory");
    let target_path = tmpdir.join("target_directory");

    std::fs::create_dir(&source_path).unwrap();
    std::fs::create_dir(&target_path).unwrap();

    let target_path_file = target_path.join("target_file.txt");
    std::fs::write(target_path.join("target_file.txt"), b"target hello world").unwrap();
    println!("wrote {target_path_file:?}");

    println!("{source_path:?} -> {target_path:?}");
    let err = std::fs::rename(source_path, target_path).unwrap_err();
    assert_eq!(err.kind(), std::io::ErrorKind::DirectoryNotEmpty);
}
```

```bash
XFS_BLOCK=image-xfs
truncate -s 512M image-xfs
mkfs.xfs -q image-xfs
mkdir mnt-xfs
sudo mount -o loop image-xfs mnt-xfs
sudo chmod 777 mnt-xfs
cargo run -- mnt-xfs/
```

Output:

```
wrote "mnt-xfs/target_directory/target_file.txt"
"mnt-xfs/source_directory" -> "mnt-xfs/target_directory"

thread 'main' (267220) panicked at src/main.rs:30:5:
assertion `left == right` failed
  left: AlreadyExists
 right: DirectoryNotEmpty
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
@Hoverbear Hoverbear force-pushed the hoverbear/xfs-test-fix branch from bce4a4e to 3cbe424 Compare June 8, 2026 14:25
@Hoverbear

Copy link
Copy Markdown
Contributor Author

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 8, 2026
@Mark-Simulacrum

Copy link
Copy Markdown
Member

@bors r+ rollup

@rust-bors

rust-bors Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 3cbe424 has been approved by Mark-Simulacrum

It is now in the queue for this repository.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 8, 2026
rust-bors Bot pushed a commit that referenced this pull request Jun 8, 2026
…uwer

Rollup of 13 pull requests

Successful merges:

 - #147302 (asm! support for the Xtensa architecture)
 - #148820 (Add very basic "comptime" fn implementation)
 - #157299 (Fix unstable diagnostics in tests)
 - #143511 (Improve TLS codegen by marking the panic/init path as cold)
 - #154608 (Add `_value` API for number literals in proc-macro)
 - #156762 (xfs support in `test_rename_directory_to_non_empty_directory`)
 - #157300 (Relax test requirements for consistency)
 - #157383 (tests: codegen-llvm: Ignore BPF targets in c-variadic-opt)
 - #157413 (fix: don't suggest .into_iter() for .cloned()/.copied() on non-reference Option)
 - #157578 (Fix diagnostics for non-exhaustive destructuring assignments (#157553))
 - #157587 (explain that the size_of constant also serves to avoid optimizing away 'unused' size_of calls)
 - #157596 (test: remove ineffective link-extern-crate-with-drop-type test)
 - #157602 (rustdoc: Remove unnecessary fast path)
@rust-bors rust-bors Bot merged commit fbe0e33 into rust-lang:main Jun 8, 2026
12 checks passed
@rustbot rustbot added this to the 1.98.0 milestone Jun 8, 2026
rust-timer added a commit that referenced this pull request Jun 8, 2026
Rollup merge of #156762 - ferrocene:hoverbear/xfs-test-fix, r=Mark-Simulacrum

xfs support in `test_rename_directory_to_non_empty_directory`

While running Ferrocene's test suite we use a variety of filesystems, including XFS. Those systems caught a failing test in [a recent upstream pull](ferrocene/ferrocene#2375).

The test failing:

https://github.com/rust-lang/rust/blob/1ea1171c1e537f295225be1c7b67dba46794e6ad/library/std/src/fs/tests.rs#L2141-L2157

It was recently removed from being Windows-only in: a0298aa#diff-0ec4075fea7f5f4cc82c306e975ae7638b1fc500d30c11a83f337a69ef1dfd65L2177

Seemingly on XFS only, the `AlreadyExists` variant is returned instead.

This workaround allows both possible errors. I am unsure at this time if it is a signal of incorrectness in Rust somewhere, but on Python a similar failure can be noted:

```bash
ana@autonoma ~/git/ferrocene/scratch
❯ mkdir blap flap
ana@autonoma ~/git/ferrocene/scratch
❯ touch flap/zap
ana@autonoma ~/git/ferrocene/scratch
❯ python
Python 3.13.13 (main, May 15 2026, 12:38:54) [GCC 15.2.1 20260214] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.rename("blap", "flap")
Traceback (most recent call last):
  File "<python-input-3>", line 1, in <module>
    os.rename("blap", "flap")
    ~~~~~~~~~^^^^^^^^^^^^^^^^
FileExistsError: [Errno 17] File exists: 'blap' -> 'flap'
ana@autonoma ~/git/ferrocene/scratch
❯ cd /tmp/
ana@autonoma /tmp
❯ mkdir blap flap
ana@autonoma /tmp
❯ touch flap/zap
ana@autonoma /tmp
❯ python
Python 3.13.13 (main, May 15 2026, 12:38:54) [GCC 15.2.1 20260214] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.rename("blap", "flap")
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    os.rename("blap", "flap")
    ~~~~~~~~~^^^^^^^^^^^^^^^^
OSError: [Errno 39] Directory not empty: 'blap' -> 'flap'
```

I tested on `ext4`, `tmpfs`, `overlayfs`, `btrfs`, and `xfs`. Only XFS seems to display this error.

## Reproduction

On Linux hosts:

```rust
use clap::Parser;

struct Args {
    /// Destination to try
    #[arg()]
    path: std::path::PathBuf,
}

fn main() {
    let args = Args::parse();

    // Renaming a directory over a non-empty existing directory should fail.
    let tmpdir = std::path::Path::new(&args.path);
    std::fs::create_dir_all(tmpdir).unwrap();

    let source_path = tmpdir.join("source_directory");
    let target_path = tmpdir.join("target_directory");

    std::fs::create_dir(&source_path).unwrap();
    std::fs::create_dir(&target_path).unwrap();

    let target_path_file = target_path.join("target_file.txt");
    std::fs::write(target_path.join("target_file.txt"), b"target hello world").unwrap();
    println!("wrote {target_path_file:?}");

    println!("{source_path:?} -> {target_path:?}");
    let err = std::fs::rename(source_path, target_path).unwrap_err();
    assert_eq!(err.kind(), std::io::ErrorKind::DirectoryNotEmpty);
}
```

```bash
XFS_BLOCK=image-xfs
truncate -s 512M image-xfs
mkfs.xfs -q image-xfs
mkdir mnt-xfs
sudo mount -o loop image-xfs mnt-xfs
sudo chmod 777 mnt-xfs
cargo run -- mnt-xfs/
```

Output:

```
wrote "mnt-xfs/target_directory/target_file.txt"
"mnt-xfs/source_directory" -> "mnt-xfs/target_directory"

thread 'main' (267220) panicked at src/main.rs:30:5:
assertion `left == right` failed
  left: AlreadyExists
 right: DirectoryNotEmpty
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

You can run this test directly:

```bash
./x.py --stage 2 test library/std --target x86_64-unknown-linux-gnu -- fs::tests::test_rename_directory_to_non_empty_directory --nocapture
```
@tshepang tshepang deleted the hoverbear/xfs-test-fix branch June 9, 2026 04:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants