X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/6844f8c992ec4e276a3a0d93b544de0127eebbd2..448c931a776c3e3f65ca2eab11da0c062d597818:/backup.go?ds=sidebyside diff --git a/backup.go b/backup.go index 56cf516..c03e633 100644 --- a/backup.go +++ b/backup.go @@ -37,8 +37,10 @@ func backup(ctx context.Context, path string, out io.Writer) (err error) { }() stop := context.AfterFunc(ctx, func() { - _ = conn.Close() + // Cancellation closes the socket only to interrupt pending I/O. + conn.Close() // nolint: errcheck }) + defer stop() err = json.NewEncoder(conn).Encode(SocketRequest{ @@ -92,42 +94,6 @@ func restore(ctx context.Context, path string, out io.Writer) error { return nil } -// backupData stages a session snapshot, then copies the data under snapshot's -// write locks. Compression runs after the locks are released. -func backupData(ctx context.Context, dir, path string, whatsapp *WhatsApp, snapshot func(context.Context, func() error) error) (size int64, err error) { - if !filepath.IsAbs(path) { - return 0, errors.New("backup path must be absolute") - } - - stage, err := os.MkdirTemp("", "onechat-backup-*") - if err != nil { - return 0, fmt.Errorf("create backup directory: %w", err) - } - - defer func() { - err = errors.Join(err, os.RemoveAll(stage)) - }() - - err = whatsapp.BackupSession(ctx, filepath.Join(stage, whatsappDirName, whatsappSessionFileName)) - if err != nil { - return 0, fmt.Errorf("copy WhatsApp session: %w", err) - } - - err = snapshot(ctx, func() error { - return backupCopy(ctx, dir, stage, path) - }) - if err != nil { - return 0, fmt.Errorf("copy data directory: %w", err) - } - - size, err = backupArchive(ctx, stage, path) - if err != nil { - return 0, fmt.Errorf("archive backup: %w", err) - } - - return size, nil -} - // backupRestore installs a validated archive into an empty data directory while // holding the token lock. It keeps the lock file so daemon starts use that same // inode, including after a failed restore. @@ -204,6 +170,42 @@ func backupRestore(ctx context.Context, path, dir string) (err error) { return nil } +// backupData stages a session snapshot, then copies the data under snapshot's +// write locks. Compression runs after the locks are released. +func backupData(ctx context.Context, dir, path string, whatsapp *WhatsApp, snapshot func(context.Context, func() error) error) (size int64, err error) { + if !filepath.IsAbs(path) { + return 0, errors.New("backup path must be absolute") + } + + stage, err := os.MkdirTemp("", "onechat-backup-*") + if err != nil { + return 0, fmt.Errorf("create backup directory: %w", err) + } + + defer func() { + err = errors.Join(err, os.RemoveAll(stage)) + }() + + err = whatsapp.BackupSession(ctx, filepath.Join(stage, whatsappDirName, whatsappSessionFileName)) + if err != nil { + return 0, fmt.Errorf("copy WhatsApp session: %w", err) + } + + err = snapshot(ctx, func() error { + return backupCopy(ctx, dir, stage, path) + }) + if err != nil { + return 0, fmt.Errorf("copy data directory: %w", err) + } + + size, err = backupArchive(ctx, stage, path) + if err != nil { + return 0, fmt.Errorf("archive backup: %w", err) + } + + return size, nil +} + // backupCopy stages regular files and directories, excluding runtime files, the // output archive, and raw session database files. Each file keeps its mode. func backupCopy(ctx context.Context, source, target, output string) error {