changeset 8877:30d389dd4713

Improve lseek module. * lib/lseek.c (rpl_lseek): Detect EBADF on mingw. * lib/unistd_.h (lseek): Scale back link warning message. * tests/test-lseek.c: Beef up test. * tests/test-lseek.sh: Exercise more facets of lseek. Reported by Bruno Haible.
author Eric Blake <ebb9@byu.net>
date Mon, 28 May 2007 12:43:30 +0000
parents b80fefef40b5
children a8cf4cce248b
files ChangeLog lib/lseek.c lib/unistd_.h tests/test-lseek.c tests/test-lseek.sh
diffstat 5 files changed, 93 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2007-05-28  Eric Blake  <ebb9@byu.net>
+
+	Improve lseek module.
+	* lib/lseek.c (rpl_lseek): Detect EBADF on mingw.
+	* lib/unistd_.h (lseek): Scale back link warning message.
+	* tests/test-lseek.c: Beef up test.
+	* tests/test-lseek.sh: Exercise more facets of lseek.
+	Reported by Bruno Haible.
+
 2007-05-28  Bruno Haible  <bruno@clisp.org>
 
 	* tests/test-unistd.c: Test all the types that <unistd.h> is expected
--- a/lib/lseek.c
+++ b/lib/lseek.c
@@ -31,7 +31,13 @@
 rpl_lseek (int fd, off_t offset, int whence)
 {
   /* mingw lseek mistakenly succeeds on pipes, sockets, and terminals.  */
-  if (GetFileType ((HANDLE) _get_osfhandle (fd)) != FILE_TYPE_DISK)
+  HANDLE h = (HANDLE) _get_osfhandle (fd);
+  if (h == INVALID_HANDLE_VALUE)
+    {
+      errno = EBADF;
+      return -1;
+    }
+  if (GetFileType (h) != FILE_TYPE_DISK)
     {
       errno = ESPIPE;
       return -1;
--- a/lib/unistd_.h
+++ b/lib/unistd_.h
@@ -188,9 +188,8 @@
 #elif defined GNULIB_POSIXCHECK
 # undef lseek
 # define lseek(f,o,w) \
-    (GL_LINK_WARNING ("lseek does not fail with ESPIPE on non-seekable " \
-                      "files on some systems - " \
-                      "use gnulib module lseek for portability"), \
+    (GL_LINK_WARNING ("lseek does not fail with ESPIPE on pipes on some " \
+                      "systems - use gnulib module lseek for portability"), \
      lseek (f, o, w))
 #endif
 
--- a/tests/test-lseek.c
+++ b/tests/test-lseek.c
@@ -19,11 +19,69 @@
 
 #include <config.h>
 
+#include <errno.h>
+#include <stdio.h>
 #include <unistd.h>
 
+#define ASSERT(expr) \
+  do									     \
+    {									     \
+      if (!(expr))							     \
+        {								     \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+          abort ();							     \
+        }								     \
+    }									     \
+  while (0)
+
+/* ARGC must be 2; *ARGV[1] is '0' if stdin and stdout are files, '1'
+   if they are pipes, and '2' if they are closed.  Check for proper
+   semantics of lseek.  */
 int
-main ()
+main (int argc, char **argv)
 {
-  /* Exit with success only if stdin is seekable.  */
-  return lseek (0, (off_t)0, SEEK_CUR) < 0;
+  if (argc != 2)
+    return 2;
+  switch (*argv[1])
+    {
+    case '0': /* regular files */
+      ASSERT (lseek (0, (off_t)2, SEEK_SET) == 2);
+      ASSERT (lseek (0, (off_t)-4, SEEK_CUR) == -1);
+      ASSERT (errno == EINVAL);
+      errno = 0;
+      ASSERT (lseek (0, (off_t)0, SEEK_CUR) == 2);
+      ASSERT (lseek (0, (off_t)0, (SEEK_SET | SEEK_CUR | SEEK_END) + 1) == -1);
+      ASSERT (errno == EINVAL);
+      ASSERT (lseek (1, (off_t)2, SEEK_SET) == 2);
+      errno = 0;
+      ASSERT (lseek (1, (off_t)-4, SEEK_CUR) == -1);
+      ASSERT (errno == EINVAL);
+      errno = 0;
+      ASSERT (lseek (1, (off_t)0, SEEK_CUR) == 2);
+      ASSERT (lseek (1, (off_t)0, (SEEK_SET | SEEK_CUR | SEEK_END) + 1) == -1);
+      ASSERT (errno == EINVAL);
+      break;
+
+    case '1': /* pipes */
+      errno = 0;
+      ASSERT (lseek (0, (off_t)0, SEEK_CUR) == -1);
+      ASSERT (errno == ESPIPE);
+      errno = 0;
+      ASSERT (lseek (1, (off_t)0, SEEK_CUR) == -1);
+      ASSERT (errno == ESPIPE);
+      break;
+
+    case '2': /* closed */
+      errno = 0;
+      ASSERT (lseek (0, (off_t)0, SEEK_CUR) == -1);
+      ASSERT (errno == EBADF);
+      errno = 0;
+      ASSERT (lseek (1, (off_t)0, SEEK_CUR) == -1);
+      ASSERT (errno == EBADF);
+      break;
+
+    default:
+      return 1;
+    }
+  return 0;
 }
--- a/tests/test-lseek.sh
+++ b/tests/test-lseek.sh
@@ -1,7 +1,17 @@
 #!/bin/sh
 
-# Succeed on seekable stdin
-./test-lseek${EXEEXT} < "$srcdir/test-lseek.sh" || exit 1
-# Fail on pipe stdin
-echo hi | ./test-lseek${EXEEXT} && exit 1
+tmpfiles=
+trap 'rm -fr $tmpfiles' 1 2 3 15
+
+tmpfiles=t-lseek.tmp
+# seekable files
+./test-lseek${EXEEXT} 0 < "$srcdir/test-lseek.sh" > t-lseek.tmp || exit 1
+
+# pipes
+echo hi | ./test-lseek${EXEEXT} 1 | cat || exit 1
+
+# closed descriptors
+./test-lseek${EXEEXT} 2 <&- >&- || exit 1
+
+rm -rf $tmpfiles
 exit 0