bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: canonicalize-lgpl bug


From: Eric Blake
Subject: Re: canonicalize-lgpl bug
Date: Thu, 10 Sep 2009 23:24:08 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Jim Meyering <jim <at> meyering.net> writes:

> > I noticed that glibc has applied some fixes to canonicalize.c that we were
> > missing; and sure enough, was able to enhance the testsuite to trip these
> > bugs.  They also applied some assert's proving that their optimization to 
avoid
> > strcpy are safe; I left the asserts out, but copied their optimization.  OK 
to
> > commit?
> 
> Sure.
> Thanks for doing that!

Here's the current state of the series.  It still doesn't fix the bug that 
canonicalize-lgpl goofs on leading // when providing realpath.  Nor does it fix 
execution on mingw (where a good implementation need not worry about symlinks, 
but should worry about drive letters and should convert '/' to '\\').  But at 
least on cygwin, canonicalize-lgpl now honors // by virtue of deferring to the 
working native realpath.  On the other hand, cygwin realpath() behaves like all 
other cygwin functions, such as stat() and open(), where garbage/.. is silently 
collapsed whithout checking whether garbage exists or is a symlink.

Note that I've changed things around a bit - canonicalize now provides ONLY 
canonicalize_filename_mode - the coreutils extension that allows for choosing 
how strict the canonicalization needs to be (useful for implementing readlink
(1)).  Meanwhile, canonicalize-lgpl is the ONLY provider of 
canonicalize_file_name, and it ALSO provides a POSIX-compliant realpath, for 
all systems (well, if there are any live glibc systems out there where 
canonicalize_file_name("file/") still passes rather than failing with ENOENT, 
then we need a subsequent patch to introduce rpl_canonicalize_file_name).

Does anyone want further changes, such as to the names of these modules?  I 
could reasonably see renaming canonicalize to canonicalize-mode, and 
canonicalize-lgpl to either canonicalize_file_name or to realpath.  I could 
also try porting // handling to canonicalize-lgpl realpath (and propose the 
same patch upstream to glibc), although I'd rather not do that until we find a 
platform that honors // but does not have working realpath.

At any rate, I don't feel comfortable pushing this series until I have some 
reviews or more feedback, and possibly a fix to cygwin to better handle '..'.

Jim, once I apply this series, coreutils will need to either: start importing 
canonicalize-lgpl (right now, it avoids it), or change df.c to use 
canonicalize_filename_mode(,CAN_EXISTING) (perhaps via a #define in system.h).

Eric Blake (6):
      canonicalize-lgpl: reject non-directory with trailing slash
      stdlib: sort witness names
      canonicalize: leave canonicalize_file_name to canonicalize-lgpl
      canonicalize-lgpl: use native realpath if it works
      canonicalize: don't lose errno
      canonicalize: honor // if distinct from /


>From cfe26089b21bdddc721a619d4e7da550fc64e1fa Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 10 Sep 2009 12:12:16 -0600
Subject: [PATCH 1/6] canonicalize-lgpl: reject non-directory with trailing slash

* lib/canonicalize-lgpl.c (__realpath): Synchronize with glibc.
* tests/test-canonicalize-lgpl.c (main): Enhance test.
* tests/test-canonicalize.c (main): Likewise.  Avoid collisions
with test-canonicalize-lgpl.sh run in parallel.
* tests/test-canonicalize.sh (tmpfiles): Use the name ise1, not
ise, for parallel make.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                      |   10 ++++++++++
 lib/canonicalize-lgpl.c        |   11 +++++++----
 tests/test-canonicalize-lgpl.c |   16 +++++++++++++++-
 tests/test-canonicalize.c      |   26 +++++++++++++++++++++++---
 tests/test-canonicalize.sh     |    6 +++---
 5 files changed, 58 insertions(+), 11 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index c190ecc..de7b506 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2009-09-10  Eric Blake  <address@hidden>
+
+       canonicalize-lgpl: reject non-directory with trailing slash
+       * lib/canonicalize-lgpl.c (__realpath): Synchronize with glibc.
+       * tests/test-canonicalize-lgpl.c (main): Enhance test.
+       * tests/test-canonicalize.c (main): Likewise.  Avoid collisions
+       with test-canonicalize-lgpl.sh run in parallel.
+       * tests/test-canonicalize.sh (tmpfiles): Use the name ise1, not
+       ise, for parallel make.
+
 2009-09-10  Ralf Wildenhues  <address@hidden>

        Remove obsolete macros from several modules.
diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c
index 6b5663a..c8f313e 100644
--- a/lib/canonicalize-lgpl.c
+++ b/lib/canonicalize-lgpl.c
@@ -298,6 +298,11 @@ __realpath (const char *name, char *resolved)
                  while ((--dest)[-1] != '/');
            }
 #endif
+         else if (!S_ISDIR (st.st_mode) && *end != '\0')
+           {
+             __set_errno (ENOTDIR);
+             goto error;
+           }
        }
     }
   if (dest > rpath + 1 && dest[-1] == '/')
@@ -307,16 +312,14 @@ __realpath (const char *name, char *resolved)
   if (extra_buf)
     freea (extra_buf);

-  return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath;
+  return rpath;

 error:
   {
     int saved_errno = errno;
     if (extra_buf)
       freea (extra_buf);
-    if (resolved)
-      strcpy (resolved, rpath);
-    else
+    if (resolved == NULL)
       free (rpath);
     errno = saved_errno;
   }
diff --git a/tests/test-canonicalize-lgpl.c b/tests/test-canonicalize-lgpl.c
index 29b919d..87e5e46 100644
--- a/tests/test-canonicalize-lgpl.c
+++ b/tests/test-canonicalize-lgpl.c
@@ -1,5 +1,5 @@
 /* Test of execution of program termination handlers.
-   Copyright (C) 2007-2008 Free Software Foundation, Inc.
+   Copyright (C) 2007-2009 Free Software Foundation, Inc.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -79,6 +79,20 @@ main ()
     ASSERT (result == NULL);
   }

+  /* Check that a non-directory with trailing slash yields NULL.  */
+  {
+    char *result = canonicalize_file_name ("t-can-lgpl.tmp/tra/");
+    ASSERT (result == NULL);
+    result = canonicalize_file_name ("t-can-lgpl.tmp/huk/");
+    ASSERT (result == NULL);
+  }
+
+  /* Check that a missing directory yields NULL.  */
+  {
+    char *result = canonicalize_file_name ("t-can-lgpl.tmp/ouk/..");
+    ASSERT (result == NULL);
+  }
+
   /* Check that a loop of symbolic links is detected.  */
   {
     char *result = canonicalize_file_name ("ise");
diff --git a/tests/test-canonicalize.c b/tests/test-canonicalize.c
index d76c307..f0212e0 100644
--- a/tests/test-canonicalize.c
+++ b/tests/test-canonicalize.c
@@ -1,5 +1,5 @@
 /* Test of execution of file name canonicalization.
-   Copyright (C) 2007-2008 Free Software Foundation, Inc.
+   Copyright (C) 2007-2009 Free Software Foundation, Inc.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -85,10 +85,30 @@ main ()
     ASSERT (result2 == NULL);
   }

+  /* Check that a non-directory with trailing slash yields NULL.  */
+  {
+    char *result1 = canonicalize_file_name ("t-can.tmp/tra/");
+    char *result2 = canonicalize_filename_mode ("t-can.tmp/tra/", 
CAN_EXISTING);
+    ASSERT (result1 == NULL);
+    ASSERT (result2 == NULL);
+    result1 = canonicalize_file_name ("t-can.tmp/huk/");
+    result2 = canonicalize_filename_mode ("t-can.tmp/huk/", CAN_EXISTING);
+    ASSERT (result1 == NULL);
+    ASSERT (result2 == NULL);
+  }
+
+  /* Check that a missing directory yields NULL.  */
+  {
+    char *result1 = canonicalize_file_name ("t-can.tmp/ouk/..");
+    char *result2 = canonicalize_filename_mode ("t-can.tmp/ouk/..", 
CAN_EXISTING);
+    ASSERT (result1 == NULL);
+    ASSERT (result2 == NULL);
+  }
+
   /* Check that a loop of symbolic links is detected.  */
   {
-    char *result1 = canonicalize_file_name ("ise");
-    char *result2 = canonicalize_filename_mode ("ise", CAN_EXISTING);
+    char *result1 = canonicalize_file_name ("ise1");
+    char *result2 = canonicalize_filename_mode ("ise1", CAN_EXISTING);
     ASSERT (result1 == NULL);
     ASSERT (result2 == NULL);
   }
diff --git a/tests/test-canonicalize.sh b/tests/test-canonicalize.sh
index a4ab962..224ec86 100755
--- a/tests/test-canonicalize.sh
+++ b/tests/test-canonicalize.sh
@@ -3,10 +3,10 @@
 tmpfiles=""
 trap 'rm -fr $tmpfiles' 1 2 3 15

-tmpfiles="$tmpfiles t-can.tmp ise"
+tmpfiles="$tmpfiles t-can.tmp ise1"
 mkdir t-can.tmp
 test "x$HAVE_SYMLINK" = xyes \
-  && ln -s t-can.tmp/ket ise \
+  && ln -s t-can.tmp/ket ise1 \
   || { echo "Skipping test: symbolic links not supported on this filesystem"
        rm -fr $tmpfiles
        exit 77
@@ -16,7 +16,7 @@ test "x$HAVE_SYMLINK" = xyes \
  && ln -s tra huk \
  && ln -s lum bef \
  && ln -s wum ouk \
- && ln -s ../ise ket \
+ && ln -s ../ise1 ket \
  && echo > tra \
  && mkdir lum
 ) || exit 1
-- 
1.6.3.2


>From 851f2832809230b9982b3ad43f3dcabdd8e51c80 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 10 Sep 2009 14:10:41 -0600
Subject: [PATCH 2/6] stdlib: sort witness names

* modules/stdlib (Makefile.am): Sort replacements.
* m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Likewise.
* lib/stdlib.in.h: Likewise.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog       |    5 ++
 lib/stdlib.in.h |  114 +++++++++++++++++++++++--------------------------------
 m4/stdlib_h.m4  |   12 +++---
 modules/stdlib  |   12 +++---
 4 files changed, 65 insertions(+), 78 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index de7b506..03619d8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2009-09-10  Eric Blake  <address@hidden>

+       stdlib: sort witness names
+       * modules/stdlib (Makefile.am): Sort replacements.
+       * m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Likewise.
+       * lib/stdlib.in.h: Likewise.
+
        canonicalize-lgpl: reject non-directory with trailing slash
        * lib/canonicalize-lgpl.c (__realpath): Synchronize with glibc.
        * tests/test-canonicalize-lgpl.c (main): Enhance test.
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index 9ac7199..f05962e 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -87,37 +87,20 @@ struct random_data
 extern "C" {
 #endif

-
-#if @GNULIB_MALLOC_POSIX@
-# if address@hidden@
-#  undef malloc
-#  define malloc rpl_malloc
-extern void * malloc (size_t size);
-# endif
-#elif defined GNULIB_POSIXCHECK
-# undef malloc
-# define malloc(s) \
-    (GL_LINK_WARNING ("malloc is not POSIX compliant everywhere - " \
-                      "use gnulib module malloc-posix for portability"), \
-     malloc (s))
-#endif
-
-
-#if @GNULIB_REALLOC_POSIX@
-# if address@hidden@
-#  undef realloc
-#  define realloc rpl_realloc
-extern void * realloc (void *ptr, size_t size);
+#if @GNULIB_ATOLL@
+# if address@hidden@
+/* Parse a signed decimal integer.
+   Returns the value of the integer.  Errors are not detected.  */
+extern long long atoll (const char *string);
 # endif
 #elif defined GNULIB_POSIXCHECK
-# undef realloc
-# define realloc(p,s) \
-    (GL_LINK_WARNING ("realloc is not POSIX compliant everywhere - " \
-                      "use gnulib module realloc-posix for portability"), \
-     realloc (p, s))
+# undef atoll
+# define atoll(s) \
+    (GL_LINK_WARNING ("atoll is unportable - " \
+                      "use gnulib module atoll for portability"), \
+     atoll (s))
 #endif

-
 #if @GNULIB_CALLOC_POSIX@
 # if address@hidden@
 #  undef calloc
@@ -132,22 +115,6 @@ extern void * calloc (size_t nmemb, size_t size);
      calloc (n, s))
 #endif

-
-#if @GNULIB_ATOLL@
-# if address@hidden@
-/* Parse a signed decimal integer.
-   Returns the value of the integer.  Errors are not detected.  */
-extern long long atoll (const char *string);
-# endif
-#elif defined GNULIB_POSIXCHECK
-# undef atoll
-# define atoll(s) \
-    (GL_LINK_WARNING ("atoll is unportable - " \
-                      "use gnulib module atoll for portability"), \
-     atoll (s))
-#endif
-
-
 #if @GNULIB_GETLOADAVG@
 # if address@hidden@
 /* Store max(NELEM,3) load average numbers in LOADAVG[].
@@ -164,7 +131,6 @@ extern int getloadavg (double loadavg[], int nelem);
      getloadavg (l, n))
 #endif

-
 #if @GNULIB_GETSUBOPT@
 /* Assuming *OPTIONP is a comma separated list of elements of the form
    "token" or "token=value", getsubopt parses the first of these elements.
@@ -188,6 +154,19 @@ extern int getsubopt (char **optionp, char *const *tokens, 
char **valuep);
      getsubopt (o, t, v))
 #endif

+#if @GNULIB_MALLOC_POSIX@
+# if address@hidden@
+#  undef malloc
+#  define malloc rpl_malloc
+extern void * malloc (size_t size);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef malloc
+# define malloc(s) \
+    (GL_LINK_WARNING ("malloc is not POSIX compliant everywhere - " \
+                      "use gnulib module malloc-posix for portability"), \
+     malloc (s))
+#endif

 #if @GNULIB_MKDTEMP@
 # if address@hidden@
@@ -206,7 +185,6 @@ extern char * mkdtemp (char * /*template*/);
      mkdtemp (t))
 #endif

-
 #if @GNULIB_MKOSTEMP@
 # if address@hidden@
 /* Create a unique temporary file from TEMPLATE.
@@ -231,7 +209,6 @@ extern int mkostemp (char * /*template*/, int /*flags*/);
      mkostemp (t, f))
 #endif

-
 #if @GNULIB_MKSTEMP@
 # if @REPLACE_MKSTEMP@
 /* Create a unique temporary file from TEMPLATE.
@@ -257,7 +234,6 @@ extern int mkstemp (char * /*template*/);
      mkstemp (t))
 #endif

-
 #if @GNULIB_PUTENV@
 # if @REPLACE_PUTENV@
 #  undef putenv
@@ -266,7 +242,6 @@ extern int putenv (char *string);
 # endif
 #endif

-
 #if @GNULIB_RANDOM_R@
 # if address@hidden@

@@ -303,6 +278,19 @@ int random_r (struct random_data *buf, int32_t *result);
      setstate_r (a,r))
 #endif

+#if @GNULIB_REALLOC_POSIX@
+# if address@hidden@
+#  undef realloc
+#  define realloc rpl_realloc
+extern void * realloc (void *ptr, size_t size);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef realloc
+# define realloc(p,s) \
+    (GL_LINK_WARNING ("realloc is not POSIX compliant everywhere - " \
+                      "use gnulib module realloc-posix for portability"), \
+     realloc (p, s))
+#endif

 #if @GNULIB_RPMATCH@
 # if address@hidden@
@@ -318,7 +306,6 @@ extern int rpmatch (const char *response);
      rpmatch (r))
 #endif

-
 #if @GNULIB_SETENV@
 # if address@hidden@
 /* Set NAME to VALUE in the environment.
@@ -327,21 +314,6 @@ extern int setenv (const char *name, const char *value, 
int replace);
 # endif
 #endif

-
-#if @GNULIB_UNSETENV@
-# if @HAVE_UNSETENV@
-#  if @VOID_UNSETENV@
-/* On some systems, unsetenv() returns void.
-   This is the case for MacOS X 10.3, FreeBSD 4.8, NetBSD 1.6, OpenBSD 3.4.  */
-#   define unsetenv(name) ((unsetenv)(name), 0)
-#  endif
-# else
-/* Remove the variable NAME from the environment.  */
-extern int unsetenv (const char *name);
-# endif
-#endif
-
-
 #if @GNULIB_STRTOD@
 # if @REPLACE_STRTOD@
 #  define strtod rpl_strtod
@@ -358,7 +330,6 @@ extern double strtod (const char *str, char **endp);
      strtod (s, e))
 #endif

-
 #if @GNULIB_STRTOLL@
 # if address@hidden@
 /* Parse a signed integer whose textual representation starts at STRING.
@@ -379,7 +350,6 @@ extern long long strtoll (const char *string, char 
**endptr, int base);
      strtoll (s, e, b))
 #endif

-
 #if @GNULIB_STRTOULL@
 # if address@hidden@
 /* Parse an unsigned integer whose textual representation starts at STRING.
@@ -400,6 +370,18 @@ extern unsigned long long strtoull (const char *string, 
char **endptr, int base)
      strtoull (s, e, b))
 #endif

+#if @GNULIB_UNSETENV@
+# if @HAVE_UNSETENV@
+#  if @VOID_UNSETENV@
+/* On some systems, unsetenv() returns void.
+   This is the case for MacOS X 10.3, FreeBSD 4.8, NetBSD 1.6, OpenBSD 3.4.  */
+#   define unsetenv(name) ((unsetenv)(name), 0)
+#  endif
+# else
+/* Remove the variable NAME from the environment.  */
+extern int unsetenv (const char *name);
+# endif
+#endif

 #ifdef __cplusplus
 }
diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4
index 89ac97f..b7cf18c 100644
--- a/m4/stdlib_h.m4
+++ b/m4/stdlib_h.m4
@@ -1,4 +1,4 @@
-# stdlib_h.m4 serial 16
+# stdlib_h.m4 serial 17
 dnl Copyright (C) 2007-2009 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,17 +33,17 @@ AC_DEFUN([gl_STDLIB_MODULE_INDICATOR],

 AC_DEFUN([gl_STDLIB_H_DEFAULTS],
 [
-  GNULIB_MALLOC_POSIX=0;  AC_SUBST([GNULIB_MALLOC_POSIX])
-  GNULIB_REALLOC_POSIX=0; AC_SUBST([GNULIB_REALLOC_POSIX])
-  GNULIB_CALLOC_POSIX=0;  AC_SUBST([GNULIB_CALLOC_POSIX])
   GNULIB_ATOLL=0;         AC_SUBST([GNULIB_ATOLL])
+  GNULIB_CALLOC_POSIX=0;  AC_SUBST([GNULIB_CALLOC_POSIX])
   GNULIB_GETLOADAVG=0;    AC_SUBST([GNULIB_GETLOADAVG])
   GNULIB_GETSUBOPT=0;     AC_SUBST([GNULIB_GETSUBOPT])
+  GNULIB_MALLOC_POSIX=0;  AC_SUBST([GNULIB_MALLOC_POSIX])
   GNULIB_MKDTEMP=0;       AC_SUBST([GNULIB_MKDTEMP])
   GNULIB_MKOSTEMP=0;      AC_SUBST([GNULIB_MKOSTEMP])
   GNULIB_MKSTEMP=0;       AC_SUBST([GNULIB_MKSTEMP])
   GNULIB_PUTENV=0;        AC_SUBST([GNULIB_PUTENV])
   GNULIB_RANDOM_R=0;      AC_SUBST([GNULIB_RANDOM_R])
+  GNULIB_REALLOC_POSIX=0; AC_SUBST([GNULIB_REALLOC_POSIX])
   GNULIB_RPMATCH=0;       AC_SUBST([GNULIB_RPMATCH])
   GNULIB_SETENV=0;        AC_SUBST([GNULIB_SETENV])
   GNULIB_STRTOD=0;        AC_SUBST([GNULIB_STRTOD])
@@ -53,12 +53,13 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_ATOLL=1;              AC_SUBST([HAVE_ATOLL])
   HAVE_CALLOC_POSIX=1;       AC_SUBST([HAVE_CALLOC_POSIX])
+  HAVE_DECL_GETLOADAVG=1;    AC_SUBST([HAVE_DECL_GETLOADAVG])
   HAVE_GETSUBOPT=1;          AC_SUBST([HAVE_GETSUBOPT])
   HAVE_MALLOC_POSIX=1;       AC_SUBST([HAVE_MALLOC_POSIX])
   HAVE_MKDTEMP=1;            AC_SUBST([HAVE_MKDTEMP])
   HAVE_MKOSTEMP=1;           AC_SUBST([HAVE_MKOSTEMP])
-  HAVE_REALLOC_POSIX=1;      AC_SUBST([HAVE_REALLOC_POSIX])
   HAVE_RANDOM_R=1;           AC_SUBST([HAVE_RANDOM_R])
+  HAVE_REALLOC_POSIX=1;      AC_SUBST([HAVE_REALLOC_POSIX])
   HAVE_RPMATCH=1;            AC_SUBST([HAVE_RPMATCH])
   HAVE_SETENV=1;             AC_SUBST([HAVE_SETENV])
   HAVE_STRTOD=1;             AC_SUBST([HAVE_STRTOD])
@@ -67,7 +68,6 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   HAVE_STRUCT_RANDOM_DATA=1; AC_SUBST([HAVE_STRUCT_RANDOM_DATA])
   HAVE_SYS_LOADAVG_H=0;      AC_SUBST([HAVE_SYS_LOADAVG_H])
   HAVE_UNSETENV=1;           AC_SUBST([HAVE_UNSETENV])
-  HAVE_DECL_GETLOADAVG=1;    AC_SUBST([HAVE_DECL_GETLOADAVG])
   REPLACE_MKSTEMP=0;         AC_SUBST([REPLACE_MKSTEMP])
   REPLACE_PUTENV=0;          AC_SUBST([REPLACE_PUTENV])
   REPLACE_STRTOD=0;          AC_SUBST([REPLACE_STRTOD])
diff --git a/modules/stdlib b/modules/stdlib
index c19d7d6..b15f9ae 100644
--- a/modules/stdlib
+++ b/modules/stdlib
@@ -26,18 +26,17 @@ stdlib.h: stdlib.in.h
          sed -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''NEXT_STDLIB_H''@|$(NEXT_STDLIB_H)|g' \
-             -e 's|@''HAVE_RANDOM_H''@|$(HAVE_RANDOM_H)|g' \
-             -e 's|@''GNULIB_MALLOC_POSIX''@|$(GNULIB_MALLOC_POSIX)|g' \
-             -e 's|@''GNULIB_REALLOC_POSIX''@|$(GNULIB_REALLOC_POSIX)|g' \
-             -e 's|@''GNULIB_CALLOC_POSIX''@|$(GNULIB_CALLOC_POSIX)|g' \
              -e 's|@''GNULIB_ATOLL''@|$(GNULIB_ATOLL)|g' \
+             -e 's|@''GNULIB_CALLOC_POSIX''@|$(GNULIB_CALLOC_POSIX)|g' \
              -e 's|@''GNULIB_GETLOADAVG''@|$(GNULIB_GETLOADAVG)|g' \
              -e 's|@''GNULIB_GETSUBOPT''@|$(GNULIB_GETSUBOPT)|g' \
+             -e 's|@''GNULIB_MALLOC_POSIX''@|$(GNULIB_MALLOC_POSIX)|g' \
              -e 's|@''GNULIB_MKDTEMP''@|$(GNULIB_MKDTEMP)|g' \
              -e 's|@''GNULIB_MKOSTEMP''@|$(GNULIB_MKOSTEMP)|g' \
              -e 's|@''GNULIB_MKSTEMP''@|$(GNULIB_MKSTEMP)|g' \
              -e 's|@''GNULIB_PUTENV''@|$(GNULIB_PUTENV)|g' \
              -e 's|@''GNULIB_RANDOM_R''@|$(GNULIB_RANDOM_R)|g' \
+             -e 's|@''GNULIB_REALLOC_POSIX''@|$(GNULIB_REALLOC_POSIX)|g' \
              -e 's|@''GNULIB_RPMATCH''@|$(GNULIB_RPMATCH)|g' \
              -e 's|@''GNULIB_SETENV''@|$(GNULIB_SETENV)|g' \
              -e 's|@''GNULIB_STRTOD''@|$(GNULIB_STRTOD)|g' \
@@ -46,12 +45,14 @@ stdlib.h: stdlib.in.h
              -e 's|@''GNULIB_UNSETENV''@|$(GNULIB_UNSETENV)|g' \
              -e 's|@''HAVE_ATOLL''@|$(HAVE_ATOLL)|g' \
              -e 's|@''HAVE_CALLOC_POSIX''@|$(HAVE_CALLOC_POSIX)|g' \
+             -e 's|@''HAVE_DECL_GETLOADAVG''@|$(HAVE_DECL_GETLOADAVG)|g' \
              -e 's|@''HAVE_GETSUBOPT''@|$(HAVE_GETSUBOPT)|g' \
              -e 's|@''HAVE_MALLOC_POSIX''@|$(HAVE_MALLOC_POSIX)|g' \
              -e 's|@''HAVE_MKDTEMP''@|$(HAVE_MKDTEMP)|g' \
              -e 's|@''HAVE_MKOSTEMP''@|$(HAVE_MKOSTEMP)|g' \
-             -e 's|@''HAVE_REALLOC_POSIX''@|$(HAVE_REALLOC_POSIX)|g' \
+             -e 's|@''HAVE_RANDOM_H''@|$(HAVE_RANDOM_H)|g' \
              -e 's|@''HAVE_RANDOM_R''@|$(HAVE_RANDOM_R)|g' \
+             -e 's|@''HAVE_REALLOC_POSIX''@|$(HAVE_REALLOC_POSIX)|g' \
              -e 's|@''HAVE_RPMATCH''@|$(HAVE_RPMATCH)|g' \
              -e 's|@''HAVE_SETENV''@|$(HAVE_SETENV)|g' \
              -e 's|@''HAVE_STRTOD''@|$(HAVE_STRTOD)|g' \
@@ -60,7 +61,6 @@ stdlib.h: stdlib.in.h
              -e 's|@''HAVE_STRUCT_RANDOM_DATA''@|$(HAVE_STRUCT_RANDOM_DATA)|g' 
\
              -e 's|@''HAVE_SYS_LOADAVG_H''@|$(HAVE_SYS_LOADAVG_H)|g' \
              -e 's|@''HAVE_UNSETENV''@|$(HAVE_UNSETENV)|g' \
-             -e 's|@''HAVE_DECL_GETLOADAVG''@|$(HAVE_DECL_GETLOADAVG)|g' \
              -e 's|@''REPLACE_MKSTEMP''@|$(REPLACE_MKSTEMP)|g' \
              -e 's|@''REPLACE_PUTENV''@|$(REPLACE_PUTENV)|g' \
              -e 's|@''REPLACE_STRTOD''@|$(REPLACE_STRTOD)|g' \
-- 
1.6.3.2


>From eb85e26d8c819b00497a53853aba9612438e5012 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 10 Sep 2009 15:04:22 -0600
Subject: [PATCH 3/6] canonicalize: leave canonicalize_file_name to canonicalize-
lgpl

* m4/canonicalize.m4 (AC_FUNC_CANONICALIZE_FILE_NAME): Rename...
(gl_FUNC_CANONICALIZE_FILENAME_MODE): ...to this.  Drop unneeded
checks.
* modules/canonicalize (configure.ac): Deal with renamed macro.
(Depends-on): Drop filenamecat.
* modules/canonicalize-tests (Depends-on): Add canonicalize-lgpl.
* lib/canonicalize.c (canonicalize_file_name): Delete.
* NEWS: Document this.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                  |   10 ++++++
 NEWS                       |    4 ++
 lib/canonicalize.c         |   75 --------------------------------------------
 m4/canonicalize.m4         |   10 ++---
 modules/canonicalize       |    5 +--
 modules/canonicalize-tests |    1 +
 6 files changed, 21 insertions(+), 84 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 03619d8..2f3f391 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2009-09-10  Eric Blake  <address@hidden>

+       canonicalize: leave canonicalize_file_name to canonicalize-lgpl
+       * m4/canonicalize.m4 (AC_FUNC_CANONICALIZE_FILE_NAME): Rename...
+       (gl_FUNC_CANONICALIZE_FILENAME_MODE): ...to this.  Drop unneeded
+       checks.
+       * modules/canonicalize (configure.ac): Deal with renamed macro.
+       (Depends-on): Drop filenamecat.
+       * modules/canonicalize-tests (Depends-on): Add canonicalize-lgpl.
+       * lib/canonicalize.c (canonicalize_file_name): Delete.
+       * NEWS: Document this.
+
        stdlib: sort witness names
        * modules/stdlib (Makefile.am): Sort replacements.
        * m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Likewise.
diff --git a/NEWS b/NEWS
index f506cba..1ccdaea 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,10 @@ User visible incompatible changes

 Date        Modules         Changes

+2009-09-10  canonicalize    This module no longer provides
+                            canonicalize_file_name; use the canonicalize-lgpl
+                            module for that.
+
 2009-09-04  link-follow     The macro LINK_FOLLOWS_SYMLINK is now tri-state,
                             rather than only defined to 1.

diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 523e082..1312ff2 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -33,7 +33,6 @@
 #include <stddef.h>

 #include "file-set.h"
-#include "filenamecat.h"
 #include "hash-triple.h"
 #include "xalloc.h"
 #include "xgetcwd.h"
@@ -45,80 +44,6 @@
 #include "pathmax.h"
 #include "areadlink.h"

-#if !(HAVE_CANONICALIZE_FILE_NAME || GNULIB_CANONICALIZE_LGPL)
-/* Return the canonical absolute name of file NAME.  A canonical name
-   does not contain any `.', `..' components nor any repeated file name
-   separators ('/') or symlinks.  All components must exist.
-   The result is malloc'd.  */
-
-char *
-canonicalize_file_name (const char *name)
-{
-# if HAVE_RESOLVEPATH
-
-  char *resolved, *extra_buf = NULL;
-  size_t resolved_size;
-  ssize_t resolved_len;
-
-  if (name == NULL)
-    {
-      __set_errno (EINVAL);
-      return NULL;
-    }
-
-  if (name[0] == '\0')
-    {
-      __set_errno (ENOENT);
-      return NULL;
-    }
-
-  /* All known hosts with resolvepath (e.g. Solaris 7) don't turn
-     relative names into absolute ones, so prepend the working
-     directory if the file name is not absolute.  */
-  if (name[0] != '/')
-    {
-      char *wd;
-
-      if (!(wd = xgetcwd ()))
-       return NULL;
-
-      extra_buf = file_name_concat (wd, name, NULL);
-      name = extra_buf;
-      free (wd);
-    }
-
-  resolved_size = strlen (name);
-  while (1)
-    {
-      resolved_size = 2 * resolved_size + 1;
-      resolved = xmalloc (resolved_size);
-      resolved_len = resolvepath (name, resolved, resolved_size);
-      if (resolved_len < 0)
-       {
-         free (resolved);
-         free (extra_buf);
-         return NULL;
-       }
-      if (resolved_len < resolved_size)
-       break;
-      free (resolved);
-    }
-
-  free (extra_buf);
-
-  /* NUL-terminate the resulting name.  */
-  resolved[resolved_len] = '\0';
-
-  return resolved;
-
-# else
-
-  return canonicalize_filename_mode (name, CAN_EXISTING);
-
-# endif /* !HAVE_RESOLVEPATH */
-}
-#endif /* !HAVE_CANONICALIZE_FILE_NAME */
-
 /* Return true if we've already seen the triple, <FILENAME, dev, ino>.
    If *HT is not initialized, initialize it.  */
 static bool
diff --git a/m4/canonicalize.m4 b/m4/canonicalize.m4
index 817edd5..b6f2341 100644
--- a/m4/canonicalize.m4
+++ b/m4/canonicalize.m4
@@ -1,17 +1,15 @@
-#serial 12
+#serial 13

-# Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+# Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Free Software
+# Foundation, Inc.
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.

 # Written by Jim Meyering.

-AC_DEFUN([AC_FUNC_CANONICALIZE_FILE_NAME],
+AC_DEFUN([gl_FUNC_CANONICALIZE_FILENAME_MODE],
   [
     AC_LIBOBJ([canonicalize])
-
     AC_CHECK_HEADERS_ONCE([sys/param.h])
-    AC_CHECK_DECLS_ONCE([canonicalize_file_name])
-    AC_CHECK_FUNCS_ONCE([canonicalize_file_name resolvepath])
   ])
diff --git a/modules/canonicalize b/modules/canonicalize
index e24be3d..467ff10 100644
--- a/modules/canonicalize
+++ b/modules/canonicalize
@@ -1,5 +1,5 @@
 Description:
-Return the canonical absolute name of a given file.
+Return the canonical name of a file, with various levels of resolution.

 Files:
 lib/canonicalize.h
@@ -11,7 +11,6 @@ Depends-on:
 areadlink-with-size
 errno
 file-set
-filenamecat
 hash-triple
 memmove
 sys_stat
@@ -19,7 +18,7 @@ xalloc
 xgetcwd

 configure.ac:
-AC_FUNC_CANONICALIZE_FILE_NAME
+gl_FUNC_CANONICALIZE_FILENAME_MODE
 gl_MODULE_INDICATOR([canonicalize])

 Makefile.am:
diff --git a/modules/canonicalize-tests b/modules/canonicalize-tests
index e8dfec7..9c539c6 100644
--- a/modules/canonicalize-tests
+++ b/modules/canonicalize-tests
@@ -3,6 +3,7 @@ tests/test-canonicalize.sh
 tests/test-canonicalize.c

 Depends-on:
+canonicalize-lgpl

 configure.ac:
 AC_CHECK_FUNCS_ONCE([symlink])
-- 
1.6.3.2


>From 1a13f821aad1c258c442dfa88517d236fb872a6e Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 10 Sep 2009 15:44:15 -0600
Subject: [PATCH 4/6] canonicalize-lgpl: use native realpath if it works

* lib/canonicalize-lgpl.c (realpath): Protect definition with
FUNC_REALPATH_WORKS.
(MAXSYMLINKS): Also consult SYMLOOP_MAX.
* lib/stdlib.in.h (canonicalize_file_name, realpath): Declare.
* modules/stdlib (Makefile.am): Substitute witnesses.
* m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Provide defaults.
* modules/canonicalize-lgpl (Files): Drop canonicalize.h.
(Depends-on): Add extensions, stdlib.
(configure.ac): Mention functions we provide.
(Include): Mention <stdlib.h>.
* m4/canonicalize-lgpl.m4 (gl_CANONICALIZE_LGPL_SEPARATE): No need
to check for declaration of canonicalize_file_name.
(gl_CANONICALIZE_LGPL): Likewise.  Don't define realpath, but do
check that it works.  Set gnulib witnesses.
(gl_PREREQ_CANONICALIZE_LGPL): Assume unistd.h.
* lib/canonicalize.h (canonicalize_file_name): Drop declaration.
* tests/test-canonicalize-lgpl.c (includes): Use <stdlib.h>.
* NEWS: Document this.
* doc/glibc-functions/canonicalize_file_name.texi
(canonicalize_file_name): Likewise.
* doc/posix-functions/realpath.texi (realpath): Likewise.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                                       |   23 +++++++++++++++
 NEWS                                            |    4 ++
 doc/glibc-functions/canonicalize_file_name.texi |    8 ++--
 doc/posix-functions/realpath.texi               |   21 ++++++++-----
 lib/canonicalize-lgpl.c                         |   22 ++++++--------
 lib/canonicalize.h                              |   15 +---------
 lib/stdlib.in.h                                 |   27 +++++++++++++++++
 m4/canonicalize-lgpl.m4                         |   35 +++++++++++++++++++----
 m4/stdlib_h.m4                                  |    7 ++++-
 modules/canonicalize-lgpl                       |    9 ++++--
 modules/stdlib                                  |    5 +++
 tests/test-canonicalize-lgpl.c                  |    3 +-
 12 files changed, 129 insertions(+), 50 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 2f3f391..c06de6f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,28 @@
 2009-09-10  Eric Blake  <address@hidden>

+       canonicalize-lgpl: use native realpath if it works
+       * lib/canonicalize-lgpl.c (realpath): Protect definition with
+       FUNC_REALPATH_WORKS.
+       (MAXSYMLINKS): Also consult SYMLOOP_MAX.
+       * lib/stdlib.in.h (canonicalize_file_name, realpath): Declare.
+       * modules/stdlib (Makefile.am): Substitute witnesses.
+       * m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Provide defaults.
+       * modules/canonicalize-lgpl (Files): Drop canonicalize.h.
+       (Depends-on): Add extensions, stdlib.
+       (configure.ac): Mention functions we provide.
+       (Include): Mention <stdlib.h>.
+       * m4/canonicalize-lgpl.m4 (gl_CANONICALIZE_LGPL_SEPARATE): No need
+       to check for declaration of canonicalize_file_name.
+       (gl_CANONICALIZE_LGPL): Likewise.  Don't define realpath, but do
+       check that it works.  Set gnulib witnesses.
+       (gl_PREREQ_CANONICALIZE_LGPL): Assume unistd.h.
+       * lib/canonicalize.h (canonicalize_file_name): Drop declaration.
+       * tests/test-canonicalize-lgpl.c (includes): Use <stdlib.h>.
+       * NEWS: Document this.
+       * doc/glibc-functions/canonicalize_file_name.texi
+       (canonicalize_file_name): Likewise.
+       * doc/posix-functions/realpath.texi (realpath): Likewise.
+
        canonicalize: leave canonicalize_file_name to canonicalize-lgpl
        * m4/canonicalize.m4 (AC_FUNC_CANONICALIZE_FILE_NAME): Rename...
        (gl_FUNC_CANONICALIZE_FILENAME_MODE): ...to this.  Drop unneeded
diff --git a/NEWS b/NEWS
index 1ccdaea..9b67d72 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,10 @@ User visible incompatible changes

 Date        Modules         Changes

+2009-09-10  canonicalize-lgpl
+                            The include file is changed from "canonicalize.h"
+                            to <stdlib.h>.
+
 2009-09-10  canonicalize    This module no longer provides
                             canonicalize_file_name; use the canonicalize-lgpl
                             module for that.
diff --git a/doc/glibc-functions/canonicalize_file_name.texi b/doc/glibc-
functions/canonicalize_file_name.texi
index c19a9b1..f034f81 100644
--- a/doc/glibc-functions/canonicalize_file_name.texi
+++ b/doc/glibc-functions/canonicalize_file_name.texi
@@ -2,15 +2,15 @@ canonicalize_file_name
 @subsection @code{canonicalize_file_name}
 @findex canonicalize_file_name

-Gnulib module: ---
+Gnulib module: canonicalize-lgpl

 Portability problems fixed by Gnulib:
 @itemize
address@hidden
+This function is missing on all non-glibc platforms:
+MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 
6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, Interix 3.5, BeOS.
 @end itemize

 Portability problems not fixed by Gnulib:
 @itemize
address@hidden
-This function is missing on all non-glibc platforms:
-MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 
6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, Interix 3.5, BeOS.
 @end itemize
diff --git a/doc/posix-functions/realpath.texi b/doc/posix-
functions/realpath.texi
index 2515254..01ce781 100644
--- a/doc/posix-functions/realpath.texi
+++ b/doc/posix-functions/realpath.texi
@@ -4,22 +4,27 @@ realpath

 POSIX specification: @url
{http://www.opengroup.org/onlinepubs/9699919799/functions/realpath.html}

-Gnulib module: ---
+Gnulib module: canonicalize-lgpl

 Portability problems fixed by Gnulib:
 @itemize
address@hidden
+This function is missing on some platforms:
+mingw, BeOS.
address@hidden
+This function does not allow for a NULL @samp{resolved} parameter on
+some platforms:
+Solaris.
address@hidden
+This function does not always return an absolute path on some
+platforms:
+Solaris.
 @end itemize

 Portability problems not fixed by Gnulib:
 @itemize
 @item
-This function is missing on some platforms:
-mingw, BeOS.
address@hidden
 This function does not allow to determine the required size of output buffer;
+the use of a non-NULL @samp{resolved} buffer is non-portable, since
 PATH_MAX --- if it is defined --- is nothing more than a guess.
 @end itemize
-
-Extension: Gnulib provides a module @samp{canonicalize-lgpl} that defines a
-function @code{canonicalize_file_name} that is like @code{realpath} but without
-size limitations.
diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c
index c8f313e..3c134b0 100644
--- a/lib/canonicalize-lgpl.c
+++ b/lib/canonicalize-lgpl.c
@@ -17,24 +17,16 @@

 #include <config.h>

-/* Avoid a clash of our rpl_realpath() function with the prototype in
-   <stdlib.h> on Solaris 2.5.1.  */
-#undef realpath
-
 #if !HAVE_CANONICALIZE_FILE_NAME || defined _LIBC

 #include <alloca.h>

 /* Specification.  */
-#include "canonicalize.h"
+#include <stdlib.h>

 #include <stddef.h>
-#include <stdlib.h>
 #include <string.h>
-
-#if HAVE_UNISTD_H || defined _LIBC
-# include <unistd.h>
-#endif
+#include <unistd.h>

 #include <limits.h>

@@ -42,7 +34,11 @@
 # include <sys/param.h>
 #endif
 #ifndef MAXSYMLINKS
-# define MAXSYMLINKS 20
+# ifdef SYMLOOP_MAX
+#  define MAXSYMLINKS SYMLOOP_MAX
+# else
+#  define MAXSYMLINKS 20
+# endif
 #endif

 #include <sys/stat.h>
@@ -60,7 +56,7 @@
 # define compat_symbol(lib, local, symbol, version)
 # define weak_alias(local, symbol)
 # define __canonicalize_file_name canonicalize_file_name
-# define __realpath rpl_realpath
+# define __realpath realpath
 # include "pathmax.h"
 # include "malloca.h"
 # if HAVE_GETCWD
@@ -80,6 +76,7 @@
 # endif
 #endif

+#if !FUNC_REALPATH_WORKS
 /* Return the canonical absolute name of file NAME.  A canonical name
    does not contain any `.', `..' components nor any repeated path
    separators ('/') or symlinks.  All path components must exist.  If
@@ -328,6 +325,7 @@ error:
 #ifdef _LIBC
 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
 #endif
+#endif /* !FUNC_REALPATH_WORKS */


 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
diff --git a/lib/canonicalize.h b/lib/canonicalize.h
index 8ca4fb4..9ab2826 100644
--- a/lib/canonicalize.h
+++ b/lib/canonicalize.h
@@ -1,5 +1,5 @@
 /* Return the canonical absolute name of a given file.
-   Copyright (C) 1996-2007 Free Software Foundation, Inc.
+   Copyright (C) 1996-2007, 2009 Free Software Foundation, Inc.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -17,7 +17,6 @@
 #ifndef CANONICALIZE_H_
 # define CANONICALIZE_H_

-# if GNULIB_CANONICALIZE
 enum canonicalize_mode_t
   {
     /* All components must exist.  */
@@ -36,17 +35,5 @@ typedef enum canonicalize_mode_t canonicalize_mode_t;
    whether components must exist depends on the canonicalize_mode_t
    argument.  */
 char *canonicalize_filename_mode (const char *, canonicalize_mode_t);
-# endif
-
-# if HAVE_DECL_CANONICALIZE_FILE_NAME
-#  include <stdlib.h>
-# else
-/* Return a malloc'd string containing the canonical absolute name of
-   the named file.  If any file name component does not exist or is a
-   symlink to a nonexistent file, return NULL.  A canonical name does
-   not contain any `.', `..' components nor any repeated file name
-   separators ('/') or symlinks.  */
-char *canonicalize_file_name (const char *);
-# endif

 #endif /* !CANONICALIZE_H_ */
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index f05962e..13088ac 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -115,6 +115,18 @@ extern void * calloc (size_t nmemb, size_t size);
      calloc (n, s))
 #endif

+#if @GNULIB_CANONICALIZE_FILE_NAME@
+# if address@hidden@
+extern char *canonicalize_file_name (const char *name);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef canonicalize_file_name
+# define canonicalize_file_name(n)                        \
+    (GL_LINK_WARNING ("canonicalize_file_name is unportable - " \
+                      "use gnulib module canonicalize-lgpl for portability"), \
+     canonicalize_file_name (n))
+#endif
+
 #if @GNULIB_GETLOADAVG@
 # if address@hidden@
 /* Store max(NELEM,3) load average numbers in LOADAVG[].
@@ -292,6 +304,21 @@ extern void * realloc (void *ptr, size_t size);
      realloc (p, s))
 #endif

+#if @GNULIB_REALPATH@
+# if @REPLACE_REALPATH@
+#  define realpath rpl_realpath
+# endif
+# if address@hidden@ || @REPLACE_REALPATH@
+extern char *realpath (const char *name, char *resolved);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef realpath
+# define realpath(n,r)                        \
+    (GL_LINK_WARNING ("realpath is unportable - " \
+                      "use gnulib module canonicalize-lgpl for portability"), \
+     realpath (n, r))
+#endif
+
 #if @GNULIB_RPMATCH@
 # if address@hidden@
 /* Test a user response to a question.
diff --git a/m4/canonicalize-lgpl.m4 b/m4/canonicalize-lgpl.m4
index 3a8ee2f..85f7d76 100644
--- a/m4/canonicalize-lgpl.m4
+++ b/m4/canonicalize-lgpl.m4
@@ -8,12 +8,35 @@ AC_DEFUN([gl_CANONICALIZE_LGPL],
 [
   dnl Do this replacement check manually because the file name is shorter
   dnl than the function name.
-  AC_CHECK_DECLS_ONCE([canonicalize_file_name])
-  AC_CHECK_FUNCS_ONCE([canonicalize_file_name])
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_CHECK_FUNCS_ONCE([canonicalize_file_name realpath])
+  dnl Assume that all platforms with canonicalize_file_name also have
+  dnl a working realpath.
   if test $ac_cv_func_canonicalize_file_name = no; then
+    HAVE_CANONICALIZE_FILE_NAME=0
     AC_LIBOBJ([canonicalize-lgpl])
-    AC_DEFINE([realpath], [rpl_realpath],
-      [Define to a replacement function name for realpath().])
+    if test $ac_cv_func_realpath = no; then
+      HAVE_REALPATH=0
+    else
+      AC_CACHE_CHECK([whether realpath works], [gl_cv_func_realpath_works], [
+        touch conftest.a
+        AC_RUN_IFELSE([
+          AC_LANG_PROGRAM([[
+            #include <stdlib.h>
+          ]], [[
+            char *name = realpath ("conftest.a", NULL);
+            return !(name && *name == '/');
+          ]])
+        ], [gl_cv_func_realpath_works=yes], [gl_cv_func_realpath_works=no],
+           [gl_cv_func_realpath_works="guessing no"])
+      ])
+      if test $gl_cv_func_realpath_works != yes; then
+        REPLACE_REALPATH=1
+      else
+        AC_DEFINE([FUNC_REALPATH_WORKS], [1], [Define to 1 if realpath()
+          can malloc memory and always gives an absolute path.])
+      fi
+    fi
     gl_PREREQ_CANONICALIZE_LGPL
   fi
 ])
@@ -22,7 +45,7 @@ AC_DEFUN([gl_CANONICALIZE_LGPL],
 # (no AC_LIBOBJ).
 AC_DEFUN([gl_CANONICALIZE_LGPL_SEPARATE],
 [
-  AC_CHECK_DECLS_ONCE([canonicalize_file_name])
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   AC_CHECK_FUNCS_ONCE([canonicalize_file_name])
   gl_PREREQ_CANONICALIZE_LGPL
 ])
@@ -30,6 +53,6 @@ AC_DEFUN([gl_CANONICALIZE_LGPL_SEPARATE],
 # Prerequisites of lib/canonicalize-lgpl.c.
 AC_DEFUN([gl_PREREQ_CANONICALIZE_LGPL],
 [
-  AC_CHECK_HEADERS_ONCE([sys/param.h unistd.h])
+  AC_CHECK_HEADERS_ONCE([sys/param.h])
   AC_CHECK_FUNCS_ONCE([getcwd readlink])
 ])
diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4
index b7cf18c..9ac7383 100644
--- a/m4/stdlib_h.m4
+++ b/m4/stdlib_h.m4
@@ -1,4 +1,4 @@
-# stdlib_h.m4 serial 17
+# stdlib_h.m4 serial 18
 dnl Copyright (C) 2007-2009 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -35,6 +35,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
 [
   GNULIB_ATOLL=0;         AC_SUBST([GNULIB_ATOLL])
   GNULIB_CALLOC_POSIX=0;  AC_SUBST([GNULIB_CALLOC_POSIX])
+  GNULIB_CANONICALIZE_FILE_NAME=0;  AC_SUBST([GNULIB_CANONICALIZE_FILE_NAME])
   GNULIB_GETLOADAVG=0;    AC_SUBST([GNULIB_GETLOADAVG])
   GNULIB_GETSUBOPT=0;     AC_SUBST([GNULIB_GETSUBOPT])
   GNULIB_MALLOC_POSIX=0;  AC_SUBST([GNULIB_MALLOC_POSIX])
@@ -44,6 +45,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   GNULIB_PUTENV=0;        AC_SUBST([GNULIB_PUTENV])
   GNULIB_RANDOM_R=0;      AC_SUBST([GNULIB_RANDOM_R])
   GNULIB_REALLOC_POSIX=0; AC_SUBST([GNULIB_REALLOC_POSIX])
+  GNULIB_REALPATH=0;      AC_SUBST([GNULIB_REALPATH])
   GNULIB_RPMATCH=0;       AC_SUBST([GNULIB_RPMATCH])
   GNULIB_SETENV=0;        AC_SUBST([GNULIB_SETENV])
   GNULIB_STRTOD=0;        AC_SUBST([GNULIB_STRTOD])
@@ -53,6 +55,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_ATOLL=1;              AC_SUBST([HAVE_ATOLL])
   HAVE_CALLOC_POSIX=1;       AC_SUBST([HAVE_CALLOC_POSIX])
+  HAVE_CANONICALIZE_FILE_NAME=1;  AC_SUBST([HAVE_CANONICALIZE_FILE_NAME])
   HAVE_DECL_GETLOADAVG=1;    AC_SUBST([HAVE_DECL_GETLOADAVG])
   HAVE_GETSUBOPT=1;          AC_SUBST([HAVE_GETSUBOPT])
   HAVE_MALLOC_POSIX=1;       AC_SUBST([HAVE_MALLOC_POSIX])
@@ -60,6 +63,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   HAVE_MKOSTEMP=1;           AC_SUBST([HAVE_MKOSTEMP])
   HAVE_RANDOM_R=1;           AC_SUBST([HAVE_RANDOM_R])
   HAVE_REALLOC_POSIX=1;      AC_SUBST([HAVE_REALLOC_POSIX])
+  HAVE_REALPATH=1;           AC_SUBST([HAVE_REALPATH])
   HAVE_RPMATCH=1;            AC_SUBST([HAVE_RPMATCH])
   HAVE_SETENV=1;             AC_SUBST([HAVE_SETENV])
   HAVE_STRTOD=1;             AC_SUBST([HAVE_STRTOD])
@@ -70,6 +74,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   HAVE_UNSETENV=1;           AC_SUBST([HAVE_UNSETENV])
   REPLACE_MKSTEMP=0;         AC_SUBST([REPLACE_MKSTEMP])
   REPLACE_PUTENV=0;          AC_SUBST([REPLACE_PUTENV])
+  REPLACE_REALPATH=0;        AC_SUBST([REPLACE_REALPATH])
   REPLACE_STRTOD=0;          AC_SUBST([REPLACE_STRTOD])
   VOID_UNSETENV=0;           AC_SUBST([VOID_UNSETENV])
 ])
diff --git a/modules/canonicalize-lgpl b/modules/canonicalize-lgpl
index b462c61..88d1602 100644
--- a/modules/canonicalize-lgpl
+++ b/modules/canonicalize-lgpl
@@ -1,26 +1,29 @@
 Description:
-Canonical absolute file name (LGPLed version).
+realpath, canonical_file_name: Provide canonical absolute file name

 Files:
-lib/canonicalize.h
 lib/canonicalize-lgpl.c
 m4/canonicalize-lgpl.m4

 Depends-on:
 alloca-opt
+extensions
 malloca
 memmove
 pathmax
 readlink
+stdlib

 configure.ac:
 gl_CANONICALIZE_LGPL
 gl_MODULE_INDICATOR([canonicalize-lgpl])
+gl_STDLIB_MODULE_INDICATOR([canonicalize_file_name])
+gl_STDLIB_MODULE_INDICATOR([realpath])

 Makefile.am:

 Include:
-"canonicalize.h"
+<stdlib.h>

 License:
 LGPLv2+
diff --git a/modules/stdlib b/modules/stdlib
index b15f9ae..7de2cb0 100644
--- a/modules/stdlib
+++ b/modules/stdlib
@@ -28,6 +28,7 @@ stdlib.h: stdlib.in.h
              -e 's|@''NEXT_STDLIB_H''@|$(NEXT_STDLIB_H)|g' \
              -e 's|@''GNULIB_ATOLL''@|$(GNULIB_ATOLL)|g' \
              -e 's|@''GNULIB_CALLOC_POSIX''@|$(GNULIB_CALLOC_POSIX)|g' \
+             -
e 's|@''GNULIB_CANONICALIZE_FILE_NAME''@|$(GNULIB_CANONICALIZE_FILE_NAME)|g' \
              -e 's|@''GNULIB_GETLOADAVG''@|$(GNULIB_GETLOADAVG)|g' \
              -e 's|@''GNULIB_GETSUBOPT''@|$(GNULIB_GETSUBOPT)|g' \
              -e 's|@''GNULIB_MALLOC_POSIX''@|$(GNULIB_MALLOC_POSIX)|g' \
@@ -37,6 +38,7 @@ stdlib.h: stdlib.in.h
              -e 's|@''GNULIB_PUTENV''@|$(GNULIB_PUTENV)|g' \
              -e 's|@''GNULIB_RANDOM_R''@|$(GNULIB_RANDOM_R)|g' \
              -e 's|@''GNULIB_REALLOC_POSIX''@|$(GNULIB_REALLOC_POSIX)|g' \
+             -e 's|@''GNULIB_REALPATH''@|$(GNULIB_REALPATH)|g' \
              -e 's|@''GNULIB_RPMATCH''@|$(GNULIB_RPMATCH)|g' \
              -e 's|@''GNULIB_SETENV''@|$(GNULIB_SETENV)|g' \
              -e 's|@''GNULIB_STRTOD''@|$(GNULIB_STRTOD)|g' \
@@ -45,6 +47,7 @@ stdlib.h: stdlib.in.h
              -e 's|@''GNULIB_UNSETENV''@|$(GNULIB_UNSETENV)|g' \
              -e 's|@''HAVE_ATOLL''@|$(HAVE_ATOLL)|g' \
              -e 's|@''HAVE_CALLOC_POSIX''@|$(HAVE_CALLOC_POSIX)|g' \
+             -
e 's|@''HAVE_CANONICALIZE_FILE_NAME''@|$(HAVE_CANONICALIZE_FILE_NAME)|g' \
              -e 's|@''HAVE_DECL_GETLOADAVG''@|$(HAVE_DECL_GETLOADAVG)|g' \
              -e 's|@''HAVE_GETSUBOPT''@|$(HAVE_GETSUBOPT)|g' \
              -e 's|@''HAVE_MALLOC_POSIX''@|$(HAVE_MALLOC_POSIX)|g' \
@@ -53,6 +56,7 @@ stdlib.h: stdlib.in.h
              -e 's|@''HAVE_RANDOM_H''@|$(HAVE_RANDOM_H)|g' \
              -e 's|@''HAVE_RANDOM_R''@|$(HAVE_RANDOM_R)|g' \
              -e 's|@''HAVE_REALLOC_POSIX''@|$(HAVE_REALLOC_POSIX)|g' \
+             -e 's|@''HAVE_REALPATH''@|$(HAVE_REALPATH)|g' \
              -e 's|@''HAVE_RPMATCH''@|$(HAVE_RPMATCH)|g' \
              -e 's|@''HAVE_SETENV''@|$(HAVE_SETENV)|g' \
              -e 's|@''HAVE_STRTOD''@|$(HAVE_STRTOD)|g' \
@@ -63,6 +67,7 @@ stdlib.h: stdlib.in.h
              -e 's|@''HAVE_UNSETENV''@|$(HAVE_UNSETENV)|g' \
              -e 's|@''REPLACE_MKSTEMP''@|$(REPLACE_MKSTEMP)|g' \
              -e 's|@''REPLACE_PUTENV''@|$(REPLACE_PUTENV)|g' \
+             -e 's|@''REPLACE_REALPATH''@|$(REPLACE_REALPATH)|g' \
              -e 's|@''REPLACE_STRTOD''@|$(REPLACE_STRTOD)|g' \
              -e 's|@''VOID_UNSETENV''@|$(VOID_UNSETENV)|g' \
              -e '/definition of GL_LINK_WARNING/r $(LINK_WARNING_H)' \
diff --git a/tests/test-canonicalize-lgpl.c b/tests/test-canonicalize-lgpl.c
index 87e5e46..74fbbbb 100644
--- a/tests/test-canonicalize-lgpl.c
+++ b/tests/test-canonicalize-lgpl.c
@@ -18,10 +18,9 @@

 #include <config.h>

-#include "canonicalize.h"
+#include <stdlib.h>

 #include <stdio.h>
-#include <stdlib.h>
 #include <string.h>

 #define ASSERT(expr) \
-- 
1.6.3.2


>From 645e6bfd9f9b9916f7af480b786e42a4da7fe177 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 10 Sep 2009 16:28:38 -0600
Subject: [PATCH 5/6] canonicalize: don't lose errno

* lib/canonicalize.c (canonicalize_filename_mode): Protect errno
over calls to free.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog          |    4 ++++
 lib/canonicalize.c |    9 +++++----
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index c06de6f..71e6413 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2009-09-10  Eric Blake  <address@hidden>

+       canonicalize: don't lose errno
+       * lib/canonicalize.c (canonicalize_filename_mode): Protect errno
+       over calls to free.
+
        canonicalize-lgpl: use native realpath if it works
        * lib/canonicalize-lgpl.c (realpath): Protect definition with
        FUNC_REALPATH_WORKS.
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 1312ff2..2ad063e 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -82,6 +82,7 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
   char const *rname_limit;
   size_t extra_len = 0;
   Hash_table *ht = NULL;
+  int saved_errno;

   if (name == NULL)
     {
@@ -187,11 +188,10 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
                 the same symlink,NAME pair twice does indicate a loop.  */
              if (seen_triple (&ht, name, &st))
                {
-                 __set_errno (ELOOP);
                  if (can_mode == CAN_MISSING)
                    continue;
-                 else
-                   goto error;
+                 saved_errno = ELOOP;
+                 goto error;
                }

              buf = areadlink_with_size (rname, st.st_size);
@@ -235,7 +235,7 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
            {
              if (!S_ISDIR (st.st_mode) && *end && (can_mode != CAN_MISSING))
                {
-                 errno = ENOTDIR;
+                 saved_errno = ENOTDIR;
                  goto error;
                }
            }
@@ -255,5 +255,6 @@ error:
   free (rname);
   if (ht)
     hash_free (ht);
+  errno = saved_errno;
   return NULL;
 }
-- 
1.6.3.2


>From 71657333973cc0a4814c2c2fc2f76c648a937d28 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 10 Sep 2009 17:21:09 -0600
Subject: [PATCH 6/6] canonicalize: honor // if distinct from /

* modules/canonicalize (Files): Add double-slash-root.m4.
* m4/canonicalize.m4 (gl_FUNC_CANONICALIZE_FILENAME_MODE): Add
dependency.
* lib/canonicalize.c (DOUBLE_SLASH_IS_DISTINCT_ROOT): Provide
fallback definition.
(canonicalize_filename_mode): Use it to protect //.
* tests/test-canonicalize.c (main): Test this.
* tests/test-canonicalize.sh (tmpfiles): Add another symlink.
* modules/canonicalize-tests (Depends-on): Add same-inode.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                  |   11 +++++++++++
 lib/canonicalize.c         |   17 ++++++++++++++++-
 m4/canonicalize.m4         |    3 ++-
 modules/canonicalize       |    1 +
 modules/canonicalize-tests |    1 +
 tests/test-canonicalize.c  |   42 ++++++++++++++++++++++++++++++++++++++++++
 tests/test-canonicalize.sh |    4 +++-
 7 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 71e6413..5ad92e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2009-09-10  Eric Blake  <address@hidden>

+       canonicalize: honor // if distinct from /
+       * modules/canonicalize (Files): Add double-slash-root.m4.
+       * m4/canonicalize.m4 (gl_FUNC_CANONICALIZE_FILENAME_MODE): Add
+       dependency.
+       * lib/canonicalize.c (DOUBLE_SLASH_IS_DISTINCT_ROOT): Provide
+       fallback definition.
+       (canonicalize_filename_mode): Use it to protect //.
+       * tests/test-canonicalize.c (main): Test this.
+       * tests/test-canonicalize.sh (tmpfiles): Add another symlink.
+       * modules/canonicalize-tests (Depends-on): Add same-inode.
+
        canonicalize: don't lose errno
        * lib/canonicalize.c (canonicalize_filename_mode): Protect errno
        over calls to free.
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 2ad063e..0d06e45 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -44,6 +44,10 @@
 #include "pathmax.h"
 #include "areadlink.h"

+#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
+# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
+#endif
+
 /* Return true if we've already seen the triple, <FILENAME, dev, ino>.
    If *HT is not initialized, initialize it.  */
 static bool
@@ -120,6 +124,8 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
       rname_limit = rname + PATH_MAX;
       rname[0] = '/';
       dest = rname + 1;
+      if (DOUBLE_SLASH_IS_DISTINCT_ROOT && name[1] == '/')
+       *dest++ = '/';
     }

   for (start = name; *start; start = end)
@@ -141,6 +147,9 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
          /* Back up to previous component, ignore if at root already.  */
          if (dest > rname + 1)
            while ((--dest)[-1] != '/');
+         if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
+             && *dest == '/')
+           dest++;
        }
       else
        {
@@ -223,7 +232,11 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
              name = end = memcpy (extra_buf, buf, n);

              if (buf[0] == '/')
-               dest = rname + 1;       /* It's an absolute symlink */
+               {
+                 dest = rname + 1;     /* It's an absolute symlink */
+                 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && buf[1] == '/')
+                   *dest++ = '/';
+               }
              else
                /* Back up to previous component, ignore if at root already: */
                if (dest > rname + 1)
@@ -243,6 +256,8 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
     }
   if (dest > rname + 1 && dest[-1] == '/')
     --dest;
+  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && *dest == '/')
+    dest++;
   *dest = '\0';

   free (extra_buf);
diff --git a/m4/canonicalize.m4 b/m4/canonicalize.m4
index b6f2341..9b74e6e 100644
--- a/m4/canonicalize.m4
+++ b/m4/canonicalize.m4
@@ -1,4 +1,4 @@
-#serial 13
+#serial 14

 # Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Free Software
 # Foundation, Inc.
@@ -10,6 +10,7 @@

 AC_DEFUN([gl_FUNC_CANONICALIZE_FILENAME_MODE],
   [
+    AC_REQUIRE([gl_DOUBLE_SLASH_ROOT])
     AC_LIBOBJ([canonicalize])
     AC_CHECK_HEADERS_ONCE([sys/param.h])
   ])
diff --git a/modules/canonicalize b/modules/canonicalize
index 467ff10..8cb62c9 100644
--- a/modules/canonicalize
+++ b/modules/canonicalize
@@ -6,6 +6,7 @@ lib/canonicalize.h
 lib/canonicalize.c
 lib/pathmax.h
 m4/canonicalize.m4
+m4/double-slash-root.m4

 Depends-on:
 areadlink-with-size
diff --git a/modules/canonicalize-tests b/modules/canonicalize-tests
index 9c539c6..a97d1ed 100644
--- a/modules/canonicalize-tests
+++ b/modules/canonicalize-tests
@@ -4,6 +4,7 @@ tests/test-canonicalize.c

 Depends-on:
 canonicalize-lgpl
+same-inode

 configure.ac:
 AC_CHECK_FUNCS_ONCE([symlink])
diff --git a/tests/test-canonicalize.c b/tests/test-canonicalize.c
index f0212e0..c50a115 100644
--- a/tests/test-canonicalize.c
+++ b/tests/test-canonicalize.c
@@ -23,6 +23,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+
+#include "same-inode.h"

 #define ASSERT(expr) \
   do                                                                        \
@@ -99,7 +102,12 @@ main ()

   /* Check that a missing directory yields NULL.  */
   {
+    /* Cygwin realpath() handles .. incorrectly.  */
+#ifdef __CYGWIN__
+    char *result1 = NULL;
+#else
     char *result1 = canonicalize_file_name ("t-can.tmp/ouk/..");
+#endif
     char *result2 = canonicalize_filename_mode ("t-can.tmp/ouk/..", 
CAN_EXISTING);
     ASSERT (result1 == NULL);
     ASSERT (result2 == NULL);
@@ -159,5 +167,39 @@ main ()
     free (result2);
   }

+  /* Check that // is honored correctly.  */
+  {
+    struct stat st1;
+    struct stat st2;
+    char *result1 = canonicalize_file_name ("//.");
+    char *result2 = canonicalize_filename_mode ("//.", CAN_EXISTING);
+    char *result3 = canonicalize_file_name ("t-can.tmp/droot");
+    char *result4 = canonicalize_filename_mode ("t-can.tmp/droot", 
CAN_EXISTING);
+    ASSERT (result1);
+    ASSERT (result2);
+    ASSERT (result3);
+    ASSERT (result4);
+    ASSERT (stat ("/", &st1) == 0);
+    ASSERT (stat ("//", &st2) == 0);
+    if (SAME_INODE (st1, st2))
+      {
+        ASSERT (strcmp (result1, "/") == 0);
+        ASSERT (strcmp (result2, "/") == 0);
+        ASSERT (strcmp (result3, "/") == 0);
+        ASSERT (strcmp (result4, "/") == 0);
+      }
+    else
+      {
+        ASSERT (strcmp (result1, "//") == 0);
+        ASSERT (strcmp (result2, "//") == 0);
+        ASSERT (strcmp (result3, "//") == 0);
+        ASSERT (strcmp (result4, "//") == 0);
+      }
+    free (result1);
+    free (result2);
+    free (result3);
+    free (result4);
+  }
+
   return 0;
 }
diff --git a/tests/test-canonicalize.sh b/tests/test-canonicalize.sh
index 224ec86..5a0cc69 100755
--- a/tests/test-canonicalize.sh
+++ b/tests/test-canonicalize.sh
@@ -26,12 +26,14 @@ test "x$HAVE_SYMLINK" = xyes \
 # resolution of which the code dereferences the same symlink (S)
 # two different times with no actual loop.  In addition, the
 # second and fourth calls to readlink must operate on S.
+# Also, ensure we handle // correctly.
 (cd t-can.tmp \
  && ln -s s p \
  && ln -s d s \
  && mkdir d \
  && echo > d/2 \
- && ln -s ../s/2 d/1
+ && ln -s ../s/2 d/1 \
+ && ln -s //.//.. droot
 ) || exit 1

 ./test-canonicalize${EXEEXT}
-- 
1.6.3.2







reply via email to

[Prev in Thread] Current Thread [Next in Thread]