Pádraig Brady wrote:
It would be nice to have areadlink_with_size treat 0 as auto select some lower 
bound.

Yes, that sounds good. However, I didn't see why that would entail changing SYMLINK_MAX from 1024 to 1023, or why the patch would affect the documented API.

How about the attached patch instead? When the guessed size is zero it typically avoids a realloc by using a small stack buffer.
>From d94bf537d7fdda13f4432bb60a98a8bd19d8e18d Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Fri, 5 Jul 2019 16:48:22 -0700
Subject: [PATCH] areadlink-with-size: improve efficiency
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

If the guessed size is 0, guess 200 first, to avoid a sequence of
small readlinks in the usual case.  Reallocate at the end to the
actual size, to avoid memory waste.  Based on a suggestion by
Pádraig Brady.
* lib/areadlink-with-size.c (areadlink_with_size):
Use a small stack buffer when the stated size is zero.
* modules/areadlink-with-size (Depends-on): Add strdup-posix.
---
 ChangeLog                   | 11 +++++++++++
 lib/areadlink-with-size.c   | 26 ++++++++++++++++++++------
 modules/areadlink-with-size |  1 +
 3 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 98d5531b1..b07e26335 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2019-07-05  Paul Eggert  <egg...@cs.ucla.edu>
+
+	areadlink-with-size: improve efficiency
+	If the guessed size is 0, guess 200 first, to avoid a sequence of
+	small readlinks in the usual case.  Reallocate at the end to the
+	actual size, to avoid memory waste.  Based on a suggestion by
+	Pádraig Brady.
+	* lib/areadlink-with-size.c (areadlink_with_size):
+	Use a small stack buffer when the stated size is zero.
+	* modules/areadlink-with-size (Depends-on): Add strdup-posix.
+
 2019-07-05  Bruno Haible  <br...@clisp.org>
 
 	getcwd-lgpl, getcwd: Don't call realloc when it is pointless.
diff --git a/lib/areadlink-with-size.c b/lib/areadlink-with-size.c
index 364cc0858..9f1f7959f 100644
--- a/lib/areadlink-with-size.c
+++ b/lib/areadlink-with-size.c
@@ -60,18 +60,30 @@ areadlink_with_size (char const *file, size_t size)
                           ? symlink_max + 1
                           : INITIAL_LIMIT_BOUND);
 
+  /* Size of stack buffer for initial readlink when the link size hint
+     is zero.  */
+  enum { stackbuf_size = 200 };
+
   /* 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 +98,9 @@ areadlink_with_size (char const *file, size_t size)
 
       if (link_length < buf_size)
         {
-          buffer[link_length] = 0;
+          buf[link_length] = 0;
+          if (!buffer)
+            return strdup (buf);
           /* Shrink BUFFER before returning it.  */
           if (link_length + 1 < buf_size)
             {
diff --git a/modules/areadlink-with-size b/modules/areadlink-with-size
index 82a902187..a4ab0e178 100644
--- a/modules/areadlink-with-size
+++ b/modules/areadlink-with-size
@@ -9,6 +9,7 @@ Depends-on:
 readlink
 ssize_t
 stdint
+strdup-posix
 unistd
 
 configure.ac:
-- 
2.17.1

Reply via email to