-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrestore.go
134 lines (106 loc) · 3.19 KB
/
restore.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package cmd
import (
"archive/tar"
"context"
"fmt"
"io"
"os"
"strings"
"github.com/inpher/sb/internal/commands"
"github.com/inpher/sb/internal/helpers"
"github.com/inpher/sb/internal/models"
"github.com/mholt/archiver/v4"
"github.com/pkg/errors"
)
type Restore struct{}
func init() {
commands.RegisterCommand("restore", func() (c commands.Command, r models.Right, helper helpers.Helper, args map[string]commands.Argument) {
return new(Restore), models.Private, helpers.Helper{
Header: "restores a backup archive of this sb instance",
Usage: "restore",
Description: "restores a backup archive of this sb instance",
}, map[string]commands.Argument{
"file": {
Required: true,
Description: "The filepath of the binary file to restore",
},
"decryption-key": {
Required: true,
Description: "Key to use to decrypt the binary backup file",
},
}
})
}
func (c *Restore) Checks(ct *commands.Context) (err error) {
if !strings.HasSuffix(ct.FormattedArguments["file"], ".bin") {
return fmt.Errorf("only .bin file format is supported")
}
_, err = os.Stat(ct.FormattedArguments["file"])
if err != nil {
return fmt.Errorf("unable to find file %s on disk", ct.FormattedArguments["file"])
}
return
}
func (c *Restore) Execute(ct *commands.Context) (repl models.ReplicationData, cmdError error, err error) {
binFilepath := ct.FormattedArguments["file"]
tgzFilepath := strings.Replace(ct.FormattedArguments["file"], ".bin", ".tar.gz", 1)
err = helpers.DecryptFile(binFilepath, tgzFilepath, ct.FormattedArguments["decryption-key"])
if err != nil {
err = errors.Wrap(err, "unable to decrypt the backup file")
return
}
f, err := os.Open(tgzFilepath)
if err != nil {
err = errors.Wrap(err, "unable to open decrypted backup file")
return
}
format := archiver.CompressedArchive{
Compression: archiver.Gz{},
Archival: archiver.Tar{},
}
handler := func(ctx context.Context, f archiver.File) error {
stat := f.Sys().(*tar.Header)
if f.IsDir() {
err = os.MkdirAll(f.NameInArchive, f.Mode().Perm())
if err != nil {
return errors.Wrap(err, "unable to create directory")
}
err = os.Chown(f.NameInArchive, stat.Uid, stat.Gid)
if err != nil {
return errors.Wrap(err, "unable to chown directory")
}
return nil
}
src, err := f.Open()
if err != nil {
return errors.Wrap(err, "unable to open file for read")
}
dst, err := os.OpenFile(f.NameInArchive, os.O_RDWR|os.O_CREATE, f.Mode().Perm())
if err != nil {
return errors.Wrap(err, "unable to open file for write")
}
defer dst.Close()
_, err = io.Copy(dst, src)
if err != nil {
return errors.Wrap(err, "unable to write file content")
}
err = os.Chown(f.NameInArchive, stat.Uid, stat.Gid)
if err != nil {
return errors.Wrap(err, "unable to chown file")
}
return nil
}
err = format.Extract(context.Background(), f, nil, handler)
if err != nil {
err = errors.Wrap(err, "unable to restore backup file")
return
}
fmt.Printf("Backup successfully restored\n")
return
}
func (c *Restore) PostExecute(repl models.ReplicationData) (err error) {
return
}
func (c *Restore) Replicate(repl models.ReplicationData) (err error) {
return
}