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/compression.go b/metropolis/pkg/erofs/compression.go
new file mode 100644
index 0000000..58b2f4b
--- /dev/null
+++ b/metropolis/pkg/erofs/compression.go
@@ -0,0 +1,59 @@
+// 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 compression-related functions.
+// TODO(lorenz): Fully implement compression. These are currently unused.
+
+import "encoding/binary"
+
+// mapHeader is a legacy but still-used advisory structure at the start of a compressed VLE block. It contains constant
+// values as annotated.
+type mapHeader struct {
+ Reserved uint32 // 0
+ Advise uint16 // 1
+ AlgorithmType uint8 // 0
+ ClusterBits uint8 // 0
+}
+
+// encodeSmallVLEBlock encodes two VLE extents into a 8 byte block.
+func encodeSmallVLEBlock(vals [2]uint16, blkaddr uint32) [8]byte {
+ var out [8]byte
+ binary.LittleEndian.PutUint16(out[0:2], vals[0])
+ binary.LittleEndian.PutUint16(out[2:4], vals[1])
+ binary.LittleEndian.PutUint32(out[4:8], blkaddr)
+ return out
+}
+
+// encodeBigVLEBlock encodes 16 VLE extents into a 32 byte block.
+func encodeBigVLEBlock(vals [16]uint16, blkaddr uint32) [32]byte {
+ var out [32]byte
+ for i, val := range vals {
+ if val > 1<<14 {
+ panic("value is bigger than 14 bits, cannot encode")
+ }
+ // Writes packed 14 bit unsigned integers
+ pos := i * 14
+ bitStartPos := pos % 8
+ byteStartPos := pos / 8
+ out[byteStartPos] = out[byteStartPos]&((1<<bitStartPos)-1) | uint8(val<<bitStartPos)
+ out[byteStartPos+1] = uint8(val >> (8 - bitStartPos))
+ out[byteStartPos+2] = uint8(val >> (16 - bitStartPos))
+ }
+ binary.LittleEndian.PutUint32(out[28:32], blkaddr)
+ return out
+}