зеркало из https://github.com/microsoft/docker.git
Make TarStream return an io.ReadCloser
Currently, the resources associated with the io.Reader returned by TarStream are only freed when it is read until EOF. This means that partial uploads or exports (for example, in the case of a full disk or severed connection) can leak a goroutine and open file. This commit changes TarStream to return an io.ReadCloser. Resources are freed when Close is called. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
Родитель
49088b0b89
Коммит
21278efaee
|
@ -155,6 +155,7 @@ func (daemon *Daemon) exportContainerRw(container *Container) (archive.Archive,
|
|||
return nil, err
|
||||
}
|
||||
return ioutils.NewReadCloserWrapper(archive, func() error {
|
||||
archive.Close()
|
||||
return daemon.layerStore.Unmount(container.ID)
|
||||
}),
|
||||
nil
|
||||
|
|
|
@ -429,6 +429,7 @@ func (p *v1Pusher) pushImage(v1Image v1Image, ep string) (checksum string, err e
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer arch.Close()
|
||||
|
||||
// don't care if this fails; best effort
|
||||
size, _ := l.Size()
|
||||
|
|
|
@ -365,6 +365,7 @@ func (p *v2Pusher) pushV2Layer(bs distribution.BlobService, l layer.Layer) (dige
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer arch.Close()
|
||||
|
||||
// Send the layer
|
||||
layerUpload, err := bs.Create(context.Background())
|
||||
|
|
|
@ -287,6 +287,8 @@ func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, creat
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer arch.Close()
|
||||
|
||||
if _, err := io.Copy(tarFile, arch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"archive/tar"
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// DigestSHA256EmptyTar is the canonical sha256 digest of empty tar file -
|
||||
|
@ -15,11 +16,11 @@ type emptyLayer struct{}
|
|||
// EmptyLayer is a layer that corresponds to empty tar.
|
||||
var EmptyLayer = &emptyLayer{}
|
||||
|
||||
func (el *emptyLayer) TarStream() (io.Reader, error) {
|
||||
func (el *emptyLayer) TarStream() (io.ReadCloser, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
tarWriter := tar.NewWriter(buf)
|
||||
tarWriter.Close()
|
||||
return buf, nil
|
||||
return ioutil.NopCloser(buf), nil
|
||||
}
|
||||
|
||||
func (el *emptyLayer) ChainID() ChainID {
|
||||
|
|
|
@ -67,7 +67,7 @@ func (diffID DiffID) String() string {
|
|||
type TarStreamer interface {
|
||||
// TarStream returns a tar archive stream
|
||||
// for the contents of a layer.
|
||||
TarStream() (io.Reader, error)
|
||||
TarStream() (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
// Layer represents a read only layer
|
||||
|
|
|
@ -581,7 +581,7 @@ func (ls *layerStore) Changes(name string) ([]archive.Change, error) {
|
|||
return ls.driver.Changes(m.mountID, pid)
|
||||
}
|
||||
|
||||
func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *int64) (io.Reader, error) {
|
||||
func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *int64) (io.ReadCloser, error) {
|
||||
type diffPathDriver interface {
|
||||
DiffPath(string) (string, func() error, error)
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@ func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ts.Close()
|
||||
|
||||
layer, err := ls.Register(ts, parent)
|
||||
if err != nil {
|
||||
|
@ -521,6 +522,7 @@ func assertLayerDiff(t *testing.T, expected []byte, layer Layer) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Close()
|
||||
|
||||
actual, err := ioutil.ReadAll(ts)
|
||||
if err != nil {
|
||||
|
|
|
@ -22,12 +22,12 @@ func (ml *mountedLayer) cacheParent() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (ml *mountedLayer) TarStream() (io.Reader, error) {
|
||||
func (ml *mountedLayer) TarStream() (io.ReadCloser, error) {
|
||||
archiver, err := ml.layerStore.driver.Diff(ml.mountID, ml.cacheParent())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return autoClosingReader{archiver}, nil
|
||||
return archiver, nil
|
||||
}
|
||||
|
||||
func (ml *mountedLayer) Path() (string, error) {
|
||||
|
@ -50,15 +50,3 @@ func (ml *mountedLayer) Parent() Layer {
|
|||
func (ml *mountedLayer) Size() (int64, error) {
|
||||
return ml.layerStore.driver.DiffSize(ml.mountID, ml.cacheParent())
|
||||
}
|
||||
|
||||
type autoClosingReader struct {
|
||||
source io.ReadCloser
|
||||
}
|
||||
|
||||
func (r autoClosingReader) Read(p []byte) (n int, err error) {
|
||||
n, err = r.source.Read(p)
|
||||
if err != nil {
|
||||
r.source.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ type roLayer struct {
|
|||
references map[Layer]struct{}
|
||||
}
|
||||
|
||||
func (rl *roLayer) TarStream() (io.Reader, error) {
|
||||
func (rl *roLayer) TarStream() (io.ReadCloser, error) {
|
||||
r, err := rl.layerStore.store.TarSplitReader(rl.chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -357,7 +357,7 @@ type mockLayer struct {
|
|||
parent *mockLayer
|
||||
}
|
||||
|
||||
func (l *mockLayer) TarStream() (io.Reader, error) {
|
||||
func (l *mockLayer) TarStream() (io.ReadCloser, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче