MCPcopy
hub / github.com/FiloSottile/age / ReadAt

Method ReadAt

internal/stream/stream.go:394–451  ·  view source on GitHub ↗
(p []byte, off int64)

Source from the content-addressed store, hash-verified

392}
393
394func (r *DecryptReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
395 if off < 0 || off > r.size {
396 return 0, fmt.Errorf("offset out of range [0:%d]: %d", r.size, off)
397 }
398 if len(p) == 0 {
399 return 0, nil
400 }
401 var cacheUpdate *cachedChunk
402 chunk := make([]byte, encChunkSize)
403 for len(p) > 0 && off < r.size {
404 chunkIndex := off / ChunkSize
405 chunkOff := chunkIndex * encChunkSize
406 encSize := r.size + r.chunks*chacha20poly1305.Overhead
407 chunkSize := min(encSize-chunkOff, encChunkSize)
408
409 cached := r.cache.Load()
410 var plaintext []byte
411 if cached != nil && cached.off == chunkOff {
412 plaintext = cached.data
413 cacheUpdate = nil
414 } else {
415 nn, err := r.src.ReadAt(chunk[:chunkSize], chunkOff)
416 if err == io.EOF {
417 if int64(nn) != chunkSize {
418 err = io.ErrUnexpectedEOF
419 } else {
420 err = nil
421 }
422 }
423 if err != nil {
424 return n, fmt.Errorf("failed to read chunk at offset %d: %w", chunkOff, err)
425 }
426 nonce := nonceForChunk(chunkIndex)
427 if chunkIndex == r.chunks-1 {
428 setLastChunkFlag(nonce)
429 }
430 plaintext, err = r.a.Open(chunk[:0], nonce[:], chunk[:chunkSize], nil)
431 if err != nil {
432 return n, fmt.Errorf("failed to decrypt and authenticate chunk at offset %d: %w", chunkOff, err)
433 }
434 cacheUpdate = &cachedChunk{off: chunkOff, data: plaintext}
435 }
436
437 plainChunkOff := int(off - chunkIndex*ChunkSize)
438 copySize := min(len(plaintext)-plainChunkOff, len(p))
439 copy(p, plaintext[plainChunkOff:plainChunkOff+copySize])
440 p = p[copySize:]
441 off += int64(copySize)
442 n += copySize
443 }
444 if cacheUpdate != nil {
445 r.cache.Store(cacheUpdate)
446 }
447 if off == r.size {
448 return n, io.EOF
449 }
450 return n, nil
451}

Callers 7

TestDecryptReaderAtFunction · 0.95
TestDecryptReaderAtEmptyFunction · 0.95
NewDecryptReaderAtFunction · 0.45

Calls 2

nonceForChunkFunction · 0.85
setLastChunkFlagFunction · 0.85

Tested by 6

TestDecryptReaderAtFunction · 0.76
TestDecryptReaderAtEmptyFunction · 0.76