SubFetch returns part of a blob. The caller must close the returned io.ReadCloser. The Reader may return fewer than 'length' bytes. Callers should check. The returned error should be os.ErrNotExist if the blob doesn't exist.
(ctx context.Context, ref blob.Ref, offset, length int64)
| 32 | // check. The returned error should be os.ErrNotExist if the blob |
| 33 | // doesn't exist. |
| 34 | func (s *storage) SubFetch(ctx context.Context, ref blob.Ref, offset, length int64) (io.ReadCloser, error) { |
| 35 | // TODO: pass ctx to more calls within this method. |
| 36 | m, err := s.getMetaRow(ref) |
| 37 | if err != nil { |
| 38 | return nil, err |
| 39 | } |
| 40 | if m.isPacked() { |
| 41 | length, err = capOffsetLength(m.size, offset, length) |
| 42 | if err != nil { |
| 43 | return nil, err |
| 44 | } |
| 45 | // get the blob from the large subfetcher |
| 46 | return s.large.SubFetch(ctx, m.largeRef, int64(m.largeOff)+offset, length) |
| 47 | } |
| 48 | if sf, ok := s.small.(blob.SubFetcher); ok { |
| 49 | rc, err := sf.SubFetch(ctx, ref, offset, length) |
| 50 | if err != blob.ErrUnimplemented { |
| 51 | return rc, err |
| 52 | } |
| 53 | } |
| 54 | rc, size, err := s.small.Fetch(ctx, ref) |
| 55 | if err != nil { |
| 56 | return rc, err |
| 57 | } |
| 58 | length, err = capOffsetLength(size, offset, length) |
| 59 | if err != nil { |
| 60 | rc.Close() |
| 61 | return nil, err |
| 62 | } |
| 63 | if offset != 0 { |
| 64 | if _, err = io.CopyN(io.Discard, rc, offset); err != nil { |
| 65 | rc.Close() |
| 66 | return nil, err |
| 67 | } |
| 68 | } |
| 69 | return struct { |
| 70 | io.Reader |
| 71 | io.Closer |
| 72 | }{io.LimitReader(rc, length), rc}, nil |
| 73 | } |
| 74 | |
| 75 | func capOffsetLength(size uint32, offset, length int64) (newLength int64, err error) { |
| 76 | if offset < 0 || length < 0 { |
nothing calls this directly
no test coverage detected