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