...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package windows
16
17 import (
18 "archive/tar"
19 "bytes"
20 "errors"
21 "fmt"
22 "io"
23 "path"
24 "strings"
25
26 "github.com/google/go-containerregistry/internal/gzip"
27 v1 "github.com/google/go-containerregistry/pkg/v1"
28 "github.com/google/go-containerregistry/pkg/v1/tarball"
29 )
30
31
32
33
34
35 const userOwnerAndGroupSID = "AQAAgBQAAAAkAAAAAAAAAAAAAAABAgAAAAAABSAAAAAhAgAAAQIAAAAAAAUgAAAAIQIAAA=="
36
37
38 func Windows(layer v1.Layer) (v1.Layer, error) {
39
40
41 layerReader, err := layer.Uncompressed()
42 if err != nil {
43 return nil, fmt.Errorf("getting layer: %w", err)
44 }
45 defer layerReader.Close()
46 tarReader := tar.NewReader(layerReader)
47 w := new(bytes.Buffer)
48 tarWriter := tar.NewWriter(w)
49 defer tarWriter.Close()
50
51 for _, dir := range []string{"Files", "Hives"} {
52 if err := tarWriter.WriteHeader(&tar.Header{
53 Name: dir,
54 Typeflag: tar.TypeDir,
55
56
57
58 Mode: 0555,
59 Format: tar.FormatPAX,
60 }); err != nil {
61 return nil, fmt.Errorf("writing %s directory: %w", dir, err)
62 }
63 }
64
65 for {
66 header, err := tarReader.Next()
67 if errors.Is(err, io.EOF) {
68 break
69 }
70 if err != nil {
71 return nil, fmt.Errorf("reading layer: %w", err)
72 }
73
74 if strings.HasPrefix(header.Name, "Files/") {
75 return nil, fmt.Errorf("file path %q already suitable for Windows", header.Name)
76 }
77
78 header.Name = path.Join("Files", header.Name)
79 header.Format = tar.FormatPAX
80
81
82
83 if header.PAXRecords == nil {
84 header.PAXRecords = map[string]string{}
85 }
86 header.PAXRecords["MSWINDOWS.rawsd"] = userOwnerAndGroupSID
87
88 if err := tarWriter.WriteHeader(header); err != nil {
89 return nil, fmt.Errorf("writing tar header: %w", err)
90 }
91
92 if header.Typeflag == tar.TypeReg {
93 if _, err = io.Copy(tarWriter, tarReader); err != nil {
94 return nil, fmt.Errorf("writing layer file: %w", err)
95 }
96 }
97 }
98
99 if err := tarWriter.Close(); err != nil {
100 return nil, err
101 }
102
103 b := w.Bytes()
104
105 opener := func() (io.ReadCloser, error) {
106 return gzip.ReadCloser(io.NopCloser(bytes.NewReader(b))), nil
107 }
108 layer, err = tarball.LayerFromOpener(opener)
109 if err != nil {
110 return nil, fmt.Errorf("creating layer: %w", err)
111 }
112
113 return layer, nil
114 }
115
View as plain text