From f2e2cd21b3f08d7ed16d5158e19227ddcccf7c8c Mon Sep 17 00:00:00 2001 From: samwaf Date: Fri, 2 May 2025 16:06:48 +0800 Subject: [PATCH] feat:update backup bin #250 --- api/waf_sys_info.go | 7 +++ utils/backuputil.go | 116 ++++++++++++++++++++++++++++++++++++++++ wafdb/localdb.go | 39 ++------------ wafupdate/selfupdate.go | 28 ++++++++++ 4 files changed, 155 insertions(+), 35 deletions(-) create mode 100644 utils/backuputil.go diff --git a/api/waf_sys_info.go b/api/waf_sys_info.go index 435f77b..7366fd2 100644 --- a/api/waf_sys_info.go +++ b/api/waf_sys_info.go @@ -190,6 +190,13 @@ func (w *WafSysInfoApi) UpdateApi(c *gin.Context) { }, } go func() { + // 备份当前可执行文件 + err := wafupdate.BackupExecutable() + if err != nil { + zlog.Error("备份可执行文件失败:", err) + // 备份失败不影响升级流程,继续执行 + } + // try to update if channel != "" { err := updater.BackgroundRunWithChannel(channel) diff --git a/utils/backuputil.go b/utils/backuputil.go new file mode 100644 index 0000000..6209b85 --- /dev/null +++ b/utils/backuputil.go @@ -0,0 +1,116 @@ +package utils + +import ( + "SamWaf/common/zlog" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + "time" +) + +// BackupFile 备份文件到指定目录 +// srcFilePath: 源文件路径 +// backupDir: 备份目录 +// backupFilePrefix: 备份文件名前缀 +// keepCount: 保留的备份文件数量 +func BackupFile(srcFilePath, backupDir, backupFilePrefix string, keepCount int) (string, error) { + // 判断源文件是否存在 + if _, err := os.Stat(srcFilePath); os.IsNotExist(err) { + return "", fmt.Errorf("源文件不存在: %s", srcFilePath) + } + + // 判断备份目录是否存在,不存在则创建 + if _, err := os.Stat(backupDir); os.IsNotExist(err) { + if err := os.MkdirAll(backupDir, os.ModePerm); err != nil { + zlog.Error("创建备份目录失败:", err) + return "", err + } + } + + // 获取文件扩展名 + fileExt := filepath.Ext(srcFilePath) + + // 创建备份文件名 + backupFileName := fmt.Sprintf("%s_%s%s", backupFilePrefix, time.Now().Format("20060102150405"), fileExt) + backupFilePath := filepath.Join(backupDir, backupFileName) + + // 创建备份文件 + backupFile, err := os.Create(backupFilePath) + if err != nil { + zlog.Error("创建备份文件失败:", err) + return "", err + } + defer backupFile.Close() + + // 打开原始文件 + originalFile, err := os.Open(srcFilePath) + if err != nil { + zlog.Error("打开原始文件失败:", err) + return "", err + } + defer originalFile.Close() + + // 复制文件内容到备份文件 + _, err = io.Copy(backupFile, originalFile) + if err != nil { + zlog.Error("文件复制失败:", err) + return "", err + } + + zlog.Info("文件备份成功,备份文件路径:", backupFilePath) + + // 清理旧的备份文件,只保留最新的keepCount个 + CleanupOldBackups(backupDir, backupFilePrefix, keepCount) + + return backupFilePath, nil +} + +// CleanupOldBackups 清理旧的备份文件,只保留最新的n个 +func CleanupOldBackups(backupDir, filePrefix string, keepCount int) { + // 获取备份目录中的所有文件 + files, err := os.ReadDir(backupDir) + if err != nil { + zlog.Error("读取备份目录失败:", err) + return + } + + // 筛选出指定前缀的备份文件 + var backupFiles []os.DirEntry + for _, file := range files { + if !file.IsDir() && strings.HasPrefix(file.Name(), filePrefix) { + backupFiles = append(backupFiles, file) + } + } + + // 如果备份文件数量不超过保留数量,则不需要删除 + if len(backupFiles) <= keepCount { + return + } + + // 按文件修改时间排序(从旧到新) + sort.Slice(backupFiles, func(i, j int) bool { + infoI, err := backupFiles[i].Info() + if err != nil { + return false + } + infoJ, err := backupFiles[j].Info() + if err != nil { + return false + } + return infoI.ModTime().Before(infoJ.ModTime()) + }) + + // 删除多余的旧文件 + for i := 0; i < len(backupFiles)-keepCount; i++ { + filePath := filepath.Join(backupDir, backupFiles[i].Name()) + err := os.Remove(filePath) + if err != nil { + zlog.Error("删除旧备份文件失败:", err, filePath) + } else { + zlog.Info("已删除旧备份文件:", filePath) + } + } +} diff --git a/wafdb/localdb.go b/wafdb/localdb.go index 72dddfe..9fde367 100644 --- a/wafdb/localdb.go +++ b/wafdb/localdb.go @@ -13,7 +13,6 @@ import ( "database/sql" "fmt" "gorm.io/gorm/logger" - "io" "net/url" "os" "path/filepath" @@ -42,44 +41,14 @@ func InitCoreDb(currentDir string) { path := currentDir + "/data/local.db" // 检查文件是否存在 if _, err := os.Stat(path); !os.IsNotExist(err) { - // 文件存在的逻辑 + // 文件存在的逻辑,使用工具函数进行备份 backupDir := currentDir + "/data/backups" - // 判断备份目录是否存在,不存在则创建 - if _, err := os.Stat(backupDir); os.IsNotExist(err) { - if err := os.MkdirAll(backupDir, os.ModePerm); err != nil { - zlog.Error("创建备份目录失败:", err) - return - } - } - // 创建备份文件 - backupFilePath := filepath.Join(backupDir, fmt.Sprintf("local_backup_%s.db", time.Now().Format("20060102150405"))) - backupFile, err := os.Create(backupFilePath) + _, err := utils.BackupFile(path, backupDir, "local_backup", 10) if err != nil { - zlog.Error("创建备份文件失败:", err) - return + zlog.Error("备份数据库文件失败:", err) } - defer backupFile.Close() - - // 打开原始文件 - originalFile, err := os.Open(path) - if err != nil { - zlog.Error("打开原始文件失败:", err) - return - } - defer originalFile.Close() - - // 复制文件内容到备份文件 - _, err = io.Copy(backupFile, originalFile) - if err != nil { - zlog.Error("文件复制失败:", err) - return - } - - zlog.Info("文件备份成功,备份文件路径:", backupFilePath) - - // 检查并清理旧的备份文件,保留最新的10个 - cleanupOldBackups(backupDir, 10) } + key := url.QueryEscape(global.GWAF_PWD_COREDB) dns := fmt.Sprintf("%s?_db_key=%s", path, key) db, err := gorm.Open(sqlite.Open(dns), &gorm.Config{}) diff --git a/wafupdate/selfupdate.go b/wafupdate/selfupdate.go index b4f33e7..5f3ac2f 100644 --- a/wafupdate/selfupdate.go +++ b/wafupdate/selfupdate.go @@ -675,3 +675,31 @@ func verifySha(bin []byte, sha []byte) bool { func writeTime(path string, t time.Time) bool { return ioutil.WriteFile(path, []byte(t.Format(time.RFC3339)), 0644) == nil } + +// BackupExecutable 备份当前可执行文件 +func BackupExecutable() error { + // 获取当前可执行文件路径 + execPath, err := os.Executable() + if err != nil { + return err + } + + // 如果是符号链接,获取实际路径 + if resolvedPath, err := filepath.EvalSymlinks(execPath); err == nil { + execPath = resolvedPath + } + + // 获取当前目录 + currentDir := utils.GetCurrentDir() + + // 创建备份目录 + backupDir := filepath.Join(currentDir, "data", "backups_bin") + + // 获取文件名(不带路径) + fileName := filepath.Base(execPath) + fileNameWithoutExt := strings.TrimSuffix(fileName, filepath.Ext(fileName)) + + // 备份文件 + _, err = utils.BackupFile(execPath, backupDir, fileNameWithoutExt, 5) + return err +}