]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Make unlink() work for junction points on Windows.
authorThomas Munro <tmunro@postgresql.org>
Sat, 6 Aug 2022 00:01:42 +0000 (12:01 +1200)
committerAndrew Dunstan <andrew@dunslane.net>
Thu, 7 Nov 2024 23:06:10 +0000 (09:36 +1030)
To support harmonization of Windows and Unix code, teach our unlink()
wrapper that junction points need to be unlinked with rmdir() on
Windows.

Tested-by: Andrew Dunstan <andrew@dunslane.net>
Discussion: https://postgr.es/m/CA%2BhUKGLfOOeyZpm5ByVcAt7x5Pn-%3DxGRNCvgiUPVVzjFLtnY0w%40mail.gmail.com
(cherry picked from commit f357233c9db8be2a015163da8e1ab0630f444340)

Author: Thomas Munro <tmunro@postgresql.org>
Author: Alexandra Wang <alexandra.wang.oss@gmail.com>

src/port/dirmod.c

index 763bc5f915a670203ab19bbf2976a533d46e38aa..9403c8adb8acb093f4ae1d94397ec990808dd7ba 100644 (file)
@@ -99,6 +99,32 @@ int
 pgunlink(const char *path)
 {
        int                     loops = 0;
+       struct stat st;
+
+       /*
+        * This function might be called for a regular file or for a junction
+        * point (which we use to emulate symlinks).  The latter must be unlinked
+        * with rmdir() on Windows.  Before we worry about any of that, let's see
+        * if we can unlink directly, since that's expected to be the most common
+        * case.
+        */
+       if (unlink(path) == 0)
+               return 0;
+       if (errno != EACCES)
+               return -1;
+
+       /*
+        * EACCES is reported for many reasons including unlink() of a junction
+        * point.  Check if that's the case so we can redirect to rmdir().
+        *
+        * Note that by checking only once, we can't cope with a path that changes
+        * from regular file to junction point underneath us while we're retrying
+        * due to sharing violations, but that seems unlikely.  We could perhaps
+        * prevent that by holding a file handle ourselves across the lstat() and
+        * the retry loop, but that seems like over-engineering for now.
+        */
+       if (lstat(path, &st) < 0)
+               return -1;
 
        /*
         * We need to loop because even though PostgreSQL uses flags that allow
@@ -107,7 +133,7 @@ pgunlink(const char *path)
         * someone else to close the file, as the caller might be holding locks
         * and blocking other backends.
         */
-       while (unlink(path))
+       while ((S_ISLNK(st.st_mode) ? rmdir(path) : unlink(path)) < 0)
        {
                if (errno != EACCES)
                        return -1;