0006-Fix-lstat-on-broken-junction-points.patch
text/x-patch
Filename: 0006-Fix-lstat-on-broken-junction-points.patch
Type: text/x-patch
Part: 5
Patch
Format: format-patch
Series: patch 0006
Subject: Fix lstat() on broken junction points.
| File | + | − |
|---|---|---|
| src/port/t/001_filesystem.c | 7 | 0 |
| src/port/win32error.c | 3 | 0 |
| src/port/win32stat.c | 22 | 5 |
From b61a66f874d3b8151158e7956a3272e9259a8941 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sun, 16 Oct 2022 12:07:33 +1300
Subject: [PATCH 06/10] Fix lstat() on broken junction points.
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 testing and is
fixed here for completeness.
Also add translation ERROR_CANT_RESOLVE_FILENAME -> ENOENT, as that is
one of the errors Windows can report depending on format of the broken
path.
---
src/port/t/001_filesystem.c | 7 +++++++
src/port/win32error.c | 3 +++
src/port/win32stat.c | 27 ++++++++++++++++++++++-----
3 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/src/port/t/001_filesystem.c b/src/port/t/001_filesystem.c
index c2832b0a20..28ef069ee0 100644
--- a/src/port/t/001_filesystem.c
+++ b/src/port/t/001_filesystem.c
@@ -273,6 +273,13 @@ filesystem_metadata_tests(void)
PG_EXPECT(S_ISLNK(statbuf.st_mode));
PG_EXPECT_EQ(statbuf.st_size, strlen(path2), "got expected symlink size");
+ make_path(path, "broken-symlink");
+ make_path(path2, "does-not-exist");
+ PG_EXPECT_SYS(symlink(path2, path) == 0, "make a broken symlink");
+ PG_EXPECT_SYS(lstat(path, &statbuf) == 0, "lstat broken symlink");
+ PG_EXPECT(S_ISLNK(statbuf.st_mode));
+ PG_EXPECT_SYS(unlink(path) == 0);
+
/* Tests for link() and unlink(). */
make_path(path, "does-not-exist-1");
diff --git a/src/port/win32error.c b/src/port/win32error.c
index a78d323827..67ce805d77 100644
--- a/src/port/win32error.c
+++ b/src/port/win32error.c
@@ -167,6 +167,9 @@ static const struct
},
{
ERROR_INVALID_NAME, ENOENT
+ },
+ {
+ ERROR_CANT_RESOLVE_FILENAME, ENOENT
}
};
diff --git a/src/port/win32stat.c b/src/port/win32stat.c
index 5f3d0d22ff..ce8d87093d 100644
--- a/src/port/win32stat.c
+++ b/src/port/win32stat.c
@@ -125,15 +125,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;
@@ -169,10 +184,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;
}
--
2.37.3