length of -1 means all
(br blob.Ref, offset, length int64)
| 370 | |
| 371 | // length of -1 means all |
| 372 | func (s *storage) fetch(br blob.Ref, offset, length int64) (rc io.ReadCloser, size uint32, err error) { |
| 373 | meta, err := s.meta(br) |
| 374 | if err != nil { |
| 375 | return nil, 0, err |
| 376 | } |
| 377 | |
| 378 | if meta.file >= len(s.fds) { |
| 379 | return nil, 0, fmt.Errorf("diskpacked: attempt to fetch blob from out of range pack file %d > %d", meta.file, len(s.fds)) |
| 380 | } |
| 381 | rac := s.fds[meta.file] |
| 382 | var rs io.ReadSeeker |
| 383 | if length == -1 { |
| 384 | // normal Fetch mode |
| 385 | rs = io.NewSectionReader(rac, meta.offset, int64(meta.size)) |
| 386 | } else { |
| 387 | if offset > int64(meta.size) { |
| 388 | return nil, 0, blob.ErrOutOfRangeOffsetSubFetch |
| 389 | } else if offset+length > int64(meta.size) { |
| 390 | length = int64(meta.size) - offset |
| 391 | } |
| 392 | rs = io.NewSectionReader(rac, meta.offset+offset, length) |
| 393 | } |
| 394 | fn := rac.Name() |
| 395 | // Ensure entry is in map. |
| 396 | readVar.Add(fn, 0) |
| 397 | if v, ok := readVar.Get(fn).(*expvar.Int); ok { |
| 398 | rs = readerutil.NewStatsReadSeeker(v, rs) |
| 399 | } |
| 400 | readTotVar.Add(s.root, 0) |
| 401 | if v, ok := readTotVar.Get(s.root).(*expvar.Int); ok { |
| 402 | rs = readerutil.NewStatsReadSeeker(v, rs) |
| 403 | } |
| 404 | rsc := struct { |
| 405 | io.ReadSeeker |
| 406 | io.Closer |
| 407 | }{ |
| 408 | rs, |
| 409 | types.NopCloser, |
| 410 | } |
| 411 | return rsc, meta.size, nil |
| 412 | } |
| 413 | |
| 414 | func (s *storage) filename(file int) string { |
| 415 | return filepath.Join(s.root, fmt.Sprintf("pack-%05d.blobs", file)) |