diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2004-12-01 07:12:14 +0000 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2004-12-01 07:12:14 +0000 |
commit | 3b8fa2ba330127e0db79d101a8fcdca7ca868820 (patch) | |
tree | 9f2e84bd35546c6f2722b90f1544e9daa624e2e1 /lib/getcwd.c | |
parent | 52a0364803e279e98b3afd0cfc8dbf8b5afa2c78 (diff) | |
download | coreutils-3b8fa2ba330127e0db79d101a8fcdca7ca868820.tar.xz |
(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.
Diffstat (limited to 'lib/getcwd.c')
-rw-r--r-- | lib/getcwd.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/lib/getcwd.c b/lib/getcwd.c index 1bc7ab60a..9990b5072 100644 --- a/lib/getcwd.c +++ b/lib/getcwd.c @@ -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); + + if (buf == NULL && size == 0) + /* Ensure that the buffer is only as large as necessary. */ + buf = realloc (path, used); - /* Restore errno on successful return. */ - __set_errno (prev_errno); + 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); |