From: Bruno Haible Date: Mon, 3 Jun 2024 23:48:04 +0000 (+0200) Subject: readlink: Work around a Cygwin 3.3.6 bug. X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=f72f83c75a0ea544f8636a8640fe782a11bae4fb;p=gnulib.git 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. --- diff --git a/ChangeLog b/ChangeLog index 2426bb9cf8..6b4201e9ca 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 flock tests: Don't expect a failure on native Windows. diff --git a/doc/posix-functions/readlink.texi b/doc/posix-functions/readlink.texi index 31769d5598..8fde7f58a7 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 bc9a5deb06..7ebdb6ca14 100644 --- a/m4/readlink.m4 +++ b/m4/readlink.m4 @@ -1,5 +1,5 @@ # readlink.m4 -# serial 17 +# 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, @@ -8,7 +8,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 @@ -18,9 +18,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], @@ -31,8 +35,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 @@ -71,8 +78,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 @@ -103,6 +113,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 769f7c3968..923f0fb46c 100644 --- a/tests/test-canonicalize-lgpl.c +++ b/tests/test-canonicalize-lgpl.c @@ -283,6 +283,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 0224c2bbcf..71177681ae 100644 --- a/tests/test-canonicalize.c +++ b/tests/test-canonicalize.c @@ -421,6 +421,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);