[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug-gnulib] Re: getcwd fixes for bugs in glibc, Solaris, OpenBSD, ...
From: |
Paul Eggert |
Subject: |
[bug-gnulib] Re: getcwd fixes for bugs in glibc, Solaris, OpenBSD, ... |
Date: |
Tue, 30 Nov 2004 23:24:54 -0800 |
User-agent: |
Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux) |
Jim Meyering <address@hidden> writes:
>> How about if we use the system getcwd if it works, and fall back on
>> our own code if the system getcwd has problems? In the typical
>> case, if the system getcwd succeeds, or fails for any reason other
>> than ERANGE, ENAMETOOLONG or ENOENT, we can simply use its result.
>
> Yes, that's what I prefer, too.
OK, I installed this into coreutils and gnulib. It also attempts
to revamp the code slightly to make it more similar to glibc getcwd.c.
I haven't done a performance analysis on the result, though.
2004-11-30 Paul Eggert <address@hidden>
* lib/getcwd.c (is_ENAMETOOLONG): New macro.
(__getcwd.c): Don't restore errno; glibc doesn't.
[HAVE_PARTLY_WORKING_GETCWD && !defined AT_FDCWD]: Try system getcwd
first, falling back to our code only if its results look suspicious.
Ensure that the resulting buffer is only as large as necessary.
* m4/getcwd-path-max.m4 (gl_FUNC_GETCWD_PATH_MAX):
Define HAVE_PARTLY_WORKING_GETCWD if getcwd is partly working.
Index: lib/getcwd.c
===================================================================
RCS file: /fetish/cu/lib/getcwd.c,v
retrieving revision 1.9
diff -p -u -r1.9 getcwd.c
--- lib/getcwd.c 26 Nov 2004 07:27:45 -0000 1.9
+++ lib/getcwd.c 1 Dec 2004 07:10:44 -0000
@@ -79,6 +79,12 @@
#include <limits.h>
+#ifdef ENAMETOOLONG
+# define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG)
+#else
+# define is_ENAMETOOLONG(x) 0
+#endif
+
#ifndef MAX
# define MAX(a, b) ((a) < (b) ? (b) : (a))
#endif
@@ -144,8 +150,21 @@ __getcwd (char *buf, size_t size)
char *path;
register char *pathp;
struct stat st;
- int prev_errno = errno;
size_t allocated = size;
+ size_t used;
+
+#if HAVE_PARTLY_WORKING_GETCWD && !defined AT_FDCWD
+ /* The system getcwd works, except it sometimes fails when it
+ shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT. 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 look
+ suspicious. */
+# undef getcwd
+ path = getcwd (buf, size);
+ if (path || (errno != ERANGE && !is_ENAMETOOLONG (errno) && errno != ENOENT))
+ return path;
+#endif
if (size == 0)
{
@@ -158,14 +177,14 @@ __getcwd (char *buf, size_t size)
allocated = BIG_FILE_NAME_LENGTH + 1;
}
- if (buf != NULL)
- path = buf;
- else
+ if (buf == NULL)
{
path = malloc (allocated);
if (path == NULL)
return NULL;
}
+ else
+ path = buf;
pathp = path + allocated;
*--pathp = '\0';
@@ -350,12 +369,19 @@ __getcwd (char *buf, size_t size)
free (dotlist);
#endif
- memmove (path, pathp, path + allocated - pathp);
+ used = path + allocated - pathp;
+ memmove (path, pathp, used);
- /* Restore errno on successful return. */
- __set_errno (prev_errno);
+ if (buf == NULL && size == 0)
+ /* Ensure that the buffer is only as large as necessary. */
+ buf = realloc (path, used);
+
+ if (buf == NULL)
+ /* Either buf was NULL all along, or `realloc' failed but
+ we still have the original string. */
+ buf = path;
- return path;
+ return buf;
memory_exhausted:
__set_errno (ENOMEM);
Index: m4/getcwd-path-max.m4
===================================================================
RCS file: /fetish/cu/m4/getcwd-path-max.m4,v
retrieving revision 1.13
diff -p -u -r1.13 getcwd-path-max.m4
--- m4/getcwd-path-max.m4 25 Nov 2004 19:26:50 -0000 1.13
+++ m4/getcwd-path-max.m4 1 Dec 2004 07:10:44 -0000
@@ -1,4 +1,4 @@
-#serial 5
+#serial 6
# Check for several getcwd bugs with long paths.
# If so, arrange to compile the wrapper function.
@@ -29,12 +29,13 @@ AC_DEFUN([gl_FUNC_GETCWD_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([[
+ AC_CACHE_CHECK([whether getcwd handles long file names 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>
@@ -112,18 +113,23 @@ main (void)
as a failure, too. */
if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0)
{
- fail = 1;
+ fail = 2;
break;
}
if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE)
{
c = getcwd (buf, PATH_MAX);
- if (c || errno != ERANGE)
+ if (!c && errno == ENOENT)
{
fail = 1;
break;
}
+ if (c || ! (errno == ERANGE || is_ENAMETOOLONG (errno)))
+ {
+ fail = 2;
+ break;
+ }
}
if (dotdot_max <= cwd_len - initial_cwd_len)
@@ -131,16 +137,25 @@ main (void)
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)))
+ if (!c)
{
- fail = 1;
- break;
+ if (! (errno == ERANGE || errno == ENOENT
+ || is_ENAMETOOLONG (errno)))
+ {
+ fail = 2;
+ break;
+ }
+ if (AT_FDCWD || errno == ERANGE || errno == ENOENT)
+ {
+ fail = 1;
+ break;
+ }
}
}
if (c && strlen (c) != cwd_len)
{
- fail = 1;
+ fail = 2;
break;
}
++n_chdirs;
@@ -165,8 +180,20 @@ main (void)
exit (fail);
#endif
}
- ]])],
- [gl_cv_func_getcwd_path_max=yes],
- [gl_cv_func_getcwd_path_max=no],
- [gl_cv_func_getcwd_path_max=no])])
+ ]])],
+ [gl_cv_func_getcwd_path_max=yes],
+ [case $? in
+ 1) gl_cv_func_getcwd_path_max='no, but it is partly working';;
+ *) gl_cv_func_getcwd_path_max=no;;
+ esac],
+ [gl_cv_func_getcwd_path_max=no])
+ ])
+ case $gl_cv_func_getcwd_path_max in
+ no,*)
+ AC_DEFINE([HAVE_PARTLY_WORKING_GETCWD], 1,
+ [Define to 1 if getcwd works, except it sometimes fails when it
shouldn't,
+ setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If __GETCWD_PREFIX
+ is not defined, it doesn't matter whether HAVE_PARTLY_WORKING_GETCWD
+ is defined.]);;
+ esac
])
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [bug-gnulib] Re: getcwd fixes for bugs in glibc, Solaris, OpenBSD, ...,
Paul Eggert <=