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: Fri, 11 Sep 2009 22:35:58 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

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

> > 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 /
> 
> Sounds promising.  Thanks!
> 
> I'll read the above more carefully
> and take a look at the changes on Monday or Tuesday.

Here's the improved, refactored series, with some review commentary.  c_f_n = 
canonicalize_file_name, c_f_mode = canonicalize_filename_mode, Because of the 
glibc 2.3.5 bug in realpath/c_f_n, it still makes sense for canonicalize to 
provide a working c_f_n replacement, so I dropped patch 3 from the above 
series.  Of the three interfaces, only realpath is specified by POSIX, but 
POSIX admits that it is useless without a NULL second argument, at which point 
it is easier to read c_f_n(name) than realpath(name,NULL).  As a result, if you 
import:

canonicalize only => GPL c_f_n, GPL c_f_mode
canonicalize-lgpl only => LGPL realpath, LGPL c_f_n
both modules => LGPL realpath, LGPL c_f_n, GPL c_f_mode

Eric Blake (11):
      [1/11] stdlib: sort witness names
cleanup done up front, but could be delayed until just before patch 7

      [2/11] canonicalize, canonicalize-lgpl: update module dependencies
we were checking whether c_f_n name was declared, but without turning on 
extensions (defeating the purpose, since glibc is the only platform that 
provides it, but hides it behind extensions).  By adding extensions, we can 
drop the decl check altogether.  Also, prior to this patch, using just the 
module pair 'canonicalize-lgpl sys_stat' failed to compile on mingw, due to a 
link failure on lstat.

      [3/11] canonicalize: don't lose errno
glibc still has a bug in realpath/c_f_n where errno could be inadvertently 
changed by a call to free() during an error return, but canonicalize-lgpl was 
immune, and now canonicalize is fixed.  I guess I'll have to file a glibc bug 
report for the gnulib->glibc syncing (patch 9 gets the glibc->gnulib syncing)

      [4/11] canonicalize: avoid resolvepath
using resolvepath made sense for Solaris back when all this module did was 
replace c_f_n (and before canonicalize-lgpl did the same replacement, but with 
LGPL).  But c_f_mode can't exploit resolvepath, so our c_f_n implementation was 
just extra bulk on Solaris

      [5/11] test-canonicalize-lgpl: consolidate into single C program
      [6/11] test-canonicalize: consolidate into single C program
5 and 6 could be squashed together, if desired.  I got tired of having to clean 
up leftovers and restart an entire testsuite when debugging triggering 
failures.  By moving all the symlink creation and cleanup into C, the test app 
now works standalone from the debugger.  As a side effect, also avoids the fact 
that prior to this point, both test-canonicalize.sh and test-canonicalize-
lgpl.sh tried to create the same symlink "ise", wreaking havoc on poorly timed 
parallel tests.  This also reorders the tests slightly; on mingw, the overall 
test still exits with status 77 (skip), but at least it did real tests on non-
symlinks before that point.

      [7/11] canonicalize, canonicalize-lgpl: use <stdlib.h>
Change canonicalize-lgpl to match gnulib header conventions (any function 
declared by glibc should live in the same header in gnulib).  Also, by 
modernizing this, it is easer to replace c_f_n in later patches.  canonicalize 
still requires "canonicalize.h", because it introduces the API c_f_mode not 
present in glibc.

      [8/11] canonicalize-lgpl: use native realpath if it works
Forward-looking to when more platforms comply with POSIX 2008.  Nice for 
cygwin - c_f_n gets // handling for free.  Well, it would be nicer if cygwin 
didn't have a bug in foo/no_such_dir/.. resolution, but I'm hoping to fix that 
in cygwin before their next formal release (if I fail, then I have a followup 
patch not included in this series which beefs up the canonicalize.m4 check to 
reject cygwin's realpath as buggy)

      [9/11] canonicalize-lgpl: reject non-directory with trailing slash
      [10/11] canonicalize-lgpl: fix glibc bug with trailing slash
9 and 10 could be squashed together, if desired.  9 does the syncing with 
glibc, and 10 does the replacement of broken c_f_n (I was able to trip this 
failure on at least fencepost.gnu.org in my testing)

      [11/11] canonicalize: honor // if distinct from /
Fixes c_f_mode handling of // on cygwin.



>From a8199c8d64343f2d3510ac64395192180221b033 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 10 Sep 2009 14:10:41 -0600
Subject: [PATCH 01/11] 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       |    7 +++
 lib/stdlib.in.h |  114 +++++++++++++++++++++++--------------------------------
 m4/stdlib_h.m4  |   12 +++---
 modules/stdlib  |   12 +++---
 4 files changed, 67 insertions(+), 78 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 94bac83..2d6f56f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2009-09-11  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.
+
 2009-09-11  Jim Meyering  <address@hidden>

        announce-gen: include [$release_type] in emitted Subject:
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 54546ec7e9c96209d6b27066363828faacbd4c17 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 11 Sep 2009 08:34:37 -0600
Subject: [PATCH 02/11] canonicalize, canonicalize-lgpl: update module 
dependencies

* modules/canonicalize (Depends-on): Add extensions, lstat,
pathmax, stdlib.
(Files): Drop pathmax.h.
(configure.ac): Adjust macro name.
* modules/canonicalize-lgpl (Depends-on): Add errno, extensions,
lstat, stdlib, sys_stat.
* m4/canonicalize.m4 (AC_FUNC_CANONICALIZE_FILE_NAME): Rename...
(gl_FUNC_CANONICALIZE_FILENAME_MODE): ...to this, and require
extensions.
* m4/canonicalize-lgpl.m4 (gl_CANONICALIZE_LGPL)
(gl_CANONICALIZE_LGPL_SEPARATE): Require extensions.
(gl_PREREQ_CANONICALIZE_LGPL): Assume unistd.h.
* lib/canonicalize.h (canonicalize_file_name): Use <stdlib.h>
declaration, if available.
* lib/canonicalize-lgpl.c [HAVE_READLINK]: Delete this condition;
we can rely on the readlink module.
(MAXSYMLINKS): Also consult SYMLOOP_MAX.
(includes): Use <unistd.h> unconditionally.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                 |   20 ++++++++++++++++++++
 lib/canonicalize-lgpl.c   |   19 ++++++-------------
 lib/canonicalize.h        |    4 ++--
 m4/canonicalize-lgpl.m4   |    8 ++++----
 m4/canonicalize.m4        |   20 +++++++++++---------
 modules/canonicalize      |    6 ++++--
 modules/canonicalize-lgpl |    5 +++++
 7 files changed, 52 insertions(+), 30 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 2d6f56f..76fdb5a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
 2009-09-11  Eric Blake  <address@hidden>

+       canonicalize, canonicalize-lgpl: update module dependencies
+       * modules/canonicalize (Depends-on): Add extensions, lstat,
+       pathmax, stdlib.
+       (Files): Drop pathmax.h.
+       (configure.ac): Adjust macro name.
+       * modules/canonicalize-lgpl (Depends-on): Add errno, extensions,
+       lstat, stdlib, sys_stat.
+       * m4/canonicalize.m4 (AC_FUNC_CANONICALIZE_FILE_NAME): Rename...
+       (gl_FUNC_CANONICALIZE_FILENAME_MODE): ...to this, and require
+       extensions.
+       * m4/canonicalize-lgpl.m4 (gl_CANONICALIZE_LGPL)
+       (gl_CANONICALIZE_LGPL_SEPARATE): Require extensions.
+       (gl_PREREQ_CANONICALIZE_LGPL): Assume unistd.h.
+       * lib/canonicalize.h (canonicalize_file_name): Use <stdlib.h>
+       declaration, if available.
+       * lib/canonicalize-lgpl.c [HAVE_READLINK]: Delete this condition;
+       we can rely on the readlink module.
+       (MAXSYMLINKS): Also consult SYMLOOP_MAX.
+       (includes): Use <unistd.h> unconditionally.
+
        stdlib: sort witness names
        * modules/stdlib (Makefile.am): Sort replacements.
        * m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Likewise.
diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c
index 6b5663a..ce52cbc 100644
--- a/lib/canonicalize-lgpl.c
+++ b/lib/canonicalize-lgpl.c
@@ -31,10 +31,7 @@
 #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 +39,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>
@@ -74,10 +75,6 @@
 #  define __getcwd(buf, max) getwd (buf)
 # endif
 # define __readlink readlink
-  /* On systems without symbolic links, call stat() instead of lstat().  */
-# if !defined S_ISLNK && !HAVE_READLINK
-#  define lstat stat
-# endif
 #endif

 /* Return the canonical absolute name of file NAME.  A canonical name
@@ -97,9 +94,7 @@ __realpath (const char *name, char *resolved)
   char *rpath, *dest, *extra_buf = NULL;
   const char *start, *end, *rpath_limit;
   long int path_max;
-#if HAVE_READLINK
   int num_links = 0;
-#endif

   if (name == NULL)
     {
@@ -237,7 +232,6 @@ __realpath (const char *name, char *resolved)
 #endif
            goto error;

-#if HAVE_READLINK
          if (S_ISLNK (st.st_mode))
            {
              char *buf;
@@ -297,7 +291,6 @@ __realpath (const char *name, char *resolved)
                if (dest > rpath + 1)
                  while ((--dest)[-1] != '/');
            }
-#endif
        }
     }
   if (dest > rpath + 1 && dest[-1] == '/')
diff --git a/lib/canonicalize.h b/lib/canonicalize.h
index 8ca4fb4..e068c20 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
@@ -38,7 +38,7 @@ typedef enum canonicalize_mode_t canonicalize_mode_t;
 char *canonicalize_filename_mode (const char *, canonicalize_mode_t);
 # endif

-# if HAVE_DECL_CANONICALIZE_FILE_NAME
+# if HAVE_CANONICALIZE_FILE_NAME
 #  include <stdlib.h>
 # else
 /* Return a malloc'd string containing the canonical absolute name of
diff --git a/m4/canonicalize-lgpl.m4 b/m4/canonicalize-lgpl.m4
index 3a8ee2f..bd3a381 100644
--- a/m4/canonicalize-lgpl.m4
+++ b/m4/canonicalize-lgpl.m4
@@ -1,4 +1,4 @@
-# canonicalize-lgpl.m4 serial 5
+# canonicalize-lgpl.m4 serial 6
 dnl Copyright (C) 2003, 2006-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,
@@ -8,7 +8,7 @@ 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_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   AC_CHECK_FUNCS_ONCE([canonicalize_file_name])
   if test $ac_cv_func_canonicalize_file_name = no; then
     AC_LIBOBJ([canonicalize-lgpl])
@@ -22,7 +22,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 +30,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/canonicalize.m4 b/m4/canonicalize.m4
index 817edd5..0a42a41 100644
--- a/m4/canonicalize.m4
+++ b/m4/canonicalize.m4
@@ -1,17 +1,19 @@
-#serial 12
+#serial 13
+
+# Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Free Software
+# Foundation, Inc.

-# Copyright (C) 2003, 2004, 2005, 2006, 2007 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_LIBOBJ([canonicalize])
+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])
-  ])
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_CHECK_HEADERS_ONCE([sys/param.h])
+  AC_CHECK_FUNCS_ONCE([canonicalize_file_name resolvepath])
+])
diff --git a/modules/canonicalize b/modules/canonicalize
index e24be3d..a7e61a6 100644
--- a/modules/canonicalize
+++ b/modules/canonicalize
@@ -4,22 +4,24 @@ Return the canonical absolute name of a given file.
 Files:
 lib/canonicalize.h
 lib/canonicalize.c
-lib/pathmax.h
 m4/canonicalize.m4

 Depends-on:
 areadlink-with-size
 errno
+extensions
 file-set
 filenamecat
 hash-triple
+lstat
 memmove
+pathmax
 sys_stat
 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-lgpl b/modules/canonicalize-lgpl
index b462c61..45a9a43 100644
--- a/modules/canonicalize-lgpl
+++ b/modules/canonicalize-lgpl
@@ -8,10 +8,15 @@ m4/canonicalize-lgpl.m4

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

 configure.ac:
 gl_CANONICALIZE_LGPL
-- 
1.6.3.2


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

* lib/canonicalize.c (canonicalize_filename_mode): Protect errno
over calls to free.
(__set_errno): Delete macro, and use direct assignment.

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

diff --git a/ChangeLog b/ChangeLog
index 76fdb5a..a3fa8d8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2009-09-11  Eric Blake  <address@hidden>

+       canonicalize: don't lose errno
+       * lib/canonicalize.c (canonicalize_filename_mode): Protect errno
+       over calls to free.
+       (__set_errno): Delete macro, and use direct assignment.
+
        canonicalize, canonicalize-lgpl: update module dependencies
        * modules/canonicalize (Depends-on): Add extensions, lstat,
        pathmax, stdlib.
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 523e082..1ee0c12 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -32,19 +32,14 @@
 #include <errno.h>
 #include <stddef.h>

+#include "areadlink.h"
 #include "file-set.h"
 #include "filenamecat.h"
 #include "hash-triple.h"
+#include "pathmax.h"
 #include "xalloc.h"
 #include "xgetcwd.h"

-#ifndef __set_errno
-# define __set_errno(Val) errno = (Val)
-#endif
-
-#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
@@ -62,13 +57,13 @@ canonicalize_file_name (const char *name)

   if (name == NULL)
     {
-      __set_errno (EINVAL);
+      errno = EINVAL;
       return NULL;
     }

   if (name[0] == '\0')
     {
-      __set_errno (ENOENT);
+      errno = ENOENT;
       return NULL;
     }

@@ -157,16 +152,17 @@ 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)
     {
-      __set_errno (EINVAL);
+      errno = EINVAL;
       return NULL;
     }

   if (name[0] == '\0')
     {
-      __set_errno (ENOENT);
+      errno = ENOENT;
       return NULL;
     }

@@ -262,11 +258,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);
@@ -310,7 +305,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;
                }
            }
@@ -330,5 +325,6 @@ error:
   free (rname);
   if (ht)
     hash_free (ht);
+  errno = saved_errno;
   return NULL;
 }
-- 
1.6.3.2


>From 9c200642534c51c72df7fda7b9aa82aa93bfc745 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 11 Sep 2009 14:57:01 -0600
Subject: [PATCH 04/11] canonicalize: avoid resolvepath

* m4/canonicalize.m4 (gl_FUNC_CANONICALIZE_FILENAME_MODE): Delete
unnecessary checks.
* lib/canonicalize.c (includes): Simplify.
(canonicalize_file_name): Drop resolvepath implementation; it just
added code bulk.
* modules/canonicalize (Depends-on): Drop filenamecat.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog            |    8 +++++
 lib/canonicalize.c   |   75 ++------------------------------------------------
 m4/canonicalize.m4   |    5 +--
 modules/canonicalize |    1 -
 4 files changed, 13 insertions(+), 76 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index a3fa8d8..43c5077 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2009-09-11  Eric Blake  <address@hidden>

+       canonicalize: avoid resolvepath
+       * m4/canonicalize.m4 (gl_FUNC_CANONICALIZE_FILENAME_MODE): Delete
+       unnecessary checks.
+       * lib/canonicalize.c (includes): Simplify.
+       (canonicalize_file_name): Drop resolvepath implementation; it just
+       added code bulk.
+       * modules/canonicalize (Depends-on): Drop filenamecat.
+
        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 1ee0c12..9620c8a 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -18,23 +18,14 @@

 #include "canonicalize.h"

+#include <errno.h>
 #include <stdlib.h>
 #include <string.h>
-
-#if HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#endif
-
 #include <sys/stat.h>
-
 #include <unistd.h>

-#include <errno.h>
-#include <stddef.h>
-
 #include "areadlink.h"
 #include "file-set.h"
-#include "filenamecat.h"
 #include "hash-triple.h"
 #include "pathmax.h"
 #include "xalloc.h"
@@ -49,68 +40,7 @@
 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)
-    {
-      errno = EINVAL;
-      return NULL;
-    }
-
-  if (name[0] == '\0')
-    {
-      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 */

@@ -138,7 +68,8 @@ seen_triple (Hash_table **ht, char const *filename, struct 
stat const *st)
   return false;
 }

-/* Return the canonical absolute name of file NAME.  A canonical name
+/* Return the canonical absolute name of file NAME, while treating
+   missing elements according to CAN_MODE.  A canonical name
    does not contain any `.', `..' components nor any repeated file name
    separators ('/') or symlinks.  Whether components must exist
    or not depends on canonicalize mode.  The result is malloc'd.  */
diff --git a/m4/canonicalize.m4 b/m4/canonicalize.m4
index 0a42a41..1258b3b 100644
--- a/m4/canonicalize.m4
+++ b/m4/canonicalize.m4
@@ -1,4 +1,4 @@
-#serial 13
+# canonicalize.m4 serial 14

 # Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Free Software
 # Foundation, Inc.
@@ -14,6 +14,5 @@ AC_DEFUN([gl_FUNC_CANONICALIZE_FILENAME_MODE],
   AC_LIBOBJ([canonicalize])

   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
-  AC_CHECK_HEADERS_ONCE([sys/param.h])
-  AC_CHECK_FUNCS_ONCE([canonicalize_file_name resolvepath])
+  AC_CHECK_FUNCS_ONCE([canonicalize_file_name])
 ])
diff --git a/modules/canonicalize b/modules/canonicalize
index a7e61a6..ec94c76 100644
--- a/modules/canonicalize
+++ b/modules/canonicalize
@@ -11,7 +11,6 @@ areadlink-with-size
 errno
 extensions
 file-set
-filenamecat
 hash-triple
 lstat
 memmove
-- 
1.6.3.2


>From 68948e47db648763e44c32edc80862fe7e986bbf Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 11 Sep 2009 08:59:54 -0600
Subject: [PATCH 05/11] test-canonicalize-lgpl: consolidate into single C program

* tests/test-canonicalize-lgpl.sh: Delete; move setup into...
* tests/test-canonicalize-lgpl.c (main): ...the program, making it
easier to run in debugger.  Add some tests.  Fixes running test in
parallel with test-canonicalize.
* modules/canonicalize-lgpl-tests (Files): Remove unused file.
(configure.ac, Makefile.am): Simplify.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                       |    8 +++
 modules/canonicalize-lgpl-tests |    7 +---
 tests/test-canonicalize-lgpl.c  |   93 ++++++++++++++++++++++++++++++++++----
 tests/test-canonicalize-lgpl.sh |   29 ------------
 4 files changed, 92 insertions(+), 45 deletions(-)
 delete mode 100755 tests/test-canonicalize-lgpl.sh

diff --git a/ChangeLog b/ChangeLog
index 43c5077..653869c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2009-09-11  Eric Blake  <address@hidden>

+       test-canonicalize-lgpl: consolidate into single C program
+       * tests/test-canonicalize-lgpl.sh: Delete; move setup into...
+       * tests/test-canonicalize-lgpl.c (main): ...the program, making it
+       easier to run in debugger.  Add some tests.  Fixes running test in
+       parallel with test-canonicalize.
+       * modules/canonicalize-lgpl-tests (Files): Remove unused file.
+       (configure.ac, Makefile.am): Simplify.
+
        canonicalize: avoid resolvepath
        * m4/canonicalize.m4 (gl_FUNC_CANONICALIZE_FILENAME_MODE): Delete
        unnecessary checks.
diff --git a/modules/canonicalize-lgpl-tests b/modules/canonicalize-lgpl-tests
index ac40166..2009509 100644
--- a/modules/canonicalize-lgpl-tests
+++ b/modules/canonicalize-lgpl-tests
@@ -1,16 +1,11 @@
 Files:
-tests/test-canonicalize-lgpl.sh
 tests/test-canonicalize-lgpl.c

 Depends-on:

 configure.ac:
 AC_CHECK_FUNCS_ONCE([symlink])
-HAVE_SYMLINK=$ac_cv_func_symlink
-AC_SUBST([HAVE_SYMLINK])

 Makefile.am:
-TESTS += test-canonicalize-lgpl.sh
-TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' HAVE_SYMLINK='$(HAVE_SYMLINK)'
+TESTS += test-canonicalize-lgpl
 check_PROGRAMS += test-canonicalize-lgpl
-test_canonicalize_lgpl_LDADD = $(LDADD)
diff --git a/tests/test-canonicalize-lgpl.c b/tests/test-canonicalize-lgpl.c
index 29b919d..bc58d59 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
@@ -20,9 +20,17 @@

 #include "canonicalize.h"

+#include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#if !HAVE_SYMLINK
+# define symlink(a,b) (-1)
+#endif /* !HAVE_SYMLINK */

 #define ASSERT(expr) \
   do                                                                        \
@@ -36,6 +44,8 @@
     }                                                                       \
   while (0)

+#define BASE "t-can-lgpl.tmp"
+
 int
 main ()
 {
@@ -45,29 +55,75 @@ main ()
   return 0;
 #endif

+  /* Setup some hierarchy to be used by this test.  Start by removing
+     any leftovers from a previous partial run.  */
+  {
+    int fd;
+    ASSERT (system ("rm -rf " BASE " ise") == 0);
+    ASSERT (mkdir (BASE, 0700) == 0);
+    fd = creat (BASE "/tra", 0600);
+    ASSERT (0 <= fd);
+    ASSERT (close (fd) == 0);
+  }
+
+  /* Check for ., .., intermediate // handling, and for error cases.  */
+  {
+    char *result = canonicalize_file_name (BASE "//./..//" BASE "/tra");
+    ASSERT (result != NULL);
+    ASSERT (strstr (result, "/" BASE "/tra")
+           == result + strlen (result) - strlen ("/" BASE "/tra"));
+    free (result);
+    errno = 0;
+    result = canonicalize_file_name ("");
+    ASSERT (result == NULL);
+    ASSERT (errno == ENOENT);
+    errno = 0;
+    result = canonicalize_file_name (NULL);
+    ASSERT (result == NULL);
+    ASSERT (errno == EINVAL);
+  }
+
+  /* From here on out, tests involve symlinks.  */
+  if (symlink (BASE "/ket", "ise") != 0)
+    {
+      ASSERT (remove (BASE "/tra") == 0);
+      ASSERT (rmdir (BASE) == 0);
+      fputs ("skipping test: symlinks not supported on this filesystem\n",
+            stderr);
+      return 77;
+    }
+  ASSERT (symlink ("bef", BASE "/plo") == 0);
+  ASSERT (symlink ("tra", BASE "/huk") == 0);
+  ASSERT (symlink ("lum", BASE "/bef") == 0);
+  ASSERT (symlink ("wum", BASE "/ouk") == 0);
+  ASSERT (symlink ("../ise", BASE "/ket") == 0);
+  ASSERT (mkdir (BASE "/lum", 0700) == 0);
+
   /* Check that the symbolic link to a file can be resolved.  */
   {
-    char *result1 = canonicalize_file_name ("t-can-lgpl.tmp/huk");
-    char *result2 = canonicalize_file_name ("t-can-lgpl.tmp/tra");
+    char *result1 = canonicalize_file_name (BASE "/huk");
+    char *result2 = canonicalize_file_name (BASE "/tra");
     ASSERT (result1 != NULL);
     ASSERT (result2 != NULL);
     ASSERT (strcmp (result1, result2) == 0);
-    ASSERT (strcmp (result1 + strlen (result1) - 19, "/t-can-lgpl.tmp/tra") == 
0);
+    ASSERT (strcmp (result1 + strlen (result1) - strlen ("/" BASE "/tra"),
+                   "/" BASE "/tra") == 0);
     free (result1);
     free (result2);
   }

   /* Check that the symbolic link to a directory can be resolved.  */
   {
-    char *result1 = canonicalize_file_name ("t-can-lgpl.tmp/plo");
-    char *result2 = canonicalize_file_name ("t-can-lgpl.tmp/bef");
-    char *result3 = canonicalize_file_name ("t-can-lgpl.tmp/lum");
+    char *result1 = canonicalize_file_name (BASE "/plo");
+    char *result2 = canonicalize_file_name (BASE "/bef");
+    char *result3 = canonicalize_file_name (BASE "/lum");
     ASSERT (result1 != NULL);
     ASSERT (result2 != NULL);
     ASSERT (result3 != NULL);
     ASSERT (strcmp (result1, result2) == 0);
     ASSERT (strcmp (result2, result3) == 0);
-    ASSERT (strcmp (result1 + strlen (result1) - 19, "/t-can-lgpl.tmp/lum") == 
0);
+    ASSERT (strcmp (result1 + strlen (result1) - strlen ("/" BASE "/lum"),
+                   "/" BASE "/lum") == 0);
     free (result1);
     free (result2);
     free (result3);
@@ -75,15 +131,32 @@ main ()

   /* Check that a symbolic link to a nonexistent file yields NULL.  */
   {
-    char *result = canonicalize_file_name ("t-can-lgpl.tmp/ouk");
+    char *result;
+    errno = 0;
+    result = canonicalize_file_name (BASE "/ouk");
     ASSERT (result == NULL);
+    ASSERT (errno == ENOENT);
   }

   /* Check that a loop of symbolic links is detected.  */
   {
-    char *result = canonicalize_file_name ("ise");
+    char *result;
+    errno = 0;
+    result = canonicalize_file_name ("ise");
     ASSERT (result == NULL);
+    ASSERT (errno == ELOOP);
   }

+  /* Cleanup.  */
+  ASSERT (remove (BASE "/plo") == 0);
+  ASSERT (remove (BASE "/huk") == 0);
+  ASSERT (remove (BASE "/bef") == 0);
+  ASSERT (remove (BASE "/ouk") == 0);
+  ASSERT (remove (BASE "/ket") == 0);
+  ASSERT (remove (BASE "/lum") == 0);
+  ASSERT (remove (BASE "/tra") == 0);
+  ASSERT (remove (BASE) == 0);
+  ASSERT (remove ("ise") == 0);
+
   return 0;
 }
diff --git a/tests/test-canonicalize-lgpl.sh b/tests/test-canonicalize-lgpl.sh
deleted file mode 100755
index e439b7a..0000000
--- a/tests/test-canonicalize-lgpl.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-
-tmpfiles=""
-trap 'rm -fr $tmpfiles' 1 2 3 15
-
-tmpfiles="$tmpfiles t-can-lgpl.tmp ise"
-mkdir t-can-lgpl.tmp
-test "x$HAVE_SYMLINK" = xyes \
-  && ln -s t-can-lgpl.tmp/ket ise \
-  || { echo "Skipping test: symbolic links not supported on this filesystem"
-       rm -fr $tmpfiles
-       exit 77
-     }
-(cd t-can-lgpl.tmp \
- && ln -s bef plo \
- && ln -s tra huk \
- && ln -s lum bef \
- && ln -s wum ouk \
- && ln -s ../ise ket \
- && echo > tra \
- && mkdir lum
-) || exit 1
-
-./test-canonicalize-lgpl${EXEEXT}
-result=$?
-
-rm -fr $tmpfiles
-
-exit $result
-- 
1.6.3.2


>From 6953d84bd7fb3052b435d7dbc444235336c25798 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 11 Sep 2009 09:53:44 -0600
Subject: [PATCH 06/11] test-canonicalize: consolidate into single C program

* tests/test-canonicalize.sh: Delete; move setup into...
* tests/test-canonicalize.c (main): ...the program, making it
easier to run in debugger.  Add some tests.
* modules/canonicalize-tests (Files): Remove unused file.
(Depends-on): Add progname.
(configure.ac, Makefile.am): Simplify.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                  |    8 +++
 modules/canonicalize-tests |    7 +--
 tests/test-canonicalize.c  |  148 +++++++++++++++++++++++++++++++++++++-------
 tests/test-canonicalize.sh |   42 ------------
 4 files changed, 135 insertions(+), 70 deletions(-)
 delete mode 100755 tests/test-canonicalize.sh

diff --git a/ChangeLog b/ChangeLog
index 653869c..b3ef549 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2009-09-11  Eric Blake  <address@hidden>

+       test-canonicalize: consolidate into single C program
+       * tests/test-canonicalize.sh: Delete; move setup into...
+       * tests/test-canonicalize.c (main): ...the program, making it
+       easier to run in debugger.  Add some tests.
+       * modules/canonicalize-tests (Files): Remove unused file.
+       (Depends-on): Add progname.
+       (configure.ac, Makefile.am): Simplify.
+
        test-canonicalize-lgpl: consolidate into single C program
        * tests/test-canonicalize-lgpl.sh: Delete; move setup into...
        * tests/test-canonicalize-lgpl.c (main): ...the program, making it
diff --git a/modules/canonicalize-tests b/modules/canonicalize-tests
index e8dfec7..f91c5f9 100644
--- a/modules/canonicalize-tests
+++ b/modules/canonicalize-tests
@@ -1,16 +1,13 @@
 Files:
-tests/test-canonicalize.sh
 tests/test-canonicalize.c

 Depends-on:
+progname

 configure.ac:
 AC_CHECK_FUNCS_ONCE([symlink])
-HAVE_SYMLINK=$ac_cv_func_symlink
-AC_SUBST([HAVE_SYMLINK])

 Makefile.am:
-TESTS += test-canonicalize.sh
-TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' HAVE_SYMLINK='$(HAVE_SYMLINK)'
+TESTS += test-canonicalize
 check_PROGRAMS += test-canonicalize
 test_canonicalize_LDADD = $(LDADD) @LIBINTL@
diff --git a/tests/test-canonicalize.c b/tests/test-canonicalize.c
index d76c307..6614422 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
@@ -20,9 +20,17 @@

 #include "canonicalize.h"

+#include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#if !HAVE_SYMLINK
+# define symlink(a,b) (-1)
+#endif

 #define ASSERT(expr) \
   do                                                                        \
@@ -36,22 +44,85 @@
     }                                                                       \
   while (0)

-const char *program_name = "test-canonicalize";
+#define BASE "t-can.tmp"

 int
 main ()
 {
+  /* Setup some hierarchy to be used by this test.  Start by removing
+     any leftovers from a previous partial run.  */
+  {
+    int fd;
+    ASSERT (system ("rm -rf " BASE " ise") == 0);
+    ASSERT (mkdir (BASE, 0700) == 0);
+    fd = creat (BASE "/tra", 0600);
+    ASSERT (0 <= fd);
+    ASSERT (close (fd) == 0);
+  }
+
+  /* Check for ., .., intermediate // handling, and for error cases.  */
+  {
+    char *result1 = canonicalize_file_name (BASE "//./..//" BASE "/tra");
+    char *result2 = canonicalize_filename_mode (BASE "//./..//" BASE "/tra",
+                                                CAN_EXISTING);
+    ASSERT (result1 != NULL);
+    ASSERT (result2 != NULL);
+    ASSERT (strcmp (result1, result2) == 0);
+    ASSERT (strstr (result1, "/" BASE "/tra")
+           == result1 + strlen (result1) - strlen ("/" BASE "/tra"));
+    free (result1);
+    free (result2);
+    errno = 0;
+    result1 = canonicalize_file_name ("");
+    ASSERT (result1 == NULL);
+    ASSERT (errno == ENOENT);
+    errno = 0;
+    result2 = canonicalize_filename_mode ("", CAN_EXISTING);
+    ASSERT (result2 == NULL);
+    ASSERT (errno == ENOENT);
+    errno = 0;
+    result1 = canonicalize_file_name (NULL);
+    ASSERT (result1 == NULL);
+    ASSERT (errno == EINVAL);
+    errno = 0;
+    result2 = canonicalize_filename_mode (NULL, CAN_EXISTING);
+    ASSERT (result2 == NULL);
+    ASSERT (errno == EINVAL);
+  }
+
+  /* From here on out, tests involve symlinks.  */
+  if (symlink (BASE "/ket", "ise") != 0)
+    {
+      ASSERT (remove (BASE "/tra") == 0);
+      ASSERT (rmdir (BASE) == 0);
+      fputs ("skipping test: symlinks not supported on this filesystem\n",
+            stderr);
+      return 77;
+    }
+  ASSERT (symlink ("bef", BASE "/plo") == 0);
+  ASSERT (symlink ("tra", BASE "/huk") == 0);
+  ASSERT (symlink ("lum", BASE "/bef") == 0);
+  ASSERT (symlink ("wum", BASE "/ouk") == 0);
+  ASSERT (symlink ("../ise", BASE "/ket") == 0);
+  ASSERT (mkdir (BASE "/lum", 0700) == 0);
+  ASSERT (symlink ("s", BASE "/p") == 0);
+  ASSERT (symlink ("d", BASE "/s") == 0);
+  ASSERT (mkdir (BASE "/d", 0700) == 0);
+  ASSERT (close (creat (BASE "/d/2", 0600)) == 0);
+  ASSERT (symlink ("../s/2", BASE "/d/1") == 0);
+
   /* Check that the symbolic link to a file can be resolved.  */
   {
-    char *result1 = canonicalize_file_name ("t-can.tmp/huk");
-    char *result2 = canonicalize_file_name ("t-can.tmp/tra");
-    char *result3 = canonicalize_filename_mode ("t-can.tmp/huk", CAN_EXISTING);
+    char *result1 = canonicalize_file_name (BASE "/huk");
+    char *result2 = canonicalize_file_name (BASE "/tra");
+    char *result3 = canonicalize_filename_mode (BASE "/huk", CAN_EXISTING);
     ASSERT (result1 != NULL);
     ASSERT (result2 != NULL);
     ASSERT (result3 != NULL);
     ASSERT (strcmp (result1, result2) == 0);
     ASSERT (strcmp (result2, result3) == 0);
-    ASSERT (strcmp (result1 + strlen (result1) - 14, "/t-can.tmp/tra") == 0);
+    ASSERT (strcmp (result1 + strlen (result1) - strlen ("/" BASE "/tra"),
+                    "/" BASE "/tra") == 0);
     free (result1);
     free (result2);
     free (result3);
@@ -59,10 +130,10 @@ main ()

   /* Check that the symbolic link to a directory can be resolved.  */
   {
-    char *result1 = canonicalize_file_name ("t-can.tmp/plo");
-    char *result2 = canonicalize_file_name ("t-can.tmp/bef");
-    char *result3 = canonicalize_file_name ("t-can.tmp/lum");
-    char *result4 = canonicalize_filename_mode ("t-can.tmp/plo", CAN_EXISTING);
+    char *result1 = canonicalize_file_name (BASE "/plo");
+    char *result2 = canonicalize_file_name (BASE "/bef");
+    char *result3 = canonicalize_file_name (BASE "/lum");
+    char *result4 = canonicalize_filename_mode (BASE "/plo", CAN_EXISTING);
     ASSERT (result1 != NULL);
     ASSERT (result2 != NULL);
     ASSERT (result3 != NULL);
@@ -70,7 +141,8 @@ main ()
     ASSERT (strcmp (result1, result2) == 0);
     ASSERT (strcmp (result2, result3) == 0);
     ASSERT (strcmp (result3, result4) == 0);
-    ASSERT (strcmp (result1 + strlen (result1) - 14, "/t-can.tmp/lum") == 0);
+    ASSERT (strcmp (result1 + strlen (result1) - strlen ("/" BASE "/lum"),
+                    "/" BASE "/lum") == 0);
     free (result1);
     free (result2);
     free (result3);
@@ -79,40 +151,54 @@ main ()

   /* Check that a symbolic link to a nonexistent file yields NULL.  */
   {
-    char *result1 = canonicalize_file_name ("t-can.tmp/ouk");
-    char *result2 = canonicalize_filename_mode ("t-can.tmp/ouk", CAN_EXISTING);
+    char *result1;
+    char *result2;
+    errno = 0;
+    result1 = canonicalize_file_name (BASE "/ouk");
     ASSERT (result1 == NULL);
+    ASSERT (errno == ENOENT);
+    errno = 0;
+    result2 = canonicalize_filename_mode (BASE "/ouk", CAN_EXISTING);
     ASSERT (result2 == NULL);
+    ASSERT (errno == ENOENT);
   }

   /* 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;
+    char *result2;
+    errno = 0;
+    result1 = canonicalize_file_name ("ise");
     ASSERT (result1 == NULL);
+    ASSERT (errno == ELOOP);
+    errno = 0;
+    result2 = canonicalize_filename_mode ("ise", CAN_EXISTING);
     ASSERT (result2 == NULL);
+    ASSERT (errno == ELOOP);
   }

   /* Check that alternate modes can resolve missing basenames.  */
   {
-    char *result1 = canonicalize_filename_mode ("t-can.tmp/zzz", 
CAN_ALL_BUT_LAST);
-    char *result2 = canonicalize_filename_mode ("t-can.tmp/zzz", CAN_MISSING);
+    char *result1 = canonicalize_filename_mode (BASE "/zzz", CAN_ALL_BUT_LAST);
+    char *result2 = canonicalize_filename_mode (BASE "/zzz", CAN_MISSING);
     ASSERT (result1 != NULL);
     ASSERT (result2 != NULL);
     ASSERT (strcmp (result1, result2) == 0);
-    ASSERT (strcmp (result1 + strlen (result1) - 14, "/t-can.tmp/zzz") == 0);
+    ASSERT (strcmp (result1 + strlen (result1) - strlen ("/" BASE "/zzz"),
+                    "/" BASE "/zzz") == 0);
     free (result1);
     free (result2);
   }

   /* Check that alternate modes can resolve broken symlink basenames.  */
   {
-    char *result1 = canonicalize_filename_mode ("t-can.tmp/ouk", 
CAN_ALL_BUT_LAST);
-    char *result2 = canonicalize_filename_mode ("t-can.tmp/ouk", CAN_MISSING);
+    char *result1 = canonicalize_filename_mode (BASE "/ouk", CAN_ALL_BUT_LAST);
+    char *result2 = canonicalize_filename_mode (BASE "/ouk", CAN_MISSING);
     ASSERT (result1 != NULL);
     ASSERT (result2 != NULL);
     ASSERT (strcmp (result1, result2) == 0);
-    ASSERT (strcmp (result1 + strlen (result1) - 14, "/t-can.tmp/wum") == 0);
+    ASSERT (strcmp (result1 + strlen (result1) - strlen ("/" BASE "/wum"),
+                    "/" BASE "/wum") == 0);
     free (result1);
     free (result2);
   }
@@ -130,8 +216,8 @@ main ()
   /* Ensure that the following is resolved properly.
      Before 2007-09-27, it would mistakenly report a loop.  */
   {
-    char *result1 = canonicalize_filename_mode ("t-can.tmp", CAN_EXISTING);
-    char *result2 = canonicalize_filename_mode ("t-can.tmp/p/1", CAN_EXISTING);
+    char *result1 = canonicalize_filename_mode (BASE, CAN_EXISTING);
+    char *result2 = canonicalize_filename_mode (BASE "/p/1", CAN_EXISTING);
     ASSERT (result1 != NULL);
     ASSERT (result2 != NULL);
     ASSERT (strcmp (result2 + strlen (result1), "/d/2") == 0);
@@ -139,5 +225,21 @@ main ()
     free (result2);
   }

+  /* Cleanup.  */
+  ASSERT (remove (BASE "/d/1") == 0);
+  ASSERT (remove (BASE "/d/2") == 0);
+  ASSERT (remove (BASE "/d") == 0);
+  ASSERT (remove (BASE "/s") == 0);
+  ASSERT (remove (BASE "/p") == 0);
+  ASSERT (remove (BASE "/plo") == 0);
+  ASSERT (remove (BASE "/huk") == 0);
+  ASSERT (remove (BASE "/bef") == 0);
+  ASSERT (remove (BASE "/ouk") == 0);
+  ASSERT (remove (BASE "/ket") == 0);
+  ASSERT (remove (BASE "/lum") == 0);
+  ASSERT (remove (BASE "/tra") == 0);
+  ASSERT (remove (BASE) == 0);
+  ASSERT (remove ("ise") == 0);
+
   return 0;
 }
diff --git a/tests/test-canonicalize.sh b/tests/test-canonicalize.sh
deleted file mode 100755
index a4ab962..0000000
--- a/tests/test-canonicalize.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/sh
-
-tmpfiles=""
-trap 'rm -fr $tmpfiles' 1 2 3 15
-
-tmpfiles="$tmpfiles t-can.tmp ise"
-mkdir t-can.tmp
-test "x$HAVE_SYMLINK" = xyes \
-  && ln -s t-can.tmp/ket ise \
-  || { echo "Skipping test: symbolic links not supported on this filesystem"
-       rm -fr $tmpfiles
-       exit 77
-     }
-(cd t-can.tmp \
- && ln -s bef plo \
- && ln -s tra huk \
- && ln -s lum bef \
- && ln -s wum ouk \
- && ln -s ../ise ket \
- && echo > tra \
- && mkdir lum
-) || exit 1
-
-# Trigger a bug that would make the function mistakenly report a loop.
-# To trigger it, we have to construct a name/situation during the
-# 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.
-(cd t-can.tmp \
- && ln -s s p \
- && ln -s d s \
- && mkdir d \
- && echo > d/2 \
- && ln -s ../s/2 d/1
-) || exit 1
-
-./test-canonicalize${EXEEXT}
-result=$?
-
-rm -fr $tmpfiles
-
-exit $result
-- 
1.6.3.2


>From 12a600db720ef817f012acb3d6c3926998b8aac8 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 11 Sep 2009 12:18:10 -0600
Subject: [PATCH 07/11] canonicalize, canonicalize-lgpl: use <stdlib.h>

* modules/canonicalize-lgpl (Files): Drop canonicalize.h.
(Include): Mention <stdlib.h>.
(configure.ac): Mention functions we provide.
* modules/canonicalize (configure.ac): Likewise.
* m4/canonicalize-lgpl.m4 (gl_CANONICALIZE_LGPL): Always replace
realpath if canonicalize_file_name is missing.
* m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Provide defaults.
* modules/stdlib (Makefile.am): Substitute witnesses.
* lib/stdlib.in.h (canonicalize_file_name, realpath): Declare.
* lib/canonicalize-lgpl.c (includes): Adjust accordingly.
* lib/canonicalize.h (canonicalize_file_name): Drop declaration.
* NEWS: Document this.
* doc/glibc-functions/canonicalize_file_name.texi
(canonicalize_file_name): Likewise.
* doc/posix-functions/realpath.texi (realpath): Likewise.
* tests/test-canonicalize-lgpl.c (includes): Use <stdlib.h>.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                                       |   18 ++++++++++++++++
 NEWS                                            |    4 +++
 doc/glibc-functions/canonicalize_file_name.texi |    8 +++---
 doc/posix-functions/realpath.texi               |   21 ++++++++++++-------
 lib/canonicalize-lgpl.c                         |    9 +------
 lib/canonicalize.h                              |   15 +------------
 lib/stdlib.in.h                                 |   25 +++++++++++++++++++++++
 m4/canonicalize-lgpl.m4                         |    8 ++++--
 m4/stdlib_h.m4                                  |    6 ++++-
 modules/canonicalize                            |    1 +
 modules/canonicalize-lgpl                       |    7 +++--
 modules/stdlib                                  |    4 +++
 tests/test-canonicalize-lgpl.c                  |    3 +-
 13 files changed, 88 insertions(+), 41 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b3ef549..9541299 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
 2009-09-11  Eric Blake  <address@hidden>

+       canonicalize, canonicalize-lgpl: use <stdlib.h>
+       * modules/canonicalize-lgpl (Files): Drop canonicalize.h.
+       (Include): Mention <stdlib.h>.
+       (configure.ac): Mention functions we provide.
+       * modules/canonicalize (configure.ac): Likewise.
+       * m4/canonicalize-lgpl.m4 (gl_CANONICALIZE_LGPL): Always replace
+       realpath if canonicalize_file_name is missing.
+       * m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Provide defaults.
+       * modules/stdlib (Makefile.am): Substitute witnesses.
+       * lib/stdlib.in.h (canonicalize_file_name, realpath): Declare.
+       * lib/canonicalize-lgpl.c (includes): Adjust accordingly.
+       * lib/canonicalize.h (canonicalize_file_name): Drop declaration.
+       * NEWS: Document this.
+       * doc/glibc-functions/canonicalize_file_name.texi
+       (canonicalize_file_name): Likewise.
+       * doc/posix-functions/realpath.texi (realpath): Likewise.
+       * tests/test-canonicalize-lgpl.c (includes): Use <stdlib.h>.
+
        test-canonicalize: consolidate into single C program
        * tests/test-canonicalize.sh: Delete; move setup into...
        * tests/test-canonicalize.c (main): ...the program, making it
diff --git a/NEWS b/NEWS
index f506cba..2a8d2e1 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,10 @@ User visible incompatible changes

 Date        Modules         Changes

+2009-09-11  canonicalize-lgpl
+                            The include file is changed from "canonicalize.h"
+                            to <stdlib.h>.
+
 2009-09-04  link-follow     The macro LINK_FOLLOWS_SYMLINK is now tri-state,
                             rather than only defined to 1.

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 ce52cbc..c8f7e16 100644
--- a/lib/canonicalize-lgpl.c
+++ b/lib/canonicalize-lgpl.c
@@ -17,19 +17,14 @@

 #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>
 #include <unistd.h>

@@ -61,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
diff --git a/lib/canonicalize.h b/lib/canonicalize.h
index e068c20..bcf84f6 100644
--- a/lib/canonicalize.h
+++ b/lib/canonicalize.h
@@ -17,7 +17,8 @@
 #ifndef CANONICALIZE_H_
 # define CANONICALIZE_H_

-# if GNULIB_CANONICALIZE
+#include <stdlib.h> /* for canonicalize_file_name */
+
 enum canonicalize_mode_t
   {
     /* All components must exist.  */
@@ -36,17 +37,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_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..a6512c5 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,19 @@ extern void * realloc (void *ptr, size_t size);
      realloc (p, s))
 #endif

+#if @GNULIB_REALPATH@
+# if @REPLACE_REALPATH@
+#  define realpath rpl_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 or 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 bd3a381..d040c68 100644
--- a/m4/canonicalize-lgpl.m4
+++ b/m4/canonicalize-lgpl.m4
@@ -1,4 +1,4 @@
-# canonicalize-lgpl.m4 serial 6
+# canonicalize-lgpl.m4 serial 7
 dnl Copyright (C) 2003, 2006-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,
@@ -10,10 +10,12 @@ AC_DEFUN([gl_CANONICALIZE_LGPL],
   dnl than the function name.
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   AC_CHECK_FUNCS_ONCE([canonicalize_file_name])
+  dnl Assume that all platforms with canonicalize_file_name also have
+  dnl a working realpath; otherwise assume realpath is broken.
   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().])
+    REPLACE_REALPATH=1
     gl_PREREQ_CANONICALIZE_LGPL
   fi
 ])
diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4
index b7cf18c..8cb5d48 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])
@@ -70,6 +73,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 b/modules/canonicalize
index ec94c76..d039854 100644
--- a/modules/canonicalize
+++ b/modules/canonicalize
@@ -22,6 +22,7 @@ xgetcwd
 configure.ac:
 gl_FUNC_CANONICALIZE_FILENAME_MODE
 gl_MODULE_INDICATOR([canonicalize])
+gl_STDLIB_MODULE_INDICATOR([canonicalize_file_name])

 Makefile.am:

diff --git a/modules/canonicalize-lgpl b/modules/canonicalize-lgpl
index 45a9a43..c5ecd4f 100644
--- a/modules/canonicalize-lgpl
+++ b/modules/canonicalize-lgpl
@@ -1,8 +1,7 @@
 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

@@ -21,11 +20,13 @@ sys_stat
 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..fe429a0 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' \
@@ -63,6 +66,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 bc58d59..704c0ec 100644
--- a/tests/test-canonicalize-lgpl.c
+++ b/tests/test-canonicalize-lgpl.c
@@ -18,12 +18,11 @@

 #include <config.h>

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

 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <unistd.h>
-- 
1.6.3.2


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

* lib/canonicalize-lgpl.c (realpath): Guard with
FUNC_REALPATH_WORKS.
* lib/stdlib.in.h (realpath): Make declaration optional based on
HAVE_REALPATH.
* m4/canonicalize-lgpl.m4 (gl_CANONICALIZE_LGPL): Check whether
native realpath works.
* m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Provide default.
* modules/stdlib (Makefile.am): Substitute witness.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog               |   10 ++++++++++
 lib/canonicalize-lgpl.c |    4 ++--
 lib/stdlib.in.h         |    2 ++
 m4/canonicalize-lgpl.m4 |   29 +++++++++++++++++++++++++----
 m4/stdlib_h.m4          |    3 ++-
 modules/stdlib          |    1 +
 6 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9541299..6e77c20 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2009-09-11  Eric Blake  <address@hidden>

+       canonicalize-lgpl: use native realpath if it works
+       * lib/canonicalize-lgpl.c (realpath): Guard with
+       FUNC_REALPATH_WORKS.
+       * lib/stdlib.in.h (realpath): Make declaration optional based on
+       HAVE_REALPATH.
+       * m4/canonicalize-lgpl.m4 (gl_CANONICALIZE_LGPL): Check whether
+       native realpath works.
+       * m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Provide default.
+       * modules/stdlib (Makefile.am): Substitute witness.
+
        canonicalize, canonicalize-lgpl: use <stdlib.h>
        * modules/canonicalize-lgpl (Files): Drop canonicalize.h.
        (Include): Mention <stdlib.h>.
diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c
index c8f7e16..edf91e2 100644
--- a/lib/canonicalize-lgpl.c
+++ b/lib/canonicalize-lgpl.c
@@ -72,6 +72,7 @@
 # define __readlink readlink
 #endif

+#if !FUNC_REALPATH_WORKS || defined _LIBC
 /* 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
@@ -310,9 +311,8 @@ error:
   }
   return NULL;
 }
-#ifdef _LIBC
 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
-#endif
+#endif /* !FUNC_REALPATH_WORKS || defined _LIBC */


 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index a6512c5..b20f699 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -307,6 +307,8 @@ extern void * realloc (void *ptr, size_t size);
 #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
diff --git a/m4/canonicalize-lgpl.m4 b/m4/canonicalize-lgpl.m4
index d040c68..5f2e1a4 100644
--- a/m4/canonicalize-lgpl.m4
+++ b/m4/canonicalize-lgpl.m4
@@ -1,4 +1,4 @@
-# canonicalize-lgpl.m4 serial 7
+# canonicalize-lgpl.m4 serial 8
 dnl Copyright (C) 2003, 2006-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,
@@ -9,13 +9,34 @@ AC_DEFUN([gl_CANONICALIZE_LGPL],
   dnl Do this replacement check manually because the file name is shorter
   dnl than the function name.
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
-  AC_CHECK_FUNCS_ONCE([canonicalize_file_name])
+  AC_CHECK_FUNCS_ONCE([canonicalize_file_name realpath])
   dnl Assume that all platforms with canonicalize_file_name also have
-  dnl a working realpath; otherwise assume realpath is broken.
+  dnl a working realpath.
   if test $ac_cv_func_canonicalize_file_name = no; then
     HAVE_CANONICALIZE_FILE_NAME=0
     AC_LIBOBJ([canonicalize-lgpl])
-    REPLACE_REALPATH=1
+    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
 ])
diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4
index 8cb5d48..1bcf06e 100644
--- a/m4/stdlib_h.m4
+++ b/m4/stdlib_h.m4
@@ -1,4 +1,4 @@
-# stdlib_h.m4 serial 18
+# stdlib_h.m4 serial 19
 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,
@@ -63,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])
diff --git a/modules/stdlib b/modules/stdlib
index fe429a0..7de2cb0 100644
--- a/modules/stdlib
+++ b/modules/stdlib
@@ -56,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' \
-- 
1.6.3.2


>From b4a797b8de7f51e08fb24b93f044cf4dc95728e0 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 11 Sep 2009 13:31:06 -0600
Subject: [PATCH 09/11] canonicalize-lgpl: reject non-directory with trailing 
slash

* lib/canonicalize-lgpl.c (__realpath): Synchronize with glibc.
* tests/test-canonicalize-lgpl.c (main): Enhance test.  This
catches failures in glibc 2.3.5.
* tests/test-canonicalize.c (main): Likewise.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                      |    6 ++++
 lib/canonicalize-lgpl.c        |   47 ++++++++++++++++-----------------
 tests/test-canonicalize-lgpl.c |   36 +++++++++++++++++++++++++
 tests/test-canonicalize.c      |   56 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 121 insertions(+), 24 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6e77c20..f13b9a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2009-09-11  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.  This
+       catches failures in glibc 2.3.5.
+       * tests/test-canonicalize.c (main): Likewise.
+
        canonicalize-lgpl: use native realpath if it works
        * lib/canonicalize-lgpl.c (realpath): Guard with
        FUNC_REALPATH_WORKS.
diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c
index edf91e2..63aecb5 100644
--- a/lib/canonicalize-lgpl.c
+++ b/lib/canonicalize-lgpl.c
@@ -1,5 +1,5 @@
 /* Return the canonical absolute name of a given file.
-   Copyright (C) 1996-2003, 2005-2009 Free Software Foundation, Inc.
+   Copyright (C) 1996-2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.

    This program is free software: you can redistribute it and/or modify
@@ -15,38 +15,25 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

-#include <config.h>
+#ifndef _LIBC
+# include <config.h>
+#endif

 #if !HAVE_CANONICALIZE_FILE_NAME || defined _LIBC

-#include <alloca.h>
-
 /* Specification.  */
 #include <stdlib.h>

-#include <stddef.h>
+#include <alloca.h>
 #include <string.h>
 #include <unistd.h>
-
 #include <limits.h>
-
 #if HAVE_SYS_PARAM_H || defined _LIBC
 # include <sys/param.h>
 #endif
-#ifndef MAXSYMLINKS
-# ifdef SYMLOOP_MAX
-#  define MAXSYMLINKS SYMLOOP_MAX
-# else
-#  define MAXSYMLINKS 20
-# endif
-#endif
-
 #include <sys/stat.h>
-
 #include <errno.h>
-#ifndef _LIBC
-# define __set_errno(e) errno = (e)
-#endif
+#include <stddef.h>

 #ifdef _LIBC
 # include <shlib-compat.h>
@@ -70,6 +57,14 @@
 #  define __getcwd(buf, max) getwd (buf)
 # endif
 # define __readlink readlink
+# define __set_errno(e) errno = (e)
+# ifndef MAXSYMLINKS
+#  ifdef SYMLOOP_MAX
+#   define MAXSYMLINKS SYMLOOP_MAX
+#  else
+#   define MAXSYMLINKS 20
+#  endif
+# endif
 #endif

 #if !FUNC_REALPATH_WORKS || defined _LIBC
@@ -155,6 +150,7 @@ __realpath (const char *name, char *resolved)
 #else
       struct stat st;
 #endif
+      int n;

       /* Skip sequence of multiple path-separators.  */
       while (*start == '/')
@@ -232,7 +228,6 @@ __realpath (const char *name, char *resolved)
            {
              char *buf;
              size_t len;
-             int n;

              if (++num_links > MAXSYMLINKS)
                {
@@ -287,6 +282,11 @@ __realpath (const char *name, char *resolved)
                if (dest > rpath + 1)
                  while ((--dest)[-1] != '/');
            }
+         else if (!S_ISDIR (st.st_mode) && *end != '\0')
+           {
+             __set_errno (ENOTDIR);
+             goto error;
+           }
        }
     }
   if (dest > rpath + 1 && dest[-1] == '/')
@@ -296,16 +296,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;
   }
@@ -317,6 +315,7 @@ versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);

 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
 char *
+attribute_compat_text_section
 __old_realpath (const char *name, char *resolved)
 {
   if (resolved == NULL)
diff --git a/tests/test-canonicalize-lgpl.c b/tests/test-canonicalize-lgpl.c
index 704c0ec..f2c4e7a 100644
--- a/tests/test-canonicalize-lgpl.c
+++ b/tests/test-canonicalize-lgpl.c
@@ -82,6 +82,24 @@ main ()
     ASSERT (errno == EINVAL);
   }

+  /* Check that a non-directory with trailing slash yields NULL.  */
+  {
+    char *result;
+    errno = 0;
+    result = canonicalize_file_name (BASE "/tra/");
+    ASSERT (result == NULL);
+    ASSERT (errno == ENOTDIR);
+  }
+
+  /* Check that a missing directory yields NULL.  */
+  {
+    char *result;
+    errno = 0;
+    result = canonicalize_file_name (BASE "/zzz/..");
+    ASSERT (result == NULL);
+    ASSERT (errno == ENOENT);
+  }
+
   /* From here on out, tests involve symlinks.  */
   if (symlink (BASE "/ket", "ise") != 0)
     {
@@ -137,6 +155,24 @@ main ()
     ASSERT (errno == ENOENT);
   }

+  /* Check that a non-directory symlink with trailing slash yields NULL.  */
+  {
+    char *result;
+    errno = 0;
+    result = canonicalize_file_name (BASE "/huk/");
+    ASSERT (result == NULL);
+    ASSERT (errno == ENOTDIR);
+  }
+
+  /* Check that a missing directory via symlink yields NULL.  */
+  {
+    char *result;
+    errno = 0;
+    result = canonicalize_file_name (BASE "/ouk/..");
+    ASSERT (result == NULL);
+    ASSERT (errno == ENOENT);
+  }
+
   /* Check that a loop of symbolic links is detected.  */
   {
     char *result;
diff --git a/tests/test-canonicalize.c b/tests/test-canonicalize.c
index 6614422..1601a5b 100644
--- a/tests/test-canonicalize.c
+++ b/tests/test-canonicalize.c
@@ -90,6 +90,34 @@ main ()
     ASSERT (errno == EINVAL);
   }

+  /* Check that a non-directory with trailing slash yields NULL.  */
+  {
+    char *result1;
+    char *result2;
+    errno = 0;
+    result1 = canonicalize_file_name (BASE "/tra/");
+    ASSERT (result1 == NULL);
+    ASSERT (errno == ENOTDIR);
+    errno = 0;
+    result2 = canonicalize_filename_mode (BASE "/tra/", CAN_EXISTING);
+    ASSERT (result2 == NULL);
+    ASSERT (errno == ENOTDIR);
+  }
+
+  /* Check that a missing directory yields NULL.  */
+  {
+    char *result1;
+    char *result2;
+    errno = 0;
+    result1 = canonicalize_file_name (BASE "/zzz/..");
+    ASSERT (result1 == NULL);
+    ASSERT (errno == ENOENT);
+    errno = 0;
+    result1 = canonicalize_filename_mode (BASE "/zzz/..", CAN_EXISTING);
+    ASSERT (result2 == NULL);
+    ASSERT (errno == ENOENT);
+  }
+
   /* From here on out, tests involve symlinks.  */
   if (symlink (BASE "/ket", "ise") != 0)
     {
@@ -163,6 +191,34 @@ main ()
     ASSERT (errno == ENOENT);
   }

+  /* Check that a non-directory symlink with trailing slash yields NULL.  */
+  {
+    char *result1;
+    char *result2;
+    errno = 0;
+    result1 = canonicalize_file_name (BASE "/huk/");
+    ASSERT (result1 == NULL);
+    ASSERT (errno == ENOTDIR);
+    errno = 0;
+    result2 = canonicalize_filename_mode (BASE "/huk/", CAN_EXISTING);
+    ASSERT (result2 == NULL);
+    ASSERT (errno == ENOTDIR);
+  }
+
+  /* Check that a missing directory via symlink yields NULL.  */
+  {
+    char *result1;
+    char *result2;
+    errno = 0;
+    result1 = canonicalize_file_name (BASE "/ouk/..");
+    ASSERT (result1 == NULL);
+    ASSERT (errno == ENOENT);
+    errno = 0;
+    result2 = canonicalize_filename_mode (BASE "/ouk/..", CAN_EXISTING);
+    ASSERT (result2 == NULL);
+    ASSERT (errno == ENOENT);
+  }
+
   /* Check that a loop of symbolic links is detected.  */
   {
     char *result1;
-- 
1.6.3.2


>From 94ee151770f2b7712a3bd59069e0c54aaf6c6bec Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 11 Sep 2009 13:57:55 -0600
Subject: [PATCH 10/11] canonicalize-lgpl: fix glibc bug with trailing slash

* m4/canonicalize-lgpl.m4: Move contents...
* m4/canonicalize.m4: ...here.
(gl_CANONICALIZE_LGPL): Factor realpath check...
(gl_FUNC_REALPATH_WORKS): ...into new macro.  Enhance to catch
glibc 2.3.5 bug, fixed 2005-04-27.
(gl_FUNC_CANONICALIZE_FILENAME_MODE): Use it.
(gl_PREREQ_CANONICALIZE_LGPL): Inline...
(gl_CANONICALIZE_LGPL_SEPARATE): ...into this macro.
* modules/canonicalize-lgpl (Files): Manage file rename.
* m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Provide default.
* modules/stdlib (Makefile.am): Substitute witness.
* lib/stdlib.in.h (canonicalize_file_name): Declare if replacement
is needed.
* doc/glibc-functions/canonicalize_file_name.texi
(canonicalize_file_name): Document this.
* doc/posix-functions/realpath.texi (realpath): Likewise.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                                       |   18 +++++
 doc/glibc-functions/canonicalize_file_name.texi |    4 +
 doc/posix-functions/realpath.texi               |    4 +
 lib/stdlib.in.h                                 |    5 +-
 m4/canonicalize-lgpl.m4                         |   58 -----------------
 m4/canonicalize.m4                              |   76 ++++++++++++++++++++---
 m4/stdlib_h.m4                                  |    3 +-
 modules/canonicalize-lgpl                       |    2 +-
 modules/stdlib                                  |    1 +
 9 files changed, 102 insertions(+), 69 deletions(-)
 delete mode 100644 m4/canonicalize-lgpl.m4

diff --git a/ChangeLog b/ChangeLog
index f13b9a0..41601f3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
 2009-09-11  Eric Blake  <address@hidden>

+       canonicalize-lgpl: fix glibc bug with trailing slash
+       * m4/canonicalize-lgpl.m4: Move contents...
+       * m4/canonicalize.m4: ...here.
+       (gl_CANONICALIZE_LGPL): Factor realpath check...
+       (gl_FUNC_REALPATH_WORKS): ...into new macro.  Enhance to catch
+       glibc 2.3.5 bug, fixed 2005-04-27.
+       (gl_FUNC_CANONICALIZE_FILENAME_MODE): Use it.
+       (gl_PREREQ_CANONICALIZE_LGPL): Inline...
+       (gl_CANONICALIZE_LGPL_SEPARATE): ...into this macro.
+       * modules/canonicalize-lgpl (Files): Manage file rename.
+       * m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Provide default.
+       * modules/stdlib (Makefile.am): Substitute witness.
+       * lib/stdlib.in.h (canonicalize_file_name): Declare if replacement
+       is needed.
+       * doc/glibc-functions/canonicalize_file_name.texi
+       (canonicalize_file_name): Document this.
+       * doc/posix-functions/realpath.texi (realpath): 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.  This
diff --git a/doc/glibc-functions/canonicalize_file_name.texi b/doc/glibc-
functions/canonicalize_file_name.texi
index f034f81..5d17e26 100644
--- a/doc/glibc-functions/canonicalize_file_name.texi
+++ b/doc/glibc-functions/canonicalize_file_name.texi
@@ -9,6 +9,10 @@ canonicalize_file_name
 @item
 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.
address@hidden
+This function fails to detect trailing slashes on non-directories on
+some platforms:
+glibc 2.3.5.
 @end itemize

 Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/realpath.texi b/doc/posix-
functions/realpath.texi
index 01ce781..253845f 100644
--- a/doc/posix-functions/realpath.texi
+++ b/doc/posix-functions/realpath.texi
@@ -19,6 +19,10 @@ realpath
 This function does not always return an absolute path on some
 platforms:
 Solaris.
address@hidden
+This function fails to detect trailing slashes on non-directories on
+some platforms:
+glibc 2.3.5.
 @end itemize

 Portability problems not fixed by Gnulib:
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index b20f699..7a9246a 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -116,7 +116,10 @@ extern void * calloc (size_t nmemb, size_t size);
 #endif

 #if @GNULIB_CANONICALIZE_FILE_NAME@
-# if address@hidden@
+# if @REPLACE_CANONICALIZE_FILE_NAME@
+#  define canonicalize_file_name rpl_canonicalize_file_name
+# endif
+# if address@hidden@ || @REPLACE_CANONICALIZE_FILE_NAME@
 extern char *canonicalize_file_name (const char *name);
 # endif
 #elif defined GNULIB_POSIXCHECK
diff --git a/m4/canonicalize-lgpl.m4 b/m4/canonicalize-lgpl.m4
deleted file mode 100644
index 5f2e1a4..0000000
--- a/m4/canonicalize-lgpl.m4
+++ /dev/null
@@ -1,58 +0,0 @@
-# canonicalize-lgpl.m4 serial 8
-dnl Copyright (C) 2003, 2006-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,
-dnl with or without modifications, as long as this notice is preserved.
-
-AC_DEFUN([gl_CANONICALIZE_LGPL],
-[
-  dnl Do this replacement check manually because the file name is shorter
-  dnl than the function 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])
-    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
-])
-
-# Like gl_CANONICALIZE_LGPL, except prepare for separate compilation
-# (no AC_LIBOBJ).
-AC_DEFUN([gl_CANONICALIZE_LGPL_SEPARATE],
-[
-  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
-  AC_CHECK_FUNCS_ONCE([canonicalize_file_name])
-  gl_PREREQ_CANONICALIZE_LGPL
-])
-
-# Prerequisites of lib/canonicalize-lgpl.c.
-AC_DEFUN([gl_PREREQ_CANONICALIZE_LGPL],
-[
-  AC_CHECK_HEADERS_ONCE([sys/param.h])
-  AC_CHECK_FUNCS_ONCE([getcwd readlink])
-])
diff --git a/m4/canonicalize.m4 b/m4/canonicalize.m4
index 1258b3b..452285e 100644
--- a/m4/canonicalize.m4
+++ b/m4/canonicalize.m4
@@ -1,18 +1,78 @@
-# canonicalize.m4 serial 14
+# canonicalize.m4 serial 15

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

+# Provides canonicalize_file_name and canonicalize_filename_mode, but does
+# not provide or fix realpath.
 AC_DEFUN([gl_FUNC_CANONICALIZE_FILENAME_MODE],
 [
   AC_LIBOBJ([canonicalize])

   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   AC_CHECK_FUNCS_ONCE([canonicalize_file_name])
+  AC_REQUIRE([gl_FUNC_REALPATH_WORKS])
+  if test $ac_cv_func_canonicalize_file_name = no; then
+    HAVE_CANONICALIZE_FILE_NAME=0
+  elif test $gl_cv_func_realpath_works != yes; then
+    REPLACE_CANONICALIZE_FILE_NAME=1
+  fi
+])
+
+# Provides canonicalize_file_name and realpath.
+AC_DEFUN([gl_CANONICALIZE_LGPL],
+[
+  AC_REQUIRE([gl_CANONICALIZE_LGPL_SEPARATE])
+  if test $ac_cv_func_canonicalize_file_name = no; then
+    HAVE_CANONICALIZE_FILE_NAME=0
+    AC_LIBOBJ([canonicalize-lgpl])
+    if test $ac_cv_func_realpath = no; then
+      HAVE_REALPATH=0
+    elif test $gl_cv_func_realpath_works != yes; then
+      REPLACE_REALPATH=1
+    fi
+  elif test $gl_cv_func_realpath_works != yes; then
+    AC_LIBOBJ([canonicalize-lgpl])
+    REPLACE_REALPATH=1
+    REPLACE_CANONICALIZE_FILE_NAME=1
+  fi
+])
+
+# Like gl_CANONICALIZE_LGPL, except prepare for separate compilation
+# (no AC_LIBOBJ).
+AC_DEFUN([gl_CANONICALIZE_LGPL_SEPARATE],
+[
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_CHECK_FUNCS_ONCE([canonicalize_file_name getcwd readlink])
+  AC_REQUIRE([gl_FUNC_REALPATH_WORKS])
+  AC_CHECK_HEADERS_ONCE([sys/param.h])
+])
+
+# Check whether realpath works.  Assume that if a platform has both
+# realpath and canonicalize_file_name, but the former is broken, then
+# so is the latter.
+AC_DEFUN([gl_FUNC_REALPATH_WORKS],
+[
+  AC_CHECK_FUNCS_ONCE([realpath])
+  AC_CACHE_CHECK([whether realpath works], [gl_cv_func_realpath_works], [
+    touch conftest.a
+    AC_RUN_IFELSE([
+      AC_LANG_PROGRAM([[
+        #include <stdlib.h>
+      ]], [[
+        char *name1 = realpath ("conftest.a", NULL);
+        char *name2 = realpath ("conftest.a/", NULL);
+        return !(name1 && *name1 == '/' && !name2);
+      ]])
+    ], [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
+    AC_DEFINE([FUNC_REALPATH_WORKS], [1], [Define to 1 if realpath()
+      can malloc memory, always gives an absolute path, and handles
+      trailing slash correctly.])
+  fi
 ])
diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4
index 1bcf06e..42d551d 100644
--- a/m4/stdlib_h.m4
+++ b/m4/stdlib_h.m4
@@ -1,4 +1,4 @@
-# stdlib_h.m4 serial 19
+# stdlib_h.m4 serial 20
 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,
@@ -72,6 +72,7 @@ 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])
+  REPLACE_CANONICALIZE_FILE_NAME=0;  AC_SUBST([REPLACE_CANONICALIZE_FILE_NAME])
   REPLACE_MKSTEMP=0;         AC_SUBST([REPLACE_MKSTEMP])
   REPLACE_PUTENV=0;          AC_SUBST([REPLACE_PUTENV])
   REPLACE_REALPATH=0;        AC_SUBST([REPLACE_REALPATH])
diff --git a/modules/canonicalize-lgpl b/modules/canonicalize-lgpl
index c5ecd4f..f6b0055 100644
--- a/modules/canonicalize-lgpl
+++ b/modules/canonicalize-lgpl
@@ -3,7 +3,7 @@ realpath, canonical_file_name: Provide canonical absolute file 
name

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

 Depends-on:
 alloca-opt
diff --git a/modules/stdlib b/modules/stdlib
index 7de2cb0..323216c 100644
--- a/modules/stdlib
+++ b/modules/stdlib
@@ -65,6 +65,7 @@ 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|@''REPLACE_CANONICALIZE_FILE_NAME''@|$(REPLACE_CANONICALIZE_FILE_NAME)|g' \
              -e 's|@''REPLACE_MKSTEMP''@|$(REPLACE_MKSTEMP)|g' \
              -e 's|@''REPLACE_PUTENV''@|$(REPLACE_PUTENV)|g' \
              -e 's|@''REPLACE_REALPATH''@|$(REPLACE_REALPATH)|g' \
-- 
1.6.3.2


>From c598921828c933d74e721a3da262d359844802dc Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 10 Sep 2009 17:21:09 -0600
Subject: [PATCH 11/11] 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.
* modules/canonicalize-tests (Depends-on): Add same-inode.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                  |   10 ++++++++++
 lib/canonicalize.c         |   17 ++++++++++++++++-
 m4/canonicalize.m4         |    3 ++-
 modules/canonicalize       |    1 +
 modules/canonicalize-tests |    1 +
 tests/test-canonicalize.c  |   38 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 41601f3..50c23d8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2009-09-11  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.
+       * modules/canonicalize-tests (Depends-on): Add same-inode.
+
        canonicalize-lgpl: fix glibc bug with trailing slash
        * m4/canonicalize-lgpl.m4: Move contents...
        * m4/canonicalize.m4: ...here.
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 9620c8a..d3ea544 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -31,6 +31,10 @@
 #include "xalloc.h"
 #include "xgetcwd.h"

+#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
+# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
+#endif
+
 #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
@@ -121,6 +125,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)
@@ -142,6 +148,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
        {
@@ -224,7 +233,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)
@@ -244,6 +257,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 452285e..378b9ea 100644
--- a/m4/canonicalize.m4
+++ b/m4/canonicalize.m4
@@ -1,4 +1,4 @@
-# canonicalize.m4 serial 15
+# canonicalize.m4 serial 16

 dnl Copyright (C) 2003-2007, 2009 Free Software Foundation, Inc.

@@ -10,6 +10,7 @@ dnl with or without modifications, as long as this notice is 
preserved.
 # not provide or fix realpath.
 AC_DEFUN([gl_FUNC_CANONICALIZE_FILENAME_MODE],
 [
+  AC_REQUIRE([gl_DOUBLE_SLASH_ROOT])
   AC_LIBOBJ([canonicalize])

   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
diff --git a/modules/canonicalize b/modules/canonicalize
index d039854..39a5102 100644
--- a/modules/canonicalize
+++ b/modules/canonicalize
@@ -5,6 +5,7 @@ Files:
 lib/canonicalize.h
 lib/canonicalize.c
 m4/canonicalize.m4
+m4/double-slash-root.m4

 Depends-on:
 areadlink-with-size
diff --git a/modules/canonicalize-tests b/modules/canonicalize-tests
index f91c5f9..202d639 100644
--- a/modules/canonicalize-tests
+++ b/modules/canonicalize-tests
@@ -3,6 +3,7 @@ tests/test-canonicalize.c

 Depends-on:
 progname
+same-inode

 configure.ac:
 AC_CHECK_FUNCS_ONCE([symlink])
diff --git a/tests/test-canonicalize.c b/tests/test-canonicalize.c
index 1601a5b..ce38252 100644
--- a/tests/test-canonicalize.c
+++ b/tests/test-canonicalize.c
@@ -28,6 +28,8 @@
 #include <sys/stat.h>
 #include <unistd.h>

+#include "same-inode.h"
+
 #if !HAVE_SYMLINK
 # define symlink(a,b) (-1)
 #endif
@@ -138,6 +140,7 @@ main ()
   ASSERT (mkdir (BASE "/d", 0700) == 0);
   ASSERT (close (creat (BASE "/d/2", 0600)) == 0);
   ASSERT (symlink ("../s/2", BASE "/d/1") == 0);
+  ASSERT (symlink ("//.//..", BASE "/droot") == 0);

   /* Check that the symbolic link to a file can be resolved.  */
   {
@@ -281,7 +284,42 @@ 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 (BASE "/droot");
+    char *result4 = canonicalize_filename_mode (BASE "/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);
+  }
+
   /* Cleanup.  */
+  ASSERT (remove (BASE "/droot") == 0);
   ASSERT (remove (BASE "/d/1") == 0);
   ASSERT (remove (BASE "/d/2") == 0);
   ASSERT (remove (BASE "/d") == 0);
-- 
1.6.3.2







reply via email to

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