BTW this would allocate more for empty symlinks,
but they're rare: https://lwn.net/Articles/551224/

cheers,
Pádraig
>From 6be031b4c9d6cb742a010dbe3fe38f77fe515fec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
Date: Thu, 4 Jul 2019 11:50:16 +0100
Subject: [PATCH] areadlink-with-size: guess a lower bound with 0 size

* lib/areadlink-with-size.c (areadlink_with_size): The size
is usually taken from st_size, which can be zero, resulting
in inefficient operation as seen with:

  $ strace -e readlink stat -c %N /proc/$$/cwd
  readlink("/proc/9036/cwd", "/", 1)      = 1
  readlink("/proc/9036/cwd", "/h", 2)     = 2
  readlink("/proc/9036/cwd", "/hom", 4)   = 4
  readlink("/proc/9036/cwd", "/home/pa", 8) = 8
  readlink("/proc/9036/cwd", "/home/padraig", 16) = 13

Instead let zero select an appropriate lower bound,
as was already done for sizes more than 8Ki.
We also change SYMLINK_MAX to 1023 so that the initial
allocation is a power of two.
---
 ChangeLog                 | 10 ++++++++++
 lib/areadlink-with-size.c |  7 ++++---
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ea2e86a..bbd91f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2019-07-04  Pádraig Brady  <p...@draigbrady.com>
+
+	areadlink-with-size: guess a lower bound with 0 size
+	* lib/areadlink-with-size.c (areadlink_with_size):
+	SIZE is usually taken from st_size, which can be zero.
+	Instead let zero select an appropriate lower bound,
+	as was already done for sizes more than 8Ki.
+	We also change SYMLINK_MAX to 1023 so that the initial
+	allocation is a power of two.
+
 2019-07-03  Bruno Haible  <br...@clisp.org>
 
 	mbrtowc: Fix invalid use of mbtowc() on MSVC.
diff --git a/lib/areadlink-with-size.c b/lib/areadlink-with-size.c
index eacad3f..2fbe51c 100644
--- a/lib/areadlink-with-size.c
+++ b/lib/areadlink-with-size.c
@@ -36,14 +36,15 @@
    check, so it's OK to guess too small on hosts where there is no
    arbitrary limit to symbolic link length.  */
 #ifndef SYMLINK_MAX
-# define SYMLINK_MAX 1024
+# define SYMLINK_MAX 1023
 #endif
 
 #define MAXSIZE (SIZE_MAX < SSIZE_MAX ? SIZE_MAX : SSIZE_MAX)
 
 /* Call readlink to get the symbolic link value of FILE.
    SIZE is a hint as to how long the link is expected to be;
-   typically it is taken from st_size.  It need not be correct.
+   typically it is taken from st_size.  It need not be correct,
+   and a value of 0 (or more than 8Ki) will select an appropriate lower bound.
    Return a pointer to that NUL-terminated string in malloc'd storage.
    If readlink fails, malloc fails, or if the link value is longer
    than SSIZE_MAX, return NULL (caller may use errno to diagnose).  */
@@ -61,7 +62,7 @@ areadlink_with_size (char const *file, size_t size)
                           : INITIAL_LIMIT_BOUND);
 
   /* The initial buffer size for the link value.  */
-  size_t buf_size = size < initial_limit ? size + 1 : initial_limit;
+  size_t buf_size = size && size < initial_limit ? size + 1 : initial_limit;
 
   while (1)
     {
-- 
2.9.3

Reply via email to