313 lines
8.9 KiB
Go
313 lines
8.9 KiB
Go
|
// Copyright 2017 Google Inc. All rights reserved.
|
||
|
//
|
||
|
// 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 fs
|
||
|
|
||
|
import (
|
||
|
"os"
|
||
|
"reflect"
|
||
|
"runtime"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
func TestParseDirent(t *testing.T) {
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
in []byte
|
||
|
out []*dirEntryInfo
|
||
|
}{
|
||
|
{
|
||
|
// Test that type DT_DIR is translated to os.ModeDir
|
||
|
name: "dir",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x28, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
},
|
||
|
out: []*dirEntryInfo{
|
||
|
{".module_paths", os.ModeDir, true},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// Test that type DT_REG is translated to a regular file
|
||
|
name: "file",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x28, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x08,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
},
|
||
|
out: []*dirEntryInfo{
|
||
|
{".module_paths", 0, true},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// Test that type DT_LNK is translated to a regular os.ModeSymlink
|
||
|
name: "symlink",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x28, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x0a,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
},
|
||
|
out: []*dirEntryInfo{
|
||
|
{".module_paths", os.ModeSymlink, true},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// Test that type DT_UNKNOWN sets modeExists: false
|
||
|
name: "unknown",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x28, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x00,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
},
|
||
|
out: []*dirEntryInfo{
|
||
|
{".module_paths", 0, false},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// Test a name with no padding after the null terminator
|
||
|
name: "no padding",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x20, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
|
||
|
},
|
||
|
out: []*dirEntryInfo{
|
||
|
{".module_path", os.ModeDir, true},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// Test two sequential entries
|
||
|
name: "two entries",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x28, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x28, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x74,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
},
|
||
|
out: []*dirEntryInfo{
|
||
|
{".module_paths", os.ModeDir, true},
|
||
|
{".module_patht", os.ModeDir, true},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// Test two sequential entries with no padding between them
|
||
|
name: "two entries no padding",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x20, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
|
||
|
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x28, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
},
|
||
|
out: []*dirEntryInfo{
|
||
|
{".module_path", os.ModeDir, true},
|
||
|
{".module_paths", os.ModeDir, true},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// Test an empty buffer. This shouldn't happen in practice because
|
||
|
// readdir doesn't call parseDirent if no bytes were returned.
|
||
|
name: "empty",
|
||
|
in: []byte{},
|
||
|
out: nil,
|
||
|
},
|
||
|
{
|
||
|
name: "missing null terminator",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x20, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||
|
},
|
||
|
out: []*dirEntryInfo{
|
||
|
{".module_paths", os.ModeDir, true},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// Test two sequential entries where the first has an incorrect d_reclen.
|
||
|
// Should return with no entries.
|
||
|
name: "two entries first malformed",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x10, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
|
||
|
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x28, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
},
|
||
|
out: nil,
|
||
|
},
|
||
|
{
|
||
|
// Test two sequential entries where the second has an incorrect d_reclen.
|
||
|
// Should return the first entry.
|
||
|
name: "two entries second malformed",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x28, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
|
||
|
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x10, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
},
|
||
|
out: []*dirEntryInfo{
|
||
|
{".module_path", os.ModeDir, true},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// Test a reclen that goes past the end of the buffer.
|
||
|
name: "overrun",
|
||
|
in: []byte{
|
||
|
// __ino64_t d_ino;
|
||
|
0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
// __off64_t d_off;
|
||
|
0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
|
||
|
// unsigned short int d_reclen;
|
||
|
0x30, 0x00,
|
||
|
// unsigned char d_type;
|
||
|
0x04,
|
||
|
// char d_name[];
|
||
|
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
|
||
|
},
|
||
|
out: nil,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
if runtime.GOOS != "linux" {
|
||
|
t.Skip("depends on Linux definitions of syscall.Dirent")
|
||
|
}
|
||
|
|
||
|
for _, testCase := range testCases {
|
||
|
t.Run(testCase.name, func(t *testing.T) {
|
||
|
entries := parseDirent(testCase.in, nil)
|
||
|
if !reflect.DeepEqual(testCase.out, entries) {
|
||
|
t.Fatalf("expected:\n %v\ngot:\n %v\n", testCase.out, entries)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|