On Tue, Aug 9, 2022 at 8:30 AM Thomas Munro <thomas.mu...@gmail.com> wrote: > On Mon, Aug 8, 2022 at 8:23 PM <r.zhar...@postgrespro.ru> wrote: > > "C:/HOME" is the junction point to the second volume on my hard drive - > > "\??\Volume{GUID}\" which name pgreadlink() erroneously strips here: > > https://github.com/postgres/postgres/blob/7e29a79a46d30dc236d097825ab849158929d977/src/port/dirmod.c#L357.
> ... Would it > be better to say: if it doesn't begin with "\??\X:", where X could be > any letter, then don't modify it? Concretely, I wonder if this is a good fix at least in the short term. Does this work for you, and do the logic and explanation make sense?
From 9772b2bf5a1b11605ea16cfd17b3b50e0274aadf Mon Sep 17 00:00:00 2001 From: Thomas Munro <thomas.mu...@gmail.com> Date: Tue, 9 Aug 2022 10:29:08 +1200 Subject: [PATCH] Fix readlink() for more complex Windows paths. Our symlink() and readlink() replacements perform a very naive transformation from "DOS" paths to "NT" paths and back, as required by the junction point APIs. This was enough for the simple paths we expect users to provide for tablespaces, for example 'd:\my\fast\storage'. Since commit c5cb8f3b taught stat() to follow symlinks, and since initdb uses pg_mkdir_p(), and that examines parent directories, our humble readlink() implementation can now be exposed to junction points not of PostgreSQL origin. Those might be corrupted by our naive path mangling, which doesn't really understand NT paths in general. It's possible that we should investigate using Rtl*() library routines to do path transformation, but for now, simply decline to transform paths that don't fit the simple drive-qualified pattern. That means that readlink() returns an NT path, which works just as well as a DOS path when following the link. Reported-by: Roman Zharkov <r.zhar...@postgrespro.ru> Discussion: https://postgr.es/m/4590c37927d7b8ee84f9855d83229018%40postgrespro.ru --- src/port/dirmod.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/port/dirmod.c b/src/port/dirmod.c index 2818bfd2e9..821563c290 100644 --- a/src/port/dirmod.c +++ b/src/port/dirmod.c @@ -352,9 +352,11 @@ pgreadlink(const char *path, char *buf, size_t size) /* * If the path starts with "\??\", which it will do in most (all?) cases, - * strip those out. + * strip those out, but only if it's of the simple drive-letter-qualified + * type that we know how to transform from NT to DOS format. */ - if (r > 4 && strncmp(buf, "\\??\\", 4) == 0) + if (r >= 6 && strncmp(buf, "\\??\\", 4) == 0 && isalpha(buf[4]) && + buf[5] == ':') { memmove(buf, buf + 4, strlen(buf + 4) + 1); r -= 4; -- 2.35.1