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