osbase/fat32: adopt structfs

Change the external interface of the FAT32 writer to take a
structfs.Tree instead of a FAT32-specific data structure. Producers of
file system data are no longer specific to FAT32.

With these changes, the blkio package becomes obsolete. The
LazyFileReader did not actually work as intended when used with
osbase/fat32, because fat32 copies data with io.CopyN and thus stops
reading before reaching EOF, so the LazyFileReader is never closed. The
new Blob interface requires the consumer to explicitly Open and Close.

Change-Id: I9a71a5f0bddf36ac38c656659e6dcfe520b88fb0
Reviewed-on: https://review.monogon.dev/c/monogon/+/4037
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/cli/metroctl/core/install.go b/metropolis/cli/metroctl/core/install.go
index 190f66a..5d43a89 100644
--- a/metropolis/cli/metroctl/core/install.go
+++ b/metropolis/cli/metroctl/core/install.go
@@ -4,7 +4,6 @@
 package core
 
 import (
-	"bytes"
 	"errors"
 	"fmt"
 	"math"
@@ -16,6 +15,7 @@
 	"source.monogon.dev/osbase/blockdev"
 	"source.monogon.dev/osbase/fat32"
 	"source.monogon.dev/osbase/gpt"
+	"source.monogon.dev/osbase/structfs"
 )
 
 type MakeInstallerImageArgs struct {
@@ -23,13 +23,13 @@
 	TargetPath string
 
 	// Reader for the installer EFI executable. Mandatory.
-	Installer fat32.SizedReader
+	Installer structfs.Blob
 
 	// Optional NodeParameters to be embedded for use by the installer.
 	NodeParams *api.NodeParameters
 
 	// Optional Reader for a Metropolis bundle for use by the installer.
-	Bundle fat32.SizedReader
+	Bundle structfs.Blob
 }
 
 // MakeInstallerImage generates an installer disk image containing a Table
@@ -40,7 +40,7 @@
 		return errors.New("installer is mandatory")
 	}
 
-	espRoot := fat32.Inode{Attrs: fat32.AttrDirectory}
+	var espRoot structfs.Tree
 
 	// This needs to be a "Removable Media" according to the UEFI Specification
 	// V2.9 Section 3.5.1.1. This file is booted by any compliant UEFI firmware
@@ -54,7 +54,7 @@
 		if err != nil {
 			return fmt.Errorf("failed to marshal node params: %w", err)
 		}
-		if err := espRoot.PlaceFile("metropolis-installer/nodeparams.pb", bytes.NewReader(nodeParamsRaw)); err != nil {
+		if err := espRoot.PlaceFile("metropolis-installer/nodeparams.pb", structfs.Bytes(nodeParamsRaw)); err != nil {
 			return err
 		}
 	}