| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- //go:build darwin || linux || windows
- package libbox
- import (
- "archive/zip"
- "io"
- "io/fs"
- "os"
- "path/filepath"
- "runtime"
- "runtime/debug"
- "time"
- )
- type crashReportMetadata struct {
- reportMetadata
- CrashedAt string `json:"crashedAt,omitempty"`
- SignalName string `json:"signalName,omitempty"`
- SignalCode string `json:"signalCode,omitempty"`
- ExceptionName string `json:"exceptionName,omitempty"`
- ExceptionReason string `json:"exceptionReason,omitempty"`
- }
- func archiveCrashReport(path string, crashReportsDir string) {
- content, err := os.ReadFile(path)
- if err != nil || len(content) == 0 {
- return
- }
- info, _ := os.Stat(path)
- crashTime := time.Now().UTC()
- if info != nil {
- crashTime = info.ModTime().UTC()
- }
- initReportDir(crashReportsDir)
- destPath, err := nextAvailableReportPath(crashReportsDir, crashTime)
- if err != nil {
- return
- }
- initReportDir(destPath)
- writeReportFile(destPath, "go.log", content)
- metadata := crashReportMetadata{
- reportMetadata: baseReportMetadata(),
- CrashedAt: crashTime.Format(time.RFC3339),
- }
- writeReportMetadata(destPath, metadata)
- os.Remove(path)
- copyConfigSnapshot(destPath)
- }
- func configSnapshotPath() string {
- return filepath.Join(sBasePath, "configuration.json")
- }
- func saveConfigSnapshot(configContent string) {
- snapshotPath := configSnapshotPath()
- os.WriteFile(snapshotPath, []byte(configContent), 0o666)
- chownReport(snapshotPath)
- }
- func redirectStderr(path string) error {
- crashReportsDir := filepath.Join(sWorkingPath, "crash_reports")
- archiveCrashReport(path, crashReportsDir)
- archiveCrashReport(path+".old", crashReportsDir)
- outputFile, err := os.Create(path)
- if err != nil {
- return err
- }
- if runtime.GOOS != "android" && runtime.GOOS != "windows" {
- err = outputFile.Chown(sUserID, sGroupID)
- if err != nil {
- outputFile.Close()
- os.Remove(outputFile.Name())
- return err
- }
- }
- err = debug.SetCrashOutput(outputFile, debug.CrashOptions{})
- if err != nil {
- outputFile.Close()
- os.Remove(outputFile.Name())
- return err
- }
- _ = outputFile.Close()
- return nil
- }
- func CreateZipArchive(sourcePath string, destinationPath string) error {
- sourceInfo, err := os.Stat(sourcePath)
- if err != nil {
- return err
- }
- if !sourceInfo.IsDir() {
- return os.ErrInvalid
- }
- destinationFile, err := os.Create(destinationPath)
- if err != nil {
- return err
- }
- defer func() {
- _ = destinationFile.Close()
- }()
- zipWriter := zip.NewWriter(destinationFile)
- rootName := filepath.Base(sourcePath)
- err = filepath.WalkDir(sourcePath, func(path string, d fs.DirEntry, err error) error {
- if err != nil {
- return err
- }
- relativePath, err := filepath.Rel(sourcePath, path)
- if err != nil {
- return err
- }
- if relativePath == "." {
- return nil
- }
- archivePath := filepath.ToSlash(filepath.Join(rootName, relativePath))
- if d.IsDir() {
- _, err = zipWriter.Create(archivePath + "/")
- return err
- }
- fileInfo, err := d.Info()
- if err != nil {
- return err
- }
- header, err := zip.FileInfoHeader(fileInfo)
- if err != nil {
- return err
- }
- header.Name = archivePath
- header.Method = zip.Deflate
- writer, err := zipWriter.CreateHeader(header)
- if err != nil {
- return err
- }
- sourceFile, err := os.Open(path)
- if err != nil {
- return err
- }
- _, err = io.Copy(writer, sourceFile)
- closeErr := sourceFile.Close()
- if err != nil {
- return err
- }
- return closeErr
- })
- if err != nil {
- _ = zipWriter.Close()
- return err
- }
- return zipWriter.Close()
- }
|