Skip to content

fix(fs): canonicalize paths for file lock keys#2

Merged
donk8r merged 1 commit into
masterfrom
fix/lock
May 2, 2026
Merged

fix(fs): canonicalize paths for file lock keys#2
donk8r merged 1 commit into
masterfrom
fix/lock

Conversation

@donk8r

@donk8r donk8r commented May 1, 2026

Copy link
Copy Markdown
Member
  • Use canonicalized paths to prevent concurrent write corruption
  • Ensure aliased paths map to the same mutex in the lock map
  • Fall back to raw path string if canonicalization fails
  • Add tests to verify path alias collapse for file locks

- Use canonicalized paths to prevent concurrent write corruption
- Ensure aliased paths map to the same mutex in the lock map
- Fall back to raw path string if canonicalization fails
- Add tests to verify path alias collapse for file locks
@github-actions

github-actions Bot commented May 1, 2026

Copy link
Copy Markdown

Octomind — developer:brief (ollama:glm-5.1)

Now I have all the information I need. Let me compile the brief.


📦 Brief: Canonicalize file paths for lock/history map keys to prevent concurrent write corruption via aliased paths

Overall risk: 🟢 LOW · Cards: 2

# Change Risk Confidence
1 Path aliasing no longer creates separate mutex locks — ./x, x//y, and symlinks to the same file now serialize under one key 🟢 ●●●
2 Undo history now uses the same canonicalized key as the file lock, so save_file_history and undo_edit stay consistent regardless of how the path was spelled 🟢 ●●●

Card 1/2: Canonicalized lock keys prevent aliased-path lock bypass · 🟢 · ●●●

INTENT
Fix a data-race bug where two callers referencing the same file through different path spellings (e.g. ./foo.txt vs foo.txt, or symlink targets) would acquire different mutex locks, allowing concurrent writes that could corrupt the file.

WHAT CHANGED

  • New pub fn lock_key_for(path: &Path) in text_editing.rs — canonicalizes the path via std::path::Path::canonicalize(), falling back to the raw path string if canonicalization fails (e.g. file doesn't exist yet for text_editor create).
  • acquire_file_lock now uses lock_key_for(path) instead of path.to_string_lossy() as the HashMap key, so all aliases of the same real file map to the same Arc<AsyncMutex<()>>.
  • Test test_lock_key_collapses_aliased_paths verifies that raw, ./raw, and raw//path forms produce identical keys.

IMPACT RADIUS

  • acquire_file_lock is called by str_replace_spec and batch_edit_spec — the two write paths. Both now serialize correctly for aliased paths.
  • lock_key_for is pub, so any future code that needs a consistent per-file key can reuse it.

RISK
🟢 LOW. The fix is narrow and well-targeted. The only edge case — canonicalize failing for a non-existent file — is handled by falling back to the raw path string, preserving the pre-fix behavior for text_editor create. On Linux, canonicalize resolves symlinks and .. components; on Windows it also handles case normalization. No behavioral regression for existing callers that already passed canonical paths.

📎 Source

Card 2/2: Undo history keys aligned with lock keys · 🟢 · ●●●

INTENT
Ensure the undo-history HashMap uses the same canonicalized key as the file lock, so that saving history under one path spelling and undoing under another still finds the correct history entry.

WHAT CHANGED

  • save_file_history and undo_edit in core.rs now call text_editing::lock_key_for(path) instead of path.to_string_lossy() for their HashMap key.
  • This makes the history map consistent with the lock map: both collapse aliased paths to the same canonical key.

IMPACT RADIUS

  • save_file_history is called before every str_replace and batch_edit write. undo_edit is called on the undo_edit command. Both now use the same key derivation as the lock, so a save via ./foo.txt and an undo via foo.txt will match.
  • FILE_HISTORY is a HashMap<String, Vec<String>> — the key type is unchanged (String), just the derivation logic.

RISK
🟢 LOW. Consistent keying across lock and history maps is strictly better than divergent keying. No downstream consumers beyond these two functions use FILE_HISTORY directly.

📎 Source


📂 Files changed (3 files, ~41 insertions, ~4 deletions)

{tokens:246366,cost:0.2513138}

@donk8r donk8r merged commit 5a1e675 into master May 2, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant