Damjan Jovanovic : msvcrt: Fix fstat's handling of pipes and char
devices.
Alexandre Julliard
julliard at wine.codeweavers.com
Fri Feb 16 07:08:43 CST 2007
Module: wine
Branch: master
Commit: 2705d7887692ff3019c7a4b0cf9b7812b10763eb
URL: http://source.winehq.org/git/wine.git/?a=commit;h=2705d7887692ff3019c7a4b0cf9b7812b10763eb
Author: Damjan Jovanovic <damjan.jov at gmail.com>
Date: Fri Feb 16 09:19:34 2007 +0200
msvcrt: Fix fstat's handling of pipes and char devices.
For pipes/char devices, st_dev and st_rdev should be the fd, st_nlink
is always 1, and st_mode is S_IFIFO and S_IFCHR respectively.
Added tests to prove the new behaviour right.
---
dlls/msvcrt/file.c | 51 +++++++++++++++++------------
dlls/msvcrt/tests/file.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+), 21 deletions(-)
diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c
index b55d600..2a44e6d 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 7294ff9..d7d7676 100644
--- a/dlls/msvcrt/tests/file.c
+++ b/dlls/msvcrt/tests/file.c
@@ -27,6 +27,7 @@
#include <share.h>
#include <sys/stat.h>
#include <io.h>
+#include <direct.h>
#include <windef.h>
#include <winbase.h>
#include <winnls.h>
@@ -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();
More information about the wine-cvs
mailing list