Skip to content

Commit 449e5f5

Browse files
author
Ramkumar Chinchani
committed
feat(erofs): initial commit for erofs support
Fixes opencontainers/image-spec#1190 Signed-off-by: Ramkumar Chinchani <[email protected]>
1 parent 8fbf329 commit 449e5f5

File tree

9 files changed

+3494
-0
lines changed

9 files changed

+3494
-0
lines changed

pkg/erofs/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Files in this package have been initially copied from The Monogon Monorepo [1].
2+
The copied portion is under these copyright and license terms.
3+
4+
// Copyright 2020 The Monogon Project Authors.
5+
//
6+
// SPDX-License-Identifier: Apache-2.0
7+
//
8+
// Licensed under the Apache License, Version 2.0 (the "License");
9+
// you may not use this file except in compliance with the License.
10+
// You may obtain a copy of the License at
11+
//
12+
// http://www.apache.org/licenses/LICENSE-2.0
13+
//
14+
// Unless required by applicable law or agreed to in writing, software
15+
// distributed under the License is distributed on an "AS IS" BASIS,
16+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
// See the License for the specific language governing permissions and
18+
// limitations under the License.
19+
20+
[1] https://github.com/monogon-dev/monogon/tree/main/metropolis/pkg/erofs

pkg/erofs/compression.go

Lines changed: 2369 additions & 0 deletions
Large diffs are not rendered by default.

pkg/erofs/compression_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright 2020 The Monogon Project Authors.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package erofs
18+
19+
import (
20+
"reflect"
21+
"testing"
22+
)
23+
24+
func TestEncodeSmallVLEBlock(t *testing.T) {
25+
type args struct {
26+
vals [2]uint16
27+
blkaddr uint32
28+
}
29+
tests := []struct {
30+
name string
31+
args args
32+
want [8]byte
33+
}{
34+
{
35+
name: "Reference",
36+
args: args{vals: [2]uint16{vleClusterTypeHead | 1527, vleClusterTypeNonhead | 1}, blkaddr: 1},
37+
want: [8]byte{0xf7, 0x15, 0x01, 0x20, 0x01, 0x00, 0x00, 0x00},
38+
},
39+
}
40+
for _, tt := range tests {
41+
t.Run(tt.name, func(t *testing.T) {
42+
if got := encodeSmallVLEBlock(tt.args.vals, tt.args.blkaddr); !reflect.DeepEqual(got, tt.want) {
43+
t.Errorf("encodeSmallVLEBlock() = %v, want %v", got, tt.want)
44+
}
45+
})
46+
}
47+
}
48+
49+
func TestEncodeBigVLEBlock(t *testing.T) {
50+
type args struct {
51+
vals [16]uint16
52+
blkaddr uint32
53+
}
54+
tests := []struct {
55+
name string
56+
args args
57+
want [32]byte
58+
}{
59+
{
60+
name: "Reference",
61+
args: args{
62+
vals: [16]uint16{
63+
vleClusterTypeNonhead | 2,
64+
vleClusterTypeHead | 1460,
65+
vleClusterTypeNonhead | 1,
66+
vleClusterTypeNonhead | 2,
67+
vleClusterTypeHead | 2751,
68+
vleClusterTypeNonhead | 1,
69+
vleClusterTypeNonhead | 2,
70+
vleClusterTypeHead | 940,
71+
vleClusterTypeNonhead | 1,
72+
vleClusterTypeHead | 3142,
73+
vleClusterTypeNonhead | 1,
74+
vleClusterTypeNonhead | 2,
75+
vleClusterTypeHead | 1750,
76+
vleClusterTypeNonhead | 1,
77+
vleClusterTypeNonhead | 2,
78+
vleClusterTypeHead | 683,
79+
},
80+
blkaddr: 3,
81+
},
82+
want: [32]byte{0x02, 0x20, 0x6d, 0x15, 0x00, 0x0a, 0x80, 0xbf, 0x5a, 0x00, 0x28, 0x00, 0xb2, 0x4e, 0x01, 0xa0, 0x11, 0x17, 0x00, 0x0a, 0x80, 0xd6, 0x56, 0x00, 0x28, 0x00, 0xae, 0x4a, 0x03, 0x00, 0x00, 0x00}},
83+
}
84+
for _, tt := range tests {
85+
t.Run(tt.name, func(t *testing.T) {
86+
if got := encodeBigVLEBlock(tt.args.vals, tt.args.blkaddr); !reflect.DeepEqual(got, tt.want) {
87+
t.Errorf("encodeBigVLEBlock() = %v, want %v", got, tt.want)
88+
}
89+
})
90+
}
91+
}

pkg/erofs/defs.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright 2020 The Monogon Project Authors.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package erofs
18+
19+
// This file contains definitions coming from the in-Kernel implementation of
20+
// the EROFS filesystem. All definitions come from @linux//fs/erofs:erofs_fs.h
21+
// unless stated otherwise.
22+
23+
// Magic contains the 4 magic bytes starting at position 1024 identifying an
24+
// EROFS filesystem. Defined in @linux//include/uapi/linux/magic.h
25+
// EROFS_SUPER_MAGIC_V1
26+
var Magic = [4]byte{0xe2, 0xe1, 0xf5, 0xe0}
27+
28+
const blockSizeBits = 12
29+
const BlockSize = 1 << blockSizeBits
30+
31+
// Defined in @linux//include/linux:fs_types.h starting at FT_UNKNOWN
32+
const (
33+
fileTypeUnknown = iota
34+
fileTypeRegularFile
35+
fileTypeDirectory
36+
fileTypeCharacterDevice
37+
fileTypeBlockDevice
38+
fileTypeFIFO
39+
fileTypeSocket
40+
fileTypeSymbolicLink
41+
)
42+
43+
// Anonymous enum starting at EROFS_INODE_FLAT_PLAIN
44+
const (
45+
inodeFlatPlain = 0
46+
inodeFlatCompressionLegacy = 1
47+
inodeFlatInline = 2
48+
inodeFlatCompression = 3
49+
)
50+
51+
// struct erofs_dirent
52+
type directoryEntryRaw struct {
53+
NodeNumber uint64
54+
NameStartOffset uint16
55+
FileType uint8
56+
Reserved uint8
57+
}
58+
59+
// struct erofs_super_block
60+
type superblock struct {
61+
Magic [4]byte
62+
Checksum uint32
63+
FeatureCompat uint32
64+
BlockSizeBits uint8
65+
Reserved0 uint8
66+
RootNodeNumber uint16
67+
TotalInodes uint64
68+
BuildTimeSeconds uint64
69+
BuildTimeNanoseconds uint32
70+
Blocks uint32
71+
MetaStartAddr uint32
72+
SharedXattrStartAddr uint32
73+
UUID [16]byte
74+
VolumeName [16]byte
75+
FeaturesIncompatible uint32
76+
Reserved1 [44]byte
77+
}
78+
79+
// struct erofs_inode_compact
80+
type inodeCompact struct {
81+
Format uint16
82+
XattrCount uint16
83+
Mode uint16
84+
HardlinkCount uint16
85+
Size uint32
86+
Reserved0 uint32
87+
Union uint32
88+
InodeNumCompat uint32
89+
UID uint16
90+
GID uint16
91+
Reserved1 uint32
92+
}
93+
94+
// Anonymous enum starting at Z_EROFS_VLE_CLUSTER_TYPE_PLAIN
95+
const (
96+
vleClusterTypePlain = iota << 12
97+
vleClusterTypeHead
98+
vleClusterTypeNonhead
99+
)

pkg/erofs/defs_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2020 The Monogon Project Authors.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package erofs
18+
19+
import (
20+
"bytes"
21+
"encoding/binary"
22+
"testing"
23+
24+
"github.com/stretchr/testify/assert"
25+
)
26+
27+
// These test that the specified structures serialize to the same number of
28+
// bytes as the ones in the EROFS kernel module.
29+
30+
func TestSuperblockSize(t *testing.T) {
31+
var buf bytes.Buffer
32+
if err := binary.Write(&buf, binary.LittleEndian, &superblock{}); err != nil {
33+
t.Fatalf("failed to write superblock: %v", err)
34+
}
35+
assert.Equal(t, 128, buf.Len())
36+
}
37+
38+
func TestDirectoryEntrySize(t *testing.T) {
39+
var buf bytes.Buffer
40+
if err := binary.Write(&buf, binary.LittleEndian, &directoryEntryRaw{}); err != nil {
41+
t.Fatalf("failed to write directory entry: %v", err)
42+
}
43+
assert.Equal(t, 12, buf.Len())
44+
}
45+
46+
func TestInodeCompactSize(t *testing.T) {
47+
var buf bytes.Buffer
48+
if err := binary.Write(&buf, binary.LittleEndian, &inodeCompact{}); err != nil {
49+
t.Fatalf("failed to write compact inode: %v", err)
50+
}
51+
assert.Equal(t, 32, buf.Len())
52+
}

0 commit comments

Comments
 (0)