Add EROFS library

This adds a library to write EROFS filesystems. It supports most of the non-deprecated features the
filesystem supports other than extended inodes (which have no benefits for most use cases where EROFS would be
appropriate). EROFS's variable-length extent compression is partially implemented but it requires an LZ4
compressor with support for fixed-size output which Go's https://github.com/pierrec/lz4 doesn't have. This means
that VLE compression is currently not wired up.

This will be used later as a replacement for our current initramfs-based root filesystem.

Test Plan: Has both integration and some unit tests. Confirmed working for our whole rootfs.

X-Origin-Diff: phab/D692
GitOrigin-RevId: 8c52b45ea05c617c80047e99c04c2b63e1b60c7c
diff --git a/metropolis/pkg/erofs/defs.go b/metropolis/pkg/erofs/defs.go
new file mode 100644
index 0000000..b547867
--- /dev/null
+++ b/metropolis/pkg/erofs/defs.go
@@ -0,0 +1,97 @@
+// Copyright 2020 The Monogon Project Authors.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package erofs
+
+// This file contains definitions coming from the in-Kernel implementation of the EROFS filesystem.
+// All definitions come from @linux//fs/erofs:erofs_fs.h unless stated otherwise.
+
+// Magic contains the 4 magic bytes starting at position 1024 identifying an EROFS filesystem.
+// Defined in @linux//include/uapi/linux/magic.h EROFS_SUPER_MAGIC_V1
+var Magic = [4]byte{0xe2, 0xe1, 0xf5, 0xe0}
+
+const blockSizeBits = 12
+const BlockSize = 1 << blockSizeBits
+
+// Defined in @linux//include/linux:fs_types.h starting at FT_UNKNOWN
+const (
+	fileTypeUnknown = iota
+	fileTypeRegularFile
+	fileTypeDirectory
+	fileTypeCharacterDevice
+	fileTypeBlockDevice
+	fileTypeFIFO
+	fileTypeSocket
+	fileTypeSymbolicLink
+)
+
+// Anonymous enum starting at EROFS_INODE_FLAT_PLAIN
+const (
+	inodeFlatPlain             = 0
+	inodeFlatCompressionLegacy = 1
+	inodeFlatInline            = 2
+	inodeFlatCompression       = 3
+)
+
+// struct erofs_dirent
+type directoryEntryRaw struct {
+	NodeNumber      uint64
+	NameStartOffset uint16
+	FileType        uint8
+	Reserved        uint8
+}
+
+// struct erofs_super_block
+type superblock struct {
+	Magic                [4]byte
+	Checksum             uint32
+	FeatureCompat        uint32
+	BlockSizeBits        uint8
+	Reserved0            uint8
+	RootNodeNumber       uint16
+	TotalInodes          uint64
+	BuildTimeSeconds     uint64
+	BuildTimeNanoseconds uint32
+	Blocks               uint32
+	MetaStartAddr        uint32
+	SharedXattrStartAddr uint32
+	UUID                 [16]byte
+	VolumeName           [16]byte
+	FeaturesIncompatible uint32
+	Reserved1            [44]byte
+}
+
+// struct erofs_inode_compact
+type inodeCompact struct {
+	Format         uint16
+	XattrCount     uint16
+	Mode           uint16
+	HardlinkCount  uint16
+	Size           uint32
+	Reserved0      uint32
+	Union          uint32
+	InodeNumCompat uint32
+	UID            uint16
+	GID            uint16
+	Reserved1      uint32
+}
+
+// Anonymous enum starting at Z_EROFS_VLE_CLUSTER_TYPE_PLAIN
+const (
+	vleClusterTypePlain = iota << 12
+	vleClusterTypeHead
+	vleClusterTypeNonhead
+)