load returns a reader that yields the contents of the file with the given handle. rd must be closed after use. If an error is returned, the ReadCloser is nil. The bool return value indicates whether the requested file exists in the cache. It can be true even when no reader is returned because length
(h backend.Handle, length int, offset int64)
| 38 | // file exists in the cache. It can be true even when no reader is returned |
| 39 | // because length or offset are out of bounds |
| 40 | func (c *Cache) load(h backend.Handle, length int, offset int64) (io.ReadCloser, bool, error) { |
| 41 | debug.Log("Load(%v, %v, %v) from cache", h, length, offset) |
| 42 | if !c.canBeCached(h.Type) { |
| 43 | return nil, false, errors.New("cannot be cached") |
| 44 | } |
| 45 | |
| 46 | f, err := os.Open(c.filename(h)) |
| 47 | if err != nil { |
| 48 | return nil, false, errors.WithStack(err) |
| 49 | } |
| 50 | |
| 51 | fi, err := f.Stat() |
| 52 | if err != nil { |
| 53 | _ = f.Close() |
| 54 | return nil, true, errors.WithStack(err) |
| 55 | } |
| 56 | |
| 57 | size := fi.Size() |
| 58 | if size <= int64(crypto.CiphertextLength(0)) { |
| 59 | _ = f.Close() |
| 60 | return nil, true, errors.Errorf("cached file %v is truncated", h) |
| 61 | } |
| 62 | |
| 63 | if size < offset+int64(length) { |
| 64 | _ = f.Close() |
| 65 | return nil, true, errors.Errorf("cached file %v is too short", h) |
| 66 | } |
| 67 | |
| 68 | if offset > 0 { |
| 69 | if _, err = f.Seek(offset, io.SeekStart); err != nil { |
| 70 | _ = f.Close() |
| 71 | return nil, true, err |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | if length <= 0 { |
| 76 | return f, true, nil |
| 77 | } |
| 78 | return util.LimitReadCloser(f, int64(length)), true, nil |
| 79 | } |
| 80 | |
| 81 | // save saves a file in the cache. |
| 82 | func (c *Cache) save(h backend.Handle, rd io.Reader) error { |