From 042254e5ac3f3f26169e3a3063b2c1c1c6eea980 Mon Sep 17 00:00:00 2001 From: lbl <1791778603@qq.com> Date: Fri, 21 Aug 2026 03:05:48 +0800 Subject: [PATCH] =?UTF-8?q?fix(cli):=20wintun.dll=20=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E5=8F=AA=E6=8C=89=E5=AD=98=E5=9C=A8=E6=80=A7=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 此前仅当 wintun.dll 不存在时才释放内嵌版本,损坏或被替换的旧版 dll 会永久残留,后续创建 TUN 设备时才以难以理解的方式失败。 改为与内嵌版本做内容比较,不一致(不存在/损坏/旧版)即重写。 测试:缺失时写入、损坏时重写、一致时跳过。 --- src/extract_wintun_dll.rs | 54 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/src/extract_wintun_dll.rs b/src/extract_wintun_dll.rs index a633404..9becd99 100644 --- a/src/extract_wintun_dll.rs +++ b/src/extract_wintun_dll.rs @@ -25,9 +25,55 @@ fn extract_wintun_impl() -> io::Result<()> { .and_then(|p| p.parent().map(|d| d.join("wintun.dll"))) .unwrap_or_else(|| Path::new("wintun.dll").to_path_buf()); - if !path.exists() { - let mut file = fs::File::create(&path)?; - file.write_all(WINTUN_DLL)?; - } + ensure_dll(&path)?; Ok(()) } + +/// 确保 path 处的 dll 与内嵌版本一致,不一致(不存在/损坏/旧版)时重写。 +/// 返回是否发生了写入。只按存在性判断会让损坏或旧版 dll 永久残留。 +fn ensure_dll(path: &Path) -> io::Result { + let up_to_date = fs::read(path) + .map(|content| content.as_slice() == WINTUN_DLL) + .unwrap_or(false); + if up_to_date { + return Ok(false); + } + let mut file = fs::File::create(path)?; + file.write_all(WINTUN_DLL)?; + Ok(true) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn temp_dll_path(tag: &str) -> std::path::PathBuf { + std::env::temp_dir().join(format!("vnt_wintun_test_{}_{}.dll", std::process::id(), tag)) + } + + #[test] + fn test_ensure_dll_writes_when_missing() { + let path = temp_dll_path("missing"); + let _ = fs::remove_file(&path); + assert!(ensure_dll(&path).unwrap()); + assert_eq!(fs::read(&path).unwrap(), WINTUN_DLL); + let _ = fs::remove_file(&path); + } + + #[test] + fn test_ensure_dll_rewrites_corrupt() { + let path = temp_dll_path("corrupt"); + fs::write(&path, b"corrupt").unwrap(); + assert!(ensure_dll(&path).unwrap()); + assert_eq!(fs::read(&path).unwrap(), WINTUN_DLL); + let _ = fs::remove_file(&path); + } + + #[test] + fn test_ensure_dll_skips_when_up_to_date() { + let path = temp_dll_path("uptodate"); + fs::write(&path, WINTUN_DLL).unwrap(); + assert!(!ensure_dll(&path).unwrap()); + let _ = fs::remove_file(&path); + } +}