Skip to content

Commit bbaa498

Browse files
aledbfroboquat
authored andcommitted
Refactor backup restauration
1 parent f6cfa94 commit bbaa498

File tree

1 file changed

+21
-139
lines changed
  • components/content-service/pkg/archive

1 file changed

+21
-139
lines changed

components/content-service/pkg/archive/tar.go

Lines changed: 21 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,13 @@
55
package archive
66

77
import (
8-
"archive/tar"
98
"context"
109
"io"
11-
"os"
12-
"os/exec"
13-
"path"
14-
"sort"
15-
"syscall"
1610
"time"
1711

18-
"github.com/moby/moby/pkg/system"
12+
"github.com/containers/storage/pkg/archive"
13+
"github.com/containers/storage/pkg/idtools"
1914
"github.com/opentracing/opentracing-go"
20-
"golang.org/x/xerrors"
2115

2216
"github.com/gitpod-io/gitpod/common-go/log"
2317
"github.com/gitpod-io/gitpod/common-go/tracing"
@@ -66,141 +60,29 @@ func ExtractTarbal(ctx context.Context, src io.Reader, dst string, opts ...TarOp
6660
opt(&cfg)
6761
}
6862

69-
pr, pw := io.Pipe()
70-
src = io.TeeReader(src, pw)
71-
tarReader := tar.NewReader(pr)
72-
73-
type Info struct {
74-
UID, GID int
75-
IsSymlink bool
76-
Xattrs map[string]string
77-
}
78-
79-
finished := make(chan bool)
80-
m := make(map[string]Info)
81-
82-
go func() {
83-
defer close(finished)
84-
for {
85-
hdr, err := tarReader.Next()
86-
if err == io.EOF {
87-
finished <- true
88-
return
89-
}
90-
91-
if err != nil {
92-
log.WithError(err).Error("error reading tar")
93-
return
94-
}
95-
96-
m[hdr.Name] = Info{
97-
UID: hdr.Uid,
98-
GID: hdr.Gid,
99-
IsSymlink: (hdr.Linkname != ""),
100-
//nolint:staticcheck
101-
Xattrs: hdr.Xattrs,
102-
}
63+
uidMaps := make([]idtools.IDMap, len(cfg.UIDMaps))
64+
for i, m := range cfg.UIDMaps {
65+
uidMaps[i] = idtools.IDMap{
66+
ContainerID: m.ContainerID,
67+
HostID: m.HostID,
68+
Size: m.Size,
10369
}
104-
}()
105-
106-
// Be explicit about the tar flags. We want to restore the exact content without changes
107-
tarcmd := exec.Command(
108-
"tar",
109-
"--extract",
110-
"--preserve-permissions",
111-
"--xattrs", "--xattrs-include=security.capability",
112-
)
113-
tarcmd.Dir = dst
114-
tarcmd.Stdin = src
115-
116-
var msg []byte
117-
msg, err = tarcmd.CombinedOutput()
118-
if err != nil {
119-
return xerrors.Errorf("tar %s: %s", dst, err.Error()+";"+string(msg))
12070
}
121-
122-
log.WithField("log", string(msg)).Debug("decompressing tar stream log")
123-
124-
<-finished
125-
126-
// lets create a sorted list of pathes and chown depth first.
127-
paths := make([]string, 0, len(m))
128-
for path := range m {
129-
paths = append(paths, path)
130-
}
131-
sort.Sort(sort.Reverse(sort.StringSlice(paths)))
132-
133-
// We need to remap the UID and GID between the host and the container to avoid permission issues.
134-
for _, p := range paths {
135-
v := m[p]
136-
uid := toHostID(v.UID, cfg.UIDMaps)
137-
gid := toHostID(v.GID, cfg.GIDMaps)
138-
139-
if v.IsSymlink {
140-
continue
141-
}
142-
143-
err = remapFile(path.Join(dst, p), uid, gid, v.Xattrs)
144-
if err != nil {
145-
log.WithError(err).WithField("uid", uid).WithField("gid", gid).WithField("path", p).Warn("cannot chown")
71+
gidMaps := make([]idtools.IDMap, len(cfg.GIDMaps))
72+
for i, m := range cfg.GIDMaps {
73+
gidMaps[i] = idtools.IDMap{
74+
ContainerID: m.ContainerID,
75+
HostID: m.HostID,
76+
Size: m.Size,
14677
}
14778
}
14879

149-
log.WithField("duration", time.Since(start).Milliseconds()).Debug("untar complete")
150-
return nil
151-
}
80+
err = archive.Untar(src, dst, &archive.TarOptions{
81+
UIDMaps: uidMaps,
82+
GIDMaps: gidMaps,
83+
Compression: archive.Uncompressed,
84+
})
15285

153-
func toHostID(containerID int, idMap []IDMapping) int {
154-
for _, m := range idMap {
155-
if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) {
156-
hostID := m.HostID + (containerID - m.ContainerID)
157-
return hostID
158-
}
159-
}
160-
return containerID
161-
}
162-
163-
// remapFile changes the UID and GID of a file preserving existing file mode bits.
164-
func remapFile(name string, uid, gid int, xattrs map[string]string) error {
165-
// current info of the file before any change
166-
fileInfo, err := os.Stat(name)
167-
if err != nil {
168-
return err
169-
}
170-
171-
// nothing to do for symlinks
172-
if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink {
173-
return nil
174-
}
175-
176-
// changing UID or GID can break files with suid/sgid
177-
err = os.Lchown(name, uid, gid)
178-
if err != nil {
179-
return err
180-
}
181-
182-
// restore original permissions
183-
err = os.Chmod(name, fileInfo.Mode())
184-
if err != nil {
185-
return err
186-
}
187-
188-
for key, value := range xattrs {
189-
if err := system.Lsetxattr(name, key, []byte(value), 0); err != nil {
190-
log.WithField("name", key).WithField("value", value).WithField("file", name).WithError(err).Error("restoring extended attributes")
191-
if err == syscall.ENOTSUP || err == syscall.EPERM {
192-
continue
193-
}
194-
195-
return err
196-
}
197-
}
198-
199-
// restore file times
200-
fileTime := fileInfo.Sys().(*syscall.Stat_t)
201-
return os.Chtimes(name, timespecToTime(fileTime.Atim), timespecToTime(fileTime.Mtim))
202-
}
203-
204-
func timespecToTime(ts syscall.Timespec) time.Time {
205-
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
86+
log.WithField("duration", time.Since(start).Milliseconds()).Debug("untar complete")
87+
return
20688
}

0 commit comments

Comments
 (0)