edit: plan from a new description of the held file, not a clone (Linux)

Planning from a mapping of a clone of the locked descriptor shared its
flock: a process forked by another thread meanwhile (any Command) kept the
lock alive for a moment after the editor was dropped, and a test that
reopened the file at once saw Error::Locked (once in a full run). On Linux
plan through /proc/self/fd (a new open file description of the same
file, which still follows a rename); elsewhere keep the clone.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
osobh
2026-09-27 07:51:22 -05:00
co-authored by Claude Opus 5.5
parent b0930708b6
commit d09e55e229
+15 -2
View File
@@ -832,10 +832,23 @@ impl FileEditor {
Ok(f) Ok(f)
} }
/// A reader over the held file itself for planning an edit (it shares /// A reader over the held file for planning an edit (dropped before the
/// the file's lock, and is dropped before the edit writes). /// edit writes). On Linux a new open file description through
/// `/proc/self/fd`: a mapping of a clone of the held descriptor would
/// share its `flock`, and a process forked meanwhile (any
/// `std::process::Command` on another thread) would briefly keep the
/// lock alive after the editor is dropped. Elsewhere a clone of the
/// held descriptor, which follows the file wherever its path goes.
fn plan_reader(&self) -> Result<File, Error> { fn plan_reader(&self) -> Result<File, Error> {
let dir = self.path.parent().map(Path::to_path_buf); let dir = self.path.parent().map(Path::to_path_buf);
#[cfg(target_os = "linux")]
{
use std::os::fd::AsRawFd;
let proc = format!("/proc/self/fd/{}", self.file.as_raw_fd());
if let Ok(f) = std::fs::File::open(proc) {
return File::from_std_file(f, dir);
}
}
File::from_std_file(self.file.try_clone()?, dir) File::from_std_file(self.file.try_clone()?, dir)
} }