From 41e8574920743832d6d55f97a9fca6088434a294 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 10 Oct 2011 16:27:55 +0200 Subject: [PATCH] unix: don't alloc memory for readdir on empty dir --- src/unix/fs.c | 17 +++++++++-------- test/test-fs.c | 41 +++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 1bc4f71e..76de94de 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -85,8 +85,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) { switch (req->fs_type) { case UV_FS_READDIR: - assert((req->result == -1 && req->ptr == NULL) - || (req->result >= 0 && req->ptr != NULL)); + assert(req->result > 0 ? (req->ptr != NULL) : (req->ptr == NULL)); free(req->ptr); req->ptr = NULL; break; @@ -116,9 +115,6 @@ static int uv__fs_after(eio_req* eio) { switch (req->fs_type) { case UV_FS_READDIR: - if (req->eio->result == -1) - break; /* opendir() or readdir() operation failed. */ - /* * XXX This is pretty bad. * We alloc and copy the large null terminated string list from libeio. @@ -128,16 +124,21 @@ static int uv__fs_after(eio_req* eio) { */ buflen = 0; name = req->eio->ptr2; + for (i = 0; i < req->result; i++) { namelen = strlen(name); buflen += namelen + 1; - /* TODO check ENOMEM */ name += namelen; assert(*name == '\0'); name++; } - req->ptr = malloc(buflen); - memcpy(req->ptr, req->eio->ptr2, buflen); + + if (buflen) { + if ((req->ptr = malloc(buflen))) + memcpy(req->ptr, req->eio->ptr2, buflen); + else + uv__set_sys_error(req->loop, ENOMEM); + } break; case UV_FS_STAT: diff --git a/test/test-fs.c b/test/test-fs.c index d1cc0ade..38953fd3 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -354,6 +354,16 @@ static void readdir_cb(uv_fs_t* req) { } +static void empty_readdir_cb(uv_fs_t* req) { + ASSERT(req == &readdir_req); + ASSERT(req->fs_type == UV_FS_READDIR); + ASSERT(req->result == 0); + ASSERT(req->ptr == NULL); + uv_fs_req_cleanup(req); + readdir_cb_count++; +} + + static void stat_cb(uv_fs_t* req) { ASSERT(req == &stat_req); ASSERT(req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_LSTAT); @@ -1292,3 +1302,34 @@ TEST_IMPL(fs_stat_missing_path) { return 0; } + + +TEST_IMPL(fs_readdir_empty_dir) { + const char* path; + uv_fs_t req; + int r; + + path = "./empty_dir/"; + loop = uv_default_loop(); + + uv_fs_mkdir(loop, &req, path, 0777, NULL); + uv_fs_req_cleanup(&req); + + r = uv_fs_readdir(loop, &req, path, 0, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + ASSERT(req.ptr == NULL); + uv_fs_req_cleanup(&req); + + r = uv_fs_readdir(loop, &readdir_req, path, 0, empty_readdir_cb); + ASSERT(r == 0); + + ASSERT(readdir_cb_count == 0); + uv_run(loop); + ASSERT(readdir_cb_count == 1); + + uv_fs_rmdir(loop, &req, path, NULL); + uv_fs_req_cleanup(&req); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index d11257aa..dcf27860 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -99,6 +99,7 @@ TEST_DECLARE (fs_stat_missing_path) TEST_DECLARE (fs_event_watch_dir) TEST_DECLARE (fs_event_watch_file) TEST_DECLARE (fs_event_watch_file_current_dir) +TEST_DECLARE (fs_readdir_empty_dir) TEST_DECLARE (threadpool_queue_work_simple) #ifdef _WIN32 TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) @@ -232,6 +233,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_watch_dir) TEST_ENTRY (fs_event_watch_file) TEST_ENTRY (fs_event_watch_file_current_dir) + TEST_ENTRY (fs_readdir_empty_dir) TEST_ENTRY (threadpool_queue_work_simple)