Browse code

Fix uses of "int" where "int64" should be used instead

Some structures use int for sizes and UNIX timestamps. On some
platforms, int is 32 bits, so this can lead to the year 2038 issues and
overflows when dealing with large containers or layers.

Consistently use int64 to store sizes and UNIX timestamps in
api/types/types.go. Update related to code accordingly (i.e.
strconv.FormatInt instead of strconv.Itoa).

Use int64 in progressreader package to avoid integer overflow when
dealing with large quantities. Update related code accordingly.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>

Aaron Lehmann authored on 2015/07/24 06:19:58
Showing 22 changed files
... ...
@@ -462,7 +462,7 @@ func getContextFromURL(out io.Writer, remoteURL, dockerfileName string) (absCont
462 462
 		In:        response.Body,
463 463
 		Out:       out,
464 464
 		Formatter: streamformatter.NewStreamFormatter(),
465
-		Size:      int(response.ContentLength),
465
+		Size:      response.ContentLength,
466 466
 		NewLines:  true,
467 467
 		ID:        "",
468 468
 		Action:    fmt.Sprintf("Downloading build context from remote url: %s", remoteURL),
... ...
@@ -27,7 +27,7 @@ func TestContainerContextID(t *testing.T) {
27 27
 		{types.Container{Image: "ubuntu"}, true, "ubuntu", imageHeader, ctx.Image},
28 28
 		{types.Container{Image: ""}, true, "<no image>", imageHeader, ctx.Image},
29 29
 		{types.Container{Command: "sh -c 'ls -la'"}, true, `"sh -c 'ls -la'"`, commandHeader, ctx.Command},
30
-		{types.Container{Created: int(unix)}, true, time.Unix(unix, 0).String(), createdAtHeader, ctx.CreatedAt},
30
+		{types.Container{Created: unix}, true, time.Unix(unix, 0).String(), createdAtHeader, ctx.CreatedAt},
31 31
 		{types.Container{Ports: []types.Port{{PrivatePort: 8080, PublicPort: 8080, Type: "tcp"}}}, true, "8080/tcp", portsHeader, ctx.Ports},
32 32
 		{types.Container{Status: "RUNNING"}, true, "RUNNING", statusHeader, ctx.Status},
33 33
 		{types.Container{SizeRw: 10}, true, "10 B", sizeHeader, ctx.Size},
... ...
@@ -70,9 +70,9 @@ type Image struct {
70 70
 	ParentId    string
71 71
 	RepoTags    []string
72 72
 	RepoDigests []string
73
-	Created     int
74
-	Size        int
75
-	VirtualSize int
73
+	Created     int64
74
+	Size        int64
75
+	VirtualSize int64
76 76
 	Labels      map[string]string
77 77
 }
78 78
 
... ...
@@ -112,10 +112,10 @@ type Container struct {
112 112
 	Names      []string
113 113
 	Image      string
114 114
 	Command    string
115
-	Created    int
115
+	Created    int64
116 116
 	Ports      []Port
117
-	SizeRw     int `json:",omitempty"`
118
-	SizeRootFs int `json:",omitempty"`
117
+	SizeRw     int64 `json:",omitempty"`
118
+	SizeRootFs int64 `json:",omitempty"`
119 119
 	Labels     map[string]string
120 120
 	Status     string
121 121
 	HostConfig struct {
... ...
@@ -330,7 +330,7 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri
330 330
 			In:        resp.Body,
331 331
 			Out:       b.OutOld,
332 332
 			Formatter: b.StreamFormatter,
333
-			Size:      int(resp.ContentLength),
333
+			Size:      resp.ContentLength,
334 334
 			NewLines:  true,
335 335
 			ID:        "",
336 336
 			Action:    "Downloading",
... ...
@@ -139,7 +139,7 @@ func Build(d *daemon.Daemon, buildConfig *Config) error {
139 139
 		}
140 140
 		defer f.Body.Close()
141 141
 		ct := f.Header.Get("Content-Type")
142
-		clen := int(f.ContentLength)
142
+		clen := f.ContentLength
143 143
 		contentType, bodyReader, err := inspectResponse(ct, f.Body, clen)
144 144
 
145 145
 		defer bodyReader.Close()
... ...
@@ -316,7 +316,7 @@ func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) {
316 316
 //    - an io.Reader for the response body
317 317
 //    - an error value which will be non-nil either when something goes wrong while
318 318
 //      reading bytes from r or when the detected content-type is not acceptable.
319
-func inspectResponse(ct string, r io.ReadCloser, clen int) (string, io.ReadCloser, error) {
319
+func inspectResponse(ct string, r io.ReadCloser, clen int64) (string, io.ReadCloser, error) {
320 320
 	plen := clen
321 321
 	if plen <= 0 || plen > maxPreambleLength {
322 322
 		plen = maxPreambleLength
... ...
@@ -31,7 +31,7 @@ func TestInspectEmptyResponse(t *testing.T) {
31 31
 func TestInspectResponseBinary(t *testing.T) {
32 32
 	ct := "application/octet-stream"
33 33
 	br := ioutil.NopCloser(bytes.NewReader(binaryContext))
34
-	contentType, bReader, err := inspectResponse(ct, br, len(binaryContext))
34
+	contentType, bReader, err := inspectResponse(ct, br, int64(len(binaryContext)))
35 35
 	if err != nil {
36 36
 		t.Fatal(err)
37 37
 	}
... ...
@@ -56,7 +56,7 @@ func TestResponseUnsupportedContentType(t *testing.T) {
56 56
 	content := []byte(textPlainDockerfile)
57 57
 	ct := "application/json"
58 58
 	br := ioutil.NopCloser(bytes.NewReader(content))
59
-	contentType, bReader, err := inspectResponse(ct, br, len(textPlainDockerfile))
59
+	contentType, bReader, err := inspectResponse(ct, br, int64(len(textPlainDockerfile)))
60 60
 
61 61
 	if err == nil {
62 62
 		t.Fatal("Should have returned an error on content-type 'application/json'")
... ...
@@ -77,7 +77,7 @@ func TestInspectResponseTextSimple(t *testing.T) {
77 77
 	content := []byte(textPlainDockerfile)
78 78
 	ct := "text/plain"
79 79
 	br := ioutil.NopCloser(bytes.NewReader(content))
80
-	contentType, bReader, err := inspectResponse(ct, br, len(content))
80
+	contentType, bReader, err := inspectResponse(ct, br, int64(len(content)))
81 81
 	if err != nil {
82 82
 		t.Fatal(err)
83 83
 	}
... ...
@@ -96,7 +96,7 @@ func TestInspectResponseTextSimple(t *testing.T) {
96 96
 func TestInspectResponseEmptyContentType(t *testing.T) {
97 97
 	content := []byte(textPlainDockerfile)
98 98
 	br := ioutil.NopCloser(bytes.NewReader(content))
99
-	contentType, bodyReader, err := inspectResponse("", br, len(content))
99
+	contentType, bodyReader, err := inspectResponse("", br, int64(len(content)))
100 100
 	if err != nil {
101 101
 		t.Fatal(err)
102 102
 	}
... ...
@@ -152,7 +152,7 @@ func (daemon *Daemon) Containers(config *ContainersConfig) ([]*types.Container,
152 152
 		} else {
153 153
 			newC.Command = fmt.Sprintf("%s", container.Path)
154 154
 		}
155
-		newC.Created = int(container.Created.Unix())
155
+		newC.Created = container.Created.Unix()
156 156
 		newC.Status = container.State.String()
157 157
 		newC.HostConfig.NetworkMode = string(container.hostConfig.NetworkMode)
158 158
 
... ...
@@ -185,8 +185,8 @@ func (daemon *Daemon) Containers(config *ContainersConfig) ([]*types.Container,
185 185
 
186 186
 		if config.Size {
187 187
 			sizeRw, sizeRootFs := container.GetSize()
188
-			newC.SizeRw = int(sizeRw)
189
-			newC.SizeRootFs = int(sizeRootFs)
188
+			newC.SizeRw = sizeRw
189
+			newC.SizeRootFs = sizeRootFs
190 190
 		}
191 191
 		newC.Labels = container.Config.Labels
192 192
 		containers = append(containers, newC)
... ...
@@ -190,7 +190,7 @@ func (graph *Graph) Get(name string) (*image.Image, error) {
190 190
 		}
191 191
 
192 192
 		img.Size = size
193
-		if err := graph.saveSize(graph.imageRoot(id), int(img.Size)); err != nil {
193
+		if err := graph.saveSize(graph.imageRoot(id), img.Size); err != nil {
194 194
 			return nil, err
195 195
 		}
196 196
 	}
... ...
@@ -490,8 +490,8 @@ func (graph *Graph) loadImage(id string) (*image.Image, error) {
490 490
 }
491 491
 
492 492
 // saveSize stores the `size` in the provided graph `img` directory `root`.
493
-func (graph *Graph) saveSize(root string, size int) error {
494
-	if err := ioutil.WriteFile(filepath.Join(root, layersizeFileName), []byte(strconv.Itoa(size)), 0600); err != nil {
493
+func (graph *Graph) saveSize(root string, size int64) error {
494
+	if err := ioutil.WriteFile(filepath.Join(root, layersizeFileName), []byte(strconv.FormatInt(size, 10)), 0600); err != nil {
495 495
 		return fmt.Errorf("Error storing image size in %s/%s: %s", root, layersizeFileName, err)
496 496
 	}
497 497
 	return nil
... ...
@@ -95,7 +95,7 @@ func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader
95 95
 		}
96 96
 	}
97 97
 
98
-	if err := graph.saveSize(root, int(img.Size)); err != nil {
98
+	if err := graph.saveSize(root, img.Size); err != nil {
99 99
 		return err
100 100
 	}
101 101
 
... ...
@@ -95,7 +95,7 @@ func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader
95 95
 			}
96 96
 		}
97 97
 
98
-		if err := graph.saveSize(root, int(img.Size)); err != nil {
98
+		if err := graph.saveSize(root, img.Size); err != nil {
99 99
 			return err
100 100
 		}
101 101
 
... ...
@@ -45,7 +45,7 @@ func (s *TagStore) Import(src string, repo string, tag string, inConfig io.ReadC
45 45
 			In:        resp.Body,
46 46
 			Out:       outStream,
47 47
 			Formatter: sf,
48
-			Size:      int(resp.ContentLength),
48
+			Size:      resp.ContentLength,
49 49
 			NewLines:  true,
50 50
 			ID:        "",
51 51
 			Action:    "Importing",
... ...
@@ -99,9 +99,9 @@ func (s *TagStore) Images(filterArgs, filter string, all bool) ([]*types.Image,
99 99
 					newImage := new(types.Image)
100 100
 					newImage.ParentId = image.Parent
101 101
 					newImage.ID = image.ID
102
-					newImage.Created = int(image.Created.Unix())
103
-					newImage.Size = int(image.Size)
104
-					newImage.VirtualSize = int(s.graph.GetParentsSize(image) + image.Size)
102
+					newImage.Created = image.Created.Unix()
103
+					newImage.Size = image.Size
104
+					newImage.VirtualSize = s.graph.GetParentsSize(image) + image.Size
105 105
 					newImage.Labels = image.ContainerConfig.Labels
106 106
 
107 107
 					if utils.DigestReference(ref) {
... ...
@@ -136,9 +136,9 @@ func (s *TagStore) Images(filterArgs, filter string, all bool) ([]*types.Image,
136 136
 			newImage.RepoTags = []string{"<none>:<none>"}
137 137
 			newImage.RepoDigests = []string{"<none>@<none>"}
138 138
 			newImage.ID = image.ID
139
-			newImage.Created = int(image.Created.Unix())
140
-			newImage.Size = int(image.Size)
141
-			newImage.VirtualSize = int(s.graph.GetParentsSize(image) + image.Size)
139
+			newImage.Created = image.Created.Unix()
140
+			newImage.Size = image.Size
141
+			newImage.VirtualSize = s.graph.GetParentsSize(image) + image.Size
142 142
 			newImage.Labels = image.ContainerConfig.Labels
143 143
 
144 144
 			images = append(images, newImage)
... ...
@@ -256,7 +256,7 @@ func (p *v1Puller) pullImage(imgID, endpoint string, token []string) (bool, erro
256 256
 			out.Write(p.sf.FormatProgress(stringid.TruncateID(id), "Pulling metadata", nil))
257 257
 			var (
258 258
 				imgJSON []byte
259
-				imgSize int
259
+				imgSize int64
260 260
 				err     error
261 261
 				img     *image.Image
262 262
 			)
... ...
@@ -290,7 +290,7 @@ func (p *v1Puller) pullImage(imgID, endpoint string, token []string) (bool, erro
290 290
 					status = fmt.Sprintf("Pulling fs layer [retries: %d]", j)
291 291
 				}
292 292
 				out.Write(p.sf.FormatProgress(stringid.TruncateID(id), status, nil))
293
-				layer, err := p.session.GetRemoteImageLayer(img.ID, endpoint, int64(imgSize))
293
+				layer, err := p.session.GetRemoteImageLayer(img.ID, endpoint, imgSize)
294 294
 				if uerr, ok := err.(*url.Error); ok {
295 295
 					err = uerr.Err
296 296
 				}
... ...
@@ -167,7 +167,7 @@ func (p *v2Puller) download(di *downloadInfo) {
167 167
 		In:        ioutil.NopCloser(io.TeeReader(layerDownload, verifier)),
168 168
 		Out:       out,
169 169
 		Formatter: p.sf,
170
-		Size:      int(di.size),
170
+		Size:      di.size,
171 171
 		NewLines:  false,
172 172
 		ID:        stringid.TruncateID(di.img.ID),
173 173
 		Action:    "Downloading",
... ...
@@ -264,7 +264,7 @@ func (p *v2Puller) pullV2Tag(tag, taggedName string) (bool, error) {
264 264
 					In:        d.tmpFile,
265 265
 					Out:       out,
266 266
 					Formatter: p.sf,
267
-					Size:      int(d.size),
267
+					Size:      d.size,
268 268
 					NewLines:  false,
269 269
 					ID:        stringid.TruncateID(d.img.ID),
270 270
 					Action:    "Extracting",
... ...
@@ -289,7 +289,7 @@ func (p *v1Pusher) pushImage(imgID, ep string, token []string) (checksum string,
289 289
 			In:        layerData,
290 290
 			Out:       p.out,
291 291
 			Formatter: p.sf,
292
-			Size:      int(layerData.Size),
292
+			Size:      layerData.Size,
293 293
 			NewLines:  false,
294 294
 			ID:        stringid.TruncateID(imgData.ID),
295 295
 			Action:    "Pushing",
... ...
@@ -239,7 +239,7 @@ func (p *v2Pusher) pushV2Image(bs distribution.BlobService, img *image.Image) (d
239 239
 		In:        ioutil.NopCloser(tf),
240 240
 		Out:       out,
241 241
 		Formatter: p.sf,
242
-		Size:      int(size),
242
+		Size:      size,
243 243
 		NewLines:  false,
244 244
 		ID:        stringid.TruncateID(img.ID),
245 245
 		Action:    "Pushing",
... ...
@@ -23,8 +23,8 @@ func (e *JSONError) Error() string {
23 23
 
24 24
 type JSONProgress struct {
25 25
 	terminalFd uintptr
26
-	Current    int   `json:"current,omitempty"`
27
-	Total      int   `json:"total,omitempty"`
26
+	Current    int64 `json:"current,omitempty"`
27
+	Total      int64 `json:"total,omitempty"`
28 28
 	Start      int64 `json:"start,omitempty"`
29 29
 }
30 30
 
... ...
@@ -64,7 +64,7 @@ func (p *JSONProgress) String() string {
64 64
 	numbersBox = fmt.Sprintf("%8v/%v", current, total)
65 65
 
66 66
 	if p.Current > 0 && p.Start > 0 && percentage < 50 {
67
-		fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
67
+		fromStart := time.Now().UTC().Sub(time.Unix(p.Start, 0))
68 68
 		perEntry := fromStart / time.Duration(p.Current)
69 69
 		left := time.Duration(p.Total-p.Current) * perEntry
70 70
 		left = (left / time.Second) * time.Second
... ...
@@ -14,9 +14,9 @@ type Config struct {
14 14
 	In         io.ReadCloser // Stream to read from
15 15
 	Out        io.Writer     // Where to send progress bar to
16 16
 	Formatter  *streamformatter.StreamFormatter
17
-	Size       int
18
-	Current    int
19
-	LastUpdate int
17
+	Size       int64
18
+	Current    int64
19
+	LastUpdate int64
20 20
 	NewLines   bool
21 21
 	ID         string
22 22
 	Action     string
... ...
@@ -29,11 +29,11 @@ func New(newReader Config) *Config {
29 29
 
30 30
 func (config *Config) Read(p []byte) (n int, err error) {
31 31
 	read, err := config.In.Read(p)
32
-	config.Current += read
33
-	updateEvery := 1024 * 512 //512kB
32
+	config.Current += int64(read)
33
+	updateEvery := int64(1024 * 512) //512kB
34 34
 	if config.Size > 0 {
35 35
 		// Update progress for every 1% read if 1% < 512kB
36
-		if increment := int(0.01 * float64(config.Size)); increment < updateEvery {
36
+		if increment := int64(0.01 * float64(config.Size)); increment < updateEvery {
37 37
 			updateEvery = increment
38 38
 		}
39 39
 	}
... ...
@@ -20,7 +20,7 @@ func TestOutputOnPrematureClose(t *testing.T) {
20 20
 		In:        reader,
21 21
 		Out:       writer,
22 22
 		Formatter: streamformatter.NewStreamFormatter(),
23
-		Size:      len(content),
23
+		Size:      int64(len(content)),
24 24
 		NewLines:  true,
25 25
 		ID:        "Test",
26 26
 		Action:    "Read",
... ...
@@ -60,7 +60,7 @@ func TestCompleteSilently(t *testing.T) {
60 60
 		In:        reader,
61 61
 		Out:       writer,
62 62
 		Formatter: streamformatter.NewStreamFormatter(),
63
-		Size:      len(content),
63
+		Size:      int64(len(content)),
64 64
 		NewLines:  true,
65 65
 		ID:        "Test",
66 66
 		Action:    "Read",
... ...
@@ -95,17 +95,17 @@ func (f tarHeaderSelectFunc) selectHeaders(h *tar.Header) (orderedHeaders [][2]s
95 95
 func v0TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) {
96 96
 	return [][2]string{
97 97
 		{"name", h.Name},
98
-		{"mode", strconv.Itoa(int(h.Mode))},
98
+		{"mode", strconv.FormatInt(h.Mode, 10)},
99 99
 		{"uid", strconv.Itoa(h.Uid)},
100 100
 		{"gid", strconv.Itoa(h.Gid)},
101
-		{"size", strconv.Itoa(int(h.Size))},
102
-		{"mtime", strconv.Itoa(int(h.ModTime.UTC().Unix()))},
101
+		{"size", strconv.FormatInt(h.Size, 10)},
102
+		{"mtime", strconv.FormatInt(h.ModTime.UTC().Unix(), 10)},
103 103
 		{"typeflag", string([]byte{h.Typeflag})},
104 104
 		{"linkname", h.Linkname},
105 105
 		{"uname", h.Uname},
106 106
 		{"gname", h.Gname},
107
-		{"devmajor", strconv.Itoa(int(h.Devmajor))},
108
-		{"devminor", strconv.Itoa(int(h.Devminor))},
107
+		{"devmajor", strconv.FormatInt(h.Devmajor, 10)},
108
+		{"devminor", strconv.FormatInt(h.Devminor, 10)},
109 109
 	}
110 110
 }
111 111
 
... ...
@@ -185,7 +185,7 @@ func TestGetRemoteImageJSON(t *testing.T) {
185 185
 	if err != nil {
186 186
 		t.Fatal(err)
187 187
 	}
188
-	assertEqual(t, size, 154, "Expected size 154")
188
+	assertEqual(t, size, int64(154), "Expected size 154")
189 189
 	if len(json) <= 0 {
190 190
 		t.Fatal("Expected non-empty json")
191 191
 	}
... ...
@@ -240,7 +240,7 @@ func (r *Session) LookupRemoteImage(imgID, registry string) error {
240 240
 }
241 241
 
242 242
 // GetRemoteImageJSON retrieves an image's JSON metadata from the registry.
243
-func (r *Session) GetRemoteImageJSON(imgID, registry string) ([]byte, int, error) {
243
+func (r *Session) GetRemoteImageJSON(imgID, registry string) ([]byte, int64, error) {
244 244
 	res, err := r.client.Get(registry + "images/" + imgID + "/json")
245 245
 	if err != nil {
246 246
 		return nil, -1, fmt.Errorf("Failed to download json: %s", err)
... ...
@@ -250,9 +250,9 @@ func (r *Session) GetRemoteImageJSON(imgID, registry string) ([]byte, int, error
250 250
 		return nil, -1, httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
251 251
 	}
252 252
 	// if the size header is not present, then set it to '-1'
253
-	imageSize := -1
253
+	imageSize := int64(-1)
254 254
 	if hdr := res.Header.Get("X-Docker-Size"); hdr != "" {
255
-		imageSize, err = strconv.Atoi(hdr)
255
+		imageSize, err = strconv.ParseInt(hdr, 10, 64)
256 256
 		if err != nil {
257 257
 			return nil, -1, err
258 258
 		}