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/blockdev_linux_test.go b/osbase/blockdev/blockdev_linux_test.go
new file mode 100644
index 0000000..31aa827
--- /dev/null
+++ b/osbase/blockdev/blockdev_linux_test.go
@@ -0,0 +1,68 @@
+//go:build linux
+
+package blockdev
+
+import (
+	"os"
+	"testing"
+
+	"source.monogon.dev/osbase/loop"
+)
+
+const loopBlockSize = 1024
+const loopBlockCount = 8
+
+func TestLoopDevice(t *testing.T) {
+	if os.Getenv("IN_KTEST") != "true" {
+		t.Skip("Not in ktest")
+	}
+	underlying, err := os.CreateTemp("/tmp", "")
+	if err != nil {
+		t.Fatalf("CreateTemp failed: %v", err)
+	}
+	defer os.Remove(underlying.Name())
+
+	_, err = underlying.Write(make([]byte, loopBlockSize*loopBlockCount))
+	if err != nil {
+		t.Fatalf("Write failed: %v", err)
+	}
+
+	loopDev, err := loop.Create(underlying, loop.Config{
+		BlockSize: loopBlockSize,
+	})
+	if err != nil {
+		t.Fatalf("loop.Create failed: %v", err)
+	}
+	defer loopDev.Remove()
+
+	devPath, err := loopDev.DevPath()
+	if err != nil {
+		t.Fatalf("loopDev.DevPath failed: %v", err)
+	}
+
+	loopDev.Close()
+	blk, err := Open(devPath)
+	if err != nil {
+		t.Fatalf("Failed to open loop device: %v", err)
+	}
+	defer blk.Close()
+
+	ValidateBlockDev(t, blk, loopBlockCount, loopBlockSize, loopBlockSize)
+}
+
+const fileBlockSize = 1024
+const fileBlockCount = 8
+
+func TestFile(t *testing.T) {
+	if os.Getenv("IN_KTEST") != "true" {
+		t.Skip("Not in ktest")
+	}
+
+	blk, err := CreateFile("/tmp/testfile", fileBlockSize, fileBlockCount)
+	if err != nil {
+		t.Fatalf("Failed to create file: %v", err)
+	}
+	defer os.Remove("/tmp/testfile")
+
+	ValidateBlockDev(t, blk, fileBlockCount, fileBlockSize, fileBlockSize)
+}