osbase/blockdev: add tests, fix minor issues
Add a lot of bounds checks which should make BlockDev safer to use. Fix
a bug in the ReadWriteSeeker.Seek function with io.SeekEnd; the offset
should be added to, not subtracted from the size. Add the Sync()
function to the BlockDev interface.
Change-Id: I247095b3dbc6410064844b4ac7c6208d88a7abcd
Reviewed-on: https://review.monogon.dev/c/monogon/+/3338
Tested-by: Jenkins CI
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/osbase/blockdev/memory.go b/osbase/blockdev/memory.go
index 193f93c..cf5e21d 100644
--- a/osbase/blockdev/memory.go
+++ b/osbase/blockdev/memory.go
@@ -43,70 +43,47 @@
return m
}
-func (m *Memory) ReadAt(p []byte, off int64) (int, error) {
- devSize := m.blockSize * m.blockCount
- if off > devSize {
+func (m *Memory) ReadAt(p []byte, off int64) (n int, err error) {
+ if off < 0 {
+ return 0, errors.New("blockdev.Memory.ReadAt: negative offset")
+ }
+ if off > int64(len(m.data)) {
return 0, io.EOF
}
// TODO: Alignment checks?
- copy(p, m.data[off:])
- n := len(m.data[off:])
+ n = copy(p, m.data[off:])
if n < len(p) {
- return n, io.EOF
+ err = io.EOF
}
- return len(p), nil
+ return
}
-func (m *Memory) WriteAt(p []byte, off int64) (int, error) {
- devSize := m.blockSize * m.blockCount
- if off > devSize {
- return 0, io.EOF
+func (m *Memory) WriteAt(p []byte, off int64) (n int, err error) {
+ if off < 0 || off > int64(len(m.data)) {
+ return 0, ErrOutOfBounds
}
// TODO: Alignment checks?
- copy(m.data[off:], p)
- n := len(m.data[off:])
+ n = copy(m.data[off:], p)
if n < len(p) {
- return n, io.EOF
+ err = ErrOutOfBounds
}
- return len(p), nil
-}
-
-func (m *Memory) BlockSize() int64 {
- return m.blockSize
+ return
}
func (m *Memory) BlockCount() int64 {
return m.blockCount
}
+func (m *Memory) BlockSize() int64 {
+ return m.blockSize
+}
+
func (m *Memory) OptimalBlockSize() int64 {
return m.blockSize
}
-func (m *Memory) validRange(startByte, endByte int64) error {
- if startByte > endByte {
- return fmt.Errorf("startByte (%d) larger than endByte (%d), invalid interval", startByte, endByte)
- }
- devSize := m.blockSize * m.blockCount
- if startByte >= devSize || startByte < 0 {
- return fmt.Errorf("startByte (%d) out of range (0-%d)", endByte, devSize)
- }
- if endByte > devSize || endByte < 0 {
- return fmt.Errorf("endByte (%d) out of range (0-%d)", endByte, devSize)
- }
- // Alignment check works for powers of two by looking at every bit below
- // the bit set in the block size.
- if startByte&(m.blockSize-1) != 0 {
- return fmt.Errorf("startByte (%d) is not aligned to blockSize (%d)", startByte, m.blockSize)
- }
- if endByte&(m.blockSize-1) != 0 {
- return fmt.Errorf("endByte (%d) is not aligned to blockSize (%d)", startByte, m.blockSize)
- }
- return nil
-}
-
func (m *Memory) Discard(startByte, endByte int64) error {
- if err := m.validRange(startByte, endByte); err != nil {
+ if err := validAlignedRange(m, startByte, endByte); err != nil {
return err
}
for i := startByte; i < endByte; i++ {
@@ -118,7 +95,7 @@
}
func (m *Memory) Zero(startByte, endByte int64) error {
- if err := m.validRange(startByte, endByte); err != nil {
+ if err := validAlignedRange(m, startByte, endByte); err != nil {
return err
}
for i := startByte; i < endByte; i++ {
@@ -126,3 +103,7 @@
}
return nil
}
+
+func (m *Memory) Sync() error {
+ return nil
+}