fix: EXIF解析越界与转正丢文件、.psb归类、日志接管panic恢复

This commit is contained in:
2025-05-25 21:01:16 +08:00
parent a2cded251a
commit cf8d991974
3 changed files with 29 additions and 8 deletions
+2 -2
View File
@@ -280,8 +280,8 @@ type imageProbeResult struct {
// 只读数据库(查指纹),这是安全的。 // 只读数据库(查指纹),这是安全的。
func (o *Organizer) probeImage(f scanner.File) imageProbeResult { func (o *Organizer) probeImage(f scanner.File) imageProbeResult {
r := imageProbeResult{} r := imageProbeResult{}
// PSD 不体检,直接标记"原样收走" // PSD/PSB 设计稿不体检,直接标记"原样收走"
if strings.EqualFold(f.Ext, ".psd") { if strings.EqualFold(f.Ext, ".psd") || strings.EqualFold(f.Ext, ".psb") {
r.psd = true r.psd = true
return r return r
} }
+14 -6
View File
@@ -71,13 +71,21 @@ func RotateImage(ffmpegPath, filePath string) error {
} }
} }
// 用转正后的文件替换原文件 // 用转正后的文件替换原文件:先把原文件改名成备份,再让转正结果顶上,最后删备份。
if err := os.Remove(filePath); err != nil { // 这样即使中途失败,原文件也还在(只是改了名),不会弄丢。
backup := filePath + ".rotate.bak"
if err := os.Rename(filePath, backup); err != nil {
_ = os.Remove(tmp)
return fmt.Errorf("备份原文件失败: %v", err)
}
if err := os.Rename(tmp, filePath); err != nil {
// 转正结果放不回去:把备份挪回来尽量恢复原状
_ = os.Rename(backup, filePath)
_ = os.Remove(tmp) _ = os.Remove(tmp)
return fmt.Errorf("替换原文件失败: %v", err) return fmt.Errorf("替换原文件失败: %v", err)
} }
if err := os.Rename(tmp, filePath); err != nil { if err := os.Remove(backup); err != nil {
return fmt.Errorf("替换原文件失败: %v", err) fmt.Printf("=== 删除原文件备份失败(可手动清理 %s): %v\n", backup, err)
} }
return nil return nil
} }
@@ -120,7 +128,7 @@ func readExifAPP1(filePath string) ([]byte, error) {
if segLen < 2 { if segLen < 2 {
break break
} }
if marker == 0xE1 && segLen >= 8 && string(buf[pos+4:pos+8]) == "Exif" { if marker == 0xE1 && segLen >= 8 && pos+8 <= len(buf) && string(buf[pos+4:pos+8]) == "Exif" {
end := pos + 2 + segLen end := pos + 2 + segLen
if end > len(buf) { if end > len(buf) {
end = len(buf) end = len(buf)
@@ -254,7 +262,7 @@ func stripExifAPP1(rest []byte) []byte {
out = append(out, rest[pos:]...) out = append(out, rest[pos:]...)
return out return out
} }
isExif := marker == 0xE1 && segLen >= 8 && string(rest[pos+4:pos+8]) == "Exif" isExif := marker == 0xE1 && segLen >= 8 && pos+8 <= len(rest) && string(rest[pos+4:pos+8]) == "Exif"
if !isExif { if !isExif {
out = append(out, rest[pos:pos+2+segLen]...) out = append(out, rest[pos:pos+2+segLen]...)
} }
+13
View File
@@ -17,6 +17,7 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime/debug"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -327,6 +328,18 @@ func (s *ScanService) run(rootDir, destDir string) {
} }
}() }()
// 收尾必须恢复 stdout 并关闭管道,否则整个进程后续输出都会丢进这根无人读的管道里。
// 用 defer 保证即使 runScan 中途 panic 也不会留下这种状态;panic 还会被接住,
// 转成"出错"状态推给前端,而不是让整个程序崩溃。
defer func() {
os.Stdout = oldStdout
_ = w.Close()
<-done // 等读日志的 goroutine 把剩下的日志读完
if rcv := recover(); rcv != nil {
s.finish(ScanError, fmt.Sprintf("扫描整理内部错误: %v\n%s", rcv, debug.Stack()))
}
}()
// 真正开始干活。期间程序里所有 fmt.Println/Printf 都会进上面的管道 // 真正开始干活。期间程序里所有 fmt.Println/Printf 都会进上面的管道
scanErr := s.runScan(rootDir, destDir) scanErr := s.runScan(rootDir, destDir)