From 91e22cf7a3b61b15df6f4fbef2b8af59fda6d266 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Tue, 4 Jun 2024 01:48:04 +0200 Subject: [PATCH] readlink: Work around a Cygwin 3.3.6 bug. * m4/readlink.m4 (gl_FUNC_READLINK): Set REPLACE_READLINK to 1 on Cygwin. * lib/readlink.c (rpl_readlink): On Cygwin, for /dev/* files, don't return results that start with a backslash. * tests/test-readlink.h (test_readlink): Add a test of /dev/null. * tests/test-canonicalize-lgpl.c (main): Likewise. * tests/test-canonicalize.c (main): Likewise. * doc/posix-functions/readlink.texi: Mention the Cygwin bug. --- ChangeLog | 11 ++++++++++ doc/posix-functions/readlink.texi | 4 ++++ lib/readlink.c | 10 +++++++++ m4/readlink.m4 | 34 +++++++++++++++++++++++-------- tests/test-canonicalize-lgpl.c | 7 +++++++ tests/test-canonicalize.c | 11 ++++++++++ tests/test-readlink.h | 6 ++++++ 7 files changed, 75 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3985d66d37..06c0e34ce2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2024-06-03 Bruno Haible + + readlink: Work around a Cygwin 3.3.6 bug. + * m4/readlink.m4 (gl_FUNC_READLINK): Set REPLACE_READLINK to 1 on Cygwin. + * lib/readlink.c (rpl_readlink): On Cygwin, for /dev/* files, don't + return results that start with a backslash. + * tests/test-readlink.h (test_readlink): Add a test of /dev/null. + * tests/test-canonicalize-lgpl.c (main): Likewise. + * tests/test-canonicalize.c (main): Likewise. + * doc/posix-functions/readlink.texi: Mention the Cygwin bug. + 2024-06-03 Bruno Haible nstrftime tests: Avoid some failures on native Windows. diff --git a/doc/posix-functions/readlink.texi b/doc/posix-functions/readlink.texi index d4421380a8..732349ea15 100644 --- a/doc/posix-functions/readlink.texi +++ b/doc/posix-functions/readlink.texi @@ -18,6 +18,10 @@ FreeBSD 7.2, Solaris 9, Mac OS X 10.10. On some platforms, this function returns @code{int} instead of @code{ssize_t}: glibc 2.4, FreeBSD 6.0, OpenBSD 6.7, Cygwin 1.5.x, AIX 7.1. +@item +For the file name @file{/dev/null}, this function returns @file{\Device\Null}, +which is unusable, on some platforms: +Cygwin 3.3.6. @end itemize Portability problems mostly fixed by Gnulib: diff --git a/lib/readlink.c b/lib/readlink.c index a5369fa977..f4af30ebc4 100644 --- a/lib/readlink.c +++ b/lib/readlink.c @@ -98,6 +98,16 @@ rpl_readlink (char const *file, char *buf, size_t bufsize) } # endif +# if defined __CYGWIN__ + /* On Cygwin 3.3.6, readlink("/dev/null") returns "\\Device\\Null", which + is unusable. Better fail with EINVAL. */ + if (r > 0 && strncmp (file, "/dev/", 5) == 0 && buf[0] == '\\') + { + errno = EINVAL; + return -1; + } +# endif + return r; } diff --git a/m4/readlink.m4 b/m4/readlink.m4 index 6d78ec84a0..e6edb80f87 100644 --- a/m4/readlink.m4 +++ b/m4/readlink.m4 @@ -1,4 +1,4 @@ -# readlink.m4 serial 17 +# readlink.m4 serial 18 dnl Copyright (C) 2003, 2007, 2009-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -7,7 +7,7 @@ dnl with or without modifications, as long as this notice is preserved. AC_DEFUN([gl_FUNC_READLINK], [ AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) - AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_REQUIRE([AC_CANONICAL_HOST]) AC_CHECK_FUNCS_ONCE([readlink]) if test $ac_cv_func_readlink = no; then HAVE_READLINK=0 @@ -17,9 +17,13 @@ AC_DEFUN([gl_FUNC_READLINK], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include - /* Cause compilation failure if original declaration has wrong type. */ - ssize_t readlink (const char *, char *, size_t);]])], + /* Cause compilation failure if original declaration has + wrong type. */ + ssize_t readlink (const char *, char *, size_t); + ]]) + ], [gl_cv_decl_readlink_works=yes], [gl_cv_decl_readlink_works=no])]) + dnl Solaris 9 ignores trailing slash. dnl FreeBSD 7.2 dereferences only one level of links with trailing slash. AC_CACHE_CHECK([whether readlink handles trailing slash correctly], @@ -30,8 +34,11 @@ AC_DEFUN([gl_FUNC_READLINK], AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[#include -]], [[char buf[20]; - return readlink ("conftest.lnk2/", buf, sizeof buf) != -1;]])], + ]], + [[char buf[20]; + return readlink ("conftest.lnk2/", buf, sizeof buf) != -1; + ]]) + ], [gl_cv_func_readlink_trailing_slash=yes], [gl_cv_func_readlink_trailing_slash=no], [case "$host_os" in @@ -70,8 +77,11 @@ AC_DEFUN([gl_FUNC_READLINK], AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[#include -]], [[char c; - return readlink ("conftest.link", &c, 1) != 1;]])], + ]], + [[char c; + return readlink ("conftest.link", &c, 1) != 1; + ]]) + ], [gl_cv_func_readlink_truncate=yes], [gl_cv_func_readlink_truncate=no], [case "$host_os" in @@ -102,6 +112,14 @@ AC_DEFUN([gl_FUNC_READLINK], REPLACE_READLINK=1 ;; esac + + dnl On Cygwin 3.3.6, readlink("/dev/null") returns "\\Device\\Null", which + dnl is unusable. + case "$host_os" in + cygwin*) + REPLACE_READLINK=1 + ;; + esac fi ]) diff --git a/tests/test-canonicalize-lgpl.c b/tests/test-canonicalize-lgpl.c index 21211e5eac..921fdbde70 100644 --- a/tests/test-canonicalize-lgpl.c +++ b/tests/test-canonicalize-lgpl.c @@ -281,6 +281,13 @@ main (void) free (result2); } +#if !(defined _WIN32 && !defined __CYGWIN__) + /* Check a device file. */ + { + char *result = canonicalize_file_name ("/dev/null"); + ASSERT (result != NULL); + } +#endif /* Cleanup. */ ASSERT (remove (BASE "/droot") == 0); diff --git a/tests/test-canonicalize.c b/tests/test-canonicalize.c index 5d19285c00..1ef7bb3959 100644 --- a/tests/test-canonicalize.c +++ b/tests/test-canonicalize.c @@ -419,6 +419,17 @@ main (void) free (result4); } +#if !(defined _WIN32 && !defined __CYGWIN__) + /* Check a device file. */ + { + char *result1 = canonicalize_file_name ("/dev/null"); + char *result2 = canonicalize_filename_mode ("/dev/null", CAN_ALL_BUT_LAST); + ASSERT (result1 != NULL); + ASSERT (result2 != NULL); + ASSERT (strcmp (result1, result2) == 0); + } +#endif + /* Cleanup. */ ASSERT (remove (BASE "/droot") == 0); ASSERT (remove (BASE "/d/1") == 0); diff --git a/tests/test-readlink.h b/tests/test-readlink.h index c04ae311e2..d547bec959 100644 --- a/tests/test-readlink.h +++ b/tests/test-readlink.h @@ -113,6 +113,12 @@ test_readlink (ssize_t (*func) (char const *, char *, size_t), bool print) either left alone, or NUL-terminated. */ ASSERT (buf[len] == '\0' || buf[len] == (char) 0xff); } + { + /* On Cygwin 3.3.6, readlink("/dev/null") returns "\\Device\\Null", which + is unusable. Verify that gnulib works around this nonsense. */ + ssize_t result = func ("/dev/null", buf, sizeof buf); + ASSERT (result == -1 || buf[0] != '\\'); + } ASSERT (rmdir (BASE "dir") == 0); ASSERT (unlink (BASE "link") == 0); -- 2.39.5