+2019-07-06 Paul Eggert <eggert@cs.ucla.edu>
+
+ areadlink-with-size: avoid realloc when size==0
+ * lib/areadlink-with-size.c (areadlink_with_size):
+ * lib/areadlinkat-with-size.c (areadlinkat_with_size):
+ Reallocate at the end to the actual size, to avoid memory waste,
+ as suggested by Bruno Haible. But when the guessed size is zero -
+ useful when the size is unknown - do the initial small readlink
+ into the stack, to avoid that realloc in the usual case.
+
2019-07-06 Pádraig Brady <P@draigBrady.com>
areadlink-with-size: guess a buffer size with 0 size
? symlink_max + 1
: INITIAL_LIMIT_BOUND);
+ enum { stackbuf_size = 128 };
+
/* The initial buffer size for the link value. */
- size_t buf_size = (size == 0 ? 128
+ 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
if (link_length < buf_size)
{
- buffer[link_length] = 0;
- /* Shrink BUFFER before returning it. */
- if (link_length + 1 < buf_size)
+ 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;
? symlink_max + 1
: INITIAL_LIMIT_BOUND);
+ enum { stackbuf_size = 128 };
+
/* The initial buffer size for the link value. */
- size_t buf_size = (size == 0 ? 128
+ 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 = readlinkat (fd, file, buffer, buf_size);
+ r = readlinkat (fd, file, buf, buf_size);
link_length = r;
/* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1
if (link_length < buf_size)
{
- buffer[link_length] = 0;
- /* Shrink BUFFER before returning it. */
- if (link_length + 1 < buf_size)
+ 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;