blob: 24a6d1884ae12b8090d5d84255f17ab59b326997 [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) {
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}