+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
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;
#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
#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;
}
#!/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