bug-gnulib
[Top][All Lists]
Advanced

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

[PATCH 2/3] getcwd-lgpl: new module


From: Eric Blake
Subject: [PATCH 2/3] getcwd-lgpl: new module
Date: Mon, 25 Apr 2011 16:28:26 -0600

For programs that aren't worried about being invoked from an
arbitrarily long current working directory (perhaps because it
always does chdir to a sane location first), the getcwd module
is overkill, given that all modern portability have a getcwd
that works on short paths.

* modules/getcwd-lgpl: New module.
* doc/posix-functions/getcwd.texi (getcwd): Document it.
* MODULES.html.sh (lacking POSIX:2008): Likewise.
* m4/getcwd.m4 (gl_PREREQ_GETCWD): Define extra witness.
(gl_FUNC_GETCWD_LGPL): New macro.
* lib/getcwd.c (rpl_getcwd): Provide alternate LGPL
implementation.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                       |    9 ++
 MODULES.html.sh                 |    1 +
 doc/posix-functions/getcwd.texi |   13 ++-
 lib/getcwd.c                    |  208 +++++++++++++++++++++++++--------------
 m4/getcwd.m4                    |   30 +++++-
 modules/getcwd-lgpl             |   25 +++++
 6 files changed, 205 insertions(+), 81 deletions(-)
 create mode 100644 modules/getcwd-lgpl

diff --git a/ChangeLog b/ChangeLog
index f113c64..1105b88 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2011-04-25  Eric Blake  <address@hidden>

+       getcwd-lgpl: new module
+       * modules/getcwd-lgpl: New module.
+       * doc/posix-functions/getcwd.texi (getcwd): Document it.
+       * MODULES.html.sh (lacking POSIX:2008): Likewise.
+       * m4/getcwd.m4 (gl_PREREQ_GETCWD): Define extra witness.
+       (gl_FUNC_GETCWD_LGPL): New macro.
+       * lib/getcwd.c (rpl_getcwd): Provide alternate LGPL
+       implementation.
+
        getcwd: consolidate m4 files
        * m4/getcwd-abort-bug.m4, m4/getcwd-path-max.m4: Delete, moving
        contents...
diff --git a/MODULES.html.sh b/MODULES.html.sh
index 8d32a21..a584c4e 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -2353,6 +2353,7 @@ func_all_modules ()
   func_module futimens
   func_module getaddrinfo
   func_module getcwd
+  func_module getcwd-lgpl
   func_module getgroups
   func_module gethostname
   func_module getlogin
diff --git a/doc/posix-functions/getcwd.texi b/doc/posix-functions/getcwd.texi
index 4d00af8..a8dba96 100644
--- a/doc/posix-functions/getcwd.texi
+++ b/doc/posix-functions/getcwd.texi
@@ -4,15 +4,20 @@ getcwd

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

-Gnulib module: getcwd
+Gnulib module: getcwd or getcwd-lgpl

-Portability problems fixed by Gnulib:
+Portability problems fixed by either Gnulib module @code{getcwd} or
address@hidden:
 @itemize
 @item
-This function is missing on some older platforms.
address@hidden
 On glibc platforms, @code{getcwd (NULL, n)} allocates memory for the result.
 On other platforms, this call is not allowed.
address@hidden itemize
+
+Portability problems fixed by Gnulib module @code{getcwd}:
address@hidden
address@hidden
+This function is missing on some older platforms.
 @item
 This function does not handle long file names (greater than @code{PATH_MAX})
 correctly on some platforms.
diff --git a/lib/getcwd.c b/lib/getcwd.c
index e52af18..c221ecc 100644
--- a/lib/getcwd.c
+++ b/lib/getcwd.c
@@ -20,73 +20,77 @@
 #endif

 #include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <stdbool.h>
-#include <stddef.h>
+#include <string.h>
+
+#if USE_GPL_GETCWD
+
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <stddef.h>

-#include <fcntl.h> /* For AT_FDCWD on Solaris 9.  */
+# include <fcntl.h> /* For AT_FDCWD on Solaris 9.  */

 /* If this host provides the openat function, then enable
    code below to make getcwd more efficient and robust.  */
-#ifdef HAVE_OPENAT
-# define HAVE_OPENAT_SUPPORT 1
-#else
-# define HAVE_OPENAT_SUPPORT 0
-#endif
+# ifdef HAVE_OPENAT
+#  define HAVE_OPENAT_SUPPORT 1
+# else
+#  define HAVE_OPENAT_SUPPORT 0
+# endif

-#ifndef __set_errno
-# define __set_errno(val) (errno = (val))
-#endif
+# ifndef __set_errno
+#  define __set_errno(val) (errno = (val))
+# endif

-#include <dirent.h>
-#ifndef _D_EXACT_NAMLEN
-# define _D_EXACT_NAMLEN(d) strlen ((d)->d_name)
-#endif
-#ifndef _D_ALLOC_NAMLEN
-# define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1)
-#endif
+# include <dirent.h>
+# ifndef _D_EXACT_NAMLEN
+#  define _D_EXACT_NAMLEN(d) strlen ((d)->d_name)
+# endif
+# ifndef _D_ALLOC_NAMLEN
+#  define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1)
+# endif

-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
+# include <unistd.h>
+# include <stdlib.h>
+# include <string.h>

-#if _LIBC
-# ifndef mempcpy
-#  define mempcpy __mempcpy
+# if _LIBC
+#  ifndef mempcpy
+#   define mempcpy __mempcpy
+#  endif
 # endif
-#endif

-#include <limits.h>
+# include <limits.h>

-#ifndef MAX
-# define MAX(a, b) ((a) < (b) ? (b) : (a))
-#endif
-#ifndef MIN
-# define MIN(a, b) ((a) < (b) ? (a) : (b))
-#endif
+# ifndef MAX
+#  define MAX(a, b) ((a) < (b) ? (b) : (a))
+# endif
+# ifndef MIN
+#  define MIN(a, b) ((a) < (b) ? (a) : (b))
+# endif

-#ifndef PATH_MAX
-# ifdef MAXPATHLEN
-#  define PATH_MAX MAXPATHLEN
-# else
-#  define PATH_MAX 1024
+# ifndef PATH_MAX
+#  ifdef MAXPATHLEN
+#   define PATH_MAX MAXPATHLEN
+#  else
+#   define PATH_MAX 1024
+#  endif
 # endif
-#endif

-#if D_INO_IN_DIRENT
-# define MATCHING_INO(dp, ino) ((dp)->d_ino == (ino))
-#else
-# define MATCHING_INO(dp, ino) true
-#endif
+# if D_INO_IN_DIRENT
+#  define MATCHING_INO(dp, ino) ((dp)->d_ino == (ino))
+# else
+#  define MATCHING_INO(dp, ino) true
+# endif

-#if !_LIBC
-# define __getcwd rpl_getcwd
-# define __lstat lstat
-# define __closedir closedir
-# define __opendir opendir
-# define __readdir readdir
-#endif
+# if !_LIBC
+#  define __getcwd rpl_getcwd
+#  define __lstat lstat
+#  define __closedir closedir
+#  define __opendir opendir
+#  define __readdir readdir
+# endif

 /* The results of opendir() in this file are not used with dirfd and fchdir,
    and we do not leak fds to any single-threaded code that could use stdio,
@@ -94,8 +98,8 @@
    FIXME - if the kernel ever adds support for multi-thread safety for
    avoiding standard fds, then we should use opendir_safer and
    openat_safer.  */
-#undef opendir
-#undef closedir
+# undef opendir
+# undef closedir
 
 /* Get the name of the current working directory, and put it in SIZE
    bytes of BUF.  Returns NULL if the directory couldn't be determined or
@@ -118,15 +122,15 @@ __getcwd (char *buf, size_t size)
       DEEP_NESTING = 100
     };

-#if HAVE_OPENAT_SUPPORT
+# if HAVE_OPENAT_SUPPORT
   int fd = AT_FDCWD;
   bool fd_needs_closing = false;
-#else
+# else
   char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
   char *dotlist = dots;
   size_t dotsize = sizeof dots;
   size_t dotlen = 0;
-#endif
+# endif
   DIR *dirstream = NULL;
   dev_t rootdev, thisdev;
   ino_t rootino, thisino;
@@ -136,7 +140,7 @@ __getcwd (char *buf, size_t size)
   size_t allocated = size;
   size_t used;

-#if HAVE_RAW_DECL_GETCWD
+# if HAVE_RAW_DECL_GETCWD
   /* If AT_FDCWD is not defined, the algorithm below is O(N**2) and
      this is much slower than the system getcwd (at least on
      GNU/Linux).  So trust the system getcwd's results unless they
@@ -146,7 +150,7 @@ __getcwd (char *buf, size_t size)
      system getcwd works even when a parent is unreadable, while the
      openat-based approach does not.  */

-# undef getcwd
+#  undef getcwd
   dir = getcwd (buf, size);
   if (dir)
     return dir;
@@ -163,13 +167,13 @@ __getcwd (char *buf, size_t size)
         return strdup (dir);
     }

-# if HAVE_PARTLY_WORKING_GETCWD
+#  if HAVE_PARTLY_WORKING_GETCWD
   /* The system getcwd works, except it sometimes fails when it
      shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT.    */
   if (errno != ERANGE && errno != ENAMETOOLONG && errno != ENOENT)
     return NULL;
+#  endif
 # endif
-#endif

   if (size == 0)
     {
@@ -216,18 +220,18 @@ __getcwd (char *buf, size_t size)
       bool use_d_ino = true;

       /* Look at the parent directory.  */
-#if HAVE_OPENAT_SUPPORT
+# if HAVE_OPENAT_SUPPORT
       fd = openat (fd, "..", O_RDONLY);
       if (fd < 0)
         goto lose;
       fd_needs_closing = true;
       parent_status = fstat (fd, &st);
-#else
+# else
       dotlist[dotlen++] = '.';
       dotlist[dotlen++] = '.';
       dotlist[dotlen] = '\0';
       parent_status = __lstat (dotlist, &st);
-#endif
+# endif
       if (parent_status != 0)
         goto lose;

@@ -243,17 +247,17 @@ __getcwd (char *buf, size_t size)
       mount_point = dotdev != thisdev;

       /* Search for the last directory.  */
-#if HAVE_OPENAT_SUPPORT
+# if HAVE_OPENAT_SUPPORT
       dirstream = fdopendir (fd);
       if (dirstream == NULL)
         goto lose;
       fd_needs_closing = false;
-#else
+# else
       dirstream = __opendir (dotlist);
       if (dirstream == NULL)
         goto lose;
       dotlist[dotlen++] = '/';
-#endif
+# endif
       for (;;)
         {
           /* Clear errno to distinguish EOF from error if readdir returns
@@ -297,9 +301,9 @@ __getcwd (char *buf, size_t size)

           {
             int entry_status;
-#if HAVE_OPENAT_SUPPORT
+# if HAVE_OPENAT_SUPPORT
             entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
-#else
+# else
             /* Compute size needed for this file name, or for the file
                name ".." in the same directory, whichever is larger.
                Room for ".." might be needed the next time through
@@ -336,7 +340,7 @@ __getcwd (char *buf, size_t size)

             memcpy (dotlist + dotlen, d->d_name, _D_ALLOC_NAMLEN (d));
             entry_status = __lstat (dotlist, &st);
-#endif
+# endif
             /* We don't fail here if we cannot stat() a directory entry.
                This can happen when (network) file systems fail.  If this
                entry is in fact the one we are looking for we will find
@@ -393,10 +397,10 @@ __getcwd (char *buf, size_t size)
   if (dirp == &dir[allocated - 1])
     *--dirp = '/';

-#if ! HAVE_OPENAT_SUPPORT
+# if ! HAVE_OPENAT_SUPPORT
   if (dotlist != dots)
     free (dotlist);
-#endif
+# endif

   used = dir + allocated - dirp;
   memmove (dir, dirp, used);
@@ -419,13 +423,13 @@ __getcwd (char *buf, size_t size)
     int save = errno;
     if (dirstream)
       __closedir (dirstream);
-#if HAVE_OPENAT_SUPPORT
+# if HAVE_OPENAT_SUPPORT
     if (fd_needs_closing)
       close (fd);
-#else
+# else
     if (dotlist != dots)
       free (dotlist);
-#endif
+# endif
     if (buf == NULL)
       free (dir);
     __set_errno (save);
@@ -433,6 +437,60 @@ __getcwd (char *buf, size_t size)
   return NULL;
 }

-#ifdef weak_alias
+# ifdef weak_alias
 weak_alias (__getcwd, getcwd)
+# endif
+
+#else
+/* LGPL version - only guarantees that NULL can be used as first
+   argument.  */
+
+# undef getcwd
+char *
+rpl_getcwd (char *buf, size_t size)
+{
+  char *tmp = NULL;
+  bool first = true;
+
+  if (buf)
+    return getcwd (buf, size);
+
+  do
+    {
+      tmp = buf;
+      if (first)
+        {
+          size = size ? size : 4096;
+          first = false;
+        }
+      else
+        {
+          size <<= 1;
+        }
+      if ((buf = realloc (tmp, size)) == NULL)
+        {
+          free (tmp);
+          errno = ENOMEM;
+          return NULL;
+        }
+      tmp = getcwd (buf, size);
+    }
+  while (!tmp && errno == ERANGE);
+
+  if (!tmp)
+    {
+      int saved_errno = errno;
+      free (buf);
+      errno = saved_errno;
+    }
+  else
+    {
+      /* Trim to fit, if possible.  */
+      tmp = realloc (buf, strlen (buf) + 1);
+      if (!tmp)
+        tmp = buf;
+    }
+  return tmp;
+}
+
 #endif
diff --git a/m4/getcwd.m4 b/m4/getcwd.m4
index 5016a1b..79f5276 100644
--- a/m4/getcwd.m4
+++ b/m4/getcwd.m4
@@ -6,7 +6,7 @@
 # with or without modifications, as long as this notice is preserved.

 # Written by Paul Eggert.
-# serial 4
+# serial 5

 AC_DEFUN([gl_FUNC_GETCWD_NULL],
   [
@@ -333,6 +333,28 @@ main ()
 ])


+dnl Check just for getcwd behavior on NULL.  Assumes that either the
+dnl system getcwd works, or that the code is okay with spurious
+dnl failures when run from super-deep hierarchies.
+dnl
+dnl Assumes that getcwd exists; if you are worried about obsolete
+dnl platforms that lacked getcwd(), then you need to use the GPL module.
+AC_DEFUN([gl_FUNC_GETCWD_LGPL],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_REQUIRE([gl_FUNC_GETCWD_NULL])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+
+  case $gl_cv_func_getcwd_null in
+  *yes) ;;
+  *)
+    dnl Minimal replacement
+    REPLACE_GETCWD=1
+    AC_LIBOBJ([getcwd])
+  esac
+])
+
+
 dnl Check for all known getcwd bugs; useful for a program likely to be
 dnl executed from an arbitrary location, by augmenting native getcwd.
 AC_DEFUN([gl_FUNC_GETCWD],
@@ -353,16 +375,20 @@ AC_DEFUN([gl_FUNC_GETCWD],
   case $gl_cv_func_getcwd_null,$gl_cv_func_getcwd_path_max,$gl_abort_bug in
   *yes,yes,no) ;;
   *)
+    dnl Full replacement.
     REPLACE_GETCWD=1
     AC_LIBOBJ([getcwd])
     gl_PREREQ_GETCWD;;
   esac
 ])

-# Prerequisites of lib/getcwd.c.
+# Prerequisites of lib/getcwd.c, when full replacement is in effect.
 AC_DEFUN([gl_PREREQ_GETCWD],
 [
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   AC_REQUIRE([gl_CHECK_TYPE_STRUCT_DIRENT_D_INO])
+  AC_DEFINE([USE_GPL_GETCWD], [1],
+      [Define to 1 if GPL code should be used to attempt to work around
+       native getcwd failures.])
   :
 ])
diff --git a/modules/getcwd-lgpl b/modules/getcwd-lgpl
new file mode 100644
index 0000000..e043623
--- /dev/null
+++ b/modules/getcwd-lgpl
@@ -0,0 +1,25 @@
+Description:
+Ensure getcwd(NULL, 0) returns a buffer allocated by malloc().
+
+Files:
+lib/getcwd.c
+m4/getcwd.m4
+
+Depends-on:
+stdbool
+unistd
+
+configure.ac:
+gl_FUNC_GETCWD_LGPL
+gl_UNISTD_MODULE_INDICATOR([getcwd])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+Eric Blake
-- 
1.7.4.4




reply via email to

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