diff options
author | Thomas Munro <tmunro@postgresql.org> | 2022-10-25 15:20:00 +1300 |
---|---|---|
committer | Andrew Dunstan <andrew@dunslane.net> | 2024-11-08 09:29:15 +1030 |
commit | f2a4a137bb93922a925255665f5a47094ed8c9df (patch) | |
tree | 2550fc5a5f6600e8aa3737954d92b175dab27ae8 | |
parent | b73c1496dc7aba7748eb3d55b29c4eb0dc788296 (diff) | |
download | postgresql-f2a4a137bb93922a925255665f5a47094ed8c9df.tar.gz postgresql-f2a4a137bb93922a925255665f5a47094ed8c9df.zip |
Fix lstat() for broken junction points on Windows.
When using junction points to emulate symlinks on Windows, one edge case
was not handled correctly by commit c5cb8f3b: if a junction point is
broken (pointing to a non-existent path), we'd report ENOENT. This
doesn't break any known use case, but was noticed while developing a
test suite for these functions and is fixed here for completeness.
Also add translation ERROR_CANT_RESOLVE_FILENAME -> ENOENT, as that is
one of the errors Windows can report for some kinds of broken paths.
Discussion: https://postgr.es/m/CA%2BhUKG%2BajSQ_8eu2AogTncOnZ5me2D-Cn66iN_-wZnRjLN%2Bicg%40mail.gmail.com
(cherry picked from commit 387803d81d6256fcb60b9192bb5b00042442b4e3)
Author: Thomas Munro <tmunro@postgresql.org>
Author: Alexandra Wang <alexandra.wang.oss@gmail.com>
-rw-r--r-- | src/port/win32error.c | 6 | ||||
-rw-r--r-- | src/port/win32stat.c | 27 |
2 files changed, 28 insertions, 5 deletions
diff --git a/src/port/win32error.c b/src/port/win32error.c index fca867ba3d5..67ce805d775 100644 --- a/src/port/win32error.c +++ b/src/port/win32error.c @@ -164,6 +164,12 @@ static const struct }, { ERROR_DELETE_PENDING, ENOENT + }, + { + ERROR_INVALID_NAME, ENOENT + }, + { + ERROR_CANT_RESOLVE_FILENAME, ENOENT } }; diff --git a/src/port/win32stat.c b/src/port/win32stat.c index dd626e1034c..c0521d6ffa9 100644 --- a/src/port/win32stat.c +++ b/src/port/win32stat.c @@ -127,15 +127,30 @@ _pglstat64(const char *name, struct stat *buf) hFile = pgwin32_open_handle(name, O_RDONLY, true); if (hFile == INVALID_HANDLE_VALUE) - return -1; - - ret = fileinfo_to_stat(hFile, buf); + { + if (errno == ENOENT) + { + /* + * If it's a junction point pointing to a non-existent path, we'll + * have ENOENT here (because pgwin32_open_handle does not use + * FILE_FLAG_OPEN_REPARSE_POINT). In that case, we'll try again + * with readlink() below, which will distinguish true ENOENT from + * pseudo-symlink. + */ + memset(buf, 0, sizeof(*buf)); + ret = 0; + } + else + return -1; + } + else + ret = fileinfo_to_stat(hFile, buf); /* * Junction points appear as directories to fileinfo_to_stat(), so we'll * need to do a bit more work to distinguish them. */ - if (ret == 0 && S_ISDIR(buf->st_mode)) + if ((ret == 0 && S_ISDIR(buf->st_mode)) || hFile == INVALID_HANDLE_VALUE) { char next[MAXPGPATH]; ssize_t size; @@ -171,10 +186,12 @@ _pglstat64(const char *name, struct stat *buf) buf->st_mode &= ~S_IFDIR; buf->st_mode |= S_IFLNK; buf->st_size = size; + ret = 0; } } - CloseHandle(hFile); + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle(hFile); return ret; } |