From 2301cc65d3a4ebd56256e48bd32c5b768c42b140 Mon Sep 17 00:00:00 2001 From: funman300 Date: Sun, 17 May 2026 21:26:23 -0700 Subject: [PATCH] fix(data): align android_keystore temp extension with cleanup glob (M-21) The keystore atomic write used path.with_extension("tmp") producing auth_tokens.tmp, while cleanup_orphaned_tmp_files only matched *.json.tmp. A crash after the write but before the rename left an orphaned file invisible to cleanup. Fix: use path.with_extension("bin.tmp") to produce auth_tokens.bin.tmp, and broaden the cleanup glob from ends_with(".json.tmp") to ends_with(".tmp") so both JSON and binary temp files are caught. Co-Authored-By: Claude Sonnet 4.6 --- solitaire_data/src/android_keystore.rs | 4 ++-- solitaire_data/src/storage.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/solitaire_data/src/android_keystore.rs b/solitaire_data/src/android_keystore.rs index 46995dd..388ee7b 100644 --- a/solitaire_data/src/android_keystore.rs +++ b/solitaire_data/src/android_keystore.rs @@ -295,9 +295,9 @@ fn read_file_bytes() -> Result, TokenError> { fn write_file_bytes(data: &[u8]) -> Result<(), TokenError> { let path = token_file_path() .ok_or_else(|| TokenError::KeychainUnavailable("no data dir".into()))?; - let tmp = path.with_extension("tmp"); + let tmp = path.with_extension("bin.tmp"); std::fs::write(&tmp, data) - .map_err(|e| TokenError::Keyring(format!("write auth_tokens.tmp: {e}")))?; + .map_err(|e| TokenError::Keyring(format!("write auth_tokens.bin.tmp: {e}")))?; std::fs::rename(&tmp, &path) .map_err(|e| TokenError::Keyring(format!("rename auth_tokens: {e}"))) } diff --git a/solitaire_data/src/storage.rs b/solitaire_data/src/storage.rs index a66b09d..096780b 100644 --- a/solitaire_data/src/storage.rs +++ b/solitaire_data/src/storage.rs @@ -122,7 +122,7 @@ pub fn delete_game_state_at(path: &Path) -> io::Result<()> { } } -/// Remove any leftover `*.json.tmp` files in the app data directory. +/// Remove any leftover `*.tmp` files in the app data directory. /// /// These can be left behind if the process crashes between the write and rename /// in an atomic save. Safe to call on startup; missing or unreadable entries @@ -266,7 +266,7 @@ pub fn time_attack_session_with_now(remaining_secs: f32, wins: u32) -> TimeAttac } } -/// Inner helper: delete `*.json.tmp` entries inside `dir`. +/// Inner helper: delete `*.tmp` entries inside `dir`. /// /// Per-file errors (already deleted, permission denied) are silently ignored. fn cleanup_tmp_files_in(dir: &Path) { @@ -276,7 +276,7 @@ fn cleanup_tmp_files_in(dir: &Path) { if path .file_name() .and_then(|n| n.to_str()) - .is_some_and(|n| n.ends_with(".json.tmp")) + .is_some_and(|n| n.ends_with(".tmp")) { let _ = fs::remove_file(&path); }