9p filesystem does not honor turning off O_APPEND if a file handle is opened with O_APPEND
- Dominant language
- C++
- Stars
- 33.7k
- Forks
- 1.8k
- Avg merge
- 3d 17h
- Merged PRs (30d)
- 116
Description
### Windows Version
Microsoft Windows [Version 10.0.26200.8457]
### WSL Version
2.6.3.0
### Are you using WSL 1 or WSL 2?
- [x] 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.
```rs
#[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_
Contributor guide
Research direction
Start by running the provided Rust test against a file under /mnt/d, focusing on fcntl F_SETFL and the 9p filesystem path. Trace how clearing O_APPEND is handled after the handle is opened in append mode. Done means the seek/write operation updates the file as expected and the test produces "Hello, earth!" with the expected offset.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, linux, rust
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100