diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 2c1d8ae68568d3..890e6b0d1a46be 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -371,3 +371,8 @@ yeyuanfeng erw7 Thomas Karl Pietrowski evgley +Andreas Rohner +Rich Trott +Milad Farazmand +zlargon +Yury Selivanov diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index 01a7c47e578452..7b25511939e62e 100644 --- a/deps/uv/CMakeLists.txt +++ b/deps/uv/CMakeLists.txt @@ -53,6 +53,7 @@ set(uv_test_sources test/test-fs-event.c test/test-fs-poll.c test/test-fs.c + test/test-fs-readdir.c test/test-get-currentexe.c test/test-get-loadavg.c test/test-get-memory.c @@ -62,6 +63,7 @@ set(uv_test_sources test/test-getnameinfo.c test/test-getsockname.c test/test-getters-setters.c + test/test-gettimeofday.c test/test-handle-fileno.c test/test-homedir.c test/test-hrtime.c @@ -262,7 +264,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android") src/unix/sysinfo-memory.c) endif() -if(CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|Linux|OS/390") +if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Android|Linux|OS/390") list(APPEND uv_sources src/unix/proctitle.c) endif() @@ -275,11 +277,11 @@ if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|NetBSD|OpenBSD") list(APPEND uv_libraries kvm) endif() -if(CMAKE_SYSTEM_NAME MATCHES "Darwin|DragonFly|FreeBSD|NetBSD|OpenBSD") +if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|NetBSD|OpenBSD") list(APPEND uv_sources src/unix/bsd-ifaddrs.c src/unix/kqueue.c) endif() -if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") +if(APPLE) list(APPEND uv_defines _DARWIN_UNLIMITED_SELECT=1 _DARWIN_USE_64_BIT_INODE=1) list(APPEND uv_sources src/unix/darwin-proctitle.c @@ -333,7 +335,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") list(APPEND uv_sources src/unix/no-proctitle.c src/unix/sunos.c) endif() -if(CMAKE_SYSTEM_NAME MATCHES "Darwin|DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") +if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") list(APPEND uv_test_libraries util) endif() diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 62d6073d7d4340..3095f9fc1029a2 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,38 @@ +2019.04.16, Version 1.28.0 (Stable), 7bf8fabfa934660ee0fe889f78e151198a1165fc + +Changes since version 1.27.0: + +* unix,win: add uv_gettimeofday() (cjihrig) + +* unix,win: add uv_fs_{open,read,close}dir() (cjihrig) + +* unix: fix uv_interface_addresses() (Andreas Rohner) + +* fs: remove macOS-specific copyfile(3) (Rich Trott) + +* fs: add test for copyfile() respecting permissions (Rich Trott) + +* build: partially revert 5234b1c43a (Ben Noordhuis) + +* zos: fix setsockopt error when using AF_UNIX (Milad Farazmand) + +* unix: suppress EINTR/EINPROGRESS in uv_fs_close() (Ben Noordhuis) + +* build: use cmake APPLE variable to detect platform (zlargon) + +* distcheck: remove duplicate test/ entry (Jameson Nash) + +* unix: remove unused cmpxchgl() function (Ben Noordhuis) + +* unix: support sockaddr_un in uv_udp_send() (Yury Selivanov) + +* unix: guard use of PTHREAD_STACK_MIN (Kamil Rytarowski) + +* unix,win: introduce uv_timeval64_t (cjihrig) + +* doc: document uv_timeval_t and uv_timeval64_t (cjihrig) + + 2019.03.17, Version 1.27.0 (Stable), a4fc9a66cc35256dbc4dcd67c910174f05b6daa6 Changes since version 1.26.0: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 595a5aea03913d..22069625e328c4 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -45,12 +45,10 @@ libuv_la_SOURCES = src/fs-poll.c \ src/version.c if SUNOS -if GCC # Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers # on other platforms complain that the argument is unused during compilation. libuv_la_CFLAGS += -pthreads endif -endif if WINNT @@ -120,7 +118,6 @@ endif # WINNT EXTRA_DIST = test/fixtures/empty_file \ test/fixtures/load_error.node \ include \ - test \ docs \ img \ samples \ @@ -143,20 +140,14 @@ check_PROGRAMS = test/run-tests if OS390 test_run_tests_CFLAGS = else -if GCC test_run_tests_CFLAGS = -Wno-long-long -else -test_run_tests_CFLAGS = -endif endif if SUNOS -if GCC # Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers # on other platforms complain that the argument is unused during compilation. test_run_tests_CFLAGS += -pthreads endif -endif test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ @@ -191,6 +182,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-fs-event.c \ test/test-fs-poll.c \ test/test-fs.c \ + test/test-fs-readdir.c \ test/test-fork.c \ test/test-getters-setters.c \ test/test-get-currentexe.c \ @@ -201,6 +193,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-gethostname.c \ test/test-getnameinfo.c \ test/test-getsockname.c \ + test/test-gettimeofday.c \ test/test-handle-fileno.c \ test/test-homedir.c \ test/test-hrtime.c \ diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 336e55b15f92d6..75275aa8785f43 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.27.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.28.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) @@ -24,18 +24,16 @@ AC_ENABLE_SHARED AC_ENABLE_STATIC AC_PROG_CC AM_PROG_CC_C_O +AS_IF([AS_CASE([$host_os],[openedition*], [false], [true])], [ + CC_CHECK_CFLAGS_APPEND([-pedantic]) +]) CC_FLAG_VISIBILITY #[-fvisibility=hidden] CC_CHECK_CFLAGS_APPEND([-g]) -AS_IF([test "x$GCC" = xyes], [ - AS_IF([AS_CASE([$host_os], [openedition*], [false], [true])], [ - CC_CHECK_CFLAGS_APPEND([-pedantic]) - ]) - CC_CHECK_CFLAGS_APPEND([-std=gnu89]) - CC_CHECK_CFLAGS_APPEND([-Wall]) - CC_CHECK_CFLAGS_APPEND([-Wextra]) - CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) - CC_CHECK_CFLAGS_APPEND([-Wstrict-prototypes]) -]) +CC_CHECK_CFLAGS_APPEND([-std=gnu89]) +CC_CHECK_CFLAGS_APPEND([-Wall]) +CC_CHECK_CFLAGS_APPEND([-Wextra]) +CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) +CC_CHECK_CFLAGS_APPEND([-Wstrict-prototypes]) # AM_PROG_AR is not available in automake v0.11 but it's essential in v0.12. m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) # autoconf complains if AC_PROG_LIBTOOL precedes AM_PROG_AR. @@ -52,7 +50,6 @@ AC_CHECK_LIB([rt], [clock_gettime]) AC_CHECK_LIB([sendfile], [sendfile]) AC_CHECK_LIB([socket], [socket]) AC_SYS_LARGEFILE -AM_CONDITIONAL([GCC], [AS_IF([test "x$GCC" = xyes], [true], [false])]) AM_CONDITIONAL([AIX], [AS_CASE([$host_os],[aix*], [true], [false])]) AM_CONDITIONAL([ANDROID], [AS_CASE([$host_os],[linux-android*],[true], [false])]) AM_CONDITIONAL([CYGWIN], [AS_CASE([$host_os],[cygwin*], [true], [false])]) diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index af97ec3a648882..177db5708426dc 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -122,6 +122,21 @@ Data types uv_dirent_type_t type; } uv_dirent_t; +.. c:type:: uv_dir_t + + Data type used for streaming directory iteration. + Used by :c:func:`uv_fs_opendir()`, :c:func:`uv_fs_readdir()`, and + :c:func:`uv_fs_closedir()`. `dirents` represents a user provided array of + `uv_dirent_t`s used to hold results. `nentries` is the user provided maximum + array size of `dirents`. + + :: + + typedef struct uv_dir_s { + uv_dirent_t* dirents; + size_t nentries; + } uv_dir_t; + Public members ^^^^^^^^^^^^^^ @@ -208,6 +223,49 @@ API Equivalent to :man:`rmdir(2)`. +.. c:function:: int uv_fs_opendir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Opens `path` as a directory stream. On success, a `uv_dir_t` is allocated + and returned via `req->ptr`. This memory is not freed by + `uv_fs_req_cleanup()`, although `req->ptr` is set to `NULL`. The allocated + memory must be freed by calling `uv_fs_closedir()`. On failure, no memory + is allocated. + + The contents of the directory can be iterated over by passing the resulting + `uv_dir_t` to `uv_fs_readdir()`. + + .. versionadded:: 1.28.0 + +.. c:function:: int uv_fs_closedir(uv_loop_t* loop, uv_fs_t* req, uv_dir_t* dir, uv_fs_cb cb) + + Closes the directory stream represented by `dir` and frees the memory + allocated by `uv_fs_opendir()`. + + .. versionadded:: 1.28.0 + +.. c:function:: int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, uv_dir_t* dir, uv_fs_cb cb) + + Iterates over the directory stream, `dir`, returned by a successful + `uv_fs_opendir()` call. Prior to invoking `uv_fs_readdir()`, the caller + must set `dir->dirents` and `dir->nentries`, representing the array of + :c:type:`uv_dirent_t` elements used to hold the read directory entries and + its size. + + On success, the result is an integer >= 0 representing the number of entries + read from the stream. + + .. versionadded:: 1.28.0 + + .. warning:: + `uv_fs_readdir()` is not thread safe. + + .. note:: + This function does not return the "." and ".." entries. + + .. note:: + On success this function allocates memory that must be freed using + `uv_fs_req_cleanup()`. + .. c:function:: int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) .. c:function:: int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 14e9acce9abb2b..4ad4e40af9f7be 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -65,6 +65,28 @@ Data types .. versionadded:: 1.16.0 +.. c:type:: uv_timeval_t + + Data type for storing times. + + :: + + typedef struct { + long tv_sec; + long tv_usec; + } uv_timeval_t; + +.. c:type:: uv_timeval64_t + + Alternative data type for storing times. + + :: + + typedef struct { + int64_t tv_sec; + int32_t tv_usec; + } uv_timeval64_t; + .. c:type:: uv_rusage_t Data type for resource usage results. @@ -578,3 +600,10 @@ API zero on success, and a non-zero error value otherwise. .. versionadded:: 1.25.0 + +.. c:function:: int uv_gettimeofday(uv_timeval64_t* tv) + + Cross-platform implementation of :man:`gettimeofday(2)`. The timezone + argument to `gettimeofday()` is not supported, as it is considered obsolete. + + .. versionadded:: 1.28.0 diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 43895ac80dd670..df15b836789070 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -202,6 +202,7 @@ typedef enum { /* Handle types. */ typedef struct uv_loop_s uv_loop_t; typedef struct uv_handle_s uv_handle_t; +typedef struct uv_dir_s uv_dir_t; typedef struct uv_stream_s uv_stream_t; typedef struct uv_tcp_s uv_tcp_t; typedef struct uv_udp_s uv_udp_t; @@ -1098,6 +1099,11 @@ typedef struct { long tv_usec; } uv_timeval_t; +typedef struct { + int64_t tv_sec; + int32_t tv_usec; +} uv_timeval64_t; + typedef struct { uv_timeval_t ru_utime; /* user CPU time used */ uv_timeval_t ru_stime; /* system CPU time used */ @@ -1196,9 +1202,19 @@ typedef enum { UV_FS_FCHOWN, UV_FS_REALPATH, UV_FS_COPYFILE, - UV_FS_LCHOWN + UV_FS_LCHOWN, + UV_FS_OPENDIR, + UV_FS_READDIR, + UV_FS_CLOSEDIR } uv_fs_type; +struct uv_dir_s { + uv_dirent_t* dirents; + size_t nentries; + void* reserved[4]; + UV_DIR_PRIVATE_FIELDS +}; + /* uv_fs_t is a subclass of uv_req_t. */ struct uv_fs_s { UV_REQ_FIELDS @@ -1291,6 +1307,18 @@ UV_EXTERN int uv_fs_scandir(uv_loop_t* loop, uv_fs_cb cb); UV_EXTERN int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent); +UV_EXTERN int uv_fs_opendir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_readdir(uv_loop_t* loop, + uv_fs_t* req, + uv_dir_t* dir, + uv_fs_cb cb); +UV_EXTERN int uv_fs_closedir(uv_loop_t* loop, + uv_fs_t* req, + uv_dir_t* dir, + uv_fs_cb cb); UV_EXTERN int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, @@ -1586,6 +1614,8 @@ UV_EXTERN void uv_key_delete(uv_key_t* key); UV_EXTERN void* uv_key_get(uv_key_t* key); UV_EXTERN void uv_key_set(uv_key_t* key, void* value); +UV_EXTERN int uv_gettimeofday(uv_timeval64_t* tv); + typedef void (*uv_thread_cb)(void* arg); UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg); diff --git a/deps/uv/include/uv/unix.h b/deps/uv/include/uv/unix.h index 2363701b414728..26df0ec17a3069 100644 --- a/deps/uv/include/uv/unix.h +++ b/deps/uv/include/uv/unix.h @@ -166,6 +166,9 @@ typedef uid_t uv_uid_t; typedef struct dirent uv__dirent_t; +#define UV_DIR_PRIVATE_FIELDS \ + DIR* dir; + #if defined(DT_UNKNOWN) # define HAVE_DIRENT_TYPES # if defined(DT_REG) diff --git a/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h index 4f653983075150..fcb813b3121815 100644 --- a/deps/uv/include/uv/version.h +++ b/deps/uv/include/uv/version.h @@ -31,7 +31,7 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 27 +#define UV_VERSION_MINOR 28 #define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv/win.h b/deps/uv/include/uv/win.h index edd2cc6eb9cd3f..acbd958be4cd47 100644 --- a/deps/uv/include/uv/win.h +++ b/deps/uv/include/uv/win.h @@ -301,6 +301,11 @@ typedef struct uv__dirent_s { char d_name[1]; } uv__dirent_t; +#define UV_DIR_PRIVATE_FIELDS \ + HANDLE dir_handle; \ + WIN32_FIND_DATAW find_data; \ + BOOL need_find_call; + #define HAVE_DIRENT_TYPES #define UV__DT_DIR UV_DIRENT_DIR #define UV__DT_FILE UV_DIRENT_FILE diff --git a/deps/uv/src/unix/atomic-ops.h b/deps/uv/src/unix/atomic-ops.h index fb46978859813d..541a6c864882a0 100644 --- a/deps/uv/src/unix/atomic-ops.h +++ b/deps/uv/src/unix/atomic-ops.h @@ -23,7 +23,6 @@ #endif UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)); -UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)); UV_UNUSED(static void cpu_relax(void)); /* Prefer hand-rolled assembly over the gcc builtins because the latter also @@ -55,42 +54,6 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { #endif } -UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { -#if defined(__i386__) || defined(__x86_64__) - long out; - __asm__ __volatile__ ("lock; cmpxchg %2, %1;" - : "=a" (out), "+m" (*(volatile long*) ptr) - : "r" (newval), "0" (oldval) - : "memory"); - return out; -#elif defined(_AIX) && defined(__xlC__) - const long out = (*(volatile int*) ptr); -# if defined(__64BIT__) - __compare_and_swaplp(ptr, &oldval, newval); -# else - __compare_and_swap(ptr, &oldval, newval); -# endif /* if defined(__64BIT__) */ - return out; -#elif defined (__MVS__) -#ifdef _LP64 - unsigned long long op4; - if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval, - (unsigned long long*) ptr, *ptr, &op4)) -#else - unsigned long op4; - if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, - (unsigned int*) ptr, *ptr, &op4)) -#endif - return oldval; - else - return op4; -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) - return atomic_cas_ulong((ulong_t *)ptr, (ulong_t)oldval, (ulong_t)newval); -#else - return __sync_val_compare_and_swap(ptr, oldval, newval); -#endif -} - UV_UNUSED(static void cpu_relax(void)) { #if defined(__i386__) || defined(__x86_64__) __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */ diff --git a/deps/uv/src/unix/bsd-ifaddrs.c b/deps/uv/src/unix/bsd-ifaddrs.c index 3c2253f0c9c952..a4c6bf9d11c7f4 100644 --- a/deps/uv/src/unix/bsd-ifaddrs.c +++ b/deps/uv/src/unix/bsd-ifaddrs.c @@ -84,7 +84,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return 0; } - *addresses = uv__malloc(*count * sizeof(**addresses)); + /* Make sure the memory is initiallized to zero using calloc() */ + *addresses = uv__calloc(*count, sizeof(**addresses)); if (*addresses == NULL) { freeifaddrs(addrs); @@ -116,6 +117,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address++; } +#if !(defined(__CYGWIN__) || defined(__MSYS__)) /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) @@ -124,20 +126,15 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (i = 0; i < *count; i++) { -#if defined(__CYGWIN__) || defined(__MSYS__) - memset(address->phys_addr, 0, sizeof(address->phys_addr)); -#else if (strcmp(address->name, ent->ifa_name) == 0) { struct sockaddr_dl* sa_addr; sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); - } else { - memset(address->phys_addr, 0, sizeof(address->phys_addr)); } -#endif address++; } } +#endif freeifaddrs(addrs); diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index ca0e345da05bc1..e7e9f4b8c10a72 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -41,6 +41,7 @@ #include /* getrusage */ #include #include +#include #ifdef __sun # include @@ -1429,3 +1430,17 @@ int uv__getsockpeername(const uv_handle_t* handle, *namelen = (int) socklen; return 0; } + +int uv_gettimeofday(uv_timeval64_t* tv) { + struct timeval time; + + if (tv == NULL) + return UV_EINVAL; + + if (gettimeofday(&time, NULL) != 0) + return UV__ERR(errno); + + tv->tv_sec = (int64_t) time.tv_sec; + tv->tv_usec = (int32_t) time.tv_usec; + return 0; +} diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index f4b4280ca0c420..c6d2259adc4080 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -60,7 +60,6 @@ #endif #if defined(__APPLE__) -# include # include #elif defined(__linux__) && !defined(FICLONE) # include @@ -143,6 +142,18 @@ extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */ while (0) +static int uv__fs_close(int fd) { + int rc; + + rc = close(fd); + if (rc == -1) + if (errno == EINTR || errno == EINPROGRESS) + rc = 0; /* The close is in progress, not an error. */ + + return rc; +} + + static ssize_t uv__fs_fsync(uv_fs_t* req) { #if defined(__APPLE__) /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache @@ -351,7 +362,7 @@ static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) { static ssize_t uv__fs_scandir(uv_fs_t* req) { - uv__dirent_t **dents; + uv__dirent_t** dents; int n; dents = NULL; @@ -375,6 +386,87 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) { return n; } +static int uv__fs_opendir(uv_fs_t* req) { + uv_dir_t* dir; + + dir = uv__malloc(sizeof(*dir)); + if (dir == NULL) + goto error; + + dir->dir = opendir(req->path); + if (dir->dir == NULL) + goto error; + + req->ptr = dir; + return 0; + +error: + uv__free(dir); + req->ptr = NULL; + return -1; +} + +static int uv__fs_readdir(uv_fs_t* req) { + uv_dir_t* dir; + uv_dirent_t* dirent; + struct dirent* res; + unsigned int dirent_idx; + unsigned int i; + + dir = req->ptr; + dirent_idx = 0; + + while (dirent_idx < dir->nentries) { + /* readdir() returns NULL on end of directory, as well as on error. errno + is used to differentiate between the two conditions. */ + errno = 0; + res = readdir(dir->dir); + + if (res == NULL) { + if (errno != 0) + goto error; + break; + } + + if (strcmp(res->d_name, ".") == 0 || strcmp(res->d_name, "..") == 0) + continue; + + dirent = &dir->dirents[dirent_idx]; + dirent->name = uv__strdup(res->d_name); + + if (dirent->name == NULL) + goto error; + + dirent->type = uv__fs_get_dirent_type(res); + ++dirent_idx; + } + + return dirent_idx; + +error: + for (i = 0; i < dirent_idx; ++i) { + uv__free((char*) dir->dirents[i].name); + dir->dirents[i].name = NULL; + } + + return -1; +} + +static int uv__fs_closedir(uv_fs_t* req) { + uv_dir_t* dir; + + dir = req->ptr; + + if (dir->dir != NULL) { + closedir(dir->dir); + dir->dir = NULL; + } + + uv__free(req->ptr); + req->ptr = NULL; + return 0; +} + #if defined(_POSIX_PATH_MAX) # define UV__FS_PATH_MAX _POSIX_PATH_MAX #elif defined(PATH_MAX) @@ -808,45 +900,6 @@ static ssize_t uv__fs_write(uv_fs_t* req) { } static ssize_t uv__fs_copyfile(uv_fs_t* req) { -#if defined(__APPLE__) && !TARGET_OS_IPHONE - /* On macOS, use the native copyfile(3). */ - static int can_clone; - copyfile_flags_t flags; - char buf[64]; - size_t len; - int major; - - flags = COPYFILE_ALL; - - if (req->flags & UV_FS_COPYFILE_EXCL) - flags |= COPYFILE_EXCL; - - /* Check OS version. Cloning is only supported on macOS >= 10.12. */ - if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { - if (can_clone == 0) { - len = sizeof(buf); - if (sysctlbyname("kern.osrelease", buf, &len, NULL, 0)) - return UV__ERR(errno); - - if (1 != sscanf(buf, "%d", &major)) - abort(); - - can_clone = -1 + 2 * (major >= 16); /* macOS >= 10.12 */ - } - - if (can_clone < 0) - return UV_ENOSYS; - } - - /* copyfile() simply ignores COPYFILE_CLONE if it's not supported. */ - if (req->flags & UV_FS_COPYFILE_FICLONE) - flags |= 1 << 24; /* COPYFILE_CLONE */ - - if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) - flags |= 1 << 25; /* COPYFILE_CLONE_FORCE */ - - return copyfile(req->path, req->new_path, NULL, flags); -#else uv_fs_t fs_req; uv_file srcfd; uv_file dstfd; @@ -973,7 +1026,6 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { errno = UV__ERR(result); return -1; -#endif } static void uv__to_stat(struct stat* src, uv_stat_t* dst) { @@ -1249,7 +1301,7 @@ static void uv__fs_work(struct uv__work* w) { X(ACCESS, access(req->path, req->flags)); X(CHMOD, chmod(req->path, req->mode)); X(CHOWN, chown(req->path, req->uid, req->gid)); - X(CLOSE, close(req->file)); + X(CLOSE, uv__fs_close(req->file)); X(COPYFILE, uv__fs_copyfile(req)); X(FCHMOD, fchmod(req->file, req->mode)); X(FCHOWN, fchown(req->file, req->uid, req->gid)); @@ -1266,6 +1318,9 @@ static void uv__fs_work(struct uv__work* w) { X(OPEN, uv__fs_open(req)); X(READ, uv__fs_read(req)); X(SCANDIR, uv__fs_scandir(req)); + X(OPENDIR, uv__fs_opendir(req)); + X(READDIR, uv__fs_readdir(req)); + X(CLOSEDIR, uv__fs_closedir(req)); X(READLINK, uv__fs_readlink(req)); X(REALPATH, uv__fs_realpath(req)); X(RENAME, rename(req->path, req->new_path)); @@ -1536,6 +1591,40 @@ int uv_fs_scandir(uv_loop_t* loop, POST; } +int uv_fs_opendir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb) { + INIT(OPENDIR); + PATH; + POST; +} + +int uv_fs_readdir(uv_loop_t* loop, + uv_fs_t* req, + uv_dir_t* dir, + uv_fs_cb cb) { + INIT(READDIR); + + if (dir == NULL || dir->dir == NULL || dir->dirents == NULL) + return UV_EINVAL; + + req->ptr = dir; + POST; +} + +int uv_fs_closedir(uv_loop_t* loop, + uv_fs_t* req, + uv_dir_t* dir, + uv_fs_cb cb) { + INIT(CLOSEDIR); + + if (dir == NULL) + return UV_EINVAL; + + req->ptr = dir; + POST; +} int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, @@ -1676,6 +1765,9 @@ void uv_fs_req_cleanup(uv_fs_t* req) { req->path = NULL; req->new_path = NULL; + if (req->fs_type == UV_FS_READDIR && req->ptr != NULL) + uv__fs_readdir_cleanup(req); + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) uv__fs_scandir_cleanup(req); @@ -1683,7 +1775,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) { uv__free(req->bufs); req->bufs = NULL; - if (req->ptr != &req->statbuf) + if (req->fs_type != UV_FS_OPENDIR && req->ptr != &req->statbuf) uv__free(req->ptr); req->ptr = NULL; } diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index 7165fe2fb4dd1b..f8973bb36be7ae 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -860,7 +860,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return 0; } - *addresses = uv__malloc(*count * sizeof(**addresses)); + /* Make sure the memory is initiallized to zero using calloc() */ + *addresses = uv__calloc(*count, sizeof(**addresses)); if (!(*addresses)) { freeifaddrs(addrs); return UV_ENOMEM; @@ -902,8 +903,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (strcmp(address->name, ent->ifa_name) == 0) { sll = (struct sockaddr_ll*)ent->ifa_addr; memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr)); - } else { - memset(address->phys_addr, 0, sizeof(address->phys_addr)); } address++; } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index 6088c77f712a95..9a50448e62ce58 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -219,8 +219,10 @@ int uv_thread_create_ex(uv_thread_t* tid, pagesize = (size_t)getpagesize(); /* Round up to the nearest page boundary. */ stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1); +#ifdef PTHREAD_STACK_MIN if (stack_size < PTHREAD_STACK_MIN) stack_size = PTHREAD_STACK_MIN; +#endif } if (stack_size > 0) { diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 15fa5937b3e712..b578e7bc1037ef 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -30,6 +30,7 @@ #if defined(__MVS__) #include #endif +#include #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP @@ -232,8 +233,16 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { h.msg_namelen = 0; } else { h.msg_name = &req->addr; - h.msg_namelen = req->addr.ss_family == AF_INET6 ? - sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); + if (req->addr.ss_family == AF_INET6) + h.msg_namelen = sizeof(struct sockaddr_in6); + else if (req->addr.ss_family == AF_INET) + h.msg_namelen = sizeof(struct sockaddr_in); + else if (req->addr.ss_family == AF_UNIX) + h.msg_namelen = sizeof(struct sockaddr_un); + else { + assert(0 && "unsupported address family"); + abort(); + } } h.msg_iov = (struct iovec*) req->bufs; h.msg_iovlen = req->nbufs; @@ -268,16 +277,30 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { * are different from the BSDs: it _shares_ the port rather than steal it * from the current listener. While useful, it's not something we can emulate * on other platforms so we don't enable it. + * + * zOS does not support getsockname with SO_REUSEPORT option when using + * AF_UNIX. */ static int uv__set_reuse(int fd) { int yes; - -#if defined(SO_REUSEPORT) && !defined(__linux__) yes = 1; + +#if defined(SO_REUSEPORT) && defined(__MVS__) + struct sockaddr_in sockfd; + unsigned int sockfd_len = sizeof(sockfd); + if (getsockname(fd, (struct sockaddr*) &sockfd, &sockfd_len) == -1) + return UV__ERR(errno); + if (sockfd.sin_family == AF_UNIX) { + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return UV__ERR(errno); + } else { + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) + return UV__ERR(errno); + } +#elif defined(SO_REUSEPORT) && !defined(__linux__) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); #else - yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) return UV__ERR(errno); #endif diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 94dd59fb071ca0..066eb31d03892d 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -34,6 +34,7 @@ # include /* malloc */ #else # include /* if_nametoindex */ +# include /* AF_UNIX, sockaddr_un */ #endif @@ -376,6 +377,10 @@ int uv__udp_check_before_send(uv_udp_t* handle, const struct sockaddr* addr) { addrlen = sizeof(struct sockaddr_in); else if (addr->sa_family == AF_INET6) addrlen = sizeof(struct sockaddr_in6); +#if defined(AF_UNIX) && !defined(_WIN32) + else if (addr->sa_family == AF_UNIX) + addrlen = sizeof(struct sockaddr_un); +#endif else return UV_EINVAL; } else { @@ -631,37 +636,66 @@ int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { dent = dents[(*nbufs)++]; ent->name = dent->d_name; + ent->type = uv__fs_get_dirent_type(dent); + + return 0; +} + +uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent) { + uv_dirent_type_t type; + #ifdef HAVE_DIRENT_TYPES switch (dent->d_type) { case UV__DT_DIR: - ent->type = UV_DIRENT_DIR; + type = UV_DIRENT_DIR; break; case UV__DT_FILE: - ent->type = UV_DIRENT_FILE; + type = UV_DIRENT_FILE; break; case UV__DT_LINK: - ent->type = UV_DIRENT_LINK; + type = UV_DIRENT_LINK; break; case UV__DT_FIFO: - ent->type = UV_DIRENT_FIFO; + type = UV_DIRENT_FIFO; break; case UV__DT_SOCKET: - ent->type = UV_DIRENT_SOCKET; + type = UV_DIRENT_SOCKET; break; case UV__DT_CHAR: - ent->type = UV_DIRENT_CHAR; + type = UV_DIRENT_CHAR; break; case UV__DT_BLOCK: - ent->type = UV_DIRENT_BLOCK; + type = UV_DIRENT_BLOCK; break; default: - ent->type = UV_DIRENT_UNKNOWN; + type = UV_DIRENT_UNKNOWN; } #else - ent->type = UV_DIRENT_UNKNOWN; + type = UV_DIRENT_UNKNOWN; #endif - return 0; + return type; +} + +void uv__fs_readdir_cleanup(uv_fs_t* req) { + uv_dir_t* dir; + uv_dirent_t* dirents; + int i; + + if (req->ptr == NULL) + return; + + dir = req->ptr; + dirents = dir->dirents; + req->ptr = NULL; + + if (dirents == NULL) + return; + + for (i = 0; i < req->result; ++i) { + uv__free((char*) dirents[i].name); + dirents[i].name = NULL; + } } diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index e09a57b2c24b41..f788161c3955ed 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -193,6 +193,8 @@ size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs); int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value); void uv__fs_scandir_cleanup(uv_fs_t* req); +void uv__fs_readdir_cleanup(uv_fs_t* req); +uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent); int uv__next_timeout(const uv_loop_t* loop); void uv__run_timers(uv_loop_t* loop); diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 65d936bf08f555..9e2f084c8d0e9c 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -1125,6 +1125,137 @@ void fs__scandir(uv_fs_t* req) { uv__free(dirents); } +void fs__opendir(uv_fs_t* req) { + WCHAR* pathw; + size_t len; + const WCHAR* fmt; + WCHAR* find_path; + uv_dir_t* dir; + + pathw = req->file.pathw; + dir = NULL; + find_path = NULL; + + /* Figure out whether path is a file or a directory. */ + if (!(GetFileAttributesW(pathw) & FILE_ATTRIBUTE_DIRECTORY)) { + SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY); + goto error; + } + + dir = uv__malloc(sizeof(*dir)); + if (dir == NULL) { + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); + goto error; + } + + len = wcslen(pathw); + + if (len == 0) + fmt = L"./*"; + else if (IS_SLASH(pathw[len - 1])) + fmt = L"%s*"; + else + fmt = L"%s\\*"; + + find_path = uv__malloc(sizeof(WCHAR) * (len + 4)); + if (find_path == NULL) { + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); + goto error; + } + + _snwprintf(find_path, len + 3, fmt, pathw); + dir->dir_handle = FindFirstFileW(find_path, &dir->find_data); + uv__free(find_path); + find_path = NULL; + if (dir->dir_handle == INVALID_HANDLE_VALUE && + GetLastError() != ERROR_FILE_NOT_FOUND) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + dir->need_find_call = FALSE; + req->ptr = dir; + SET_REQ_RESULT(req, 0); + return; + +error: + uv__free(dir); + uv__free(find_path); + req->ptr = NULL; +} + +void fs__readdir(uv_fs_t* req) { + uv_dir_t* dir; + uv_dirent_t* dirents; + uv__dirent_t dent; + unsigned int dirent_idx; + PWIN32_FIND_DATAW find_data; + unsigned int i; + int r; + + req->flags |= UV_FS_FREE_PTR; + dir = req->ptr; + dirents = dir->dirents; + memset(dirents, 0, dir->nentries * sizeof(*dir->dirents)); + find_data = &dir->find_data; + dirent_idx = 0; + + while (dirent_idx < dir->nentries) { + if (dir->need_find_call && FindNextFileW(dir->dir_handle, find_data) == 0) { + if (GetLastError() == ERROR_NO_MORE_FILES) + break; + goto error; + } + + /* Skip "." and ".." entries. */ + if (find_data->cFileName[0] == L'.' && + (find_data->cFileName[1] == L'\0' || + (find_data->cFileName[1] == L'.' && + find_data->cFileName[2] == L'\0'))) { + dir->need_find_call = TRUE; + continue; + } + + r = uv__convert_utf16_to_utf8((const WCHAR*) &find_data->cFileName, + -1, + (char**) &dirents[dirent_idx].name); + if (r != 0) + goto error; + + /* Copy file type. */ + if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) + dent.d_type = UV__DT_DIR; + else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) + dent.d_type = UV__DT_LINK; + else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0) + dent.d_type = UV__DT_CHAR; + else + dent.d_type = UV__DT_FILE; + + dirents[dirent_idx].type = uv__fs_get_dirent_type(&dent); + dir->need_find_call = TRUE; + ++dirent_idx; + } + + SET_REQ_RESULT(req, dirent_idx); + return; + +error: + SET_REQ_WIN32_ERROR(req, GetLastError()); + for (i = 0; i < dirent_idx; ++i) { + uv__free((char*) dirents[i].name); + dirents[i].name = NULL; + } +} + +void fs__closedir(uv_fs_t* req) { + uv_dir_t* dir; + + dir = req->ptr; + FindClose(dir->dir_handle); + uv__free(req->ptr); + SET_REQ_RESULT(req, 0); +} INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, int do_lstat) { @@ -2039,6 +2170,9 @@ static void uv__fs_work(struct uv__work* w) { XX(MKDTEMP, mkdtemp) XX(RENAME, rename) XX(SCANDIR, scandir) + XX(READDIR, readdir) + XX(OPENDIR, opendir) + XX(CLOSEDIR, closedir) XX(LINK, link) XX(SYMLINK, symlink) XX(READLINK, readlink) @@ -2080,6 +2214,8 @@ void uv_fs_req_cleanup(uv_fs_t* req) { if (req->flags & UV_FS_FREE_PTR) { if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) uv__fs_scandir_cleanup(req); + else if (req->fs_type == UV_FS_READDIR) + uv__fs_readdir_cleanup(req); else uv__free(req->ptr); } @@ -2247,6 +2383,45 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, POST; } +int uv_fs_opendir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_OPENDIR); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) + return uv_translate_sys_error(err); + POST; +} + +int uv_fs_readdir(uv_loop_t* loop, + uv_fs_t* req, + uv_dir_t* dir, + uv_fs_cb cb) { + INIT(UV_FS_READDIR); + + if (dir == NULL || + dir->dirents == NULL || + dir->dir_handle == INVALID_HANDLE_VALUE) { + return UV_EINVAL; + } + + req->ptr = dir; + POST; +} + +int uv_fs_closedir(uv_loop_t* loop, + uv_fs_t* req, + uv_dir_t* dir, + uv_fs_cb cb) { + INIT(UV_FS_CLOSEDIR); + if (dir == NULL) + return UV_EINVAL; + req->ptr = dir; + POST; +} int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) { diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 395d958c036958..2c10728427b64d 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -1778,3 +1778,20 @@ int uv_os_uname(uv_utsname_t* buffer) { buffer->machine[0] = '\0'; return r; } + +int uv_gettimeofday(uv_timeval64_t* tv) { + /* Based on https://doxygen.postgresql.org/gettimeofday_8c_source.html */ + const uint64_t epoch = (uint64_t) 116444736000000000ULL; + FILETIME file_time; + ULARGE_INTEGER ularge; + + if (tv == NULL) + return UV_EINVAL; + + GetSystemTimeAsFileTime(&file_time); + ularge.LowPart = file_time.dwLowDateTime; + ularge.HighPart = file_time.dwHighDateTime; + tv->tv_sec = (int64_t) ((ularge.QuadPart - epoch) / 10000000L); + tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10); + return 0; +} diff --git a/deps/uv/test/test-fs-copyfile.c b/deps/uv/test/test-fs-copyfile.c index 7b6511c93c9787..cd8a2ea7c07b08 100644 --- a/deps/uv/test/test-fs-copyfile.c +++ b/deps/uv/test/test-fs-copyfile.c @@ -185,6 +185,17 @@ TEST_IMPL(fs_copyfile) { if (r == 0) handle_result(&req); +#ifndef _WIN32 + /* Copying respects permissions/mode. */ + unlink(dst); + touch_file(dst, 0); + chmod(dst, S_IRUSR|S_IRGRP|S_IROTH); /* Sets file mode to 444 (read-only). */ + r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); + ASSERT(req.result == UV_EACCES); + ASSERT(r == UV_EACCES); + uv_fs_req_cleanup(&req); +#endif + unlink(dst); /* Cleanup */ return 0; } diff --git a/deps/uv/test/test-fs-readdir.c b/deps/uv/test/test-fs-readdir.c new file mode 100644 index 00000000000000..a767f1fb885dcd --- /dev/null +++ b/deps/uv/test/test-fs-readdir.c @@ -0,0 +1,462 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + +static uv_fs_t opendir_req; +static uv_fs_t readdir_req; +static uv_fs_t closedir_req; + +static uv_dirent_t dirents[1]; + +static int empty_opendir_cb_count; +static int empty_closedir_cb_count; + +static void cleanup_test_files(void) { + uv_fs_t req; + + uv_fs_unlink(NULL, &req, "test_dir/file1", NULL); + uv_fs_req_cleanup(&req); + uv_fs_unlink(NULL, &req, "test_dir/file2", NULL); + uv_fs_req_cleanup(&req); + uv_fs_rmdir(NULL, &req, "test_dir/test_subdir", NULL); + uv_fs_req_cleanup(&req); + uv_fs_rmdir(NULL, &req, "test_dir", NULL); + uv_fs_req_cleanup(&req); +} + +static void empty_closedir_cb(uv_fs_t* req) { + ASSERT(req == &closedir_req); + ASSERT(req->fs_type == UV_FS_CLOSEDIR); + ASSERT(req->result == 0); + ++empty_closedir_cb_count; + uv_fs_req_cleanup(req); +} + +static void empty_readdir_cb(uv_fs_t* req) { + uv_dir_t* dir; + int r; + + ASSERT(req == &readdir_req); + ASSERT(req->fs_type == UV_FS_READDIR); + ASSERT(req->result == 0); + dir = req->ptr; + r = uv_fs_closedir(uv_default_loop(), + &closedir_req, + dir, + empty_closedir_cb); + ASSERT(r == 0); + uv_fs_req_cleanup(req); +} + +static void empty_opendir_cb(uv_fs_t* req) { + uv_dir_t* dir; + int r; + + ASSERT(req == &opendir_req); + ASSERT(req->fs_type == UV_FS_OPENDIR); + ASSERT(req->result == 0); + ASSERT(req->ptr != NULL); + dir = req->ptr; + dir->dirents = dirents; + dir->nentries = ARRAY_SIZE(dirents); + r = uv_fs_readdir(uv_default_loop(), + &readdir_req, + dir, + empty_readdir_cb); + ASSERT(r == 0); + uv_fs_req_cleanup(req); + ++empty_opendir_cb_count; +} + +/* + * This test makes sure that both synchronous and asynchronous flavors + * of the uv_fs_opendir() -> uv_fs_readdir() -> uv_fs_closedir() sequence work + * as expected when processing an empty directory. + */ +TEST_IMPL(fs_readdir_empty_dir) { + const char* path; + uv_fs_t mkdir_req; + uv_fs_t rmdir_req; + int r; + int nb_entries_read; + uv_dir_t* dir; + + path = "./empty_dir/"; + uv_fs_mkdir(uv_default_loop(), &mkdir_req, path, 0777, NULL); + uv_fs_req_cleanup(&mkdir_req); + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&opendir_req, 0xdb, sizeof(opendir_req)); + + /* Testing the synchronous flavor. */ + r = uv_fs_opendir(uv_default_loop(), + &opendir_req, + path, + NULL); + ASSERT(r == 0); + ASSERT(opendir_req.fs_type == UV_FS_OPENDIR); + ASSERT(opendir_req.result == 0); + ASSERT(opendir_req.ptr != NULL); + dir = opendir_req.ptr; + uv_fs_req_cleanup(&opendir_req); + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&readdir_req, 0xdb, sizeof(readdir_req)); + dir->dirents = dirents; + dir->nentries = ARRAY_SIZE(dirents); + nb_entries_read = uv_fs_readdir(uv_default_loop(), + &readdir_req, + dir, + NULL); + ASSERT(nb_entries_read == 0); + uv_fs_req_cleanup(&readdir_req); + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&closedir_req, 0xdb, sizeof(closedir_req)); + uv_fs_closedir(uv_default_loop(), &closedir_req, dir, NULL); + ASSERT(closedir_req.result == 0); + uv_fs_req_cleanup(&closedir_req); + + /* Testing the asynchronous flavor. */ + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&opendir_req, 0xdb, sizeof(opendir_req)); + memset(&readdir_req, 0xdb, sizeof(readdir_req)); + memset(&closedir_req, 0xdb, sizeof(closedir_req)); + + r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, empty_opendir_cb); + ASSERT(r == 0); + ASSERT(empty_opendir_cb_count == 0); + ASSERT(empty_closedir_cb_count == 0); + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(empty_opendir_cb_count == 1); + ASSERT(empty_closedir_cb_count == 1); + uv_fs_rmdir(uv_default_loop(), &rmdir_req, path, NULL); + uv_fs_req_cleanup(&rmdir_req); + MAKE_VALGRIND_HAPPY(); + return 0; +} + +/* + * This test makes sure that reading a non-existing directory with + * uv_fs_{open,read}_dir() returns proper error codes. + */ + +static int non_existing_opendir_cb_count; + +static void non_existing_opendir_cb(uv_fs_t* req) { + ASSERT(req == &opendir_req); + ASSERT(req->fs_type == UV_FS_OPENDIR); + ASSERT(req->result == UV_ENOENT); + ASSERT(req->ptr == NULL); + + uv_fs_req_cleanup(req); + ++non_existing_opendir_cb_count; +} + +TEST_IMPL(fs_readdir_non_existing_dir) { + const char* path; + int r; + + path = "./non-existing-dir/"; + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&opendir_req, 0xdb, sizeof(opendir_req)); + + /* Testing the synchronous flavor. */ + r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, NULL); + ASSERT(r == UV_ENOENT); + ASSERT(opendir_req.fs_type == UV_FS_OPENDIR); + ASSERT(opendir_req.result == UV_ENOENT); + ASSERT(opendir_req.ptr == NULL); + uv_fs_req_cleanup(&opendir_req); + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&opendir_req, 0xdb, sizeof(opendir_req)); + + /* Testing the async flavor. */ + r = uv_fs_opendir(uv_default_loop(), + &opendir_req, + path, + non_existing_opendir_cb); + ASSERT(r == 0); + ASSERT(non_existing_opendir_cb_count == 0); + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(non_existing_opendir_cb_count == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +/* + * This test makes sure that reading a file as a directory reports correct + * error codes. + */ + +static int file_opendir_cb_count; + +static void file_opendir_cb(uv_fs_t* req) { + ASSERT(req == &opendir_req); + ASSERT(req->fs_type == UV_FS_OPENDIR); + ASSERT(req->result == UV_ENOTDIR); + ASSERT(req->ptr == NULL); + + uv_fs_req_cleanup(req); + ++file_opendir_cb_count; +} + +TEST_IMPL(fs_readdir_file) { + const char* path; + int r; + + path = "test/fixtures/empty_file"; + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&opendir_req, 0xdb, sizeof(opendir_req)); + + /* Testing the synchronous flavor. */ + r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, NULL); + + ASSERT(r == UV_ENOTDIR); + ASSERT(opendir_req.fs_type == UV_FS_OPENDIR); + ASSERT(opendir_req.result == UV_ENOTDIR); + ASSERT(opendir_req.ptr == NULL); + + uv_fs_req_cleanup(&opendir_req); + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&opendir_req, 0xdb, sizeof(opendir_req)); + + /* Testing the async flavor. */ + r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, file_opendir_cb); + ASSERT(r == 0); + ASSERT(file_opendir_cb_count == 0); + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(file_opendir_cb_count == 1); + MAKE_VALGRIND_HAPPY(); + return 0; +} + +/* + * This test makes sure that reading a non-empty directory with + * uv_fs_{open,read}_dir() returns proper directory entries, including the + * correct entry types. + */ + +static int non_empty_opendir_cb_count; +static int non_empty_readdir_cb_count; +static int non_empty_closedir_cb_count; + +static void non_empty_closedir_cb(uv_fs_t* req) { + ASSERT(req == &closedir_req); + ASSERT(req->result == 0); + uv_fs_req_cleanup(req); + ++non_empty_closedir_cb_count; +} + +static void non_empty_readdir_cb(uv_fs_t* req) { + uv_dir_t* dir; + + ASSERT(req == &readdir_req); + ASSERT(req->fs_type == UV_FS_READDIR); + dir = req->ptr; + + if (req->result == 0) { + uv_fs_req_cleanup(req); + ASSERT(non_empty_readdir_cb_count == 3); + uv_fs_closedir(uv_default_loop(), + &closedir_req, + dir, + non_empty_closedir_cb); + } else { + ASSERT(req->result == 1); + ASSERT(dir->dirents == dirents); + ASSERT(strcmp(dirents[0].name, "file1") == 0 || + strcmp(dirents[0].name, "file2") == 0 || + strcmp(dirents[0].name, "test_subdir") == 0); +#ifdef HAVE_DIRENT_TYPES + if (!strcmp(dirents[0].name, "test_subdir")) + ASSERT(dirents[0].type == UV_DIRENT_DIR); + else + ASSERT(dirents[0].type == UV_DIRENT_FILE); +#else + ASSERT(dirents[0].type == UV_DIRENT_UNKNOWN); +#endif /* HAVE_DIRENT_TYPES */ + + ++non_empty_readdir_cb_count; + uv_fs_req_cleanup(req); + dir->dirents = dirents; + dir->nentries = ARRAY_SIZE(dirents); + uv_fs_readdir(uv_default_loop(), + &readdir_req, + dir, + non_empty_readdir_cb); + } +} + +static void non_empty_opendir_cb(uv_fs_t* req) { + uv_dir_t* dir; + int r; + + ASSERT(req == &opendir_req); + ASSERT(req->fs_type == UV_FS_OPENDIR); + ASSERT(req->result == 0); + ASSERT(req->ptr != NULL); + + dir = req->ptr; + dir->dirents = dirents; + dir->nentries = ARRAY_SIZE(dirents); + + r = uv_fs_readdir(uv_default_loop(), + &readdir_req, + dir, + non_empty_readdir_cb); + ASSERT(r == 0); + uv_fs_req_cleanup(req); + ++non_empty_opendir_cb_count; +} + +TEST_IMPL(fs_readdir_non_empty_dir) { + size_t entries_count; + uv_fs_t mkdir_req; + uv_fs_t rmdir_req; + uv_fs_t create_req; + uv_fs_t close_req; + uv_dir_t* dir; + int r; + + cleanup_test_files(); + + r = uv_fs_mkdir(uv_default_loop(), &mkdir_req, "test_dir", 0755, NULL); + ASSERT(r == 0); + + /* Create two files synchronously. */ + r = uv_fs_open(uv_default_loop(), + &create_req, + "test_dir/file1", + O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + uv_fs_req_cleanup(&create_req); + r = uv_fs_close(uv_default_loop(), + &close_req, + create_req.result, + NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(uv_default_loop(), + &create_req, + "test_dir/file2", + O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + uv_fs_req_cleanup(&create_req); + r = uv_fs_close(uv_default_loop(), + &close_req, + create_req.result, + NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_mkdir(uv_default_loop(), + &mkdir_req, + "test_dir/test_subdir", + 0755, + NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&mkdir_req); + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&opendir_req, 0xdb, sizeof(opendir_req)); + + /* Testing the synchronous flavor. */ + r = uv_fs_opendir(uv_default_loop(), &opendir_req, "test_dir", NULL); + ASSERT(r == 0); + ASSERT(opendir_req.fs_type == UV_FS_OPENDIR); + ASSERT(opendir_req.result == 0); + ASSERT(opendir_req.ptr != NULL); + + entries_count = 0; + dir = opendir_req.ptr; + dir->dirents = dirents; + dir->nentries = ARRAY_SIZE(dirents); + uv_fs_req_cleanup(&opendir_req); + + while (uv_fs_readdir(uv_default_loop(), + &readdir_req, + dir, + NULL) != 0) { + ASSERT(strcmp(dirents[0].name, "file1") == 0 || + strcmp(dirents[0].name, "file2") == 0 || + strcmp(dirents[0].name, "test_subdir") == 0); +#ifdef HAVE_DIRENT_TYPES + if (!strcmp(dirents[0].name, "test_subdir")) + ASSERT(dirents[0].type == UV_DIRENT_DIR); + else + ASSERT(dirents[0].type == UV_DIRENT_FILE); +#else + ASSERT(dirents[0].type == UV_DIRENT_UNKNOWN); +#endif /* HAVE_DIRENT_TYPES */ + uv_fs_req_cleanup(&readdir_req); + ++entries_count; + } + + ASSERT(entries_count == 3); + uv_fs_req_cleanup(&readdir_req); + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&closedir_req, 0xdb, sizeof(closedir_req)); + uv_fs_closedir(uv_default_loop(), &closedir_req, dir, NULL); + ASSERT(closedir_req.result == 0); + uv_fs_req_cleanup(&closedir_req); + + /* Testing the asynchronous flavor. */ + + /* Fill the req to ensure that required fields are cleaned up. */ + memset(&opendir_req, 0xdb, sizeof(opendir_req)); + + r = uv_fs_opendir(uv_default_loop(), + &opendir_req, + "test_dir", + non_empty_opendir_cb); + ASSERT(r == 0); + ASSERT(non_empty_opendir_cb_count == 0); + ASSERT(non_empty_closedir_cb_count == 0); + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(non_empty_opendir_cb_count == 1); + ASSERT(non_empty_closedir_cb_count == 1); + + uv_fs_rmdir(uv_default_loop(), &rmdir_req, "test_subdir", NULL); + uv_fs_req_cleanup(&rmdir_req); + + cleanup_test_files(); + MAKE_VALGRIND_HAPPY(); + return 0; + } diff --git a/deps/uv/test/test-gettimeofday.c b/deps/uv/test/test-gettimeofday.c new file mode 100644 index 00000000000000..4ebc11f93ed321 --- /dev/null +++ b/deps/uv/test/test-gettimeofday.c @@ -0,0 +1,39 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +TEST_IMPL(gettimeofday) { + uv_timeval64_t tv; + int r; + + tv.tv_sec = 0; + r = uv_gettimeofday(&tv); + ASSERT(r == 0); + ASSERT(tv.tv_sec != 0); + + /* Test invalid input. */ + r = uv_gettimeofday(NULL); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index f498c7dc81f1e5..ace501c9796f00 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -155,6 +155,9 @@ TEST_DECLARE (udp_open) TEST_DECLARE (udp_open_twice) TEST_DECLARE (udp_open_bound) TEST_DECLARE (udp_open_connect) +#ifndef _WIN32 +TEST_DECLARE (udp_send_unix) +#endif TEST_DECLARE (udp_try_send) TEST_DECLARE (pipe_bind_error_addrinuse) TEST_DECLARE (pipe_bind_error_addrnotavail) @@ -252,6 +255,7 @@ TEST_DECLARE (getnameinfo_basic_ip4_sync) TEST_DECLARE (getnameinfo_basic_ip6) TEST_DECLARE (getsockname_tcp) TEST_DECLARE (getsockname_udp) +TEST_DECLARE (gettimeofday) TEST_DECLARE (fail_always) TEST_DECLARE (pass_always) TEST_DECLARE (socket_buffer_size) @@ -345,6 +349,10 @@ TEST_DECLARE (fs_scandir_empty_dir) TEST_DECLARE (fs_scandir_non_existent_dir) TEST_DECLARE (fs_scandir_file) TEST_DECLARE (fs_open_dir) +TEST_DECLARE (fs_readdir_empty_dir) +TEST_DECLARE (fs_readdir_file) +TEST_DECLARE (fs_readdir_non_empty_dir) +TEST_DECLARE (fs_readdir_non_existing_dir) TEST_DECLARE (fs_rename_to_existing_file) TEST_DECLARE (fs_write_multiple_bufs) TEST_DECLARE (fs_read_write_null_arguments) @@ -652,6 +660,9 @@ TASK_LIST_START TEST_ENTRY (udp_open_bound) TEST_ENTRY (udp_open_connect) TEST_HELPER (udp_open_connect, udp4_echo_server) +#ifndef _WIN32 + TEST_ENTRY (udp_send_unix) +#endif TEST_ENTRY (pipe_bind_error_addrinuse) TEST_ENTRY (pipe_bind_error_addrnotavail) @@ -781,6 +792,8 @@ TASK_LIST_START TEST_ENTRY (getsockname_tcp) TEST_ENTRY (getsockname_udp) + TEST_ENTRY (gettimeofday) + TEST_ENTRY (poll_duplex) TEST_ENTRY (poll_unidirectional) TEST_ENTRY (poll_close) @@ -921,6 +934,10 @@ TASK_LIST_START TEST_ENTRY (fs_scandir_non_existent_dir) TEST_ENTRY (fs_scandir_file) TEST_ENTRY (fs_open_dir) + TEST_ENTRY (fs_readdir_empty_dir) + TEST_ENTRY (fs_readdir_file) + TEST_ENTRY (fs_readdir_non_empty_dir) + TEST_ENTRY (fs_readdir_non_existing_dir) TEST_ENTRY (fs_rename_to_existing_file) TEST_ENTRY (fs_write_multiple_bufs) TEST_ENTRY (fs_write_alotof_bufs) diff --git a/deps/uv/test/test-udp-open.c b/deps/uv/test/test-udp-open.c index 0390bae2e5d282..dee408baa5c09e 100644 --- a/deps/uv/test/test-udp-open.c +++ b/deps/uv/test/test-udp-open.c @@ -27,6 +27,8 @@ #ifndef _WIN32 # include +# include +# include #endif static int send_cb_called = 0; @@ -296,3 +298,53 @@ TEST_IMPL(udp_open_connect) { MAKE_VALGRIND_HAPPY(); return 0; } + +#ifndef _WIN32 +TEST_IMPL(udp_send_unix) { + /* Test that "uv_udp_send()" supports sending over + a "sockaddr_un" address. */ + struct sockaddr_un addr; + uv_udp_t handle; + uv_udp_send_t req; + uv_loop_t* loop; + uv_buf_t buf = uv_buf_init("PING", 4); + int fd; + int r; + + loop = uv_default_loop(); + + memset(&addr, 0, sizeof addr); + addr.sun_family = AF_UNIX; + ASSERT(strlen(TEST_PIPENAME) < sizeof(addr.sun_path)); + memcpy(addr.sun_path, TEST_PIPENAME, strlen(TEST_PIPENAME)); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + ASSERT(fd >= 0); + + unlink(TEST_PIPENAME); + ASSERT(0 == bind(fd, (const struct sockaddr*)&addr, sizeof addr)); + ASSERT(0 == listen(fd, 1)); + + r = uv_udp_init(loop, &handle); + ASSERT(r == 0); + r = uv_udp_open(&handle, fd); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + + r = uv_udp_send(&req, + &handle, + &buf, + 1, + (const struct sockaddr*) &addr, + NULL); + ASSERT(r == 0); + + uv_close((uv_handle_t*)&handle, NULL); + uv_run(loop, UV_RUN_DEFAULT); + close(fd); + unlink(TEST_PIPENAME); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif diff --git a/deps/uv/test/test.gyp b/deps/uv/test/test.gyp index 9c13e25dde0ef0..ff64ef0be8d4b4 100644 --- a/deps/uv/test/test.gyp +++ b/deps/uv/test/test.gyp @@ -32,6 +32,7 @@ 'test-fail-always.c', 'test-fork.c', 'test-fs.c', + 'test-fs-readdir.c', 'test-fs-copyfile.c', 'test-fs-event.c', 'test-fs-poll.c', @@ -43,6 +44,7 @@ 'test-gethostname.c', 'test-getnameinfo.c', 'test-getsockname.c', + 'test-gettimeofday.c', 'test-handle-fileno.c', 'test-homedir.c', 'test-hrtime.c',