From ecb86118e54dc36d5d7bdf59b01cbf081277be77 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Mon, 23 May 2022 22:51:26 -0700 Subject: [PATCH] working_copy: get file metadata using open file descriptor When we have just written a file or conflict, we can get metadata for it via the open file descriptor instead of using the path. That removes the risk of a race where the file got removed or replaced by another file type (at least on Unix). --- lib/src/working_copy.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/working_copy.rs b/lib/src/working_copy.rs index 79a3ef2cd..63cd6a2a3 100644 --- a/lib/src/working_copy.rs +++ b/lib/src/working_copy.rs @@ -570,11 +570,11 @@ impl TreeState { let mut contents = self.store.read_file(path, id)?; std::io::copy(&mut contents, &mut file).unwrap(); self.set_executable(disk_path, executable); - // Read the file state while we still have the file open. That way, know that - // the file exists, and the stat information is most likely accurate, - // except for other processes modifying the file concurrently (The mtime is set - // at write time and won't change when we close the file.) - let metadata = disk_path.symlink_metadata().unwrap(); + // Read the file state from the file descriptor. That way, know that the file + // exists and is of the expected type, and the stat information is most likely + // accurate, except for other processes modifying the file concurrently (The + // mtime is set at write time and won't change when we close the file.) + let metadata = file.metadata().unwrap(); let mut file_state = file_state(&metadata); // Make sure the state we record is what we tried to set above. This is mostly // for Windows, since the executable bit is not reflected in the file system @@ -624,7 +624,7 @@ impl TreeState { materialize_conflict(self.store.as_ref(), path, &conflict, &mut file).unwrap(); // TODO: Set the executable bit correctly (when possible) and preserve that on // Windows like we do with the executable bit for regular files. - let metadata = disk_path.symlink_metadata().unwrap(); + let metadata = file.metadata().unwrap(); let mut result = file_state(&metadata); result.file_type = FileType::Conflict { id: id.clone() }; Ok(result)