getcwd-lgpl: new module
authorEric Blake <eblake@redhat.com>
Tue, 26 Apr 2011 20:40:58 +0000 (14:40 -0600)
committerEric Blake <eblake@redhat.com>
Wed, 27 Apr 2011 17:27:55 +0000 (11:27 -0600)
For programs that aren't worried about being invoked from an
current working directory longer than PATH_MAX (perhaps because
the program always does chdir to a sane location first), the
getcwd module is overkill, given that all modern portability
targets have a getcwd that works on short names.

* modules/getcwd-lgpl: New module.
* lib/getcwd-lgpl.c: New file.
* doc/posix-functions/getcwd.texi (getcwd): Document it.
* MODULES.html.sh (lacking POSIX:2008): Likewise.
* modules/getcwd (configure.ac): Set C witness.
* m4/getcwd.m4 (gl_FUNC_GETCWD_LGPL): New macro.

Signed-off-by: Eric Blake <eblake@redhat.com>
ChangeLog
MODULES.html.sh
doc/posix-functions/getcwd.texi
lib/getcwd-lgpl.c [new file with mode: 0644]
m4/getcwd.m4
modules/getcwd
modules/getcwd-lgpl [new file with mode: 0644]

index 4760fedcb13393d3e3b4999e8e44d17de1d0b938..b3d036ec3564cf10d963880fe44881c02a7ec5e7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2011-04-27  Eric Blake  <eblake@redhat.com>
 
+       getcwd-lgpl: new module
+       * modules/getcwd-lgpl: New module.
+       * lib/getcwd-lgpl.c: New file.
+       * doc/posix-functions/getcwd.texi (getcwd): Document it.
+       * MODULES.html.sh (lacking POSIX:2008): Likewise.
+       * modules/getcwd (configure.ac): Set C witness.
+       * m4/getcwd.m4 (gl_FUNC_GETCWD_LGPL): New macro.
+
        getcwd: tweak comments
        * m4/getcwd-abort-bug.m4: Fix comments.
        * m4/getcwd-path-max.m4: Likewise.
index 8d32a212588ad8718087b77fd6529c0c114cb8a4..a584c4ece526fad5ab1b8ae2365f4fafe62b0598 100755 (executable)
@@ -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
index 4d00af895572ad2c82e3b2be381736e8b0af909f..a8dba967ec21a941aae1fc6f9e4397761bb06590 100644 (file)
@@ -4,15 +4,20 @@
 
 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
+@code{getcwd-lgpl}:
 @itemize
 @item
-This function is missing on some older platforms.
-@item
 On glibc platforms, @code{getcwd (NULL, n)} allocates memory for the result.
 On other platforms, this call is not allowed.
+@end itemize
+
+Portability problems fixed by Gnulib module @code{getcwd}:
+@itemize
+@item
+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-lgpl.c b/lib/getcwd-lgpl.c
new file mode 100644 (file)
index 0000000..a5596f8
--- /dev/null
@@ -0,0 +1,118 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+   This file is part of gnulib.
+
+   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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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>
+
+/* Specification */
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+
+#if GNULIB_GETCWD
+/* Favor GPL getcwd.c if both getcwd and getcwd-lgpl modules are in use.  */
+typedef int dummy;
+#else
+
+/* 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
+   (perhaps because the absolute name was longer than PATH_MAX, or
+   because of missing read/search permissions on parent directories)
+   or SIZE was too small.  If successful, returns BUF.  If BUF is
+   NULL, an array is allocated with `malloc'; the array is SIZE bytes
+   long, unless SIZE == 0, in which case it is as big as
+   necessary.  */
+
+# undef getcwd
+char *
+rpl_getcwd (char *buf, size_t size)
+{
+  char *ptr;
+  char *result;
+
+  /* Handle single size operations.  */
+  if (buf)
+    return getcwd (buf, size);
+
+  if (size)
+    {
+      buf = malloc (size);
+      if (!buf)
+        {
+          errno = ENOMEM;
+          return -1;
+        }
+      result = getcwd (buf, size);
+      if (!result)
+        {
+          int saved_errno = errno;
+          free (buf);
+          errno = saved_errno;
+        }
+      return result;
+    }
+
+  /* Flexible sizing requested.  Avoid over-allocation for the common
+     case of a name that fits within a 4k page, minus some space for
+     local variables, to be sure we don't skip over a guard page.  */
+  {
+    char tmp[4032];
+    size = sizeof tmp;
+    ptr = getcwd (tmp, size);
+    if (ptr)
+      {
+        result = strdup (ptr);
+        if (!result)
+          errno = ENOMEM;
+        return result;
+      }
+    if (errno != ERANGE)
+      return NULL;
+  }
+
+  /* My what a large directory name we have.  */
+  do
+    {
+      size <<= 1;
+      ptr = realloc (buf, size);
+      if (ptr == NULL)
+        {
+          free (buf);
+          errno = ENOMEM;
+          return NULL;
+        }
+      buf = ptr;
+      result = getcwd (buf, size);
+    }
+  while (!result && errno == ERANGE);
+
+  if (!result)
+    {
+      int saved_errno = errno;
+      free (buf);
+      errno = saved_errno;
+    }
+  else
+    {
+      /* Trim to fit, if possible.  */
+      result = realloc (buf, strlen (buf) + 1);
+      if (!result)
+        result = buf;
+    }
+  return result;
+}
+
+#endif
index 0c7e20c2e06f6f08cb844f522f1827b2d3443338..55f937222bc2549da5491ff556c53bd1e7564f16 100644 (file)
@@ -6,10 +6,11 @@
 # 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],
   [
+   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
    AC_CACHE_CHECK([whether getcwd (NULL, 0) allocates memory for result],
      [gl_cv_func_getcwd_null],
      [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
@@ -52,6 +53,29 @@ AC_DEFUN([gl_FUNC_GETCWD_NULL],
         ]])])
 ])
 
+
+dnl Guarantee that getcwd will malloc with a NULL first argument.  Assumes
+dnl that either the system getcwd is robust, or that calling code is okay
+dnl with spurious failures when run from a directory with an absolute name
+dnl larger than 4k bytes.
+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])
+
+  case $gl_cv_func_getcwd_null in
+  *yes) ;;
+  *)
+    dnl Minimal replacement
+    REPLACE_GETCWD=1
+    AC_LIBOBJ([getcwd-lgpl])
+    ;;
+  esac
+])
+
 dnl Check for all known getcwd bugs; useful for a program likely to be
 dnl executed from an arbitrary location.
 AC_DEFUN([gl_FUNC_GETCWD],
@@ -72,13 +96,14 @@ 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, overrides LGPL 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])
index 108f14b28a022592f4a8caac9f3dccfc3d530d77..27ec25a4583382b942f23d7f8bafc3a29eb2362a 100644 (file)
@@ -20,6 +20,7 @@ strdup-posix
 
 configure.ac:
 gl_FUNC_GETCWD
+gl_MODULE_INDICATOR([getcwd])
 gl_UNISTD_MODULE_INDICATOR([getcwd])
 
 Makefile.am:
diff --git a/modules/getcwd-lgpl b/modules/getcwd-lgpl
new file mode 100644 (file)
index 0000000..1b9c87b
--- /dev/null
@@ -0,0 +1,25 @@
+Description:
+Ensure getcwd(NULL, 0) returns a buffer allocated by malloc().
+
+Files:
+lib/getcwd-lgpl.c
+m4/getcwd.m4
+
+Depends-on:
+strdup
+unistd
+
+configure.ac:
+gl_FUNC_GETCWD_LGPL
+gl_UNISTD_MODULE_INDICATOR([getcwd])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+Eric Blake