test-fs-readdir.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /* Copyright libuv project contributors. All rights reserved.
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to
  5. * deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. * sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. * IN THE SOFTWARE.
  20. */
  21. #include "uv.h"
  22. #include "task.h"
  23. #include <fcntl.h>
  24. #include <string.h>
  25. static uv_fs_t opendir_req;
  26. static uv_fs_t readdir_req;
  27. static uv_fs_t closedir_req;
  28. static uv_dirent_t dirents[1];
  29. static int empty_opendir_cb_count;
  30. static int empty_closedir_cb_count;
  31. static void cleanup_test_files(void) {
  32. uv_fs_t req;
  33. uv_fs_unlink(NULL, &req, "test_dir/file1", NULL);
  34. uv_fs_req_cleanup(&req);
  35. uv_fs_unlink(NULL, &req, "test_dir/file2", NULL);
  36. uv_fs_req_cleanup(&req);
  37. uv_fs_rmdir(NULL, &req, "test_dir/test_subdir", NULL);
  38. uv_fs_req_cleanup(&req);
  39. uv_fs_rmdir(NULL, &req, "test_dir", NULL);
  40. uv_fs_req_cleanup(&req);
  41. }
  42. static void empty_closedir_cb(uv_fs_t* req) {
  43. ASSERT(req == &closedir_req);
  44. ASSERT(req->fs_type == UV_FS_CLOSEDIR);
  45. ASSERT(req->result == 0);
  46. ++empty_closedir_cb_count;
  47. uv_fs_req_cleanup(req);
  48. }
  49. static void empty_readdir_cb(uv_fs_t* req) {
  50. uv_dir_t* dir;
  51. int r;
  52. ASSERT(req == &readdir_req);
  53. ASSERT(req->fs_type == UV_FS_READDIR);
  54. ASSERT(req->result == 0);
  55. dir = req->ptr;
  56. uv_fs_req_cleanup(req);
  57. r = uv_fs_closedir(uv_default_loop(),
  58. &closedir_req,
  59. dir,
  60. empty_closedir_cb);
  61. ASSERT(r == 0);
  62. }
  63. static void empty_opendir_cb(uv_fs_t* req) {
  64. uv_dir_t* dir;
  65. int r;
  66. ASSERT(req == &opendir_req);
  67. ASSERT(req->fs_type == UV_FS_OPENDIR);
  68. ASSERT(req->result == 0);
  69. ASSERT(req->ptr != NULL);
  70. dir = req->ptr;
  71. dir->dirents = dirents;
  72. dir->nentries = ARRAY_SIZE(dirents);
  73. r = uv_fs_readdir(uv_default_loop(),
  74. &readdir_req,
  75. dir,
  76. empty_readdir_cb);
  77. ASSERT(r == 0);
  78. uv_fs_req_cleanup(req);
  79. ++empty_opendir_cb_count;
  80. }
  81. /*
  82. * This test makes sure that both synchronous and asynchronous flavors
  83. * of the uv_fs_opendir() -> uv_fs_readdir() -> uv_fs_closedir() sequence work
  84. * as expected when processing an empty directory.
  85. */
  86. TEST_IMPL(fs_readdir_empty_dir) {
  87. const char* path;
  88. uv_fs_t mkdir_req;
  89. uv_fs_t rmdir_req;
  90. int r;
  91. int nb_entries_read;
  92. uv_dir_t* dir;
  93. path = "./empty_dir/";
  94. uv_fs_mkdir(uv_default_loop(), &mkdir_req, path, 0777, NULL);
  95. uv_fs_req_cleanup(&mkdir_req);
  96. /* Fill the req to ensure that required fields are cleaned up. */
  97. memset(&opendir_req, 0xdb, sizeof(opendir_req));
  98. /* Testing the synchronous flavor. */
  99. r = uv_fs_opendir(uv_default_loop(),
  100. &opendir_req,
  101. path,
  102. NULL);
  103. ASSERT(r == 0);
  104. ASSERT(opendir_req.fs_type == UV_FS_OPENDIR);
  105. ASSERT(opendir_req.result == 0);
  106. ASSERT(opendir_req.ptr != NULL);
  107. dir = opendir_req.ptr;
  108. uv_fs_req_cleanup(&opendir_req);
  109. /* Fill the req to ensure that required fields are cleaned up. */
  110. memset(&readdir_req, 0xdb, sizeof(readdir_req));
  111. dir->dirents = dirents;
  112. dir->nentries = ARRAY_SIZE(dirents);
  113. nb_entries_read = uv_fs_readdir(uv_default_loop(),
  114. &readdir_req,
  115. dir,
  116. NULL);
  117. ASSERT(nb_entries_read == 0);
  118. uv_fs_req_cleanup(&readdir_req);
  119. /* Fill the req to ensure that required fields are cleaned up. */
  120. memset(&closedir_req, 0xdb, sizeof(closedir_req));
  121. uv_fs_closedir(uv_default_loop(), &closedir_req, dir, NULL);
  122. ASSERT(closedir_req.result == 0);
  123. uv_fs_req_cleanup(&closedir_req);
  124. /* Testing the asynchronous flavor. */
  125. /* Fill the req to ensure that required fields are cleaned up. */
  126. memset(&opendir_req, 0xdb, sizeof(opendir_req));
  127. memset(&readdir_req, 0xdb, sizeof(readdir_req));
  128. memset(&closedir_req, 0xdb, sizeof(closedir_req));
  129. r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, empty_opendir_cb);
  130. ASSERT(r == 0);
  131. ASSERT(empty_opendir_cb_count == 0);
  132. ASSERT(empty_closedir_cb_count == 0);
  133. r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
  134. ASSERT(r == 0);
  135. ASSERT(empty_opendir_cb_count == 1);
  136. ASSERT(empty_closedir_cb_count == 1);
  137. uv_fs_rmdir(uv_default_loop(), &rmdir_req, path, NULL);
  138. uv_fs_req_cleanup(&rmdir_req);
  139. MAKE_VALGRIND_HAPPY();
  140. return 0;
  141. }
  142. /*
  143. * This test makes sure that reading a non-existing directory with
  144. * uv_fs_{open,read}_dir() returns proper error codes.
  145. */
  146. static int non_existing_opendir_cb_count;
  147. static void non_existing_opendir_cb(uv_fs_t* req) {
  148. ASSERT(req == &opendir_req);
  149. ASSERT(req->fs_type == UV_FS_OPENDIR);
  150. ASSERT(req->result == UV_ENOENT);
  151. ASSERT(req->ptr == NULL);
  152. uv_fs_req_cleanup(req);
  153. ++non_existing_opendir_cb_count;
  154. }
  155. TEST_IMPL(fs_readdir_non_existing_dir) {
  156. const char* path;
  157. int r;
  158. path = "./non-existing-dir/";
  159. /* Fill the req to ensure that required fields are cleaned up. */
  160. memset(&opendir_req, 0xdb, sizeof(opendir_req));
  161. /* Testing the synchronous flavor. */
  162. r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, NULL);
  163. ASSERT(r == UV_ENOENT);
  164. ASSERT(opendir_req.fs_type == UV_FS_OPENDIR);
  165. ASSERT(opendir_req.result == UV_ENOENT);
  166. ASSERT(opendir_req.ptr == NULL);
  167. uv_fs_req_cleanup(&opendir_req);
  168. /* Fill the req to ensure that required fields are cleaned up. */
  169. memset(&opendir_req, 0xdb, sizeof(opendir_req));
  170. /* Testing the async flavor. */
  171. r = uv_fs_opendir(uv_default_loop(),
  172. &opendir_req,
  173. path,
  174. non_existing_opendir_cb);
  175. ASSERT(r == 0);
  176. ASSERT(non_existing_opendir_cb_count == 0);
  177. r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
  178. ASSERT(r == 0);
  179. ASSERT(non_existing_opendir_cb_count == 1);
  180. MAKE_VALGRIND_HAPPY();
  181. return 0;
  182. }
  183. /*
  184. * This test makes sure that reading a file as a directory reports correct
  185. * error codes.
  186. */
  187. static int file_opendir_cb_count;
  188. static void file_opendir_cb(uv_fs_t* req) {
  189. ASSERT(req == &opendir_req);
  190. ASSERT(req->fs_type == UV_FS_OPENDIR);
  191. ASSERT(req->result == UV_ENOTDIR);
  192. ASSERT(req->ptr == NULL);
  193. uv_fs_req_cleanup(req);
  194. ++file_opendir_cb_count;
  195. }
  196. TEST_IMPL(fs_readdir_file) {
  197. const char* path;
  198. int r;
  199. path = "test/fixtures/empty_file";
  200. /* Fill the req to ensure that required fields are cleaned up. */
  201. memset(&opendir_req, 0xdb, sizeof(opendir_req));
  202. /* Testing the synchronous flavor. */
  203. r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, NULL);
  204. ASSERT(r == UV_ENOTDIR);
  205. ASSERT(opendir_req.fs_type == UV_FS_OPENDIR);
  206. ASSERT(opendir_req.result == UV_ENOTDIR);
  207. ASSERT(opendir_req.ptr == NULL);
  208. uv_fs_req_cleanup(&opendir_req);
  209. /* Fill the req to ensure that required fields are cleaned up. */
  210. memset(&opendir_req, 0xdb, sizeof(opendir_req));
  211. /* Testing the async flavor. */
  212. r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, file_opendir_cb);
  213. ASSERT(r == 0);
  214. ASSERT(file_opendir_cb_count == 0);
  215. r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
  216. ASSERT(r == 0);
  217. ASSERT(file_opendir_cb_count == 1);
  218. MAKE_VALGRIND_HAPPY();
  219. return 0;
  220. }
  221. /*
  222. * This test makes sure that reading a non-empty directory with
  223. * uv_fs_{open,read}_dir() returns proper directory entries, including the
  224. * correct entry types.
  225. */
  226. static int non_empty_opendir_cb_count;
  227. static int non_empty_readdir_cb_count;
  228. static int non_empty_closedir_cb_count;
  229. static void non_empty_closedir_cb(uv_fs_t* req) {
  230. ASSERT(req == &closedir_req);
  231. ASSERT(req->result == 0);
  232. uv_fs_req_cleanup(req);
  233. ++non_empty_closedir_cb_count;
  234. }
  235. static void non_empty_readdir_cb(uv_fs_t* req) {
  236. uv_dir_t* dir;
  237. ASSERT(req == &readdir_req);
  238. ASSERT(req->fs_type == UV_FS_READDIR);
  239. dir = req->ptr;
  240. if (req->result == 0) {
  241. uv_fs_req_cleanup(req);
  242. ASSERT(non_empty_readdir_cb_count == 3);
  243. uv_fs_closedir(uv_default_loop(),
  244. &closedir_req,
  245. dir,
  246. non_empty_closedir_cb);
  247. } else {
  248. ASSERT(req->result == 1);
  249. ASSERT(dir->dirents == dirents);
  250. ASSERT(strcmp(dirents[0].name, "file1") == 0 ||
  251. strcmp(dirents[0].name, "file2") == 0 ||
  252. strcmp(dirents[0].name, "test_subdir") == 0);
  253. #ifdef HAVE_DIRENT_TYPES
  254. if (!strcmp(dirents[0].name, "test_subdir"))
  255. ASSERT(dirents[0].type == UV_DIRENT_DIR);
  256. else
  257. ASSERT(dirents[0].type == UV_DIRENT_FILE);
  258. #else
  259. ASSERT(dirents[0].type == UV_DIRENT_UNKNOWN);
  260. #endif /* HAVE_DIRENT_TYPES */
  261. ++non_empty_readdir_cb_count;
  262. uv_fs_req_cleanup(req);
  263. dir->dirents = dirents;
  264. dir->nentries = ARRAY_SIZE(dirents);
  265. uv_fs_readdir(uv_default_loop(),
  266. &readdir_req,
  267. dir,
  268. non_empty_readdir_cb);
  269. }
  270. }
  271. static void non_empty_opendir_cb(uv_fs_t* req) {
  272. uv_dir_t* dir;
  273. int r;
  274. ASSERT(req == &opendir_req);
  275. ASSERT(req->fs_type == UV_FS_OPENDIR);
  276. ASSERT(req->result == 0);
  277. ASSERT(req->ptr != NULL);
  278. dir = req->ptr;
  279. dir->dirents = dirents;
  280. dir->nentries = ARRAY_SIZE(dirents);
  281. r = uv_fs_readdir(uv_default_loop(),
  282. &readdir_req,
  283. dir,
  284. non_empty_readdir_cb);
  285. ASSERT(r == 0);
  286. uv_fs_req_cleanup(req);
  287. ++non_empty_opendir_cb_count;
  288. }
  289. TEST_IMPL(fs_readdir_non_empty_dir) {
  290. size_t entries_count;
  291. uv_fs_t mkdir_req;
  292. uv_fs_t rmdir_req;
  293. uv_fs_t create_req;
  294. uv_fs_t close_req;
  295. uv_dir_t* dir;
  296. int r;
  297. cleanup_test_files();
  298. r = uv_fs_mkdir(uv_default_loop(), &mkdir_req, "test_dir", 0755, NULL);
  299. ASSERT(r == 0);
  300. /* Create two files synchronously. */
  301. r = uv_fs_open(uv_default_loop(),
  302. &create_req,
  303. "test_dir/file1",
  304. O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR,
  305. NULL);
  306. ASSERT(r >= 0);
  307. uv_fs_req_cleanup(&create_req);
  308. r = uv_fs_close(uv_default_loop(),
  309. &close_req,
  310. create_req.result,
  311. NULL);
  312. ASSERT(r == 0);
  313. uv_fs_req_cleanup(&close_req);
  314. r = uv_fs_open(uv_default_loop(),
  315. &create_req,
  316. "test_dir/file2",
  317. O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR,
  318. NULL);
  319. ASSERT(r >= 0);
  320. uv_fs_req_cleanup(&create_req);
  321. r = uv_fs_close(uv_default_loop(),
  322. &close_req,
  323. create_req.result,
  324. NULL);
  325. ASSERT(r == 0);
  326. uv_fs_req_cleanup(&close_req);
  327. r = uv_fs_mkdir(uv_default_loop(),
  328. &mkdir_req,
  329. "test_dir/test_subdir",
  330. 0755,
  331. NULL);
  332. ASSERT(r == 0);
  333. uv_fs_req_cleanup(&mkdir_req);
  334. /* Fill the req to ensure that required fields are cleaned up. */
  335. memset(&opendir_req, 0xdb, sizeof(opendir_req));
  336. /* Testing the synchronous flavor. */
  337. r = uv_fs_opendir(uv_default_loop(), &opendir_req, "test_dir", NULL);
  338. ASSERT(r == 0);
  339. ASSERT(opendir_req.fs_type == UV_FS_OPENDIR);
  340. ASSERT(opendir_req.result == 0);
  341. ASSERT(opendir_req.ptr != NULL);
  342. entries_count = 0;
  343. dir = opendir_req.ptr;
  344. dir->dirents = dirents;
  345. dir->nentries = ARRAY_SIZE(dirents);
  346. uv_fs_req_cleanup(&opendir_req);
  347. while (uv_fs_readdir(uv_default_loop(),
  348. &readdir_req,
  349. dir,
  350. NULL) != 0) {
  351. ASSERT(strcmp(dirents[0].name, "file1") == 0 ||
  352. strcmp(dirents[0].name, "file2") == 0 ||
  353. strcmp(dirents[0].name, "test_subdir") == 0);
  354. #ifdef HAVE_DIRENT_TYPES
  355. if (!strcmp(dirents[0].name, "test_subdir"))
  356. ASSERT(dirents[0].type == UV_DIRENT_DIR);
  357. else
  358. ASSERT(dirents[0].type == UV_DIRENT_FILE);
  359. #else
  360. ASSERT(dirents[0].type == UV_DIRENT_UNKNOWN);
  361. #endif /* HAVE_DIRENT_TYPES */
  362. uv_fs_req_cleanup(&readdir_req);
  363. ++entries_count;
  364. }
  365. ASSERT(entries_count == 3);
  366. uv_fs_req_cleanup(&readdir_req);
  367. /* Fill the req to ensure that required fields are cleaned up. */
  368. memset(&closedir_req, 0xdb, sizeof(closedir_req));
  369. uv_fs_closedir(uv_default_loop(), &closedir_req, dir, NULL);
  370. ASSERT(closedir_req.result == 0);
  371. uv_fs_req_cleanup(&closedir_req);
  372. /* Testing the asynchronous flavor. */
  373. /* Fill the req to ensure that required fields are cleaned up. */
  374. memset(&opendir_req, 0xdb, sizeof(opendir_req));
  375. r = uv_fs_opendir(uv_default_loop(),
  376. &opendir_req,
  377. "test_dir",
  378. non_empty_opendir_cb);
  379. ASSERT(r == 0);
  380. ASSERT(non_empty_opendir_cb_count == 0);
  381. ASSERT(non_empty_closedir_cb_count == 0);
  382. r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
  383. ASSERT(r == 0);
  384. ASSERT(non_empty_opendir_cb_count == 1);
  385. ASSERT(non_empty_closedir_cb_count == 1);
  386. uv_fs_rmdir(uv_default_loop(), &rmdir_req, "test_subdir", NULL);
  387. uv_fs_req_cleanup(&rmdir_req);
  388. cleanup_test_files();
  389. MAKE_VALGRIND_HAPPY();
  390. return 0;
  391. }