github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/pkg/ioutils/readers.go (about)

     1  package ioutils // import "github.com/docker/docker/pkg/ioutils"
     2  
     3  import (
     4  	"context"
     5  	"crypto/sha256"
     6  	"encoding/hex"
     7  	"io"
     8  )
     9  
    10  // ReadCloserWrapper wraps an io.Reader, and implements an io.ReadCloser
    11  // It calls the given callback function when closed. It should be constructed
    12  // with NewReadCloserWrapper
    13  type ReadCloserWrapper struct {
    14  	io.Reader
    15  	closer func() error
    16  }
    17  
    18  // Close calls back the passed closer function
    19  func (r *ReadCloserWrapper) Close() error {
    20  	return r.closer()
    21  }
    22  
    23  // NewReadCloserWrapper returns a new io.ReadCloser.
    24  func NewReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser {
    25  	return &ReadCloserWrapper{
    26  		Reader: r,
    27  		closer: closer,
    28  	}
    29  }
    30  
    31  type readerErrWrapper struct {
    32  	reader io.Reader
    33  	closer func()
    34  }
    35  
    36  func (r *readerErrWrapper) Read(p []byte) (int, error) {
    37  	n, err := r.reader.Read(p)
    38  	if err != nil {
    39  		r.closer()
    40  	}
    41  	return n, err
    42  }
    43  
    44  // NewReaderErrWrapper returns a new io.Reader.
    45  func NewReaderErrWrapper(r io.Reader, closer func()) io.Reader {
    46  	return &readerErrWrapper{
    47  		reader: r,
    48  		closer: closer,
    49  	}
    50  }
    51  
    52  // HashData returns the sha256 sum of src.
    53  func HashData(src io.Reader) (string, error) {
    54  	h := sha256.New()
    55  	if _, err := io.Copy(h, src); err != nil {
    56  		return "", err
    57  	}
    58  	return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil
    59  }
    60  
    61  // OnEOFReader wraps an io.ReadCloser and a function
    62  // the function will run at the end of file or close the file.
    63  type OnEOFReader struct {
    64  	Rc io.ReadCloser
    65  	Fn func()
    66  }
    67  
    68  func (r *OnEOFReader) Read(p []byte) (n int, err error) {
    69  	n, err = r.Rc.Read(p)
    70  	if err == io.EOF {
    71  		r.runFunc()
    72  	}
    73  	return
    74  }
    75  
    76  // Close closes the file and run the function.
    77  func (r *OnEOFReader) Close() error {
    78  	err := r.Rc.Close()
    79  	r.runFunc()
    80  	return err
    81  }
    82  
    83  func (r *OnEOFReader) runFunc() {
    84  	if fn := r.Fn; fn != nil {
    85  		fn()
    86  		r.Fn = nil
    87  	}
    88  }
    89  
    90  // cancelReadCloser wraps an io.ReadCloser with a context for cancelling read
    91  // operations.
    92  type cancelReadCloser struct {
    93  	cancel func()
    94  	pR     *io.PipeReader // Stream to read from
    95  	pW     *io.PipeWriter
    96  }
    97  
    98  // NewCancelReadCloser creates a wrapper that closes the ReadCloser when the
    99  // context is cancelled. The returned io.ReadCloser must be closed when it is
   100  // no longer needed.
   101  func NewCancelReadCloser(ctx context.Context, in io.ReadCloser) io.ReadCloser {
   102  	pR, pW := io.Pipe()
   103  
   104  	// Create a context used to signal when the pipe is closed
   105  	doneCtx, cancel := context.WithCancel(context.Background())
   106  
   107  	p := &cancelReadCloser{
   108  		cancel: cancel,
   109  		pR:     pR,
   110  		pW:     pW,
   111  	}
   112  
   113  	go func() {
   114  		_, err := io.Copy(pW, in)
   115  		select {
   116  		case <-ctx.Done():
   117  			// If the context was closed, p.closeWithError
   118  			// was already called. Calling it again would
   119  			// change the error that Read returns.
   120  		default:
   121  			p.closeWithError(err)
   122  		}
   123  		in.Close()
   124  	}()
   125  	go func() {
   126  		for {
   127  			select {
   128  			case <-ctx.Done():
   129  				p.closeWithError(ctx.Err())
   130  			case <-doneCtx.Done():
   131  				return
   132  			}
   133  		}
   134  	}()
   135  
   136  	return p
   137  }
   138  
   139  // Read wraps the Read method of the pipe that provides data from the wrapped
   140  // ReadCloser.
   141  func (p *cancelReadCloser) Read(buf []byte) (n int, err error) {
   142  	return p.pR.Read(buf)
   143  }
   144  
   145  // closeWithError closes the wrapper and its underlying reader. It will
   146  // cause future calls to Read to return err.
   147  func (p *cancelReadCloser) closeWithError(err error) {
   148  	p.pW.CloseWithError(err)
   149  	p.cancel()
   150  }
   151  
   152  // Close closes the wrapper its underlying reader. It will cause
   153  // future calls to Read to return io.EOF.
   154  func (p *cancelReadCloser) Close() error {
   155  	p.closeWithError(io.EOF)
   156  	return nil
   157  }