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 }