Re: Checking pgwin32_is_junction() errors - Mailing list pgsql-hackers

From Thomas Munro
Subject Re: Checking pgwin32_is_junction() errors
Date
Msg-id CA+hUKG+AZOyOoQx11PLF7Kk+SzMz98Hp_RyY-qqSQdM_NsB4PA@mail.gmail.com
Whole thread Raw
In response to Re: Checking pgwin32_is_junction() errors  (r.zharkov@postgrespro.ru)
Responses Re: Checking pgwin32_is_junction() errors
Re: Checking pgwin32_is_junction() errors
List pgsql-hackers
On Mon, Aug 8, 2022 at 8:23 PM <r.zharkov@postgrespro.ru> wrote:
> initdb on my windows 10 system stopped working after the commit
> c5cb8f3b: "Provide lstat() for Windows."
> The error message is: creating directory C:/HOME/data ... initdb:
> error: could not create directory "C:/HOME": File exists
>
> "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.
> So initdb could not stat the file with name "Volume{GUID}", tried to
> create it and failed.
> With the attached patch initdb works fine again.

-    if (r > 4 && strncmp(buf, "\\??\\", 4) == 0)
+    if (r > 4 && strncmp(buf, "\\??\\", 4) == 0 &&
+        strncmp(buf, "\\??\\Volume", 10) != 0)
     {
         memmove(buf, buf + 4, strlen(buf + 4) + 1);
         r -= 4;

Hmm.  I suppose the problem must be in pg_mkdir_p().  Our symlink()
emulation usually adds this "\??\" prefix (making it an "NT object
path"?), because junction points only work if they are in that format.
Then our readlink() emulation removes it again, but in the case of
your \??\Volume{GUID} path, created by you, not our symlink()
emulation, removing "\??\" apparently makes it unopenable with
CreateFile() (I guess that's what fails?  What's the error?).  So your
patch just says: don't strip "\??\" if it's followed by "Volume".

I don't understand all the kinds of DOS, Windows and NT paths (let me
take a moment to say how much I love Unix), but here's a guess: could
it be that NT "\??\C:\foo" = DOS "C:\foo", but NT "\??\Volume..." =
DOS "\Volume..."?  In other words, if it hasn't got a drive letter,
maybe it still needs an initial "\" (or if not that, then *something*
special, because otherwise it looks like a relative path).  Would it
be better to say: if it doesn't begin with "\??\X:", where X could be
any letter, then don't modify it?

Maybe [1] has some clues.  It seems to give the info in a higher
density form than the Windows docs (at least to the uninitiated like
me wanting a quick overview with examples).  Hmm, I wonder if we could
get away from doing our own path mangling and use some of the proper
library calls mentioned on that page...

[1] https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html



pgsql-hackers by date:

Previous
From: Zheng Li
Date:
Subject: Re: Support logical replication of DDLs
Next
From: "Euler Taveira"
Date:
Subject: Re: logical replication restrictions