@@ -202,38 +202,30 @@ _dl_new_object (char *realname, const char *libname, int type,
}
else
{
- size_t len = realname_len;
- char *result = NULL;
-
- /* Get the current directory name. */
- origin = NULL;
- do
+ /* The rtld __getcwd implementation does not handle paths larger
+ than PATH_MAX (which would be invalid to be used on subsequent
+ open calls). */
+ origin = __getcwd (NULL, 0);
+ if (origin == NULL)
{
- char *new_origin;
-
- len += 128;
- new_origin = (char *) realloc (origin, len);
- if (new_origin == NULL)
- /* We exit the loop. Note that result == NULL. */
- break;
- origin = new_origin;
+ origin = (char *) -1;
+ goto out;
}
- while ((result = __getcwd (origin, len - realname_len)) == NULL
- && errno == ERANGE);
+ size_t len = strlen (origin);
+ char *result = realloc (origin, len + realname_len);
if (result == NULL)
{
- /* We were not able to determine the current directory.
- Note that free(origin) is OK if origin == NULL. */
free (origin);
origin = (char *) -1;
goto out;
}
+ origin = result;
+ cp = origin + len;
/* Find the end of the path and see whether we have to add a
slash. We could use rawmemchr but this need not be
fast. */
- cp = (strchr) (origin, '\0');
if (cp[-1] != '/')
*cp++ = '/';
}
@@ -17,115 +17,65 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
-#include <sys/param.h>
#include <sysdep.h>
#include <sys/syscall.h>
-
-/* If we compile the file for use in ld.so we don't need the feature
- that getcwd() allocates the buffers itself. */
-#if IS_IN (rtld)
-# define NO_ALLOCATION 1
-#endif
-
-
-/* The "proc" filesystem provides an easy method to retrieve the value.
- For each process, the corresponding directory contains a symbolic link
- named `cwd'. Reading the content of this link immediate gives us the
- information. But we have to take care for systems which do not have
- the proc filesystem mounted. Use the POSIX implementation in this case. */
-
-/* Get the code for the generic version. */
+#if !IS_IN (rtld)
+/* The generic implementation is used for valid paths larger than
+ PATH_MAX (where the syscall returns a positive value with errno
+ set to ENAMETOOLONG). */
#define GETCWD_RETURN_TYPE static char *
#include <sysdeps/posix/getcwd.c>
+#endif
char *
__getcwd (char *buf, size_t size)
{
- char *path;
- char *result;
+ char *r = NULL;
+ int len;
-#ifndef NO_ALLOCATION
- size_t alloc_size = size;
- if (size == 0)
+ if (buf != NULL)
{
- if (buf != NULL)
+ if (size == 0)
{
__set_errno (EINVAL);
return NULL;
- }
- alloc_size = MAX (PATH_MAX, __getpagesize ());
- }
-
- if (buf == NULL)
- {
- path = malloc (alloc_size);
- if (path == NULL)
- return NULL;
+ }
+ len = INLINE_SYSCALL_CALL (getcwd, buf, size);
+ if (len > 0)
+ r = buf;
}
else
-#else
-# define alloc_size size
-#endif
- path = buf;
-
- int retval;
-
- retval = INLINE_SYSCALL (getcwd, 2, path, alloc_size);
- if (retval > 0 && path[0] == '/')
- {
-#ifndef NO_ALLOCATION
- if (buf == NULL && size == 0)
- /* Ensure that the buffer is only as large as necessary. */
- buf = realloc (path, (size_t) retval);
-
- if (buf == NULL)
- /* Either buf was NULL all along, or `realloc' failed but
- we still have the original string. */
- buf = path;
-#endif
-
- return buf;
- }
-
- /* The system call either cannot handle paths longer than a page
- or can succeed without returning an absolute path. Just use the
- generic implementation right away. */
- if (retval >= 0 || errno == ENAMETOOLONG)
{
-#ifndef NO_ALLOCATION
- if (buf == NULL && size == 0)
+ char tmp[PATH_MAX];
+ size_t tmps = size == 0 || size > PATH_MAX
+ ? PATH_MAX : size;
+ len = INLINE_SYSCALL_CALL (getcwd, tmp, tmps);
+ if (len > 0)
{
- free (path);
- path = NULL;
- }
-#endif
-
- result = __getcwd_generic (path, size);
+ /* Allocates a buffer with at least SIZE bytes, even it is larger
+ than required buffer. */
+ r = malloc (size > len ? size : len);
+ if (r == NULL)
+ return NULL;
-#ifndef NO_ALLOCATION
- if (result == NULL && buf == NULL && size != 0)
- free (path);
-#endif
-
- return result;
+ memcpy (r, tmp, len);
+ }
}
- /* It should never happen that the `getcwd' syscall failed because
- the buffer is too small if we allocated the buffer ourselves
- large enough. */
- assert (errno != ERANGE || buf != NULL || size != 0);
+ if (len > 0 && r[0] == '/')
+ return r;
-#ifndef NO_ALLOCATION
- if (buf == NULL)
- free (path);
+#if !IS_IN (rtld)
+ if (len >=0 || errno == ENAMETOOLONG)
+ return __getcwd_generic (buf, size);
#endif
return NULL;