summaryrefslogtreecommitdiff
path: root/gl/lib/canonicalize-lgpl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/lib/canonicalize-lgpl.c')
-rw-r--r--gl/lib/canonicalize-lgpl.c125
1 files changed, 61 insertions, 64 deletions
diff --git a/gl/lib/canonicalize-lgpl.c b/gl/lib/canonicalize-lgpl.c
index a7fa7feb..e701297d 100644
--- a/gl/lib/canonicalize-lgpl.c
+++ b/gl/lib/canonicalize-lgpl.c
@@ -1,5 +1,5 @@
/* Return the canonical absolute name of a given file.
- Copyright (C) 1996-2022 Free Software Foundation, Inc.
+ Copyright (C) 1996-2023 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -30,7 +30,6 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
-#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -48,6 +47,7 @@
#else
# define __canonicalize_file_name canonicalize_file_name
# define __realpath realpath
+# define __strdup strdup
# include "pathmax.h"
# define __faccessat faccessat
# if defined _WIN32 && !defined __CYGWIN__
@@ -180,27 +180,16 @@ get_path_max (void)
return path_max < 0 ? 1024 : path_max <= IDX_MAX ? path_max : IDX_MAX;
}
-/* Act like __realpath (see below), with an additional argument
- rname_buf that can be used as temporary storage.
-
- If GCC_LINT is defined, do not inline this function with GCC 10.1
- and later, to avoid creating a pointer to the stack that GCC
- -Wreturn-local-addr incorrectly complains about. See:
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93644
- Although the noinline attribute can hurt performance a bit, no better way
- to pacify GCC is known; even an explicit #pragma does not pacify GCC.
- When the GCC bug is fixed this workaround should be limited to the
- broken GCC versions. */
-# if __GNUC_PREREQ (10, 1)
-# if defined GCC_LINT || defined lint
-__attribute__ ((__noinline__))
-# elif __OPTIMIZE__ && !__NO_INLINE__
-# define GCC_BOGUS_WRETURN_LOCAL_ADDR
-# endif
-# endif
+/* Scratch buffers used by realpath_stk and managed by __realpath. */
+struct realpath_bufs
+{
+ struct scratch_buffer rname;
+ struct scratch_buffer extra;
+ struct scratch_buffer link;
+};
+
static char *
-realpath_stk (const char *name, char *resolved,
- struct scratch_buffer *rname_buf)
+realpath_stk (const char *name, char *resolved, struct realpath_bufs *bufs)
{
char *dest;
char const *start;
@@ -225,12 +214,7 @@ realpath_stk (const char *name, char *resolved,
return NULL;
}
- struct scratch_buffer extra_buffer, link_buffer;
- scratch_buffer_init (&extra_buffer);
- scratch_buffer_init (&link_buffer);
- scratch_buffer_init (rname_buf);
- char *rname_on_stack = rname_buf->data;
- char *rname = rname_on_stack;
+ char *rname = bufs->rname.data;
bool end_in_extra_buffer = false;
bool failed = true;
@@ -240,16 +224,16 @@ realpath_stk (const char *name, char *resolved,
if (!IS_ABSOLUTE_FILE_NAME (name))
{
- while (!__getcwd (rname, rname_buf->length))
+ while (!__getcwd (bufs->rname.data, bufs->rname.length))
{
if (errno != ERANGE)
{
dest = rname;
goto error;
}
- if (!scratch_buffer_grow (rname_buf))
- goto error_nomem;
- rname = rname_buf->data;
+ if (!scratch_buffer_grow (&bufs->rname))
+ return NULL;
+ rname = bufs->rname.data;
}
dest = __rawmemchr (rname, '\0');
start = name;
@@ -303,13 +287,13 @@ realpath_stk (const char *name, char *resolved,
if (!ISSLASH (dest[-1]))
*dest++ = '/';
- while (rname + rname_buf->length - dest
+ while (rname + bufs->rname.length - dest
< startlen + sizeof dir_suffix)
{
idx_t dest_offset = dest - rname;
- if (!scratch_buffer_grow_preserve (rname_buf))
- goto error_nomem;
- rname = rname_buf->data;
+ if (!scratch_buffer_grow_preserve (&bufs->rname))
+ return NULL;
+ rname = bufs->rname.data;
dest = rname + dest_offset;
}
@@ -320,13 +304,13 @@ realpath_stk (const char *name, char *resolved,
ssize_t n;
while (true)
{
- buf = link_buffer.data;
- idx_t bufsize = link_buffer.length;
+ buf = bufs->link.data;
+ idx_t bufsize = bufs->link.length;
n = __readlink (rname, buf, bufsize - 1);
if (n < bufsize - 1)
break;
- if (!scratch_buffer_grow (&link_buffer))
- goto error_nomem;
+ if (!scratch_buffer_grow (&bufs->link))
+ return NULL;
}
if (0 <= n)
{
@@ -338,7 +322,7 @@ realpath_stk (const char *name, char *resolved,
buf[n] = '\0';
- char *extra_buf = extra_buffer.data;
+ char *extra_buf = bufs->extra.data;
idx_t end_idx IF_LINT (= 0);
if (end_in_extra_buffer)
end_idx = end - extra_buf;
@@ -346,13 +330,13 @@ realpath_stk (const char *name, char *resolved,
if (INT_ADD_OVERFLOW (len, n))
{
__set_errno (ENOMEM);
- goto error_nomem;
+ return NULL;
}
- while (extra_buffer.length <= len + n)
+ while (bufs->extra.length <= len + n)
{
- if (!scratch_buffer_grow_preserve (&extra_buffer))
- goto error_nomem;
- extra_buf = extra_buffer.data;
+ if (!scratch_buffer_grow_preserve (&bufs->extra))
+ return NULL;
+ extra_buf = bufs->extra.data;
}
if (end_in_extra_buffer)
end = extra_buf + end_idx;
@@ -404,20 +388,30 @@ realpath_stk (const char *name, char *resolved,
error:
*dest++ = '\0';
- if (resolved != NULL && dest - rname <= get_path_max ())
- rname = strcpy (resolved, rname);
-
-error_nomem:
- scratch_buffer_free (&extra_buffer);
- scratch_buffer_free (&link_buffer);
-
- if (failed || rname == resolved)
+ if (resolved != NULL)
+ {
+ /* Copy the full result on success or partial result if failure was due
+ to the path not existing or not being accessible. */
+ if ((!failed || errno == ENOENT || errno == EACCES)
+ && dest - rname <= get_path_max ())
+ {
+ strcpy (resolved, rname);
+ if (failed)
+ return NULL;
+ else
+ return resolved;
+ }
+ if (!failed)
+ __set_errno (ENAMETOOLONG);
+ return NULL;
+ }
+ else
{
- scratch_buffer_free (rname_buf);
- return failed ? NULL : resolved;
+ if (failed)
+ return NULL;
+ else
+ return __strdup (bufs->rname.data);
}
-
- return scratch_buffer_dupfree (rname_buf, dest - rname);
}
/* Return the canonical absolute name of file NAME. A canonical name
@@ -434,12 +428,15 @@ error_nomem:
char *
__realpath (const char *name, char *resolved)
{
- #ifdef GCC_BOGUS_WRETURN_LOCAL_ADDR
- #warning "GCC might issue a bogus -Wreturn-local-addr warning here."
- #warning "See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93644>."
- #endif
- struct scratch_buffer rname_buffer;
- return realpath_stk (name, resolved, &rname_buffer);
+ struct realpath_bufs bufs;
+ scratch_buffer_init (&bufs.rname);
+ scratch_buffer_init (&bufs.extra);
+ scratch_buffer_init (&bufs.link);
+ char *result = realpath_stk (name, resolved, &bufs);
+ scratch_buffer_free (&bufs.link);
+ scratch_buffer_free (&bufs.extra);
+ scratch_buffer_free (&bufs.rname);
+ return result;
}
libc_hidden_def (__realpath)
versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);