pull/112/merge
e0_7 2026-06-16 04:03:15 +08:00 committed by GitHub
commit 904b3d9cba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 61 additions and 8 deletions

View File

@ -233,6 +233,11 @@ fn detect_db_dir_impl() -> Option<PathBuf> {
let home = sudo_user_home_dir().or_else(dirs::home_dir)?;
let base = home.join("Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files");
detect_db_dir_under(&base)
}
#[cfg(target_os = "macos")]
fn detect_db_dir_under(base: &Path) -> Option<PathBuf> {
if !base.exists() {
return None;
}
@ -245,11 +250,7 @@ fn detect_db_dir_impl() -> Option<PathBuf> {
}
}
}
candidates.sort_by_key(|p| {
std::fs::metadata(p)
.and_then(|m| m.modified())
.unwrap_or(std::time::SystemTime::UNIX_EPOCH)
});
candidates.sort_by_key(|p| latest_db_mtime(p).unwrap_or(std::time::SystemTime::UNIX_EPOCH));
candidates.into_iter().next_back()
}
@ -284,7 +285,7 @@ fn detect_db_dir_impl() -> Option<PathBuf> {
candidates.into_iter().next_back()
}
#[cfg(any(target_os = "linux", target_os = "windows"))]
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
/// 递归查找 db_storage 目录下所有 .db 文件的最新 mtime
fn latest_db_mtime(dir: &Path) -> Option<std::time::SystemTime> {
let mut latest = None;
@ -416,8 +417,8 @@ fn detect_db_dir_impl() -> Option<PathBuf> {
#[cfg(test)]
mod tests {
use super::{
config_path_in_dir, default_config_path, find_existing_config_path, home_config_path,
resolve_cli_home,
config_path_in_dir, default_config_path, detect_db_dir_under, find_existing_config_path,
home_config_path, resolve_cli_home,
};
#[cfg(target_os = "windows")]
use super::{known_documents_dir, resolve_windows_data_root};
@ -480,6 +481,34 @@ mod tests {
assert_eq!(path, cwd.join("config.json"));
}
#[cfg(target_os = "macos")]
#[test]
fn auto_detect_db_dir_prefers_latest_db_file_mtime_over_directory_mtime() {
let home = temp_dir("macos-home");
let base = home.join("Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files");
let active_db_dir = base.join("wxid_active/db_storage");
let stale_db_dir = base.join("wxid_stale/db_storage");
let active_db_file = active_db_dir.join("message/session.db");
let stale_db_file = stale_db_dir.join("message/session.db");
fs::create_dir_all(active_db_file.parent().unwrap()).unwrap();
fs::write(&active_db_file, b"active").unwrap();
fs::create_dir_all(stale_db_file.parent().unwrap()).unwrap();
fs::write(&stale_db_file, b"stale").unwrap();
set_file_mtime(
&active_db_file,
SystemTime::now()
.checked_add(std::time::Duration::from_secs(3600))
.unwrap(),
);
let detected = detect_db_dir_under(&base).unwrap();
assert_eq!(detected, active_db_dir);
fs::remove_dir_all(home).unwrap();
}
#[cfg(target_os = "windows")]
#[test]
fn resolve_windows_data_root_passes_through_absolute_path() {
@ -499,4 +528,28 @@ mod tests {
assert_eq!(resolved, docs, "keyword {keyword:?}");
}
}
#[cfg(unix)]
fn set_file_mtime(path: &std::path::Path, mtime: SystemTime) {
use std::ffi::CString;
use std::os::unix::ffi::OsStrExt;
use std::time::Duration;
let dur = mtime
.duration_since(UNIX_EPOCH)
.unwrap_or(Duration::from_secs(0));
let times = [
libc::timeval {
tv_sec: dur.as_secs() as libc::time_t,
tv_usec: dur.subsec_micros() as libc::suseconds_t,
},
libc::timeval {
tv_sec: dur.as_secs() as libc::time_t,
tv_usec: dur.subsec_micros() as libc::suseconds_t,
},
];
let c_path = CString::new(path.as_os_str().as_bytes()).unwrap();
let rc = unsafe { libc::utimes(c_path.as_ptr(), times.as_ptr()) };
assert_eq!(rc, 0, "failed to update mtime for {}", path.display());
}
}