[Top][All Lists]
[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