readdir_test.go 8.9 KB

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