Skip to content

Commit

Permalink
Simplify pack.List
Browse files Browse the repository at this point in the history
  • Loading branch information
fd0 committed Aug 25, 2016
1 parent 3fd1e4a commit de88fb2
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 97 deletions.
10 changes: 7 additions & 3 deletions src/cmds/restic/cmd_dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,18 @@ func printPacks(repo *repository.Repository, wr io.Writer) error {
name := job.Data.(string)

h := backend.Handle{Type: backend.Data, Name: name}
ldr := pack.BackendLoader{Backend: repo.Backend(), Handle: h}

unpacker, err := pack.NewUnpacker(repo.Key(), ldr)
blobInfo, err := repo.Backend().Stat(h)
if err != nil {
return nil, err
}

return unpacker.Entries, nil
blobs, err := pack.List(repo.Key(), backend.ReaderAt(repo.Backend(), h), blobInfo.Size)
if err != nil {
return nil, err
}

return blobs, nil
}

jobCh := make(chan worker.Job)
Expand Down
3 changes: 2 additions & 1 deletion src/restic/checker/checker.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package checker

import (
"bytes"
"errors"
"fmt"
"sync"
Expand Down Expand Up @@ -676,7 +677,7 @@ func checkPack(r *repository.Repository, id backend.ID) error {
return fmt.Errorf("Pack ID does not match, want %v, got %v", id.Str(), hash.Str())
}

blobs, err := pack.List(r.Key(), pack.BufferLoader(buf))
blobs, err := pack.List(r.Key(), bytes.NewReader(buf), int64(len(buf)))
if err != nil {
return err
}
Expand Down
43 changes: 0 additions & 43 deletions src/restic/pack/loader.go

This file was deleted.

82 changes: 44 additions & 38 deletions src/restic/pack/pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,67 +228,73 @@ func (p *Packer) String() string {
return fmt.Sprintf("<Packer %d blobs, %d bytes>", len(p.blobs), p.bytes)
}

const (
preloadHeaderSize = 2048
maxHeaderSize = 16 * 1024 * 1024
)

// List returns the list of entries found in a pack file.
func List(k *crypto.Key, ldr Loader) (entries []Blob, err error) {
// readHeaderLength returns the header length read from the end of the file
// encoded in little endian.
func readHeaderLength(rd io.ReaderAt, size int64) (uint32, error) {
off := size - int64(binary.Size(uint32(0)))

// read the last 2048 byte, this will mostly be enough for the header, so
// we do not need another round trip.
buf := make([]byte, preloadHeaderSize)
n, err := ldr.Load(buf, -int64(len(buf)))
buf := make([]byte, binary.Size(uint32(0)))
n, err := rd.ReadAt(buf, off)
if err != nil {
return 0, err
}

if err == io.ErrUnexpectedEOF {
err = nil
buf = buf[:n]
if n != len(buf) {
return 0, errors.New("not enough bytes read")
}

return binary.LittleEndian.Uint32(buf), nil
}

const maxHeaderSize = 16 * 1024 * 1024

// readHeader reads the header at the end of rd. size is the length of the
// whole data accessible in rd.
func readHeader(rd io.ReaderAt, size int64) ([]byte, error) {
hl, err := readHeaderLength(rd, size)
if err != nil {
return nil, fmt.Errorf("Load at -%d failed: %v", len(buf), err)
return nil, err
}
buf = buf[:n]

bs := binary.Size(uint32(0))
p := len(buf) - bs

// read the length from the end of the buffer
length := int(binary.LittleEndian.Uint32(buf[p : p+bs]))
buf = buf[:p]
if int64(hl) > size-int64(binary.Size(hl)) {
return nil, errors.New("header is larger than file")
}

if length > maxHeaderSize {
return nil, fmt.Errorf("header too large (%d bytes)", length)
if int64(hl) > maxHeaderSize {
return nil, errors.New("header is larger than maxHeaderSize")
}

// if the header is longer than the preloaded buffer, call the loader again.
if length > len(buf) {
buf = make([]byte, length)
n, err := ldr.Load(buf, -int64(len(buf)+bs))
if err != nil {
return nil, fmt.Errorf("Load at -%d failed: %v", len(buf), err)
}
buf := make([]byte, int(hl))
n, err := rd.ReadAt(buf, size-int64(hl)-int64(binary.Size(hl)))
if err != nil {
return nil, err
}

if n != len(buf) {
return nil, fmt.Errorf("not enough header bytes read: wanted %v, got %v", len(buf), n)
}
if n != len(buf) {
return nil, errors.New("not enough bytes read")
}

buf = buf[len(buf)-length:]
return buf, nil
}

// List returns the list of entries found in a pack file.
func List(k *crypto.Key, rd io.ReaderAt, size int64) (entries []Blob, err error) {
buf, err := readHeader(rd, size)
if err != nil {
return nil, err
}

// read header
hdr, err := crypto.Decrypt(k, buf, buf)
if err != nil {
return nil, err
}

rd := bytes.NewReader(hdr)
hdrRd := bytes.NewReader(hdr)

pos := uint(0)
for {
e := headerEntry{}
err = binary.Read(rd, binary.LittleEndian, &e)
err = binary.Read(hdrRd, binary.LittleEndian, &e)
if err == io.EOF {
break
}
Expand Down
14 changes: 6 additions & 8 deletions src/restic/pack/pack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func newPack(t testing.TB, k *crypto.Key, lengths []int) ([]Buf, []byte, uint) {
return bufs, packData, p.Size()
}

func verifyBlobs(t testing.TB, bufs []Buf, k *crypto.Key, ldr pack.Loader, packSize uint) {
func verifyBlobs(t testing.TB, bufs []Buf, k *crypto.Key, rd io.ReaderAt, packSize uint) {
written := 0
for _, buf := range bufs {
written += len(buf.data)
Expand All @@ -63,7 +63,7 @@ func verifyBlobs(t testing.TB, bufs []Buf, k *crypto.Key, ldr pack.Loader, packS
Equals(t, uint(written), packSize)

// read and parse it again
entries, err := pack.List(k, ldr)
entries, err := pack.List(k, rd, int64(packSize))
OK(t, err)
Equals(t, len(entries), len(bufs))

Expand All @@ -76,7 +76,7 @@ func verifyBlobs(t testing.TB, bufs []Buf, k *crypto.Key, ldr pack.Loader, packS
buf = make([]byte, int(e.Length))
}
buf = buf[:int(e.Length)]
n, err := ldr.Load(buf, int64(e.Offset))
n, err := rd.ReadAt(buf, int64(e.Offset))
OK(t, err)
buf = buf[:n]

Expand All @@ -91,7 +91,7 @@ func TestCreatePack(t *testing.T) {

bufs, packData, packSize := newPack(t, k, testLens)
Equals(t, uint(len(packData)), packSize)
verifyBlobs(t, bufs, k, pack.BufferLoader(packData), packSize)
verifyBlobs(t, bufs, k, bytes.NewReader(packData), packSize)
}

var blobTypeJSON = []struct {
Expand Down Expand Up @@ -128,8 +128,7 @@ func TestUnpackReadSeeker(t *testing.T) {

handle := backend.Handle{Type: backend.Data, Name: id.String()}
OK(t, b.Save(handle, packData))
ldr := pack.BackendLoader{Backend: b, Handle: handle}
verifyBlobs(t, bufs, k, ldr, packSize)
verifyBlobs(t, bufs, k, backend.ReaderAt(b, handle), packSize)
}

func TestShortPack(t *testing.T) {
Expand All @@ -142,6 +141,5 @@ func TestShortPack(t *testing.T) {

handle := backend.Handle{Type: backend.Data, Name: id.String()}
OK(t, b.Save(handle, packData))
ldr := pack.BackendLoader{Backend: b, Handle: handle}
verifyBlobs(t, bufs, k, ldr, packSize)
verifyBlobs(t, bufs, k, backend.ReaderAt(b, handle), packSize)
}
3 changes: 2 additions & 1 deletion src/restic/repository/repack.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package repository

import (
"bytes"
"io"
"restic/backend"
"restic/crypto"
Expand Down Expand Up @@ -32,7 +33,7 @@ func Repack(repo *Repository, packs backend.IDSet, keepBlobs pack.BlobSet) (err

debug.Log("Repack", "pack %v loaded (%d bytes)", packID.Str(), len(buf))

blobs, err := pack.List(repo.Key(), pack.BufferLoader(buf))
blobs, err := pack.List(repo.Key(), bytes.NewReader(buf), int64(len(buf)))
if err != nil {
return err
}
Expand Down
4 changes: 1 addition & 3 deletions src/restic/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,9 +554,7 @@ func (r *Repository) ListPack(id backend.ID) ([]pack.Blob, int64, error) {
return nil, 0, err
}

ldr := pack.BackendLoader{Backend: r.Backend(), Handle: h}

blobs, err := pack.List(r.Key(), ldr)
blobs, err := pack.List(r.Key(), backend.ReaderAt(r.Backend(), h), blobInfo.Size)
if err != nil {
return nil, 0, err
}
Expand Down

0 comments on commit de88fb2

Please sign in to comment.