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.
func_module futimens
func_module getaddrinfo
func_module getcwd
+ func_module getcwd-lgpl
func_module getgroups
func_module gethostname
func_module getlogin
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.
--- /dev/null
+/* 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
# 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([[
]])])
])
+
+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],
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])
configure.ac:
gl_FUNC_GETCWD
+gl_MODULE_INDICATOR([getcwd])
gl_UNISTD_MODULE_INDICATOR([getcwd])
Makefile.am:
--- /dev/null
+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