summaryrefslogtreecommitdiff
path: root/finder/fs/readdir_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'finder/fs/readdir_test.go')
-rw-r--r--finder/fs/readdir_test.go312
1 files changed, 312 insertions, 0 deletions
diff --git a/finder/fs/readdir_test.go b/finder/fs/readdir_test.go
new file mode 100644
index 000000000..24a6d1884
--- /dev/null
+++ b/finder/fs/readdir_test.go
@@ -0,0 +1,312 @@
+// 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)
+ }
+ })
+ }
+}