Merge from coreutils for getcwd and HP-UX 11.
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 26 Nov 2004 08:35:29 +0000 (08:35 +0000)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 26 Nov 2004 08:35:29 +0000 (08:35 +0000)
14 files changed:
ChangeLog
lib/ChangeLog
lib/fsusage.c
lib/getcwd.c
lib/same.c
lib/xgetcwd.c
m4/ChangeLog
m4/getcwd-path-max.m4
m4/getcwd.m4
m4/jm-macros.m4
m4/prereq.m4
m4/xgetcwd.m4
modules/getcwd
modules/xgetcwd

index bcd6505..ca3060c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+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.
index 6cd3c60..99e5fc8 100644 (file)
@@ -1,3 +1,66 @@
+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.
index f1dfb2d..a07618c 100644 (file)
@@ -74,7 +74,6 @@
 
 #if HAVE_SYS_STATVFS_H         /* SVR4 */
 # include <sys/statvfs.h>
-int statvfs ();
 #endif
 
 #include "full-read.h"
index 3d63f04..1bc7ab6 100644 (file)
@@ -1,5 +1,6 @@
-/* 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
index 33e13a0..f018c62 100644 (file)
@@ -46,7 +46,9 @@
 #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 \
index f085803..89d9884 100644 (file)
@@ -1,7 +1,6 @@
 /* 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
 }
index ed2caee..36ae7fb 100644 (file)
@@ -1,3 +1,23 @@
+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.
index a1e1239..ec2063d 100644 (file)
@@ -1,6 +1,5 @@
-#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 --
@@ -72,14 +82,17 @@ main ()
      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;
@@ -87,35 +100,50 @@ main ()
   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.
@@ -138,13 +166,7 @@ main ()
 #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])])
 ])
index ad44909..fab8bfc 100644 (file)
@@ -1,6 +1,6 @@
-# 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>
@@ -43,10 +43,35 @@ AC_DEFUN([AC_FUNC_GETCWD_NULL],
               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)
+  :
+])
index 3529e76..b90149e 100644 (file)
@@ -1,4 +1,4 @@
-#serial 78   -*- autoconf -*-
+#serial 79   -*- autoconf -*-
 
 dnl Misc type-related macros for coreutils.
 
@@ -129,7 +129,6 @@ AC_DEFUN([gl_MACROS],
   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
index 4b0ae84..f417678 100644 (file)
@@ -1,4 +1,4 @@
-#serial 46
+#serial 47
 
 dnl We use gl_ for non Autoconf macros.
 m4_pattern_forbid([^gl_[ABCDEFGHIJKLMNOPQRSTUVXYZ]])dnl
@@ -41,6 +41,7 @@ AC_DEFUN([gl_PREREQ],
   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])
index 48b77a1..a0e2f31 100644 (file)
@@ -1,5 +1,5 @@
-# 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
@@ -8,8 +8,5 @@ dnl the same distribution terms as the rest of that 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])
 ])
index 2fa5e8d..8fc74ef 100644 (file)
@@ -2,23 +2,25 @@ Description:
 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
index 8015604..2fbc90f 100644 (file)
@@ -4,12 +4,11 @@ Return the current working directory, without size limitations.
 Files:
 lib/xgetcwd.h
 lib/xgetcwd.c
-m4/getcwd.m4
 m4/xgetcwd.m4
 
 Depends-on:
+getcwd
 xalloc
-pathmax
 
 configure.ac:
 gl_XGETCWD
@@ -25,4 +24,3 @@ GPL
 
 Maintainer:
 Jim Meyering
-