blob: 69bdcdb5013421e153b5d36dd450af37aa6c1614 [file] [log] [blame]
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001From 1e55f2a83b1f644803b640b72171b4ae0d95217b Mon Sep 17 00:00:00 2001
2From: "W. Trevor King" <wking@tremily.us>
3Date: Thu, 20 Oct 2016 23:30:22 -0700
4Subject: [PATCH 2/2] image/manifest: Split unpackLayerEntry into its own
5 function
6
7To help address:
8
9 $ make lint
10 checking lint
11 image/manifest.go:140::warning: cyclomatic complexity 39 of function unpackLayer() is high (> 35) (gocyclo)
12 ...
13
14Signed-off-by: W. Trevor King <wking@tremily.us>
15---
16 image/manifest.go | 185 +++++++++++++++++++++++++++++-------------------------
17 1 file changed, 100 insertions(+), 85 deletions(-)
18
19diff --git a/image/manifest.go b/image/manifest.go
20index 144bd4f62219..dfd5a83f70e4 100644
21--- a/src/import/image/manifest.go
22+++ b/src/import/image/manifest.go
23@@ -218,116 +218,131 @@ loop:
24 return errors.Wrapf(err, "error advancing tar stream")
25 }
26
27- hdr.Name = filepath.Clean(hdr.Name)
28- if !strings.HasSuffix(hdr.Name, string(os.PathSeparator)) {
29- // Not the root directory, ensure that the parent directory exists
30- parent := filepath.Dir(hdr.Name)
31- parentPath := filepath.Join(dest, parent)
32- if _, err2 := os.Lstat(parentPath); err2 != nil && os.IsNotExist(err2) {
33- if err3 := os.MkdirAll(parentPath, 0755); err3 != nil {
34- return err3
35- }
36- }
37- }
38- path := filepath.Join(dest, hdr.Name)
39- if entries[path] {
40- return fmt.Errorf("duplicate entry for %s", path)
41- }
42- entries[path] = true
43- rel, err := filepath.Rel(dest, path)
44+ var whiteout bool
45+ whiteout, err = unpackLayerEntry(dest, hdr, tr, &entries)
46 if err != nil {
47 return err
48 }
49- info := hdr.FileInfo()
50- if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
51- return fmt.Errorf("%q is outside of %q", hdr.Name, dest)
52+ if whiteout {
53+ continue loop
54 }
55
56- if strings.HasPrefix(info.Name(), ".wh.") {
57- path = strings.Replace(path, ".wh.", "", 1)
58+ // Directory mtimes must be handled at the end to avoid further
59+ // file creation in them to modify the directory mtime
60+ if hdr.Typeflag == tar.TypeDir {
61+ dirs = append(dirs, hdr)
62+ }
63+ }
64+ for _, hdr := range dirs {
65+ path := filepath.Join(dest, hdr.Name)
66
67- if err := os.RemoveAll(path); err != nil {
68- return errors.Wrap(err, "unable to delete whiteout path")
69+ finfo := hdr.FileInfo()
70+ // I believe the old version was using time.Now().UTC() to overcome an
71+ // invalid error from chtimes.....but here we lose hdr.AccessTime like this...
72+ if err := os.Chtimes(path, time.Now().UTC(), finfo.ModTime()); err != nil {
73+ return errors.Wrap(err, "error changing time")
74+ }
75+ }
76+ return nil
77+}
78+
79+// unpackLayerEntry unpacks a single entry from a layer.
80+func unpackLayerEntry(dest string, header *tar.Header, reader io.Reader, entries *map[string]bool) (whiteout bool, err error) {
81+ header.Name = filepath.Clean(header.Name)
82+ if !strings.HasSuffix(header.Name, string(os.PathSeparator)) {
83+ // Not the root directory, ensure that the parent directory exists
84+ parent := filepath.Dir(header.Name)
85+ parentPath := filepath.Join(dest, parent)
86+ if _, err2 := os.Lstat(parentPath); err2 != nil && os.IsNotExist(err2) {
87+ if err3 := os.MkdirAll(parentPath, 0755); err3 != nil {
88+ return false, err3
89 }
90+ }
91+ }
92+ path := filepath.Join(dest, header.Name)
93+ if (*entries)[path] {
94+ return false, fmt.Errorf("duplicate entry for %s", path)
95+ }
96+ (*entries)[path] = true
97+ rel, err := filepath.Rel(dest, path)
98+ if err != nil {
99+ return false, err
100+ }
101+ info := header.FileInfo()
102+ if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
103+ return false, fmt.Errorf("%q is outside of %q", header.Name, dest)
104+ }
105
106- continue loop
107+ if strings.HasPrefix(info.Name(), ".wh.") {
108+ path = strings.Replace(path, ".wh.", "", 1)
109+
110+ if err = os.RemoveAll(path); err != nil {
111+ return true, errors.Wrap(err, "unable to delete whiteout path")
112 }
113
114- if hdr.Typeflag != tar.TypeDir {
115- err = os.RemoveAll(path)
116- if err != nil && !os.IsNotExist(err) {
117- return err
118- }
119+ return true, nil
120+ }
121+
122+ if header.Typeflag != tar.TypeDir {
123+ err = os.RemoveAll(path)
124+ if err != nil && !os.IsNotExist(err) {
125+ return false, err
126 }
127+ }
128
129- switch hdr.Typeflag {
130- case tar.TypeDir:
131- fi, err := os.Lstat(path)
132+ switch header.Typeflag {
133+ case tar.TypeDir:
134+ fi, err := os.Lstat(path)
135+ if err != nil && !os.IsNotExist(err) {
136+ return false, err
137+ }
138+ if os.IsNotExist(err) || !fi.IsDir() {
139+ err = os.RemoveAll(path)
140 if err != nil && !os.IsNotExist(err) {
141- return err
142- }
143- if os.IsNotExist(err) || !fi.IsDir() {
144- err = os.RemoveAll(path)
145- if err != nil && !os.IsNotExist(err) {
146- return err
147- }
148- err = os.MkdirAll(path, info.Mode())
149- if err != nil {
150- return err
151- }
152+ return false, err
153 }
154-
155- case tar.TypeReg, tar.TypeRegA:
156- f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, info.Mode())
157+ err = os.MkdirAll(path, info.Mode())
158 if err != nil {
159- return errors.Wrap(err, "unable to open file")
160+ return false, err
161 }
162+ }
163
164- if _, err := io.Copy(f, tr); err != nil {
165- f.Close()
166- return errors.Wrap(err, "unable to copy")
167- }
168- f.Close()
169+ case tar.TypeReg, tar.TypeRegA:
170+ f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, info.Mode())
171+ if err != nil {
172+ return false, errors.Wrap(err, "unable to open file")
173+ }
174
175- case tar.TypeLink:
176- target := filepath.Join(dest, hdr.Linkname)
177+ if _, err := io.Copy(f, reader); err != nil {
178+ f.Close()
179+ return false, errors.Wrap(err, "unable to copy")
180+ }
181+ f.Close()
182
183- if !strings.HasPrefix(target, dest) {
184- return fmt.Errorf("invalid hardlink %q -> %q", target, hdr.Linkname)
185- }
186+ case tar.TypeLink:
187+ target := filepath.Join(dest, header.Linkname)
188
189- if err := os.Link(target, path); err != nil {
190- return err
191- }
192+ if !strings.HasPrefix(target, dest) {
193+ return false, fmt.Errorf("invalid hardlink %q -> %q", target, header.Linkname)
194+ }
195
196- case tar.TypeSymlink:
197- target := filepath.Join(filepath.Dir(path), hdr.Linkname)
198+ if err := os.Link(target, path); err != nil {
199+ return false, err
200+ }
201
202- if !strings.HasPrefix(target, dest) {
203- return fmt.Errorf("invalid symlink %q -> %q", path, hdr.Linkname)
204- }
205+ case tar.TypeSymlink:
206+ target := filepath.Join(filepath.Dir(path), header.Linkname)
207
208- if err := os.Symlink(hdr.Linkname, path); err != nil {
209- return err
210- }
211- case tar.TypeXGlobalHeader:
212- return nil
213+ if !strings.HasPrefix(target, dest) {
214+ return false, fmt.Errorf("invalid symlink %q -> %q", path, header.Linkname)
215 }
216- // Directory mtimes must be handled at the end to avoid further
217- // file creation in them to modify the directory mtime
218- if hdr.Typeflag == tar.TypeDir {
219- dirs = append(dirs, hdr)
220- }
221- }
222- for _, hdr := range dirs {
223- path := filepath.Join(dest, hdr.Name)
224
225- finfo := hdr.FileInfo()
226- // I believe the old version was using time.Now().UTC() to overcome an
227- // invalid error from chtimes.....but here we lose hdr.AccessTime like this...
228- if err := os.Chtimes(path, time.Now().UTC(), finfo.ModTime()); err != nil {
229- return errors.Wrap(err, "error changing time")
230+ if err := os.Symlink(header.Linkname, path); err != nil {
231+ return false, err
232 }
233+ case tar.TypeXGlobalHeader:
234+ return false, nil
235 }
236- return nil
237+
238+ return false, nil
239 }
240--
2412.4.0.53.g8440f74
242