summaryrefslogtreecommitdiff
path: root/gl/lib/areadlink-with-size.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2019-08-26 16:24:25 +0100
committerColin Watson <cjwatson@debian.org>2019-08-26 16:24:25 +0100
commit4022480a2cbcd303c5fcb3547dab2896ae1915a9 (patch)
treeaa7f325ed783df7e253f8474df7121c6f1f85ea2 /gl/lib/areadlink-with-size.c
parent886374b96c0da5287b5a9eba5777cb2d9f0ea3d8 (diff)
parent1c9cb89a74a0e54309eff01adcac9775e8c0563a (diff)
Import man-db_2.8.7.orig.tar.xz
Diffstat (limited to 'gl/lib/areadlink-with-size.c')
-rw-r--r--gl/lib/areadlink-with-size.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/gl/lib/areadlink-with-size.c b/gl/lib/areadlink-with-size.c
index eacad3f6..95a28b31 100644
--- a/gl/lib/areadlink-with-size.c
+++ b/gl/lib/areadlink-with-size.c
@@ -26,6 +26,7 @@
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#ifndef SSIZE_MAX
@@ -60,18 +61,28 @@ areadlink_with_size (char const *file, size_t size)
? symlink_max + 1
: INITIAL_LIMIT_BOUND);
+ enum { stackbuf_size = 128 };
+
/* The initial buffer size for the link value. */
- size_t buf_size = size < initial_limit ? size + 1 : initial_limit;
+ size_t buf_size = (size == 0 ? stackbuf_size
+ : size < initial_limit ? size + 1 : initial_limit);
while (1)
{
ssize_t r;
size_t link_length;
- char *buffer = malloc (buf_size);
+ char stackbuf[stackbuf_size];
+ char *buf = stackbuf;
+ char *buffer = NULL;
+
+ if (! (size == 0 && buf_size == stackbuf_size))
+ {
+ buf = buffer = malloc (buf_size);
+ if (!buffer)
+ return NULL;
+ }
- if (buffer == NULL)
- return NULL;
- r = readlink (file, buffer, buf_size);
+ r = readlink (file, buf, buf_size);
link_length = r;
/* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1
@@ -86,7 +97,20 @@ areadlink_with_size (char const *file, size_t size)
if (link_length < buf_size)
{
- buffer[link_length] = 0;
+ buf[link_length] = 0;
+ if (!buffer)
+ {
+ buffer = malloc (link_length + 1);
+ if (buffer)
+ return memcpy (buffer, buf, link_length + 1);
+ }
+ else if (link_length + 1 < buf_size)
+ {
+ /* Shrink BUFFER before returning it. */
+ char *shrinked_buffer = realloc (buffer, link_length + 1);
+ if (shrinked_buffer != NULL)
+ buffer = shrinked_buffer;
+ }
return buffer;
}