Commit: patch 9.1.2104: readdirex() might be slow

1 view
Skip to first unread message

Christian Brabandt

unread,
Jan 23, 2026, 2:16:24 PMJan 23
to vim...@googlegroups.com
patch 9.1.2104: readdirex() might be slow

Commit: https://github.com/vim/vim/commit/e89d97aaea0e2e94e07e24271976d0a8d2e23c38
Author: Yasuhiro Matsumoto <matt...@gmail.com>
Date: Wed Jan 21 20:29:53 2026 +0000

patch 9.1.2104: readdirex() might be slow

Problem: readdirex() might be slow (Mao-Yining)
Solution: Avoid double slash in path concatenation in
create_readdirex_item() (Yasuhiro Matsumoto)

On Cygwin and MSYS2, // has a special meaning: it is treated as a prefix
for accessing network computers.
For example, //wsl$/ is used to access WSL.

In the current Vim implementation, the directory path passed to
readdirex() and the file name found during traversal are concatenated
using "/".
When the directory path already ends with /, this results in paths like:

"/" + "/" + "$Recycle.Bin"

which produces a //-prefixed path. Such paths are interpreted as network
paths, so Vim ends up trying to retrieve the file size of a network
computer named $Recycle.Bin, which is not intended.

From a correctness perspective on Windows, file size retrieval should be
skipped for paths of the following forms:

//host
//host/share

However, as a first step, we should avoid generating // paths caused by
redundant / concatenation in the first place.

This change addresses this by preventing unnecessary / insertion when
constructing paths.

fixes: #19188
closes: #19241

Signed-off-by: Yasuhiro Matsumoto <matt...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/fileio.c b/src/fileio.c
index feb538655..e637ab397 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -4822,7 +4822,7 @@ create_readdirex_item(char_u *path, char_u *name)
{
dict_T *item;
char *p;
- size_t len;
+ size_t pathlen, len;
stat_T st;
int ret, link = FALSE;
varnumber_T size;
@@ -4836,11 +4836,15 @@ create_readdirex_item(char_u *path, char_u *name)
return NULL;
item->dv_refcount++;

- len = STRLEN(path) + 1 + STRLEN(name) + 1;
+ pathlen = STRLEN(path);
+ len = pathlen + 1 + STRLEN(name) + 1;
p = alloc(len);
if (p == NULL)
goto theend;
- vim_snprintf(p, len, "%s/%s", path, name);
+ if (pathlen > 0 && path[pathlen - 1] == '/')
+ vim_snprintf(p, len, "%s%s", path, name);
+ else
+ vim_snprintf(p, len, "%s/%s", path, name);
ret = mch_lstat(p, &st);
if (ret >= 0 && S_ISLNK(st.st_mode))
{
diff --git a/src/version.c b/src/version.c
index 47ae372a4..30c54f9f2 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 2104,
/**/
2103,
/**/
Reply all
Reply to author
Forward
0 new messages