diff --git a/include/uv/win.h b/include/uv/win.h index 5d08d637..1c69c022 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -70,6 +70,11 @@ typedef struct pollfd { # define S_IFLNK 0xA000 #endif +// Define missing in Windows Kit Include\{VERSION}\ucrt\sys\stat.h +#if defined(_CRT_INTERNAL_NONSTDC_NAMES) && _CRT_INTERNAL_NONSTDC_NAMES && !defined(S_IFIFO) +# define S_IFIFO _S_IFIFO +#endif + /* Additional signals supported by uv_signal and or uv_kill. The CRT defines * the following signals already: * diff --git a/src/win/fs.c b/src/win/fs.c index 79230799..efc23934 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -36,6 +36,8 @@ #include "handle-inl.h" #include "fs-fd-hash-inl.h" +#include + #define UV_FS_FREE_PATHS 0x0002 #define UV_FS_FREE_PTR 0x0008 @@ -1706,11 +1708,36 @@ void fs__closedir(uv_fs_t* req) { INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, int do_lstat) { + FILE_FS_DEVICE_INFORMATION device_info; FILE_ALL_INFORMATION file_info; FILE_FS_VOLUME_INFORMATION volume_info; NTSTATUS nt_status; IO_STATUS_BLOCK io_status; + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &device_info, + sizeof device_info, + FileFsDeviceInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (NT_ERROR(nt_status)) { + SetLastError(pRtlNtStatusToDosError(nt_status)); + return -1; + } + + /* If it's NUL device set fields as reasonable as possible and return. */ + if (device_info.DeviceType == FILE_DEVICE_NULL) { + memset(statbuf, 0, sizeof(uv_stat_t)); + statbuf->st_mode = _S_IFCHR; + statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | + ((_S_IREAD | _S_IWRITE) >> 6); + statbuf->st_nlink = 1; + statbuf->st_blksize = 4096; + statbuf->st_rdev = FILE_DEVICE_NULL << 16; + return 0; + } + nt_status = pNtQueryInformationFile(handle, &io_status, &file_info, @@ -1915,6 +1942,37 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { } +INLINE static int fs__fstat_handle(int fd, HANDLE handle, uv_stat_t* statbuf) { + DWORD file_type; + + /* Each file type is processed differently. */ + file_type = uv_guess_handle(fd); + switch (file_type) { + /* Disk files use the existing logic from fs__stat_handle. */ + case UV_FILE: + return fs__stat_handle(handle, statbuf, 0); + + /* Devices and pipes are processed identically. There is no more information + * for them from any API. Fields are set as reasonably as possible and the + * function returns. */ + case UV_TTY: + case UV_NAMED_PIPE: + memset(statbuf, 0, sizeof(uv_stat_t)); + statbuf->st_mode = file_type == UV_TTY ? _S_IFCHR : _S_IFIFO; + statbuf->st_nlink = 1; + statbuf->st_rdev = (file_type == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) << 16; + statbuf->st_ino = (uint64_t) handle; + return 0; + + /* If file type is unknown it is an error. */ + case UV_UNKNOWN_HANDLE: + default: + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } +} + + static void fs__stat(uv_fs_t* req) { fs__stat_prepare_path(req->file.pathw); fs__stat_impl(req, 0); @@ -1940,7 +1998,7 @@ static void fs__fstat(uv_fs_t* req) { return; } - if (fs__stat_handle(handle, &req->statbuf, 0) != 0) { + if (fs__fstat_handle(fd, handle, &req->statbuf) != 0) { SET_REQ_WIN32_ERROR(req, GetLastError()); return; } diff --git a/test/test-fs.c b/test/test-fs.c index 78ee4999..ebf41050 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1539,6 +1539,43 @@ TEST_IMPL(fs_fstat) { } +TEST_IMPL(fs_fstat_stdio) { + int fd; + int res; + uv_fs_t req; +#ifdef _WIN32 + uv_stat_t* st; + DWORD ft; +#endif + + for (fd = 0; fd <= 2; ++fd) { + res = uv_fs_fstat(NULL, &req, fd, NULL); + ASSERT(res == 0); + ASSERT(req.result == 0); + +#ifdef _WIN32 + st = req.ptr; + ft = uv_guess_handle(fd); + switch (ft) { + case UV_TTY: + case UV_NAMED_PIPE: + ASSERT(st->st_mode == ft == UV_TTY ? S_IFCHR : S_IFIFO); + ASSERT(st->st_nlink == 1); + ASSERT(st->st_rdev == (ft == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) << 16); + break; + default: + break; + } +#endif + + uv_fs_req_cleanup(&req); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(fs_access) { int r; uv_fs_t req; diff --git a/test/test-list.h b/test/test-list.h index 45261be2..ec23b344 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -347,6 +347,7 @@ TEST_DECLARE (fs_async_sendfile_nodata) TEST_DECLARE (fs_mkdtemp) TEST_DECLARE (fs_mkstemp) TEST_DECLARE (fs_fstat) +TEST_DECLARE (fs_fstat_stdio) TEST_DECLARE (fs_access) TEST_DECLARE (fs_chmod) TEST_DECLARE (fs_copyfile) @@ -1024,6 +1025,7 @@ TASK_LIST_START TEST_ENTRY (fs_mkdtemp) TEST_ENTRY (fs_mkstemp) TEST_ENTRY (fs_fstat) + TEST_ENTRY (fs_fstat_stdio) TEST_ENTRY (fs_access) TEST_ENTRY (fs_chmod) TEST_ENTRY (fs_copyfile)