fix: backup_registry 改为内部读取注册表当前值,不再依赖前端传入数据

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 22:04:16 +08:00
parent 2775a3a588
commit 804e02004d
3 changed files with 30 additions and 17 deletions
+24 -11
View File
@@ -1,5 +1,4 @@
use chrono::Local; use chrono::Local;
use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
fn backup_base_dir() -> PathBuf { fn backup_base_dir() -> PathBuf {
@@ -17,27 +16,41 @@ pub fn get_appdata_dir() -> String {
} }
/// 备份当前注册表中的系统 PATH 和用户 PATH /// 备份当前注册表中的系统 PATH 和用户 PATH
/// 返回备份文件的路径 /// 在保存前调用,备份的是注册表中的当前值(保存前的状态)
#[tauri::command] #[tauri::command]
pub fn backup_registry(custom_dir: Option<String>, sys_paths: Vec<String>, user_paths: Vec<String>) -> Result<String, String> { pub fn backup_registry(custom_dir: Option<String>) -> Result<String, String> {
// 确定备份目录 use crate::commands::registry;
use winreg::enums::*;
let backup_dir = match custom_dir { let backup_dir = match custom_dir {
Some(ref dir) if !dir.is_empty() => PathBuf::from(dir), Some(ref dir) if !dir.is_empty() => std::path::PathBuf::from(dir),
_ => backup_base_dir(), _ => backup_base_dir(),
}; };
// 创建目录 std::fs::create_dir_all(&backup_dir)
fs::create_dir_all(&backup_dir)
.map_err(|e| format!("无法创建备份目录: {}", e))?; .map_err(|e| format!("无法创建备份目录: {}", e))?;
// 生成带时间戳的文件名 // 读取当前注册表中的值(保存前的旧值)
let sys_paths = registry::load_paths(
HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
"系统",
)?;
let user_paths = registry::load_paths(
HKEY_CURRENT_USER,
"Environment",
"用户",
)?;
let timestamp = Local::now().format("%Y%m%d_%H%M%S_%3f"); let timestamp = Local::now().format("%Y%m%d_%H%M%S_%3f");
let filename = format!("path_backup_{}.txt", timestamp); let filename = format!("path_backup_{}.txt", timestamp);
let filepath = backup_dir.join(&filename); let filepath = backup_dir.join(&filename);
// 写入备份内容
let mut content = String::new(); let mut content = String::new();
content.push_str(&format!("PathEditor Backup - {}\n", Local::now().format("%Y-%m-%d %H:%M:%S"))); content.push_str(&format!(
"PathEditor Backup - {}\n",
Local::now().format("%Y-%m-%d %H:%M:%S")
));
content.push_str("\n[System PATH]\n"); content.push_str("\n[System PATH]\n");
for path in &sys_paths { for path in &sys_paths {
content.push_str(&format!("{}\n", path)); content.push_str(&format!("{}\n", path));
@@ -47,7 +60,7 @@ pub fn backup_registry(custom_dir: Option<String>, sys_paths: Vec<String>, user_
content.push_str(&format!("{}\n", path)); content.push_str(&format!("{}\n", path));
} }
fs::write(&filepath, &content) std::fs::write(&filepath, &content)
.map_err(|e| format!("无法写入备份文件: {}", e))?; .map_err(|e| format!("无法写入备份文件: {}", e))?;
let result = filepath.to_string_lossy().to_string(); let result = filepath.to_string_lossy().to_string();
+4 -4
View File
@@ -5,7 +5,7 @@ const SYS_REG_PATH: &str = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\
const USER_REG_PATH: &str = "Environment"; const USER_REG_PATH: &str = "Environment";
const PATH_VALUE: &str = "Path"; const PATH_VALUE: &str = "Path";
fn load_paths(root: winreg::HKEY, sub_path: &str, label: &str) -> Result<Vec<String>, String> { pub(crate) fn load_paths(root: winreg::HKEY, sub_path: &str, label: &str) -> Result<Vec<String>, String> {
let key = RegKey::predef(root); let key = RegKey::predef(root);
let env_key = key let env_key = key
.open_subkey_with_flags(sub_path, KEY_READ) .open_subkey_with_flags(sub_path, KEY_READ)
@@ -18,7 +18,7 @@ fn load_paths(root: winreg::HKEY, sub_path: &str, label: &str) -> Result<Vec<Str
Ok(split_path(&value)) Ok(split_path(&value))
} }
fn save_paths(root: winreg::HKEY, sub_path: &str, label: &str, paths: &[String]) -> Result<(), String> { pub(crate) fn save_paths(root: winreg::HKEY, sub_path: &str, label: &str, paths: &[String]) -> Result<(), String> {
let value = join_path(paths); let value = join_path(paths);
// Windows 注册表 REG_EXPAND_SZ 上限 32767 字符 // Windows 注册表 REG_EXPAND_SZ 上限 32767 字符
@@ -63,14 +63,14 @@ pub fn save_user_paths(paths: Vec<String>) -> Result<(), String> {
save_paths(HKEY_CURRENT_USER, USER_REG_PATH, "用户", &paths) save_paths(HKEY_CURRENT_USER, USER_REG_PATH, "用户", &paths)
} }
fn split_path(raw: &str) -> Vec<String> { pub(crate) fn split_path(raw: &str) -> Vec<String> {
raw.split(';') raw.split(';')
.map(|s| s.trim().to_string()) .map(|s| s.trim().to_string())
.filter(|s| !s.is_empty()) .filter(|s| !s.is_empty())
.collect() .collect()
} }
fn join_path(paths: &[String]) -> String { pub(crate) fn join_path(paths: &[String]) -> String {
paths paths
.iter() .iter()
.map(|p| p.trim()) .map(|p| p.trim())
+2 -2
View File
@@ -259,8 +259,8 @@ export const useAppStore = create<AppState>((set, get) => ({
if (!window.confirm('PATH 长度超过建议值,是否继续保存?')) { set({ isSaving: false }); return; } if (!window.confirm('PATH 长度超过建议值,是否继续保存?')) { set({ isSaving: false }); return; }
} }
// 备份(失败时通知用户 // 备份当前注册表(保存前备份旧值,失败仅警告不中断
invoke('backup_registry', { customDir: null, sysPaths, userPaths }) invoke('backup_registry', { customDir: null })
.catch(() => set({ statusMessage: i18n.t('status.warning_backup') })); .catch(() => set({ statusMessage: i18n.t('status.warning_backup') }));
const [sysResult, userResult] = await Promise.allSettled([ const [sysResult, userResult] = await Promise.allSettled([