+2004-11-26 Paul Eggert <eggert@cs.ucla.edu>
+
+ * modules/getcwd (Files): Add lib/getcwd.h, m4/getcwd.m4.
+ (Depends-on): Remove pathmax, same. Add mempcpy.
+ (configure.ac): GL_FUNC_GETCWD_PATH_MAX -> gl_FUNC_GETCWD.
+ (Makefile.am): Append getcwd.h to lib_SOURCES.
+ (Include): Add getcwd.h.
+ (Maintainer): Change from Jim Meyering to "all, glibc",
+ since getdate now uses intended-for-glibc code.
+ * modules/xgetcwd (Files): Remove m4/getcwd.m4.
+ (Depends-on): Depend on getcwd. Do not depend on pathmax.
+
2004-11-22 Paul Eggert <eggert@cs.ucla.edu>
* modules/canonicalize (Depends-on): Add xreadlink.
+2004-11-25 Paul Eggert <eggert@cs.ucla.edu>
+
+ Fix problems reported by Scott S. Tinsley for HP-UX 11.11 using
+ HP's ANSI C compiler.
+ * fsusage.c (statvfs) [HAVE_SYS_STATVFS_H]: Remove decl.
+ Declaring int functions causes warnings on some modern systems and
+ shouldn't be needed to compile on ancient ones.
+ * same.c (MIN) [defined MIN]: Don't define, since it's already
+ defined.
+
+ * getcwd.c: Replace by a copy of glibc/sysdeps/posix/getcwd.c, but
+ with the following changes.
+ (__set_errno): Parenthesize properly.
+ Include <stdbool.h>.
+ (MIN, MAX, MATCHING_INO): New macros.
+ (__getcwd): Define with prototype, not K&R form.
+ Use heuristics to allocate default buffer on stack if possible.
+ If AT_FDCWD is defined, use openat and fstatat to avoid O(N**2)
+ behavior, and to avoid the PATH_MAX limit when computing
+ ../../../../...
+ Use MATCHING_INO to compare inode number to file.
+ Check for arithmetic overflow in size calculations.
+ Fix bug in reallocation of dot array that caused getcwd to fail
+ on directories nested deeper than 75.
+ Be more careful about saving errno on error.
+ Do not use realloc; use only free+malloc, as this is a bit
+ more flexible and avoids a needless copy operation.
+ Do not inspect st_dev and st_ino for symbolic links; POSIX
+ doesn't specify the latter.
+ Check for closedir errors.
+ Avoid needless casts.
+ Use "#ifdef weak_alias" around weak_alias, to be like other
+ glibc code.
+ The following changes to getcwd.c have effect only when used in
+ gnulib; they have no effect inside glibc proper.
+ (#pragma alloca) [defined _AIX && !defined __GNUC__]: Remove,
+ as alloca isn't used.
+ (alloca, __alloca): Likewise.
+ [!_LIBC]: Include "getcwd.h", "mempcpy.h".
+ Include <stddef.h>, <stdlib.h>, <string.h>, <limits.h>
+ unconditionally, as gnulib assumes C89 or better.
+ Do not include <sys/param.h>.
+ (errno) [!defined __GNU_LIBRARY__ && !defined STDC_HEADERS]: Remove
+ no-longer-necessary 'extern int errno' decl; gnulib assumes C89 or
+ better.
+ (NULL) [!defined NULL]: Remove; we assume C89 or better.
+ Include <dirent.h> in a way that is compatible with modern Autoconf.
+ (_D_ALLOC_NAMELEN, _D_EXACT_NAMLEN):
+ New macros, if not already defined.
+ Include <unistd.h> if _LIBC, not if __GNU_LIBRARY__.
+ Use "_LIBC", not "defined _LIBC", for consistency.
+ (HAVE_MEMPCPY): Remove; no longer needed now that gnulib has
+ a mempcpy module.
+ (__lstat, __closedir, __opendir, __readdir) [!_LIBC]: New macros.
+ (GETCWD_RETURN_TYPE): Remove. All uses replaced by char *.
+ * xgetcwd.c: David MacKenzie's old code was removed, so give
+ credit only to Jim Meyering and adjust the copyright dates.
+ Do not include <limits.h>, <stdio.h>, <sys/types.h>,
+ <stdlib.h>, <unistd.h>, "pathmax.h".
+ Instead, include "xgetcwd.h" (first) and "getcwd.h".
+ (INITIAL_BUFFER_SIZE): Remove.
+ (xgetcwd): Rely on getcwd, since we now depend on a reliable one.
+
2004-11-23 Jim Meyering <jim@meyering.net>
* getopt_.h: Remove trailing blanks.
#if HAVE_SYS_STATVFS_H /* SVR4 */
# include <sys/statvfs.h>
-int statvfs ();
#endif
#include "full-read.h"
-/* Provide a replacement for the POSIX getcwd function.
- Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,93,94,95,96,97,98,99,2004 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
it under the terms of the GNU General Public License as published by
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, write to the Free Software Foundation,
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-/* written by Jim Meyering */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
-#include <config.h>
+#if !_LIBC
+# include "getcwd.h"
+#endif
-#include <stdlib.h>
-#include <string.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#if HAVE_FCNTL_H
+# include <fcntl.h> /* For AT_FDCWD on Solaris 9. */
+#endif
-#include "pathmax.h"
-#include "same.h"
+#ifndef __set_errno
+# define __set_errno(val) (errno = (val))
+#endif
-/* Guess high, because that makes the test below more conservative.
- But this is a kludge, because we should really use
- pathconf (".", _PC_NAME_MAX). But it's probably not worth the cost. */
-#define KLUDGE_POSIX_NAME_MAX 255
+#if HAVE_DIRENT_H || _LIBC
+# include <dirent.h>
+# ifndef _D_EXACT_NAMLEN
+# define _D_EXACT_NAMLEN(d) strlen ((d)->d_name)
+# endif
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+#ifndef _D_EXACT_NAMLEN
+# define _D_EXACT_NAMLEN(d) ((d)->d_namlen)
+#endif
+#ifndef _D_ALLOC_NAMLEN
+# define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1)
+#endif
-#define MAX_SAFE_LEN (PATH_MAX - 1 - KLUDGE_POSIX_NAME_MAX - 1)
+#if HAVE_UNISTD_H || _LIBC
+# include <unistd.h>
+#endif
-/* Undefine getcwd here, as near the use as possible, in case any
- of the files included above define it to rpl_getcwd. */
-#undef getcwd
+#include <stdlib.h>
+#include <string.h>
-/* Any declaration of getcwd from headers included above has
- been changed to a declaration of rpl_getcwd. Declare it here. */
-extern char *getcwd (char *buf, size_t size);
+#if _LIBC
+# ifndef mempcpy
+# define mempcpy __mempcpy
+# endif
+#else
+# include "mempcpy.h"
+#endif
-/* This is a wrapper for getcwd.
- Some implementations (at least GNU libc 2.3.1 + linux-2.4.20) return
- non-NULL for a working directory name longer than PATH_MAX, yet the
- returned string is a strict prefix of the desired directory name.
- Upon such a failure, free the offending string, set errno to
- ENAMETOOLONG, and return NULL.
+#include <limits.h>
- I've heard that this is a Linux kernel bug, and that it has
- been fixed between 2.4.21-pre3 and 2.4.21-pre4. */
+#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
+# 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 !_LIBC
+# define __getcwd getcwd
+# define __lstat lstat
+# define __closedir closedir
+# define __opendir opendir
+# define __readdir readdir
+#endif
+\f
+/* Get the pathname of the current working directory, and put it in SIZE
+ bytes of BUF. Returns NULL if the directory couldn't be determined or
+ SIZE was too small. If successful, returns BUF. In GNU, 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. */
char *
-rpl_getcwd (char *buf, size_t size)
+__getcwd (char *buf, size_t size)
{
- char *cwd = getcwd (buf, size);
+ /* Lengths of big file name components and entire file names, and a
+ deep level of file name nesting. These numbers are not upper
+ bounds; they are merely large values suitable for initial
+ allocations, designed to be large enough for most real-world
+ uses. */
+ enum
+ {
+ BIG_FILE_NAME_COMPONENT_LENGTH = 255,
+ BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
+ DEEP_NESTING = 100
+ };
+
+#ifdef AT_FDCWD
+ int fd = AT_FDCWD;
+ bool fd_needs_closing = false;
+#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
+ DIR *dirstream = NULL;
+ dev_t rootdev, thisdev;
+ ino_t rootino, thisino;
+ char *path;
+ register char *pathp;
+ struct stat st;
+ int prev_errno = errno;
+ size_t allocated = size;
+
+ if (size == 0)
+ {
+ if (buf != NULL)
+ {
+ __set_errno (EINVAL);
+ return NULL;
+ }
+
+ allocated = BIG_FILE_NAME_LENGTH + 1;
+ }
+
+ if (buf != NULL)
+ path = buf;
+ else
+ {
+ path = malloc (allocated);
+ if (path == NULL)
+ return NULL;
+ }
+
+ pathp = path + allocated;
+ *--pathp = '\0';
+
+ if (__lstat (".", &st) < 0)
+ goto lose;
+ thisdev = st.st_dev;
+ thisino = st.st_ino;
+
+ if (__lstat ("/", &st) < 0)
+ goto lose;
+ rootdev = st.st_dev;
+ rootino = st.st_ino;
+
+ while (!(thisdev == rootdev && thisino == rootino))
+ {
+ struct dirent *d;
+ dev_t dotdev;
+ ino_t dotino;
+ bool mount_point;
+ int parent_status;
+
+ /* Look at the parent directory. */
+#ifdef AT_FDCWD
+ fd = openat (fd, "..", O_RDONLY);
+ if (fd < 0)
+ goto lose;
+ fd_needs_closing = true;
+ parent_status = fstat (fd, &st);
+#else
+ dotlist[dotlen++] = '.';
+ dotlist[dotlen++] = '.';
+ dotlist[dotlen] = '\0';
+ parent_status = __lstat (dotlist, &st);
+#endif
+ if (parent_status != 0)
+ goto lose;
- if (cwd == NULL)
- return NULL;
+ if (dirstream && __closedir (dirstream) != 0)
+ {
+ dirstream = NULL;
+ goto lose;
+ }
- if (strlen (cwd) <= MAX_SAFE_LEN || same_name (cwd, "."))
- return cwd;
+ /* Figure out if this directory is a mount point. */
+ dotdev = st.st_dev;
+ dotino = st.st_ino;
+ mount_point = dotdev != thisdev;
- free (cwd);
- errno = ENAMETOOLONG;
+ /* Search for the last directory. */
+#ifdef AT_FDCWD
+ dirstream = fdopendir (fd);
+ if (dirstream == NULL)
+ goto lose;
+ fd_needs_closing = false;
+#else
+ dirstream = __opendir (dotlist);
+ if (dirstream == NULL)
+ goto lose;
+ dotlist[dotlen++] = '/';
+#endif
+ /* Clear errno to distinguish EOF from error if readdir returns
+ NULL. */
+ __set_errno (0);
+ while ((d = __readdir (dirstream)) != NULL)
+ {
+ if (d->d_name[0] == '.' &&
+ (d->d_name[1] == '\0' ||
+ (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ continue;
+ if (MATCHING_INO (d, thisino) || mount_point)
+ {
+ int entry_status;
+#ifdef AT_FDCWD
+ entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
+#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
+ the outer loop. */
+ size_t name_alloc = _D_ALLOC_NAMLEN (d);
+ size_t filesize = dotlen + MAX (sizeof "..", name_alloc);
+
+ if (filesize < dotlen)
+ goto memory_exhausted;
+
+ if (dotsize < filesize)
+ {
+ /* My, what a deep directory tree you have, Grandma. */
+ size_t newsize = MAX (filesize, dotsize * 2);
+ size_t i;
+ if (newsize < dotsize)
+ goto memory_exhausted;
+ if (dotlist != dots)
+ free (dotlist);
+ dotlist = malloc (newsize);
+ if (dotlist == NULL)
+ goto lose;
+ dotsize = newsize;
+
+ i = 0;
+ do
+ {
+ dotlist[i++] = '.';
+ dotlist[i++] = '.';
+ dotlist[i++] = '/';
+ }
+ while (i < dotlen);
+ }
+
+ strcpy (dotlist + dotlen, d->d_name);
+ entry_status = __lstat (dotlist, &st);
+#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
+ out soon as we reach the end of the directory without
+ having found anything. */
+ if (entry_status == 0 && S_ISDIR (st.st_mode)
+ && st.st_dev == thisdev && st.st_ino == thisino)
+ break;
+ }
+ }
+ if (d == NULL)
+ {
+ if (errno == 0)
+ /* EOF on dirstream, which means that the current directory
+ has been removed. */
+ __set_errno (ENOENT);
+ goto lose;
+ }
+ else
+ {
+ size_t pathroom = pathp - path;
+ size_t namlen = _D_EXACT_NAMLEN (d);
+
+ if (pathroom <= namlen)
+ {
+ if (size != 0)
+ {
+ __set_errno (ERANGE);
+ goto lose;
+ }
+ else
+ {
+ char *tmp;
+ size_t oldsize = allocated;
+
+ allocated += MAX (allocated, namlen);
+ if (allocated < oldsize
+ || ! (tmp = realloc (path, allocated)))
+ goto memory_exhausted;
+
+ /* Move current contents up to the end of the buffer.
+ This is guaranteed to be non-overlapping. */
+ pathp = memcpy (tmp + allocated - (oldsize - pathroom),
+ tmp + pathroom,
+ oldsize - pathroom);
+ path = tmp;
+ }
+ }
+ pathp -= namlen;
+ memcpy (pathp, d->d_name, namlen);
+ *--pathp = '/';
+ }
+
+ thisdev = dotdev;
+ thisino = dotino;
+ }
+
+ if (dirstream && __closedir (dirstream) != 0)
+ {
+ dirstream = NULL;
+ goto lose;
+ }
+
+ if (pathp == &path[allocated - 1])
+ *--pathp = '/';
+
+#ifndef AT_FDCWD
+ if (dotlist != dots)
+ free (dotlist);
+#endif
+
+ memmove (path, pathp, path + allocated - pathp);
+
+ /* Restore errno on successful return. */
+ __set_errno (prev_errno);
+
+ return path;
+
+ memory_exhausted:
+ __set_errno (ENOMEM);
+ lose:
+ {
+ int save = errno;
+ if (dirstream)
+ __closedir (dirstream);
+#ifdef AT_FDCWD
+ if (fd_needs_closing)
+ close (fd);
+#else
+ if (dotlist != dots)
+ free (dotlist);
+#endif
+ if (buf == NULL)
+ free (path);
+ __set_errno (save);
+ }
return NULL;
}
+
+#ifdef weak_alias
+weak_alias (__getcwd, getcwd)
+#endif
#include "error.h"
#include "xalloc.h"
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#ifndef MIN
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
#define SAME_INODE(Stat_buf_1, Stat_buf_2) \
((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
/* xgetcwd.c -- return current directory with unlimited length
- Copyright (C) 1992, 1996, 2000, 2001, 2003, 2004 Free Software
- Foundation, Inc.
+ Copyright (C) 2001, 2003, 2004 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
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+/* Written by Jim Meyering. */
#if HAVE_CONFIG_H
# include <config.h>
#endif
-#include <limits.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <stdlib.h>
-
-#if HAVE_UNISTD_H
-# include <unistd.h>
-#endif
+#include "xgetcwd.h"
-#if HAVE_GETCWD
-char *getcwd ();
-#else
-# include "pathmax.h"
-# define INITIAL_BUFFER_SIZE (PATH_MAX + 1)
-char *getwd ();
-# define getcwd(Buf, Max) getwd (Buf)
-#endif
+#include <errno.h>
+#include "getcwd.h"
#include "xalloc.h"
-#include "xgetcwd.h"
-/* Return the current directory, newly allocated, assuming it fits
- within PATH_MAX bytes -- this is a common system-imposed limit
- on how getcwd works.
+/* Return the current directory, newly allocated.
Upon an out-of-memory error, call xalloc_die.
Upon any other type of error, return NULL. */
char *
xgetcwd (void)
{
-#if HAVE_GETCWD_NULL
char *cwd = getcwd (NULL, 0);
if (! cwd && errno == ENOMEM)
xalloc_die ();
return cwd;
-#else
-
- int saved_errno;
-
- /* The initial buffer size for the working directory. A power of 2
- detects arithmetic overflow earlier, but is not required. */
-# ifndef INITIAL_BUFFER_SIZE
-# define INITIAL_BUFFER_SIZE 128
-# endif
-
- size_t buf_size = INITIAL_BUFFER_SIZE;
-
- while (1)
- {
- char *buf = xmalloc (buf_size);
- char *cwd = getcwd (buf, buf_size);
- if (cwd)
- return cwd;
- saved_errno = errno;
- free (buf);
- if (saved_errno != ERANGE)
- break;
-
-#ifdef PATH_MAX
- if (PATH_MAX / 2 < buf_size)
- {
- if (PATH_MAX <= buf_size)
- break;
- buf_size = PATH_MAX;
- continue;
- }
-#endif
-
- buf_size *= 2;
- if (buf_size == 0)
- xalloc_die ();
- }
-
- errno = saved_errno;
- return NULL;
-#endif
}
+2004-11-25 Paul Eggert <eggert@cs.ucla.edu>
+
+ * getcwd-path-max.m4 (gl_FUNC_GETCWD_PATH_MAX): Renamed from
+ GL_FUNC_GETCWD_PATH_MAX for consistency. All uses changed.
+ Use the _ONCE methods, for efficiency.
+ Check for fcntl.h. In test program, include <errno.h>
+ and <fcntl.h> if available. Remove old K&R cruft from
+ test program. Check for common errors in GNU/Linux,
+ OpenBSD, and Solaris. Just set gl_cv_func_getcwd_path_max;
+ don't do AC_LIBOBJ, as that's getcwd.m4's job.
+ * getcwd.m4 (gl_FUNC_GETCWD_NULL): Renamed from
+ AC_FUNC_GETCWD_NULL. All used changed. Change cache variable
+ name accordingly.
+ (gl_FUNC_GETCWD, gl_PREREQ_GETCWD): New macros. Revamp to
+ accommodate new getcwd.c.
+ * jm-macros.m4 (gl_MACROS): Don't require GL_FUNC_GETCWD_PATH_MAX.
+ * prereq.m4 (gl_PREREQ): Add gl_FUNC_MEMPCPY.
+ * xgetcwd.m4 (gl_XGETCWD): Replace with gl_FUNC_GETCWD, since
+ that's all we need now.
+
2004-11-23 Paul Eggert <eggert@cs.ucla.edu>
* utimens.m4 (gl_UTIMENS): Check for futimes function.
-#serial 4
-# Check whether getcwd has the bug that it succeeds for a working directory
-# longer than PATH_MAX, yet returns a truncated directory name.
+#serial 5
+# Check for several getcwd bugs with long paths.
# If so, arrange to compile the wrapper function.
# This is necessary for at least GNU libc on linux-2.4.19 and 2.4.20.
# From Jim Meyering
-AC_DEFUN([GL_FUNC_GETCWD_PATH_MAX],
+AC_DEFUN([gl_FUNC_GETCWD_PATH_MAX],
[
- AC_CHECK_DECLS([getcwd])
- AC_CACHE_CHECK([whether getcwd properly handles paths longer than PATH_MAX],
- gl_cv_func_getcwd_vs_path_max,
+ AC_CHECK_DECLS_ONCE(getcwd)
+ AC_CHECK_HEADERS_ONCE(fcntl.h)
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+ AC_CACHE_CHECK([whether getcwd handles long paths properly],
+ gl_cv_func_getcwd_path_max,
[
# Arrange for deletion of the temporary directory this test creates.
ac_clean_files="$ac_clean_files confdir3"
AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
-/* Don't get link errors because mkdir is redefined to rpl_mkdir. */
-#undef mkdir
-
-#ifndef CHAR_BIT
-# define CHAR_BIT 8
+#ifndef AT_FDCWD
+# define AT_FDCWD 0
+#endif
+#ifdef ENAMETOOLONG
+# define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG)
+#else
+# define is_ENAMETOOLONG(x) 0
#endif
-/* The extra casts work around common compiler bugs. */
-#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
-/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
- It is necessary at least when t == time_t. */
-#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
- ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
-#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
+/* Don't get link errors because mkdir is redefined to rpl_mkdir. */
+#undef mkdir
-#ifndef INT_MAX
-# define INT_MAX TYPE_MAXIMUM (int)
+#ifndef S_IRWXU
+# define S_IRWXU 0700
#endif
/* The length of this name must be 8. */
#define DIR_NAME "confdir3"
+#define DIR_NAME_LEN 8
+#define DIR_NAME_SIZE (DIR_NAME_LEN + 1)
+
+/* The length of "../". */
+#define DOTDOTSLASH_LEN 3
+
+/* Leftover bytes in the buffer, to work around library or OS bugs. */
+#define BUF_SLOP 20
int
-main ()
+main (void)
{
#ifndef PATH_MAX
/* The Hurd doesn't define this, so getcwd can't exhibit the bug --
about remote file systems, we'd have to enable the wrapper function
all of the time, just to be safe. That's not worth the cost. */
exit (0);
-#elif INT_MAX - 9 <= PATH_MAX
- /* The '9', above, comes from strlen (DIR_NAME) + 1. */
+#elif ((INT_MAX / (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1) \
+ - DIR_NAME_SIZE - BUF_SLOP) \
+ <= PATH_MAX)
/* FIXME: Assuming there's a system for which this is true,
this should be done in a compile test. */
exit (0);
#else
- char buf[PATH_MAX + 20];
+ char buf[PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1)
+ + DIR_NAME_SIZE + BUF_SLOP];
char *cwd = getcwd (buf, PATH_MAX);
+ size_t initial_cwd_len;
size_t cwd_len;
int fail = 0;
size_t n_chdirs = 0;
if (cwd == NULL)
exit (1);
- cwd_len = strlen (cwd);
+ cwd_len = initial_cwd_len = strlen (cwd);
while (1)
{
- char *c;
- size_t len;
+ size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN);
+ char *c = NULL;
- cwd_len += 1 + strlen (DIR_NAME);
+ cwd_len += DIR_NAME_SIZE;
/* If mkdir or chdir fails, be pessimistic and consider that
as a failure, too. */
- if (mkdir (DIR_NAME, 0700) < 0 || chdir (DIR_NAME) < 0)
+ if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0)
{
fail = 1;
break;
}
- if ((c = getcwd (buf, PATH_MAX)) == NULL)
- {
- /* This allows any failure to indicate there is no bug.
- FIXME: check errno? */
- break;
+
+ if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE)
+ {
+ c = getcwd (buf, PATH_MAX);
+ if (c || errno != ERANGE)
+ {
+ fail = 1;
+ break;
+ }
}
- if ((len = strlen (c)) != cwd_len)
+
+ if (dotdot_max <= cwd_len - initial_cwd_len)
+ {
+ if (dotdot_max + DIR_NAME_SIZE < cwd_len - initial_cwd_len)
+ break;
+ c = getcwd (buf, cwd_len + 1);
+ if (!c && (AT_FDCWD || !is_ENAMETOOLONG (errno)))
+ {
+ fail = 1;
+ break;
+ }
+ }
+
+ if (c && strlen (c) != cwd_len)
{
fail = 1;
break;
}
++n_chdirs;
- if (PATH_MAX < len)
- break;
}
/* Leaving behind such a deep directory is not polite.
#endif
}
]])],
- [gl_cv_func_getcwd_vs_path_max=yes],
- [gl_cv_func_getcwd_vs_path_max=no],
- [gl_cv_func_getcwd_vs_path_max=no])])
-
- if test $gl_cv_func_getcwd_vs_path_max = no; then
- AC_LIBOBJ(getcwd)
- AC_DEFINE(getcwd, rpl_getcwd,
- [Define to rpl_getcwd if the wrapper function should be used.])
- fi
+ [gl_cv_func_getcwd_path_max=yes],
+ [gl_cv_func_getcwd_path_max=no],
+ [gl_cv_func_getcwd_path_max=no])])
])
-# getcwd.m4 - check whether getcwd (NULL, 0) allocates memory for result
+# getcwd.m4 - check for working getcwd that is compatible with glibc
-# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2003, 2004 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
# Written by Paul Eggert.
-AC_DEFUN([AC_FUNC_GETCWD_NULL],
+AC_DEFUN([gl_FUNC_GETCWD_NULL],
[
AC_CHECK_HEADERS_ONCE(unistd.h)
AC_CACHE_CHECK([whether getcwd (NULL, 0) allocates memory for result],
- [ac_cv_func_getcwd_null],
+ [gl_cv_func_getcwd_null],
[AC_TRY_RUN(
[
# include <stdlib.h>
exit (! (f && f[0] == '/' && !f[1]));
}
}],
- [ac_cv_func_getcwd_null=yes],
- [ac_cv_func_getcwd_null=no],
- [ac_cv_func_getcwd_null=no])])
- if test $ac_cv_func_getcwd_null = yes; then
- AC_DEFINE(HAVE_GETCWD_NULL, 1,
- [Define if getcwd (NULL, 0) allocates memory for result.])
- fi])
+ [gl_cv_func_getcwd_null=yes],
+ [gl_cv_func_getcwd_null=no],
+ [gl_cv_func_getcwd_null=no])])
+])
+
+AC_DEFUN([gl_FUNC_GETCWD],
+[
+ AC_REQUIRE([gl_FUNC_GETCWD_NULL])
+
+ case $gl_cv_func_getcwd_null in
+ yes) gl_FUNC_GETCWD_PATH_MAX;;
+ esac
+
+ case $gl_cv_func_getcwd_null,$gl_cv_func_getcwd_path_max in
+ yes,yes) ;;
+ *)
+ AC_LIBOBJ([getcwd])
+ AC_DEFINE([__GETCWD_PREFIX], [[rpl_]],
+ [Define to rpl_ if the getcwd replacement function should be used.])
+ gl_PREREQ_GETCWD;;
+ esac
+])
+
+# Prerequisites of lib/getcwd.c.
+AC_DEFUN([gl_PREREQ_GETCWD],
+[
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+ AC_REQUIRE([AC_HEADER_DIRENT])
+ AC_REQUIRE([gl_CHECK_TYPE_STRUCT_DIRENT_D_INO])
+ AC_CHECK_HEADERS_ONCE(fcntl.h)
+ :
+])
-#serial 78 -*- autoconf -*-
+#serial 79 -*- autoconf -*-
dnl Misc type-related macros for coreutils.
AC_FUNC_STRTOD
AC_REQUIRE([cu_PREREQ_STAT_PROG])
- AC_REQUIRE([GL_FUNC_GETCWD_PATH_MAX])
AC_REQUIRE([GL_FUNC_READDIR])
# for dd.c and shred.c
-#serial 46
+#serial 47
dnl We use gl_ for non Autoconf macros.
m4_pattern_forbid([^gl_[ABCDEFGHIJKLMNOPQRSTUVXYZ]])dnl
AC_REQUIRE([gl_FUNC_MEMCHR])
AC_REQUIRE([gl_FUNC_MEMCPY])
AC_REQUIRE([gl_FUNC_MEMMOVE])
+ AC_REQUIRE([gl_FUNC_MEMPCPY])
AC_REQUIRE([gl_FUNC_MEMRCHR])
AC_REQUIRE([gl_FUNC_MEMSET])
AC_REQUIRE([gl_FUNC_MKTIME])
-# xgetcwd.m4 serial 2
-dnl Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+# xgetcwd.m4 serial 3
+dnl Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
dnl This file is free software, distributed under the terms of the GNU
dnl General Public License. As a special exception to the GNU General
dnl Public License, this file may be distributed as part of a program
AC_DEFUN([gl_XGETCWD],
[
- dnl Prerequisites of lib/xgetcwd.c.
- AC_CHECK_HEADERS_ONCE(unistd.h)
- AC_CHECK_FUNCS(getcwd)
- AC_FUNC_GETCWD_NULL
+ AC_REQUIRE([gl_FUNC_GETCWD])
])
Return the current working directory.
Files:
+lib/getcwd.h
lib/getcwd.c
m4/getcwd-path-max.m4
+m4/getcwd.m4
Depends-on:
-pathmax
-same
+mempcpy
configure.ac:
-GL_FUNC_GETCWD_PATH_MAX
+gl_FUNC_GETCWD
Makefile.am:
+lib_SOURCES += getcwd.h
Include:
+"getcwd.h"
License:
GPL
Maintainer:
-Jim Meyering
-
+all, glibc
Files:
lib/xgetcwd.h
lib/xgetcwd.c
-m4/getcwd.m4
m4/xgetcwd.m4
Depends-on:
+getcwd
xalloc
-pathmax
configure.ac:
gl_XGETCWD
Maintainer:
Jim Meyering
-