aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Munro <tmunro@postgresql.org>2022-10-25 15:20:00 +1300
committerAndrew Dunstan <andrew@dunslane.net>2024-11-08 09:36:40 +1030
commit8a5e4982f9c536fafa4ae9b7c331ee656ded2fe5 (patch)
tree465e64228a5897f9bd532467bc716e8126b5078c
parent895f23d9e174897a9c1a71a2c6cdb439fe5a3101 (diff)
downloadpostgresql-8a5e4982f9c536fafa4ae9b7c331ee656ded2fe5.tar.gz
postgresql-8a5e4982f9c536fafa4ae9b7c331ee656ded2fe5.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.c6
-rw-r--r--src/port/win32stat.c27
2 files changed, 28 insertions, 5 deletions
diff --git a/src/port/win32error.c b/src/port/win32error.c
index 0e5f91adfa0..60253d1e3f3 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 001e329a18d..49fbb3ce649 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;
}