summaryrefslogtreecommitdiff
path: root/lib/careadlinkat.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2020-08-21 12:19:18 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2020-08-21 12:22:04 -0700
commit3e10174fb65f4eb601b1921271bdcf10c933b879 (patch)
tree4a0948c61c187fc1f9bbd6b73a9f7957c12b74f4 /lib/careadlinkat.c
parent348686b3f318195f4d341206744b8e98470c90f4 (diff)
downloademacs-3e10174fb65f4eb601b1921271bdcf10c933b879.tar.gz
emacs-3e10174fb65f4eb601b1921271bdcf10c933b879.tar.bz2
emacs-3e10174fb65f4eb601b1921271bdcf10c933b879.zip
Update from Gnulib
This incorporates: 2020-08-20 sigabbrev_np: New module 2020-08-20 stdalign: Fix 32-bit test failures clang versions < 8 2020-08-17 careadlinkat: speedup for GCC 10 with GCC_LINT 2020-08-17 Assume autoconf >= 2.64 * build-aux/config.guess, build-aux/config.sub, lib/careadlinkat.c: * lib/stdalign.in.h, lib/string.in.h, m4/std-gnu11.m4, m4/string_h.m4: Copy from Gnulib. * lib/gnulib.mk.in: Regenerate.
Diffstat (limited to 'lib/careadlinkat.c')
-rw-r--r--lib/careadlinkat.c108
1 files changed, 62 insertions, 46 deletions
diff --git a/lib/careadlinkat.c b/lib/careadlinkat.c
index 1aa04363dac..e43aa42d5c4 100644
--- a/lib/careadlinkat.c
+++ b/lib/careadlinkat.c
@@ -38,66 +38,41 @@
#include "allocator.h"
-/* Assuming the current directory is FD, get the symbolic link value
- of FILENAME as a null-terminated string and put it into a buffer.
- If FD is AT_FDCWD, FILENAME is interpreted relative to the current
- working directory, as in openat.
-
- If the link is small enough to fit into BUFFER put it there.
- BUFFER's size is BUFFER_SIZE, and BUFFER can be null
- if BUFFER_SIZE is zero.
-
- If the link is not small, put it into a dynamically allocated
- buffer managed by ALLOC. It is the caller's responsibility to free
- the returned value if it is nonnull and is not BUFFER. A null
- ALLOC stands for the standard allocator.
-
- The PREADLINKAT function specifies how to read links. It operates
- like POSIX readlinkat()
- <https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html>
- but can assume that its first argument is the same as FD.
-
- If successful, return the buffer address; otherwise return NULL and
- set errno. */
-
-char *
-careadlinkat (int fd, char const *filename,
+enum { STACK_BUF_SIZE = 1024 };
+
+/* Act like careadlinkat (see below), with an additional argument
+ STACK_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 (defined GCC_LINT || defined lint) && _GL_GNUC_PREREQ (10, 1)
+__attribute__ ((__noinline__))
+#endif
+static char *
+readlink_stk (int fd, char const *filename,
char *buffer, size_t buffer_size,
struct allocator const *alloc,
- ssize_t (*preadlinkat) (int, char const *, char *, size_t))
+ ssize_t (*preadlinkat) (int, char const *, char *, size_t),
+ char stack_buf[STACK_BUF_SIZE])
{
char *buf;
size_t buf_size;
size_t buf_size_max =
SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
- char stack_buf[1024];
-
-#if (defined GCC_LINT || defined lint) && _GL_GNUC_PREREQ (10, 1)
- /* Pacify preadlinkat without creating a pointer to the stack
- that a broken gcc -Wreturn-local-addr would cry wolf about. See:
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95044
- This workaround differs from the mainline code, but
- no other way to pacify GCC 10.1.0 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. */
-# define WORK_AROUND_GCC_BUG_95044
-#endif
if (! alloc)
alloc = &stdlib_allocator;
if (!buffer)
{
-#ifdef WORK_AROUND_GCC_BUG_95044
- buffer = alloc->allocate (sizeof stack_buf);
-#else
- /* Allocate the initial buffer on the stack. This way, in the
- common case of a symlink of small size, we get away with a
- single small malloc() instead of a big malloc() followed by a
- shrinking realloc(). */
buffer = stack_buf;
-#endif
- buffer_size = sizeof stack_buf;
+ buffer_size = STACK_BUF_SIZE;
}
buf = buffer;
@@ -172,3 +147,44 @@ careadlinkat (int fd, char const *filename,
errno = ENOMEM;
return NULL;
}
+
+
+/* Assuming the current directory is FD, get the symbolic link value
+ of FILENAME as a null-terminated string and put it into a buffer.
+ If FD is AT_FDCWD, FILENAME is interpreted relative to the current
+ working directory, as in openat.
+
+ If the link is small enough to fit into BUFFER put it there.
+ BUFFER's size is BUFFER_SIZE, and BUFFER can be null
+ if BUFFER_SIZE is zero.
+
+ If the link is not small, put it into a dynamically allocated
+ buffer managed by ALLOC. It is the caller's responsibility to free
+ the returned value if it is nonnull and is not BUFFER. A null
+ ALLOC stands for the standard allocator.
+
+ The PREADLINKAT function specifies how to read links. It operates
+ like POSIX readlinkat()
+ <https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html>
+ but can assume that its first argument is the same as FD.
+
+ If successful, return the buffer address; otherwise return NULL and
+ set errno. */
+
+char *
+careadlinkat (int fd, char const *filename,
+ char *buffer, size_t buffer_size,
+ struct allocator const *alloc,
+ ssize_t (*preadlinkat) (int, char const *, char *, size_t))
+{
+ /* Allocate the initial buffer on the stack. This way, in the
+ common case of a symlink of small size, we get away with a
+ single small malloc instead of a big malloc followed by a
+ shrinking realloc.
+
+ If GCC -Wreturn-local-addr warns about this buffer, the warning
+ is bogus; see readlink_stk. */
+ char stack_buf[STACK_BUF_SIZE];
+ return readlink_stk (fd, filename, buffer, buffer_size, alloc,
+ preadlinkat, stack_buf);
+}