1package aws 2 3import ( 4 "io" 5 "sync" 6 7 "github.com/aws/aws-sdk-go/internal/sdkio" 8) 9 10// ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser. Should 11// only be used with an io.Reader that is also an io.Seeker. Doing so may 12// cause request signature errors, or request body's not sent for GET, HEAD 13// and DELETE HTTP methods. 14// 15// Deprecated: Should only be used with io.ReadSeeker. If using for 16// S3 PutObject to stream content use s3manager.Uploader instead. 17func ReadSeekCloser(r io.Reader) ReaderSeekerCloser { 18 return ReaderSeekerCloser{r} 19} 20 21// ReaderSeekerCloser represents a reader that can also delegate io.Seeker and 22// io.Closer interfaces to the underlying object if they are available. 23type ReaderSeekerCloser struct { 24 r io.Reader 25} 26 27// IsReaderSeekable returns if the underlying reader type can be seeked. A 28// io.Reader might not actually be seekable if it is the ReaderSeekerCloser 29// type. 30func IsReaderSeekable(r io.Reader) bool { 31 switch v := r.(type) { 32 case ReaderSeekerCloser: 33 return v.IsSeeker() 34 case *ReaderSeekerCloser: 35 return v.IsSeeker() 36 case io.ReadSeeker: 37 return true 38 default: 39 return false 40 } 41} 42 43// Read reads from the reader up to size of p. The number of bytes read, and 44// error if it occurred will be returned. 45// 46// If the reader is not an io.Reader zero bytes read, and nil error will be returned. 47// 48// Performs the same functionality as io.Reader Read 49func (r ReaderSeekerCloser) Read(p []byte) (int, error) { 50 switch t := r.r.(type) { 51 case io.Reader: 52 return t.Read(p) 53 } 54 return 0, nil 55} 56 57// Seek sets the offset for the next Read to offset, interpreted according to 58// whence: 0 means relative to the origin of the file, 1 means relative to the 59// current offset, and 2 means relative to the end. Seek returns the new offset 60// and an error, if any. 61// 62// If the ReaderSeekerCloser is not an io.Seeker nothing will be done. 63func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) { 64 switch t := r.r.(type) { 65 case io.Seeker: 66 return t.Seek(offset, whence) 67 } 68 return int64(0), nil 69} 70 71// IsSeeker returns if the underlying reader is also a seeker. 72func (r ReaderSeekerCloser) IsSeeker() bool { 73 _, ok := r.r.(io.Seeker) 74 return ok 75} 76 77// HasLen returns the length of the underlying reader if the value implements 78// the Len() int method. 79func (r ReaderSeekerCloser) HasLen() (int, bool) { 80 type lenner interface { 81 Len() int 82 } 83 84 if lr, ok := r.r.(lenner); ok { 85 return lr.Len(), true 86 } 87 88 return 0, false 89} 90 91// GetLen returns the length of the bytes remaining in the underlying reader. 92// Checks first for Len(), then io.Seeker to determine the size of the 93// underlying reader. 94// 95// Will return -1 if the length cannot be determined. 96func (r ReaderSeekerCloser) GetLen() (int64, error) { 97 if l, ok := r.HasLen(); ok { 98 return int64(l), nil 99 } 100 101 if s, ok := r.r.(io.Seeker); ok { 102 return seekerLen(s) 103 } 104 105 return -1, nil 106} 107 108// SeekerLen attempts to get the number of bytes remaining at the seeker's 109// current position. Returns the number of bytes remaining or error. 110func SeekerLen(s io.Seeker) (int64, error) { 111 // Determine if the seeker is actually seekable. ReaderSeekerCloser 112 // hides the fact that a io.Readers might not actually be seekable. 113 switch v := s.(type) { 114 case ReaderSeekerCloser: 115 return v.GetLen() 116 case *ReaderSeekerCloser: 117 return v.GetLen() 118 } 119 120 return seekerLen(s) 121} 122 123func seekerLen(s io.Seeker) (int64, error) { 124 curOffset, err := s.Seek(0, sdkio.SeekCurrent) 125 if err != nil { 126 return 0, err 127 } 128 129 endOffset, err := s.Seek(0, sdkio.SeekEnd) 130 if err != nil { 131 return 0, err 132 } 133 134 _, err = s.Seek(curOffset, sdkio.SeekStart) 135 if err != nil { 136 return 0, err 137 } 138 139 return endOffset - curOffset, nil 140} 141 142// Close closes the ReaderSeekerCloser. 143// 144// If the ReaderSeekerCloser is not an io.Closer nothing will be done. 145func (r ReaderSeekerCloser) Close() error { 146 switch t := r.r.(type) { 147 case io.Closer: 148 return t.Close() 149 } 150 return nil 151} 152 153// A WriteAtBuffer provides a in memory buffer supporting the io.WriterAt interface 154// Can be used with the s3manager.Downloader to download content to a buffer 155// in memory. Safe to use concurrently. 156type WriteAtBuffer struct { 157 buf []byte 158 m sync.Mutex 159 160 // GrowthCoeff defines the growth rate of the internal buffer. By 161 // default, the growth rate is 1, where expanding the internal 162 // buffer will allocate only enough capacity to fit the new expected 163 // length. 164 GrowthCoeff float64 165} 166 167// NewWriteAtBuffer creates a WriteAtBuffer with an internal buffer 168// provided by buf. 169func NewWriteAtBuffer(buf []byte) *WriteAtBuffer { 170 return &WriteAtBuffer{buf: buf} 171} 172 173// WriteAt writes a slice of bytes to a buffer starting at the position provided 174// The number of bytes written will be returned, or error. Can overwrite previous 175// written slices if the write ats overlap. 176func (b *WriteAtBuffer) WriteAt(p []byte, pos int64) (n int, err error) { 177 pLen := len(p) 178 expLen := pos + int64(pLen) 179 b.m.Lock() 180 defer b.m.Unlock() 181 if int64(len(b.buf)) < expLen { 182 if int64(cap(b.buf)) < expLen { 183 if b.GrowthCoeff < 1 { 184 b.GrowthCoeff = 1 185 } 186 newBuf := make([]byte, expLen, int64(b.GrowthCoeff*float64(expLen))) 187 copy(newBuf, b.buf) 188 b.buf = newBuf 189 } 190 b.buf = b.buf[:expLen] 191 } 192 copy(b.buf[pos:], p) 193 return pLen, nil 194} 195 196// Bytes returns a slice of bytes written to the buffer. 197func (b *WriteAtBuffer) Bytes() []byte { 198 b.m.Lock() 199 defer b.m.Unlock() 200 return b.buf 201} 202