github.com/sams1990/dockerrepo@v17.12.1-ce-rc2+incompatible/daemon/logger/loggerutils/multireader/multireader.go (about) 1 package 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) getOffsetToReader(rdr io.ReadSeeker) (int64, error) { 142 var offset int64 143 for _, r := range r.readers { 144 if r == rdr { 145 break 146 } 147 148 size, err := getReadSeekerSize(rdr) 149 if err != nil { 150 return -1, err 151 } 152 offset += size 153 } 154 return offset, nil 155 } 156 157 func (r *multiReadSeeker) Read(b []byte) (int, error) { 158 if r.pos == nil { 159 // make sure all readers are at 0 160 r.Seek(0, os.SEEK_SET) 161 } 162 163 bLen := int64(len(b)) 164 buf := bytes.NewBuffer(nil) 165 var rdr io.ReadSeeker 166 167 for _, rdr = range r.readers[r.pos.idx:] { 168 readBytes, err := io.CopyN(buf, rdr, bLen) 169 if err != nil && err != io.EOF { 170 return -1, err 171 } 172 bLen -= readBytes 173 174 if bLen == 0 { 175 break 176 } 177 } 178 179 rdrPos, err := rdr.Seek(0, os.SEEK_CUR) 180 if err != nil { 181 return -1, err 182 } 183 r.pos = &pos{r.posIdx[rdr], rdrPos} 184 return buf.Read(b) 185 } 186 187 func getReadSeekerSize(rdr io.ReadSeeker) (int64, error) { 188 // save the current position 189 pos, err := rdr.Seek(0, os.SEEK_CUR) 190 if err != nil { 191 return -1, err 192 } 193 194 // get the size 195 size, err := rdr.Seek(0, os.SEEK_END) 196 if err != nil { 197 return -1, err 198 } 199 200 // reset the position 201 if _, err := rdr.Seek(pos, os.SEEK_SET); err != nil { 202 return -1, err 203 } 204 return size, nil 205 } 206 207 // MultiReadSeeker returns a ReadSeeker that's the logical concatenation of the provided 208 // input readseekers. After calling this method the initial position is set to the 209 // beginning of the first ReadSeeker. At the end of a ReadSeeker, Read always advances 210 // to the beginning of the next ReadSeeker and returns EOF at the end of the last ReadSeeker. 211 // Seek can be used over the sum of lengths of all readseekers. 212 // 213 // When a MultiReadSeeker is used, no Read and Seek operations should be made on 214 // its ReadSeeker components. Also, users should make no assumption on the state 215 // of individual readseekers while the MultiReadSeeker is used. 216 func MultiReadSeeker(readers ...io.ReadSeeker) io.ReadSeeker { 217 if len(readers) == 1 { 218 return readers[0] 219 } 220 idx := make(map[io.ReadSeeker]int) 221 for i, rdr := range readers { 222 idx[rdr] = i 223 } 224 return &multiReadSeeker{ 225 readers: readers, 226 posIdx: idx, 227 } 228 }