From 03ce02e1a7c04426a2881962da661c46e389e8bf Mon Sep 17 00:00:00 2001 From: caner-akca <94343893+caner-akca@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:40:49 +0300 Subject: fix: reject oversized git ref files in workspace status reads (#3373) * fix: reject oversized git ref files in workspace status reads refs #3343 * fix: treat oversized loose refs as unavailable instead of absent refs #3343 * fix: classify git ref read errors instead of probing path existence A loose ref behind a metadata or I/O error (for example an unsearchable refs/heads directory) previously read as absent, because Path::exists() also returns false on metadata errors, letting a stale same-name packed-refs OID enter the workspace status fingerprint. The reader now classifies the open error itself: NotFound and NotADirectory mean the loose ref is absent (packed-refs fallback stays legitimate), every other error marks the ref unavailable with no fallback. This also removes the racy second existence probe. refs #3343 * fix: reject empty loose git refs refs #3343 * fix: reject dangling loose git refs refs #3343 * fix: reject dangling git refs with invalid target paths refs #3343 --- src/workspace/git/status.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/workspace/git/status.rs') diff --git a/src/workspace/git/status.rs b/src/workspace/git/status.rs index 4fb2b887..9f40170c 100644 --- a/src/workspace/git/status.rs +++ b/src/workspace/git/status.rs @@ -8,7 +8,8 @@ use super::{ discovery::{ automatic_workspace_label, canonicalize_best_effort_path, fallback_label_from_cwd, git_ref_storage_is_reftable, git_rev_parse_verify, git_space_metadata_from_info, - git_symbolic_head_full, git_worktree_info, read_ref_oid, GitWorktreeInfo, + git_symbolic_head_full, git_worktree_info, read_git_ref_file, read_ref_oid, + GitWorktreeInfo, }, }; @@ -273,7 +274,7 @@ fn read_head_identity_from_git(info: &GitWorktreeInfo) -> Option Option { - let head = std::fs::read_to_string(info.git_dir.join("HEAD")).ok()?; + let head = read_git_ref_file(&info.git_dir.join("HEAD"))?; let head = head.trim(); if let Some(full_ref) = head.strip_prefix("ref: ") { let short_name = full_ref.strip_prefix("refs/heads/")?.to_string(); -- cgit v1.2.3