Skip to content

9p filesystem does not honor turning off O_APPEND if a file handle is opened with O_APPEND #40649

@khanhtranngoccva

Description

@khanhtranngoccva

Windows Version

Microsoft Windows [Version 10.0.26200.8457]

WSL Version

2.6.3.0

Are you using WSL 1 or WSL 2?

  • WSL 2
  • WSL 1

Kernel Version

6.6.87.2-1

Distro Version

Ubuntu 24.04.3 LTS on Windows 10 x86_64

Other Software

No response

Repro Steps

This is a test case written in high-level Rust. Most of the calls here can be mapped to simple raw syscalls. It uses crates.io dependencies nix, tokio and tempdir with any necessary features.

The file handle must be created in append mode, and then the append mode is switched off.

#[cfg(test)]
mod tests {
    use std::{io::SeekFrom, os::fd::AsFd};

    use nix::fcntl::{FcntlArg, OFlag};
    use tempdir::TempDir;
    use tokio::{
        fs::OpenOptions,
        io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt},
    };

    #[tokio::test]
    async fn test_appends_on_off() {
        // /mnt/d is a 9p location
        let tempdir = TempDir::new_in("/mnt/d/path/to/dir", "test_appends_on_off").unwrap();
        let mut file = OpenOptions::new()
            .create(true)
            .append(true)
            .read(true)
            .write(true)
            .open(tempdir.path().join("test.txt"))
            .await
            .unwrap();
        file.write_all(b"Hello, world!").await.unwrap();

        // Disable append mode
        let flags =
            OFlag::from_bits_retain(nix::fcntl::fcntl(file.as_fd(), FcntlArg::F_GETFL).unwrap());
        nix::fcntl::fcntl(
            file.as_fd(),
            FcntlArg::F_SETFL(flags & !nix::fcntl::OFlag::O_APPEND),
        )
        .unwrap();

        // In this error example, the underlying filesystem does not honor removing O_APPEND. So it appends to the end of the file.
        file.seek(SeekFrom::Start(7)).await.unwrap();
        file.write_all(b"earth!").await.unwrap();

        // The cursor should have been at position 19 due to the previous bug, but it is misreported as position 13. Therefore, the caller could not know that a bug occurred and proceeds as normal.
        let current_seek = file.seek(SeekFrom::Current(0)).await.unwrap();
        println!("current_seek: {}", current_seek);
        assert_eq!(current_seek, 13);

        file.seek(SeekFrom::Start(0)).await.unwrap();
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer).await.unwrap();
        println!("buffer: {:?}", String::from_utf8_lossy(&buffer));
        assert_eq!(buffer, b"Hello, earth!");
    }
}

Expected Behavior

The test case above should pass.

Actual Behavior

The test case above failed at the last line because the last write was treated as an append.

Diagnostic Logs

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    file systemwsl2Issue/feature applies to WSL 2

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions