> and _stat32i64, when applied to the "NUL" device on mingw, reports
> that "NUL" is a regular file.

It's worth mentioning this bug in the documentation. And adding a unit
test.


2025-06-12  Bruno Haible  <br...@clisp.org>

        stat, lstat, fstat tests: Enhance tests regarding /dev/null or NUL.
        * tests/test-fstat.c: Include <fcntl.h>.
        (main): Check that fstat reports /dev/null or NUL as a character device.
        * tests/test-stat.h (test_stat_func): Likewise for stat.
        * tests/test-lstat.h (test_lstat_func): Likewise for lstat.

2025-06-12  Bruno Haible  <br...@clisp.org>

        stat: Document mingw bug.
        * doc/posix-functions/stat.texi: Mention the bug with NUL on mingw.

>From 2b918f2e68b801daf7a4268d611c1ed9cbee1574 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Fri, 13 Jun 2025 00:02:57 +0200
Subject: [PATCH 1/2] stat: Document mingw bug.

* doc/posix-functions/stat.texi: Mention the bug with NUL on mingw.
---
 ChangeLog                     | 5 +++++
 doc/posix-functions/stat.texi | 4 ++++
 2 files changed, 9 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index a12a1707c9..cb4853e4b3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2025-06-12  Bruno Haible  <br...@clisp.org>
+
+	stat: Document mingw bug.
+	* doc/posix-functions/stat.texi: Mention the bug with NUL on mingw.
+
 2025-06-12  Bruno Haible  <br...@clisp.org>
 
 	stat: Add support for mingw 13 in 32-bit mode.
diff --git a/doc/posix-functions/stat.texi b/doc/posix-functions/stat.texi
index 160e86b978..6e0df396a5 100644
--- a/doc/posix-functions/stat.texi
+++ b/doc/posix-functions/stat.texi
@@ -36,6 +36,10 @@
 different results:
 mingw, MSVC 14.
 @item
+@c https://sourceforge.net/p/mingw-w64/bugs/1009/
+On mingw, the @code{st_mode} field of @code{stat("NUL",buf)} is bogus,
+suggesting that @code{NUL} is a regular file.
+@item
 On macOS 12.6, when this function yields a timestamp with a
 nonpositive @code{tv_sec} value, @code{tv_nsec} might be in the range
 @minus{}999999999..@minus{}1, representing a negative nanoseconds
-- 
2.43.0

>From fab078415a9789b8f74aae37d2cf94f103f7261d Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 12 Jun 2025 19:45:19 +0200
Subject: [PATCH 2/2] stat, lstat, fstat tests: Enhance tests regarding
 /dev/null or NUL.

* tests/test-fstat.c: Include <fcntl.h>.
(main): Check that fstat reports /dev/null or NUL as a character device.
* tests/test-stat.h (test_stat_func): Likewise for stat.
* tests/test-lstat.h (test_lstat_func): Likewise for lstat.
---
 ChangeLog          |  8 ++++++++
 tests/test-fstat.c | 17 +++++++++++++++++
 tests/test-lstat.h |  9 +++++++++
 tests/test-stat.h  |  9 +++++++++
 4 files changed, 43 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index cb4853e4b3..da241662d7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2025-06-12  Bruno Haible  <br...@clisp.org>
+
+	stat, lstat, fstat tests: Enhance tests regarding /dev/null or NUL.
+	* tests/test-fstat.c: Include <fcntl.h>.
+	(main): Check that fstat reports /dev/null or NUL as a character device.
+	* tests/test-stat.h (test_stat_func): Likewise for stat.
+	* tests/test-lstat.h (test_lstat_func): Likewise for lstat.
+
 2025-06-12  Bruno Haible  <br...@clisp.org>
 
 	stat: Document mingw bug.
diff --git a/tests/test-fstat.c b/tests/test-fstat.c
index 474e262077..7e65ee2f23 100644
--- a/tests/test-fstat.c
+++ b/tests/test-fstat.c
@@ -22,6 +22,7 @@
 SIGNATURE_CHECK (fstat, int, (int, struct stat *));
 
 #include <errno.h>
+#include <fcntl.h>
 #include <unistd.h>
 
 #include "macros.h"
@@ -46,5 +47,21 @@ main ()
     ASSERT (errno == EBADF);
   }
 
+  /* /dev/null is a character device.  */
+  {
+    int fd;
+    struct stat statbuf;
+
+#if defined _WIN32 && !defined __CYGWIN__
+    fd = open ("NUL", O_RDWR);
+#else
+    fd = open ("/dev/null", O_RDWR);
+#endif
+    ASSERT (fstat (fd, &statbuf) == 0);
+    close (fd);
+    ASSERT (!S_ISREG (statbuf.st_mode));
+    ASSERT (S_ISCHR (statbuf.st_mode));
+  }
+
   return test_exit_status;
 }
diff --git a/tests/test-lstat.h b/tests/test-lstat.h
index b9846df710..fb9a808a76 100644
--- a/tests/test-lstat.h
+++ b/tests/test-lstat.h
@@ -64,6 +64,15 @@ test_lstat_func (int (*func) (char const *, struct stat *), bool print)
   ASSERT (func (BASE "file/", &st1) == -1);
   ASSERT (errno == ENOTDIR);
 
+  /* /dev/null is a character device.  */
+#if defined _WIN32 && !defined __CYGWIN__
+  ASSERT (func ("NUL", &st1) == 0);
+#else
+  ASSERT (func ("/dev/null", &st1) == 0);
+#endif
+  ASSERT (!S_ISREG (st1.st_mode));
+  ASSERT (S_ISCHR (st1.st_mode));
+
   /* Now for some symlink tests, where supported.  We set up:
      link1 -> directory
      link2 -> file
diff --git a/tests/test-stat.h b/tests/test-stat.h
index fc0a9d4dd5..3d2b912e8f 100644
--- a/tests/test-stat.h
+++ b/tests/test-stat.h
@@ -61,6 +61,15 @@ test_stat_func (int (*func) (char const *, struct stat *), bool print)
   ASSERT (func (BASE "file/", &st1) == -1);
   ASSERT (errno == ENOTDIR);
 
+  /* /dev/null is a character device.  */
+#if defined _WIN32 && !defined __CYGWIN__
+  ASSERT (func ("NUL", &st1) == 0);
+#else
+  ASSERT (func ("/dev/null", &st1) == 0);
+#endif
+  ASSERT (!S_ISREG (st1.st_mode));
+  ASSERT (S_ISCHR (st1.st_mode));
+
   /* Now for some symlink tests, where supported.  We set up:
      link1 -> directory
      link2 -> file
-- 
2.43.0

Reply via email to