From f3b23269e922ab27aaa589ec79f24593338c421c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 26 Nov 2004 08:35:29 +0000 Subject: [PATCH] Merge from coreutils for getcwd and HP-UX 11. --- ChangeLog | 12 ++ lib/ChangeLog | 63 ++++++++ lib/fsusage.c | 1 - lib/getcwd.c | 388 +++++++++++++++++++++++++++++++++++++++++++++----- lib/same.c | 4 +- lib/xgetcwd.c | 72 +--------- m4/ChangeLog | 20 +++ m4/getcwd-path-max.m4 | 116 +++++++++------ m4/getcwd.m4 | 47 ++++-- m4/jm-macros.m4 | 3 +- m4/prereq.m4 | 3 +- m4/xgetcwd.m4 | 9 +- modules/getcwd | 12 +- modules/xgetcwd | 4 +- 14 files changed, 574 insertions(+), 180 deletions(-) diff --git a/ChangeLog b/ChangeLog index bcd650514..ca3060c8a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2004-11-26 Paul Eggert + + * 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 * modules/canonicalize (Depends-on): Add xreadlink. diff --git a/lib/ChangeLog b/lib/ChangeLog index 6cd3c60d9..99e5fc851 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,66 @@ +2004-11-25 Paul Eggert + + 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 . + (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 , , , + unconditionally, as gnulib assumes C89 or better. + Do not include . + (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 in a way that is compatible with modern Autoconf. + (_D_ALLOC_NAMELEN, _D_EXACT_NAMLEN): + New macros, if not already defined. + Include 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 , , , + , , "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 * getopt_.h: Remove trailing blanks. diff --git a/lib/fsusage.c b/lib/fsusage.c index f1dfb2d7e..a07618c8c 100644 --- a/lib/fsusage.c +++ b/lib/fsusage.c @@ -74,7 +74,6 @@ #if HAVE_SYS_STATVFS_H /* SVR4 */ # include -int statvfs (); #endif #include "full-read.h" diff --git a/lib/getcwd.c b/lib/getcwd.c index 3d63f0480..1bc7ab60a 100644 --- a/lib/getcwd.c +++ b/lib/getcwd.c @@ -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 @@ -11,59 +12,372 @@ 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 +#if !_LIBC +# include "getcwd.h" +#endif -#include -#include #include #include +#include +#include +#include + +#if HAVE_FCNTL_H +# include /* 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 +# ifndef _D_EXACT_NAMLEN +# define _D_EXACT_NAMLEN(d) strlen ((d)->d_name) +# endif +#else +# define dirent direct +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# 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 +#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 +#include -/* 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 - 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 + +/* 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 diff --git a/lib/same.c b/lib/same.c index 33e13a01b..f018c62b6 100644 --- a/lib/same.c +++ b/lib/same.c @@ -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 \ diff --git a/lib/xgetcwd.c b/lib/xgetcwd.c index f08580357..89d98847e 100644 --- a/lib/xgetcwd.c +++ b/lib/xgetcwd.c @@ -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 @@ -17,87 +16,28 @@ 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 . */ +/* Written by Jim Meyering. */ #if HAVE_CONFIG_H # include #endif -#include -#include -#include -#include -#include - -#if HAVE_UNISTD_H -# include -#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 +#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 } diff --git a/m4/ChangeLog b/m4/ChangeLog index ed2caee26..36ae7fb83 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,23 @@ +2004-11-25 Paul Eggert + + * 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 + and 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 * utimens.m4 (gl_UTIMENS): Check for futimes function. diff --git a/m4/getcwd-path-max.m4 b/m4/getcwd-path-max.m4 index a1e123976..ec2063d65 100644 --- a/m4/getcwd-path-max.m4 +++ b/m4/getcwd-path-max.m4 @@ -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. @@ -25,46 +24,57 @@ # 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 #include #include #include #include #include #include +#if HAVE_FCNTL_H +# include +#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])]) ]) diff --git a/m4/getcwd.m4 b/m4/getcwd.m4 index ad44909f7..fab8bfcf9 100644 --- a/m4/getcwd.m4 +++ b/m4/getcwd.m4 @@ -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 @@ -18,11 +18,11 @@ # 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 @@ -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) + : +]) diff --git a/m4/jm-macros.m4 b/m4/jm-macros.m4 index 3529e7643..b90149ee0 100644 --- a/m4/jm-macros.m4 +++ b/m4/jm-macros.m4 @@ -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 diff --git a/m4/prereq.m4 b/m4/prereq.m4 index 4b0ae84c3..f417678a4 100644 --- a/m4/prereq.m4 +++ b/m4/prereq.m4 @@ -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]) diff --git a/m4/xgetcwd.m4 b/m4/xgetcwd.m4 index 48b77a16e..a0e2f3131 100644 --- a/m4/xgetcwd.m4 +++ b/m4/xgetcwd.m4 @@ -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]) ]) diff --git a/modules/getcwd b/modules/getcwd index 2fa5e8d5c..8fc74ef01 100644 --- a/modules/getcwd +++ b/modules/getcwd @@ -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 diff --git a/modules/xgetcwd b/modules/xgetcwd index 801560473..2fbc90faf 100644 --- a/modules/xgetcwd +++ b/modules/xgetcwd @@ -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 - -- 2.11.0