1// Copyright 2017 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package fs 16 17import ( 18 "os" 19 "reflect" 20 "runtime" 21 "testing" 22) 23 24func TestParseDirent(t *testing.T) { 25 testCases := []struct { 26 name string 27 in []byte 28 out []*dirEntryInfo 29 }{ 30 { 31 // Test that type DT_DIR is translated to os.ModeDir 32 name: "dir", 33 in: []byte{ 34 // __ino64_t d_ino; 35 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 36 // __off64_t d_off; 37 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 38 // unsigned short int d_reclen; 39 0x28, 0x00, 40 // unsigned char d_type; 41 0x04, 42 // char d_name[]; 43 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 }, 46 out: []*dirEntryInfo{ 47 {".module_paths", os.ModeDir, true}, 48 }, 49 }, 50 { 51 // Test that type DT_REG is translated to a regular file 52 name: "file", 53 in: []byte{ 54 // __ino64_t d_ino; 55 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 56 // __off64_t d_off; 57 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 58 // unsigned short int d_reclen; 59 0x28, 0x00, 60 // unsigned char d_type; 61 0x08, 62 // char d_name[]; 63 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 }, 66 out: []*dirEntryInfo{ 67 {".module_paths", 0, true}, 68 }, 69 }, 70 { 71 // Test that type DT_LNK is translated to a regular os.ModeSymlink 72 name: "symlink", 73 in: []byte{ 74 // __ino64_t d_ino; 75 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 76 // __off64_t d_off; 77 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 78 // unsigned short int d_reclen; 79 0x28, 0x00, 80 // unsigned char d_type; 81 0x0a, 82 // char d_name[]; 83 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 }, 86 out: []*dirEntryInfo{ 87 {".module_paths", os.ModeSymlink, true}, 88 }, 89 }, 90 { 91 // Test that type DT_UNKNOWN sets modeExists: false 92 name: "unknown", 93 in: []byte{ 94 // __ino64_t d_ino; 95 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 96 // __off64_t d_off; 97 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 98 // unsigned short int d_reclen; 99 0x28, 0x00, 100 // unsigned char d_type; 101 0x00, 102 // char d_name[]; 103 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 105 }, 106 out: []*dirEntryInfo{ 107 {".module_paths", 0, false}, 108 }, 109 }, 110 { 111 // Test a name with no padding after the null terminator 112 name: "no padding", 113 in: []byte{ 114 // __ino64_t d_ino; 115 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 116 // __off64_t d_off; 117 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 118 // unsigned short int d_reclen; 119 0x20, 0x00, 120 // unsigned char d_type; 121 0x04, 122 // char d_name[]; 123 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00, 124 }, 125 out: []*dirEntryInfo{ 126 {".module_path", os.ModeDir, true}, 127 }, 128 }, 129 { 130 // Test two sequential entries 131 name: "two entries", 132 in: []byte{ 133 // __ino64_t d_ino; 134 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 135 // __off64_t d_off; 136 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 137 // unsigned short int d_reclen; 138 0x28, 0x00, 139 // unsigned char d_type; 140 0x04, 141 // char d_name[]; 142 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 144 145 // __ino64_t d_ino; 146 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 147 // __off64_t d_off; 148 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 149 // unsigned short int d_reclen; 150 0x28, 0x00, 151 // unsigned char d_type; 152 0x04, 153 // char d_name[]; 154 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x74, 155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 156 }, 157 out: []*dirEntryInfo{ 158 {".module_paths", os.ModeDir, true}, 159 {".module_patht", os.ModeDir, true}, 160 }, 161 }, 162 { 163 // Test two sequential entries with no padding between them 164 name: "two entries no padding", 165 in: []byte{ 166 // __ino64_t d_ino; 167 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 168 // __off64_t d_off; 169 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 170 // unsigned short int d_reclen; 171 0x20, 0x00, 172 // unsigned char d_type; 173 0x04, 174 // char d_name[]; 175 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00, 176 177 // __ino64_t d_ino; 178 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 179 // __off64_t d_off; 180 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 181 // unsigned short int d_reclen; 182 0x28, 0x00, 183 // unsigned char d_type; 184 0x04, 185 // char d_name[]; 186 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 187 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 188 }, 189 out: []*dirEntryInfo{ 190 {".module_path", os.ModeDir, true}, 191 {".module_paths", os.ModeDir, true}, 192 }, 193 }, 194 { 195 // Test an empty buffer. This shouldn't happen in practice because 196 // readdir doesn't call parseDirent if no bytes were returned. 197 name: "empty", 198 in: []byte{}, 199 out: nil, 200 }, 201 { 202 name: "missing null terminator", 203 in: []byte{ 204 // __ino64_t d_ino; 205 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 206 // __off64_t d_off; 207 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 208 // unsigned short int d_reclen; 209 0x20, 0x00, 210 // unsigned char d_type; 211 0x04, 212 // char d_name[]; 213 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 214 }, 215 out: []*dirEntryInfo{ 216 {".module_paths", os.ModeDir, true}, 217 }, 218 }, 219 { 220 // Test two sequential entries where the first has an incorrect d_reclen. 221 // Should return with no entries. 222 name: "two entries first malformed", 223 in: []byte{ 224 // __ino64_t d_ino; 225 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 226 // __off64_t d_off; 227 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 228 // unsigned short int d_reclen; 229 0x10, 0x00, 230 // unsigned char d_type; 231 0x04, 232 // char d_name[]; 233 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00, 234 235 // __ino64_t d_ino; 236 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 237 // __off64_t d_off; 238 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 239 // unsigned short int d_reclen; 240 0x28, 0x00, 241 // unsigned char d_type; 242 0x04, 243 // char d_name[]; 244 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 246 }, 247 out: nil, 248 }, 249 { 250 // Test two sequential entries where the second has an incorrect d_reclen. 251 // Should return the first entry. 252 name: "two entries second malformed", 253 in: []byte{ 254 // __ino64_t d_ino; 255 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 256 // __off64_t d_off; 257 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 258 // unsigned short int d_reclen; 259 0x28, 0x00, 260 // unsigned char d_type; 261 0x04, 262 // char d_name[]; 263 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00, 264 265 // __ino64_t d_ino; 266 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 267 // __off64_t d_off; 268 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 269 // unsigned short int d_reclen; 270 0x10, 0x00, 271 // unsigned char d_type; 272 0x04, 273 // char d_name[]; 274 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 275 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 276 }, 277 out: []*dirEntryInfo{ 278 {".module_path", os.ModeDir, true}, 279 }, 280 }, 281 { 282 // Test a reclen that goes past the end of the buffer. 283 name: "overrun", 284 in: []byte{ 285 // __ino64_t d_ino; 286 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 287 // __off64_t d_off; 288 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03, 289 // unsigned short int d_reclen; 290 0x30, 0x00, 291 // unsigned char d_type; 292 0x04, 293 // char d_name[]; 294 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00, 295 }, 296 out: nil, 297 }, 298 } 299 300 if runtime.GOOS != "linux" { 301 t.Skip("depends on Linux definitions of syscall.Dirent") 302 } 303 304 for _, testCase := range testCases { 305 t.Run(testCase.name, func(t *testing.T) { 306 entries := parseDirent(testCase.in, nil) 307 if !reflect.DeepEqual(testCase.out, entries) { 308 t.Fatalf("expected:\n %v\ngot:\n %v\n", testCase.out, entries) 309 } 310 }) 311 } 312} 313