Re: Checking pgwin32_is_junction() errors

From: Thomas Munro <thomas(dot)munro(at)gmail(dot)com>
To: Жарков Роман <r(dot)zharkov(at)postgrespro(dot)ru>
Cc: Andrew Dunstan <andrew(at)dunslane(dot)net>, Michael Paquier <michael(at)paquier(dot)xyz>, pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Checking pgwin32_is_junction() errors
Date: 2022-08-08 20:30:11
Message-ID: CA+hUKG+AZOyOoQx11PLF7Kk+SzMz98Hp_RyY-qqSQdM_NsB4PA@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Mon, Aug 8, 2022 at 8:23 PM <r(dot)zharkov(at)postgrespro(dot)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

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Euler Taveira 2022-08-08 21:46:56 Re: logical replication restrictions
Previous Message Zheng Li 2022-08-08 20:22:33 Re: Support logical replication of DDLs