1
2
3 package ociwclayer
4
5 import (
6 "archive/tar"
7 "bufio"
8 "context"
9 "io"
10 "os"
11 "path"
12 "path/filepath"
13 "strings"
14
15 winio "github.com/Microsoft/go-winio"
16 "github.com/Microsoft/go-winio/backuptar"
17 "github.com/Microsoft/hcsshim/internal/wclayer"
18 )
19
20 const whiteoutPrefix = ".wh."
21
22 var (
23
24
25 mutatedFiles = map[string]string{
26 "UtilityVM/Files/EFI/Microsoft/Boot/BCD": "bcd.bak",
27 "UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG": "bcd.log.bak",
28 "UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG1": "bcd.log1.bak",
29 "UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG2": "bcd.log2.bak",
30 }
31 )
32
33
34
35
36
37
38
39
40
41 func ImportLayerFromTar(ctx context.Context, r io.Reader, path string, parentLayerPaths []string) (int64, error) {
42 err := os.MkdirAll(path, 0)
43 if err != nil {
44 return 0, err
45 }
46 w, err := wclayer.NewLayerWriter(ctx, path, parentLayerPaths)
47 if err != nil {
48 return 0, err
49 }
50 n, err := writeLayerFromTar(ctx, r, w, path)
51 cerr := w.Close()
52 if err != nil {
53 return 0, err
54 }
55 if cerr != nil {
56 return 0, cerr
57 }
58 return n, nil
59 }
60
61 func writeLayerFromTar(ctx context.Context, r io.Reader, w wclayer.LayerWriter, root string) (int64, error) {
62 t := tar.NewReader(r)
63 hdr, err := t.Next()
64 totalSize := int64(0)
65 buf := bufio.NewWriter(nil)
66 for err == nil {
67 select {
68 case <-ctx.Done():
69 return 0, ctx.Err()
70 default:
71 }
72
73 base := path.Base(hdr.Name)
74 if strings.HasPrefix(base, whiteoutPrefix) {
75 name := path.Join(path.Dir(hdr.Name), base[len(whiteoutPrefix):])
76 err = w.Remove(filepath.FromSlash(name))
77 if err != nil {
78 return 0, err
79 }
80 hdr, err = t.Next()
81 } else if hdr.Typeflag == tar.TypeLink {
82 err = w.AddLink(filepath.FromSlash(hdr.Name), filepath.FromSlash(hdr.Linkname))
83 if err != nil {
84 return 0, err
85 }
86 hdr, err = t.Next()
87 } else {
88 var (
89 name string
90 size int64
91 fileInfo *winio.FileBasicInfo
92 )
93 name, size, fileInfo, err = backuptar.FileInfoFromHeader(hdr)
94 if err != nil {
95 return 0, err
96 }
97 err = w.Add(filepath.FromSlash(name), fileInfo)
98 if err != nil {
99 return 0, err
100 }
101 hdr, err = writeBackupStreamFromTarAndSaveMutatedFiles(buf, w, t, hdr, root)
102 totalSize += size
103 }
104 }
105 if err != io.EOF {
106 return 0, err
107 }
108 return totalSize, nil
109 }
110
111
112
113
114 func writeBackupStreamFromTarAndSaveMutatedFiles(buf *bufio.Writer, w io.Writer, t *tar.Reader, hdr *tar.Header, root string) (nextHdr *tar.Header, err error) {
115 var bcdBackup *os.File
116 var bcdBackupWriter *winio.BackupFileWriter
117 if backupPath, ok := mutatedFiles[hdr.Name]; ok {
118 bcdBackup, err = os.Create(filepath.Join(root, backupPath))
119 if err != nil {
120 return nil, err
121 }
122 defer func() {
123 cerr := bcdBackup.Close()
124 if err == nil {
125 err = cerr
126 }
127 }()
128
129 bcdBackupWriter = winio.NewBackupFileWriter(bcdBackup, false)
130 defer func() {
131 cerr := bcdBackupWriter.Close()
132 if err == nil {
133 err = cerr
134 }
135 }()
136
137 buf.Reset(io.MultiWriter(w, bcdBackupWriter))
138 } else {
139 buf.Reset(w)
140 }
141
142 defer func() {
143 ferr := buf.Flush()
144 if err == nil {
145 err = ferr
146 }
147 }()
148
149 return backuptar.WriteBackupStreamFromTarFile(buf, t, hdr)
150 }
151
View as plain text