Skip to content

Commit

Permalink
feat(erofs): initial commit for erofs support
Browse files Browse the repository at this point in the history
Fixes opencontainers/image-spec#1190

Signed-off-by: Ramkumar Chinchani <[email protected]>
  • Loading branch information
rchincha committed Jun 14, 2024
1 parent 8fbf329 commit a6b5f8c
Show file tree
Hide file tree
Showing 10 changed files with 3,497 additions and 0 deletions.
20 changes: 20 additions & 0 deletions pkg/erofs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Files in this package have been initially copied from The Monogon Monorepo [1].
The copied portion is under these copyright and license terms.

// 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.

[1] https://github.com/monogon-dev/monogon/tree/main/metropolis/pkg/erofs
2,369 changes: 2,369 additions & 0 deletions pkg/erofs/compression.go

Large diffs are not rendered by default.

91 changes: 91 additions & 0 deletions pkg/erofs/compression_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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

import (
"reflect"
"testing"
)

func TestEncodeSmallVLEBlock(t *testing.T) {
type args struct {
vals [2]uint16
blkaddr uint32
}
tests := []struct {
name string
args args
want [8]byte
}{
{
name: "Reference",
args: args{vals: [2]uint16{vleClusterTypeHead | 1527, vleClusterTypeNonhead | 1}, blkaddr: 1},
want: [8]byte{0xf7, 0x15, 0x01, 0x20, 0x01, 0x00, 0x00, 0x00},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := encodeSmallVLEBlock(tt.args.vals, tt.args.blkaddr); !reflect.DeepEqual(got, tt.want) {
t.Errorf("encodeSmallVLEBlock() = %v, want %v", got, tt.want)
}
})
}
}

func TestEncodeBigVLEBlock(t *testing.T) {
type args struct {
vals [16]uint16
blkaddr uint32
}
tests := []struct {
name string
args args
want [32]byte
}{
{
name: "Reference",
args: args{
vals: [16]uint16{
vleClusterTypeNonhead | 2,
vleClusterTypeHead | 1460,
vleClusterTypeNonhead | 1,
vleClusterTypeNonhead | 2,
vleClusterTypeHead | 2751,
vleClusterTypeNonhead | 1,
vleClusterTypeNonhead | 2,
vleClusterTypeHead | 940,
vleClusterTypeNonhead | 1,
vleClusterTypeHead | 3142,
vleClusterTypeNonhead | 1,
vleClusterTypeNonhead | 2,
vleClusterTypeHead | 1750,
vleClusterTypeNonhead | 1,
vleClusterTypeNonhead | 2,
vleClusterTypeHead | 683,
},
blkaddr: 3,
},
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}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := encodeBigVLEBlock(tt.args.vals, tt.args.blkaddr); !reflect.DeepEqual(got, tt.want) {
t.Errorf("encodeBigVLEBlock() = %v, want %v", got, tt.want)
}
})
}
}
99 changes: 99 additions & 0 deletions pkg/erofs/defs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// 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
)
52 changes: 52 additions & 0 deletions pkg/erofs/defs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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

import (
"bytes"
"encoding/binary"
"testing"

"github.com/stretchr/testify/assert"
)

// These test that the specified structures serialize to the same number of
// bytes as the ones in the EROFS kernel module.

func TestSuperblockSize(t *testing.T) {
var buf bytes.Buffer
if err := binary.Write(&buf, binary.LittleEndian, &superblock{}); err != nil {
t.Fatalf("failed to write superblock: %v", err)
}
assert.Equal(t, 128, buf.Len())
}

func TestDirectoryEntrySize(t *testing.T) {
var buf bytes.Buffer
if err := binary.Write(&buf, binary.LittleEndian, &directoryEntryRaw{}); err != nil {
t.Fatalf("failed to write directory entry: %v", err)
}
assert.Equal(t, 12, buf.Len())
}

func TestInodeCompactSize(t *testing.T) {
var buf bytes.Buffer
if err := binary.Write(&buf, binary.LittleEndian, &inodeCompact{}); err != nil {
t.Fatalf("failed to write compact inode: %v", err)
}
assert.Equal(t, 32, buf.Len())
}
Loading

0 comments on commit a6b5f8c

Please sign in to comment.