github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/daemon/logger/loggerutils/multireader/multireader.go (about)

     1  package multireader // import "github.com/docker/docker/daemon/logger/loggerutils/multireader"
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  )
     9  
    10  type pos struct {
    11  	idx    int
    12  	offset int64
    13  }
    14  
    15  type multiReadSeeker struct {
    16  	readers []io.ReadSeeker
    17  	pos     *pos
    18  	posIdx  map[io.ReadSeeker]int
    19  }
    20  
    21  func (r *multiReadSeeker) Seek(offset int64, whence int) (int64, error) {
    22  	var tmpOffset int64
    23  	switch whence {
    24  	case os.SEEK_SET:
    25  		for i, rdr := range r.readers {
    26  			// get size of the current reader
    27  			s, err := rdr.Seek(0, os.SEEK_END)
    28  			if err != nil {
    29  				return -1, err
    30  			}
    31  
    32  			if offset > tmpOffset+s {
    33  				if i == len(r.readers)-1 {
    34  					rdrOffset := s + (offset - tmpOffset)
    35  					if _, err := rdr.Seek(rdrOffset, os.SEEK_SET); err != nil {
    36  						return -1, err
    37  					}
    38  					r.pos = &pos{i, rdrOffset}
    39  					return offset, nil
    40  				}
    41  
    42  				tmpOffset += s
    43  				continue
    44  			}
    45  
    46  			rdrOffset := offset - tmpOffset
    47  			idx := i
    48  
    49  			if _, err := rdr.Seek(rdrOffset, os.SEEK_SET); err != nil {
    50  				return -1, err
    51  			}
    52  			// make sure all following readers are at 0
    53  			for _, rdr := range r.readers[i+1:] {
    54  				rdr.Seek(0, os.SEEK_SET)
    55  			}
    56  
    57  			if rdrOffset == s && i != len(r.readers)-1 {
    58  				idx++
    59  				rdrOffset = 0
    60  			}
    61  			r.pos = &pos{idx, rdrOffset}
    62  			return offset, nil
    63  		}
    64  	case os.SEEK_END:
    65  		for _, rdr := range r.readers {
    66  			s, err := rdr.Seek(0, os.SEEK_END)
    67  			if err != nil {
    68  				return -1, err
    69  			}
    70  			tmpOffset += s
    71  		}
    72  		if _, err := r.Seek(tmpOffset+offset, os.SEEK_SET); err != nil {
    73  			return -1, err
    74  		}
    75  		return tmpOffset + offset, nil
    76  	case os.SEEK_CUR:
    77  		if r.pos == nil {
    78  			return r.Seek(offset, os.SEEK_SET)
    79  		}
    80  		// Just return the current offset
    81  		if offset == 0 {
    82  			return r.getCurOffset()
    83  		}
    84  
    85  		curOffset, err := r.getCurOffset()
    86  		if err != nil {
    87  			return -1, err
    88  		}
    89  		rdr, rdrOffset, err := r.getReaderForOffset(curOffset + offset)
    90  		if err != nil {
    91  			return -1, err
    92  		}
    93  
    94  		r.pos = &pos{r.posIdx[rdr], rdrOffset}
    95  		return curOffset + offset, nil
    96  	default:
    97  		return -1, fmt.Errorf("Invalid whence: %d", whence)
    98  	}
    99  
   100  	return -1, fmt.Errorf("Error seeking for whence: %d, offset: %d", whence, offset)
   101  }
   102  
   103  func (r *multiReadSeeker) getReaderForOffset(offset int64) (io.ReadSeeker, int64, error) {
   104  
   105  	var offsetTo int64
   106  
   107  	for _, rdr := range r.readers {
   108  		size, err := getReadSeekerSize(rdr)
   109  		if err != nil {
   110  			return nil, -1, err
   111  		}
   112  		if offsetTo+size > offset {
   113  			return rdr, offset - offsetTo, nil
   114  		}
   115  		if rdr == r.readers[len(r.readers)-1] {
   116  			return rdr, offsetTo + offset, nil
   117  		}
   118  		offsetTo += size
   119  	}
   120  
   121  	return nil, 0, nil
   122  }
   123  
   124  func (r *multiReadSeeker) getCurOffset() (int64, error) {
   125  	var totalSize int64
   126  	for _, rdr := range r.readers[:r.pos.idx+1] {
   127  		if r.posIdx[rdr] == r.pos.idx {
   128  			totalSize += r.pos.offset
   129  			break
   130  		}
   131  
   132  		size, err := getReadSeekerSize(rdr)
   133  		if err != nil {
   134  			return -1, fmt.Errorf("error getting seeker size: %v", err)
   135  		}
   136  		totalSize += size
   137  	}
   138  	return totalSize, nil
   139  }
   140  
   141  func (r *multiReadSeeker) Read(b []byte) (int, error) {
   142  	if r.pos == nil {
   143  		// make sure all readers are at 0
   144  		r.Seek(0, os.SEEK_SET)
   145  	}
   146  
   147  	bLen := int64(len(b))
   148  	buf := bytes.NewBuffer(nil)
   149  	var rdr io.ReadSeeker
   150  
   151  	for _, rdr = range r.readers[r.pos.idx:] {
   152  		readBytes, err := io.CopyN(buf, rdr, bLen)
   153  		if err != nil && err != io.EOF {
   154  			return -1, err
   155  		}
   156  		bLen -= readBytes
   157  
   158  		if bLen == 0 {
   159  			break
   160  		}
   161  	}
   162  
   163  	rdrPos, err := rdr.Seek(0, os.SEEK_CUR)
   164  	if err != nil {
   165  		return -1, err
   166  	}
   167  	r.pos = &pos{r.posIdx[rdr], rdrPos}
   168  	return buf.Read(b)
   169  }
   170  
   171  func getReadSeekerSize(rdr io.ReadSeeker) (int64, error) {
   172  	// save the current position
   173  	pos, err := rdr.Seek(0, os.SEEK_CUR)
   174  	if err != nil {
   175  		return -1, err
   176  	}
   177  
   178  	// get the size
   179  	size, err := rdr.Seek(0, os.SEEK_END)
   180  	if err != nil {
   181  		return -1, err
   182  	}
   183  
   184  	// reset the position
   185  	if _, err := rdr.Seek(pos, os.SEEK_SET); err != nil {
   186  		return -1, err
   187  	}
   188  	return size, nil
   189  }
   190  
   191  // MultiReadSeeker returns a ReadSeeker that's the logical concatenation of the provided
   192  // input readseekers. After calling this method the initial position is set to the
   193  // beginning of the first ReadSeeker. At the end of a ReadSeeker, Read always advances
   194  // to the beginning of the next ReadSeeker and returns EOF at the end of the last ReadSeeker.
   195  // Seek can be used over the sum of lengths of all readseekers.
   196  //
   197  // When a MultiReadSeeker is used, no Read and Seek operations should be made on
   198  // its ReadSeeker components. Also, users should make no assumption on the state
   199  // of individual readseekers while the MultiReadSeeker is used.
   200  func MultiReadSeeker(readers ...io.ReadSeeker) io.ReadSeeker {
   201  	if len(readers) == 1 {
   202  		return readers[0]
   203  	}
   204  	idx := make(map[io.ReadSeeker]int)
   205  	for i, rdr := range readers {
   206  		idx[rdr] = i
   207  	}
   208  	return &multiReadSeeker{
   209  		readers: readers,
   210  		posIdx:  idx,
   211  	}
   212  }