summaryrefslogtreecommitdiffhomepage
path: root/pkg/merkletree
diff options
context:
space:
mode:
authorChong Cai <chongc@google.com>2020-09-16 14:43:37 -0700
committergVisor bot <gvisor-bot@google.com>2020-09-16 14:45:39 -0700
commit3749e70a693007b706fb06529ab95d910a251ba6 (patch)
tree6a451242dec9261b691a43d31bfada597f0cdb47 /pkg/merkletree
parent666397c5c82ee18a776491919312d19cfe6d4a07 (diff)
Implement PRead for verity fs
PRead is implemented by read from the underlying file in blocks, and verify each block. The verified contents are saved into the output buffer. PiperOrigin-RevId: 332092267
Diffstat (limited to 'pkg/merkletree')
-rw-r--r--pkg/merkletree/merkletree.go25
-rw-r--r--pkg/merkletree/merkletree_test.go42
2 files changed, 43 insertions, 24 deletions
diff --git a/pkg/merkletree/merkletree.go b/pkg/merkletree/merkletree.go
index 36832ec86..4b4f9bd52 100644
--- a/pkg/merkletree/merkletree.go
+++ b/pkg/merkletree/merkletree.go
@@ -225,9 +225,9 @@ func Generate(data io.ReadSeeker, dataSize int64, treeReader io.ReadSeeker, tree
// Verify will modify the cursor for data, but always restores it to its
// original position upon exit. The cursor for tree is modified and not
// restored.
-func Verify(w io.Writer, data, tree io.ReadSeeker, dataSize int64, readOffset int64, readSize int64, expectedRoot []byte, dataAndTreeInSameFile bool) error {
+func Verify(w io.Writer, data, tree io.ReadSeeker, dataSize int64, readOffset int64, readSize int64, expectedRoot []byte, dataAndTreeInSameFile bool) (int64, error) {
if readSize <= 0 {
- return fmt.Errorf("Unexpected read size: %d", readSize)
+ return 0, fmt.Errorf("Unexpected read size: %d", readSize)
}
layout := InitLayout(int64(dataSize), dataAndTreeInSameFile)
@@ -240,29 +240,30 @@ func Verify(w io.Writer, data, tree io.ReadSeeker, dataSize int64, readOffset in
// finishes.
origOffset, err := data.Seek(0, io.SeekCurrent)
if err != nil {
- return fmt.Errorf("Find current data offset failed: %v", err)
+ return 0, fmt.Errorf("Find current data offset failed: %v", err)
}
defer data.Seek(origOffset, io.SeekStart)
// Move to the first block that contains target data.
if _, err := data.Seek(firstDataBlock*layout.blockSize, io.SeekStart); err != nil {
- return fmt.Errorf("Seek to datablock start failed: %v", err)
+ return 0, fmt.Errorf("Seek to datablock start failed: %v", err)
}
buf := make([]byte, layout.blockSize)
var readErr error
- bytesRead := 0
+ total := int64(0)
for i := firstDataBlock; i <= lastDataBlock; i++ {
// Read a block that includes all or part of target range in
// input data.
- bytesRead, readErr = data.Read(buf)
+ bytesRead, err := data.Read(buf)
+ readErr = err
// If at the end of input data and all previous blocks are
// verified, return the verified input data and EOF.
if readErr == io.EOF && bytesRead == 0 {
break
}
if readErr != nil && readErr != io.EOF {
- return fmt.Errorf("Read from data failed: %v", err)
+ return 0, fmt.Errorf("Read from data failed: %v", err)
}
// If this is the end of file, zero the remaining bytes in buf,
// otherwise they are still from the previous block.
@@ -274,7 +275,7 @@ func Verify(w io.Writer, data, tree io.ReadSeeker, dataSize int64, readOffset in
}
}
if err := verifyBlock(tree, layout, buf, i, expectedRoot); err != nil {
- return err
+ return 0, err
}
// startOff is the beginning of the read range within the
// current data block. Note that for all blocks other than the
@@ -298,10 +299,14 @@ func Verify(w io.Writer, data, tree io.ReadSeeker, dataSize int64, readOffset in
if endOff > int64(bytesRead) {
endOff = int64(bytesRead)
}
- w.Write(buf[startOff:endOff])
+ n, err := w.Write(buf[startOff:endOff])
+ if err != nil {
+ return total, err
+ }
+ total += int64(n)
}
- return readErr
+ return total, readErr
}
// verifyBlock verifies a block against tree. index is the number of block in
diff --git a/pkg/merkletree/merkletree_test.go b/pkg/merkletree/merkletree_test.go
index ad50ba5f6..daaca759a 100644
--- a/pkg/merkletree/merkletree_test.go
+++ b/pkg/merkletree/merkletree_test.go
@@ -67,17 +67,17 @@ func TestLayout(t *testing.T) {
t.Run(fmt.Sprintf("%d", tc.dataSize), func(t *testing.T) {
l := InitLayout(tc.dataSize, tc.dataAndTreeInSameFile)
if l.blockSize != int64(usermem.PageSize) {
- t.Errorf("got blockSize %d, want %d", l.blockSize, usermem.PageSize)
+ t.Errorf("Got blockSize %d, want %d", l.blockSize, usermem.PageSize)
}
if l.digestSize != sha256DigestSize {
- t.Errorf("got digestSize %d, want %d", l.digestSize, sha256DigestSize)
+ t.Errorf("Got digestSize %d, want %d", l.digestSize, sha256DigestSize)
}
if l.numLevels() != len(tc.expectedLevelOffset) {
- t.Errorf("got levels %d, want %d", l.numLevels(), len(tc.expectedLevelOffset))
+ t.Errorf("Got levels %d, want %d", l.numLevels(), len(tc.expectedLevelOffset))
}
for i := 0; i < l.numLevels() && i < len(tc.expectedLevelOffset); i++ {
if l.levelOffset[i] != tc.expectedLevelOffset[i] {
- t.Errorf("got levelStart[%d] %d, want %d", i, l.levelOffset[i], tc.expectedLevelOffset[i])
+ t.Errorf("Got levelStart[%d] %d, want %d", i, l.levelOffset[i], tc.expectedLevelOffset[i])
}
}
})
@@ -169,11 +169,11 @@ func TestGenerate(t *testing.T) {
}, int64(len(tc.data)), &tree, &tree, dataAndTreeInSameFile)
}
if err != nil {
- t.Fatalf("got err: %v, want nil", err)
+ t.Fatalf("Got err: %v, want nil", err)
}
if !bytes.Equal(root, tc.expectedRoot) {
- t.Errorf("got root: %v, want %v", root, tc.expectedRoot)
+ t.Errorf("Got root: %v, want %v", root, tc.expectedRoot)
}
}
})
@@ -334,14 +334,21 @@ func TestVerify(t *testing.T) {
var buf bytes.Buffer
data[tc.modifyByte] ^= 1
if tc.shouldSucceed {
- if err := Verify(&buf, bytes.NewReader(data), &tree, tc.dataSize, tc.verifyStart, tc.verifySize, root, dataAndTreeInSameFile); err != nil && err != io.EOF {
+ n, err := Verify(&buf, bytes.NewReader(data), &tree, tc.dataSize, tc.verifyStart, tc.verifySize, root, dataAndTreeInSameFile)
+ if err != nil && err != io.EOF {
t.Errorf("Verification failed when expected to succeed: %v", err)
}
- if int64(buf.Len()) != tc.verifySize || !bytes.Equal(data[tc.verifyStart:tc.verifyStart+tc.verifySize], buf.Bytes()) {
- t.Errorf("Incorrect output from Verify")
+ if n != tc.verifySize {
+ t.Errorf("Got Verify output size %d, want %d", n, tc.verifySize)
+ }
+ if int64(buf.Len()) != tc.verifySize {
+ t.Errorf("Got Verify output buf size %d, want %d,", buf.Len(), tc.verifySize)
+ }
+ if !bytes.Equal(data[tc.verifyStart:tc.verifyStart+tc.verifySize], buf.Bytes()) {
+ t.Errorf("Incorrect output buf from Verify")
}
} else {
- if err := Verify(&buf, bytes.NewReader(data), &tree, tc.dataSize, tc.verifyStart, tc.verifySize, root, dataAndTreeInSameFile); err == nil {
+ if _, err := Verify(&buf, bytes.NewReader(data), &tree, tc.dataSize, tc.verifyStart, tc.verifySize, root, dataAndTreeInSameFile); err == nil {
t.Errorf("Verification succeeded when expected to fail")
}
}
@@ -382,14 +389,21 @@ func TestVerifyRandom(t *testing.T) {
var buf bytes.Buffer
// Checks that the random portion of data from the original data is
// verified successfully.
- if err := Verify(&buf, bytes.NewReader(data), &tree, dataSize, start, size, root, dataAndTreeInSameFile); err != nil && err != io.EOF {
+ n, err := Verify(&buf, bytes.NewReader(data), &tree, dataSize, start, size, root, dataAndTreeInSameFile)
+ if err != nil && err != io.EOF {
t.Errorf("Verification failed for correct data: %v", err)
}
if size > dataSize-start {
size = dataSize - start
}
- if int64(buf.Len()) != size || !bytes.Equal(data[start:start+size], buf.Bytes()) {
- t.Errorf("Incorrect output from Verify")
+ if n != size {
+ t.Errorf("Got Verify output size %d, want %d", n, size)
+ }
+ if int64(buf.Len()) != size {
+ t.Errorf("Got Verify output buf size %d, want %d", buf.Len(), size)
+ }
+ if !bytes.Equal(data[start:start+size], buf.Bytes()) {
+ t.Errorf("Incorrect output buf from Verify")
}
buf.Reset()
@@ -397,7 +411,7 @@ func TestVerifyRandom(t *testing.T) {
randBytePos := rand.Int63n(size)
data[start+randBytePos] ^= 1
- if err := Verify(&buf, bytes.NewReader(data), &tree, dataSize, start, size, root, dataAndTreeInSameFile); err == nil {
+ if _, err := Verify(&buf, bytes.NewReader(data), &tree, dataSize, start, size, root, dataAndTreeInSameFile); err == nil {
t.Errorf("Verification succeeded for modified data")
}
}