diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index b55d600a2a7..2a44e6d5fe4 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -1126,6 +1126,7 @@ int CDECL MSVCRT__fileno(MSVCRT_FILE* file) int CDECL MSVCRT__fstat64(int fd, struct MSVCRT__stat64* buf) { DWORD dw; + DWORD type; BY_HANDLE_FILE_INFORMATION hfi; HANDLE hand = msvcrt_fdtoh(fd); @@ -1142,31 +1143,39 @@ int CDECL MSVCRT__fstat64(int fd, struct MSVCRT__stat64* buf) memset(&hfi, 0, sizeof(hfi)); memset(buf, 0, sizeof(struct MSVCRT__stat64)); - if (!GetFileInformationByHandle(hand, &hfi)) + type = GetFileType(hand); + if (type == FILE_TYPE_PIPE) { - WARN(":failed-last error (%d)\n",GetLastError()); - msvcrt_set_errno(ERROR_INVALID_PARAMETER); - return -1; + buf->st_dev = buf->st_rdev = fd; + buf->st_mode = S_IFIFO; + buf->st_nlink = 1; + } + else if (type == FILE_TYPE_CHAR) + { + buf->st_dev = buf->st_rdev = fd; + buf->st_mode = S_IFCHR; + buf->st_nlink = 1; + } + else /* FILE_TYPE_DISK etc. */ + { + if (!GetFileInformationByHandle(hand, &hfi)) + { + WARN(":failed-last error (%d)\n",GetLastError()); + msvcrt_set_errno(ERROR_INVALID_PARAMETER); + return -1; + } + buf->st_mode = S_IFREG | S_IREAD; + if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow; + RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw); + buf->st_atime = dw; + RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw); + buf->st_mtime = buf->st_ctime = dw; + buf->st_nlink = hfi.nNumberOfLinks; } - dw = GetFileType(hand); - buf->st_mode = S_IREAD; - if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) - buf->st_mode |= S_IWRITE; - /* interestingly, Windows never seems to set S_IFDIR */ - if (dw == FILE_TYPE_CHAR) - buf->st_mode |= S_IFCHR; - else if (dw == FILE_TYPE_PIPE) - buf->st_mode |= S_IFIFO; - else - buf->st_mode |= S_IFREG; TRACE(":dwFileAttributes = 0x%x, mode set to 0x%x\n",hfi.dwFileAttributes, buf->st_mode); - buf->st_nlink = hfi.nNumberOfLinks; - buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow; - RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw); - buf->st_atime = dw; - RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw); - buf->st_mtime = buf->st_ctime = dw; return 0; } diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c index 7294ff984c7..d7d7676fff2 100644 --- a/dlls/msvcrt/tests/file.c +++ b/dlls/msvcrt/tests/file.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -796,6 +797,86 @@ static void test_setmaxstdio(void) ok(-1 == _setmaxstdio(2049),"_setmaxstdio returned %d instead of -1\n",_setmaxstdio(2049)); } +static void test_stat(void) +{ + int fd; + int pipes[2]; + struct stat buf; + + /* Tests for a file */ + fd = open("stat.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE); + if (fd >= 0) + { + if (fstat(fd, &buf) == 0) + { + if (S_ISREG(buf.st_mode)) + { + ok(buf.st_dev == 0, "st_dev is %d, expected 0\n", buf.st_dev); + ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", + buf.st_dev, buf.st_rdev); + ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", + buf.st_nlink); + ok(buf.st_size == 0, "st_size is %d, expected 0\n", + buf.st_size); + } + else + skip("file is not a file?\n"); + } + else + skip("fstat failed, errno %d\n", errno); + close(fd); + remove("stat.tst"); + } + else + skip("open failed with errno %d\n", errno); + + /* Tests for a char device */ + if (_dup2(0, 10) == 0) + { + if (fstat(10, &buf) == 0) + { + if (buf.st_mode == _S_IFCHR) + { + ok(buf.st_dev == 10, "st_dev is %d, expected 10\n", buf.st_dev); + ok(buf.st_rdev == 10, "st_rdev is %d, expected 10\n", buf.st_rdev); + ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink); + } + else + skip("stdin is not a char device?\n"); + } + else + skip("fstat failed with errno %d\n", errno); + close(10); + } + else + skip("_dup2 failed with errno %d\n", errno); + + /* Tests for pipes */ + if (_pipe(pipes, 1024, O_BINARY) == 0) + { + if (fstat(pipes[0], &buf) == 0) + { + if (buf.st_mode == _S_IFIFO) + { + ok(buf.st_dev == pipes[0], "st_dev is %d, expected %d\n", + buf.st_dev, pipes[0]); + ok(buf.st_rdev == pipes[0], "st_rdev is %d, expected %d\n", + buf.st_rdev, pipes[0]); + ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", + buf.st_nlink); + } + else + skip("pipe() didn't make a pipe?\n"); + } + else + skip("fstat failed with errno %d\n", errno); + close(pipes[0]); + close(pipes[1]); + } + else + skip("pipe failed with errno %d\n", errno); +} + START_TEST(file) { int arg_c; @@ -813,6 +894,7 @@ START_TEST(file) test_file_inherit(arg_v[0]); test_file_write_read(); test_chsize(); + test_stat(); /* testing stream I/O */ test_fdopen();