Re: Checking pgwin32_is_junction() errors
Thomas Munro <thomas.munro@gmail.com>
From: Thomas Munro <thomas.munro@gmail.com>
To: Жарков Роман <r.zharkov@postgrespro.ru>
Cc: Andrew Dunstan <andrew@dunslane.net>,
Michael Paquier <michael@paquier.xyz>, pgsql-hackers <pgsql-hackers@postgresql.org>
Date: 2022-08-08T20:30:11Z
Lists: 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
Commits
-
Fix readlink() for non-PostgreSQL junction points on Windows.
- f71007fbb3b8 16.0 landed
-
Fix stat() for recursive junction points on Windows.
- 4517358ee782 16.0 landed
-
aix: fix misreading of condition in 8f12a4e7add
- 7e29a79a46d3 16.0 cited
-
Make unlink() work for junction points on Windows.
- f357233c9db8 16.0 landed
-
Replace pgwin32_is_junction() with lstat().
- 5fc88c5d53e4 16.0 landed
-
Provide lstat() for Windows.
- c5cb8f3b770c 16.0 landed