Index: /trunk/include/iprt/err.h
===================================================================
--- /trunk/include/iprt/err.h	(revision 23290)
+++ /trunk/include/iprt/err.h	(revision 23291)
@@ -710,4 +710,6 @@
 /** Too many symbolic links. */
 #define VERR_TOO_MANY_SYMLINKS              (-156)
+/** The OS does not support setting the time stamps on a symbolic link. */
+#define VERR_NS_SYMLINK_SET_TIME            (-157)
 /** @} */
 
Index: /trunk/include/iprt/path.h
===================================================================
--- /trunk/include/iprt/path.h	(revision 23290)
+++ /trunk/include/iprt/path.h	(revision 23291)
@@ -118,8 +118,24 @@
 
 
+/** @name Generic RTPath flags
+ * @{ */
+/** Last component: Work on the link. */
+#define RTPATH_F_ON_LINK          RT_BIT_32(0)
+/** Last component: Follow if link. */
+#define RTPATH_F_FOLLOW_LINK      RT_BIT_32(1)
+/** @} */
+
+
+/** Validates a flags parameter containing RTPATH_F_*.
+ * @remarks The parameters will be referneced multiple times. */
+#define RTPATH_F_IS_VALID(fFlags, fIgnore) \
+    (    ((fFlags) & ~(uint32_t)(fIgnore)) == RTPATH_F_ON_LINK \
+      || ((fFlags) & ~(uint32_t)(fIgnore)) == RTPATH_F_FOLLOW_LINK )
+
+
 /**
  * Checks if the path exists.
  *
- * Symbolic links will all be attempted resolved.
+ * Symbolic links will all be attempted resolved and broken links means false.
  *
  * @returns true if it exists and false if it doesn't.
@@ -127,4 +143,13 @@
  */
 RTDECL(bool) RTPathExists(const char *pszPath);
+
+/**
+ * Checks if the path exists.
+ *
+ * @returns true if it exists and false if it doesn't.
+ * @param   pszPath     The path to check.
+ * @param   fFlags      RTPATH_F_ON_LINK or RPATH_F_FOLLOW_LINK.
+ */
+RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags);
 
 /**
@@ -500,13 +525,13 @@
  * Query information about a file system object.
  *
- * This API will not resolve symbolic links in the last component (just
- * like unix lstat()).
- *
- * @returns VINF_SUCCESS if the object exists, information returned.
- * @returns VERR_PATH_NOT_FOUND if any but the last component in the specified
+ * This API will resolve NOT symbolic links in the last component (just like
+ * unix lstat()).
+ *
+ * @returns IPRT status code.
+ * @retval  VINF_SUCCESS if the object exists, information returned.
+ * @retval  VERR_PATH_NOT_FOUND if any but the last component in the specified
  *          path was not found or was not a directory.
- * @returns VERR_FILE_NOT_FOUND if the object does not exist (but path to the
+ * @retval  VERR_FILE_NOT_FOUND if the object does not exist (but path to the
  *          parent directory exists).
- * @returns some other iprt status code.
  *
  * @param   pszPath     Path to the file system object.
@@ -519,4 +544,23 @@
 
 /**
+ * Query information about a file system object.
+ *
+ * @returns IPRT status code.
+ * @retval  VINF_SUCCESS if the object exists, information returned.
+ * @retval  VERR_PATH_NOT_FOUND if any but the last component in the specified
+ *          path was not found or was not a directory.
+ * @retval  VERR_FILE_NOT_FOUND if the object does not exist (but path to the
+ *          parent directory exists).
+ *
+ * @param   pszPath     Path to the file system object.
+ * @param   pObjInfo    Object information structure to be filled on successful return.
+ * @param   enmAdditionalAttribs
+ *                      Which set of additional attributes to request.
+ *                      Use RTFSOBJATTRADD_NOTHING if this doesn't matter.
+ * @param   fFlags      RTPATH_F_ON_LINK or RPATH_F_FOLLOW_LINK.
+ */
+RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags);
+
+/**
  * Changes the mode flags of a file system object.
  *
@@ -573,4 +617,29 @@
 
 /**
+ * Changes one or more of the timestamps associated of file system object.
+ *
+ * @returns iprt status code.
+ * @param   pszPath             Path to the file system object.
+ * @param   pAccessTime         Pointer to the new access time.
+ * @param   pModificationTime   Pointer to the new modification time.
+ * @param   pChangeTime         Pointer to the new change time. NULL if not to be changed.
+ * @param   pBirthTime          Pointer to the new time of birth. NULL if not to be changed.
+ * @param   fFlags              RTPATH_F_ON_LINK or RPATH_F_FOLLOW_LINK.
+ *
+ * @remark  The file system might not implement all these time attributes,
+ *          the API will ignore the ones which aren't supported.
+ *
+ * @remark  The file system might not implement the time resolution
+ *          employed by this interface, the time will be chopped to fit.
+ *
+ * @remark  The file system may update the change time even if it's
+ *          not specified.
+ *
+ * @remark  POSIX can only set Access & Modification and will always set both.
+ */
+RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+                               PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags);
+
+/**
  * Gets one or more of the timestamps associated of file system object.
  *
@@ -582,5 +651,7 @@
  * @param   pBirthTime          Where to store the creation time. NULL is ok.
  *
- * @remark  This is wrapper around RTPathQueryInfo() and exists to complement RTPathSetTimes().
+ * @remark  This is wrapper around RTPathQueryInfo() and exists to complement
+ *          RTPathSetTimes().  If the last component is a symbolic link, it will
+ *          not be resolved.
  */
 RTR3DECL(int) RTPathGetTimes(const char *pszPath, PRTTIMESPEC pAccessTime, PRTTIMESPEC pModificationTime,
@@ -601,4 +672,15 @@
 
 /**
+ * Changes the owner and/or group of a file system object.
+ *
+ * @returns iprt status code.
+ * @param   pszPath     Path to the file system object.
+ * @param   uid         The new file owner user id. Use -1 (or ~0) to leave this unchanged.
+ * @param   gid         The new group id. Use -1 (or ~0) to leave this unchanged.
+ * @param   fFlags      RTPATH_F_ON_LINK or RPATH_F_FOLLOW_LINK.
+ */
+RTR3DECL(int) RTPathSetOwnerEx(const char *pszPath, uint32_t uid, uint32_t gid, uint32_t fFlags);
+
+/**
  * Gets the owner and/or group of a file system object.
  *
@@ -608,5 +690,7 @@
  * @param   pGid        Where to store the group id. NULL is ok.
  *
- * @remark  This is wrapper around RTPathQueryInfo() and exists to complement RTPathGetOwner().
+ * @remark  This is wrapper around RTPathQueryInfo() and exists to complement
+ *          RTPathGetOwner().  If the last component is a symbolic link, it will
+ *          not be resolved.
  */
 RTR3DECL(int) RTPathGetOwner(const char *pszPath, uint32_t *pUid, uint32_t *pGid);
@@ -622,4 +706,7 @@
  * Renames a path within a filesystem.
  *
+ * This will rename symbolic links.  If RTPATHRENAME_FLAGS_REPLACE is used and
+ * pszDst is a symbolic link, it will be replaced and not its target.
+ *
  * @returns IPRT status code.
  * @param   pszSrc      The source path.
Index: /trunk/src/VBox/Runtime/r3/posix/path-posix.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/posix/path-posix.cpp	(revision 23290)
+++ /trunk/src/VBox/Runtime/r3/posix/path-posix.cpp	(revision 23291)
@@ -463,14 +463,21 @@
 RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
 {
+    return RTPathQueryInfoEx(pszPath, pObjInfo, enmAdditionalAttribs, RTPATH_F_ON_LINK);
+}
+
+
+RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
+{
     /*
      * Validate input.
      */
-    AssertMsgReturn(VALID_PTR(pszPath), ("%p\n", pszPath), VERR_INVALID_POINTER);
+    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
     AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
-    AssertMsgReturn(VALID_PTR(pObjInfo), ("%p\n", pszPath), VERR_INVALID_POINTER);
+    AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
     AssertMsgReturn(    enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING
                     &&  enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
                     ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs),
                     VERR_INVALID_PARAMETER);
+    AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
 
     /*
@@ -482,5 +489,9 @@
     {
         struct stat Stat;
-        if (!stat(pszNativePath, &Stat))
+        if (fFlags & RTPATH_F_FOLLOW_LINK)
+            rc = stat(pszNativePath, &Stat);
+        else
+            rc = lstat(pszNativePath, &Stat); /** @todo how doesn't have lstat again? */
+        if (!rc)
         {
             rtFsConvertStatToObjInfo(pObjInfo, &Stat, pszPath, 0);
@@ -517,13 +528,21 @@
                              PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
 {
+    return RTPathSetTimesEx(pszPath, pAccessTime, pModificationTime, pChangeTime, pBirthTime, RTPATH_F_ON_LINK);
+}
+
+
+RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+                               PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags)
+{
     /*
      * Validate input.
      */
-    AssertMsgReturn(VALID_PTR(pszPath), ("%p\n", pszPath), VERR_INVALID_POINTER);
-    AssertMsgReturn(*pszPath, ("%p\n", pszPath), VERR_INVALID_PARAMETER);
-    AssertMsgReturn(!pAccessTime || VALID_PTR(pAccessTime), ("%p\n", pAccessTime), VERR_INVALID_POINTER);
-    AssertMsgReturn(!pModificationTime || VALID_PTR(pModificationTime), ("%p\n", pModificationTime), VERR_INVALID_POINTER);
-    AssertMsgReturn(!pChangeTime || VALID_PTR(pChangeTime), ("%p\n", pChangeTime), VERR_INVALID_POINTER);
-    AssertMsgReturn(!pBirthTime || VALID_PTR(pBirthTime), ("%p\n", pBirthTime), VERR_INVALID_POINTER);
+    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+    AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
+    AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
+    AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
 
     /*
@@ -534,18 +553,11 @@
     if (RT_SUCCESS(rc))
     {
+        RTFSOBJINFO ObjInfo;
+
         /*
          * If it's a no-op, we'll only verify the existance of the file.
          */
         if (!pAccessTime && !pModificationTime)
-        {
-            struct stat Stat;
-            if (!stat(pszNativePath, &Stat))
-                rc = VINF_SUCCESS;
-            else
-            {
-                rc = RTErrConvertFromErrno(errno);
-                Log(("RTPathSetTimes('%s',,,,): failed with %Rrc and errno=%d\n", pszPath, rc, errno));
-            }
-        }
+            rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, fFlags);
         else
         {
@@ -562,6 +574,5 @@
             else
             {
-                RTFSOBJINFO ObjInfo;
-                int rc = RTPathQueryInfo(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX);
+                rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags);
                 if (RT_SUCCESS(rc))
                 {
@@ -575,10 +586,32 @@
             if (RT_SUCCESS(rc))
             {
-                if (utimes(pszNativePath, aTimevals))
+                if (fFlags & RTPATH_F_FOLLOW_LINK)
                 {
-                    rc = RTErrConvertFromErrno(errno);
+                    if (utimes(pszNativePath, aTimevals))
+                        rc = RTErrConvertFromErrno(errno);
+                }
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX) || defined(RT_OS_OS2) /** @todo who really has lutimes? */
+                else
+                {
+                    if (lutimes(pszNativePath, aTimevals))
+                        rc = RTErrConvertFromErrno(errno);
+                }
+#else
+                else
+                {
+                    if (pAccessTime && pModificationTime)
+                        rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags);
+                    if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
+                        rc = VERR_NS_SYMLINK_SET_TIME;
+                    else if (RT_SUCCESS(rc))
+                    {
+                        if (utimes(pszNativePath, aTimevals))
+                            rc = RTErrConvertFromErrno(errno);
+                    }
+                }
+#endif
+                if (RT_FAILURE(rc))
                     Log(("RTPathSetTimes('%s',%p,%p,,): failed with %Rrc and errno=%d\n",
                          pszPath, pAccessTime, pModificationTime, rc, errno));
-                }
             }
         }
@@ -788,4 +821,10 @@
 RTDECL(bool) RTPathExists(const char *pszPath)
 {
+    return RTPathExistsEx(pszPath, RTPATH_F_FOLLOW_LINK);
+}
+
+
+RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags)
+{
     /*
      * Validate input.
@@ -793,4 +832,5 @@
     AssertPtrReturn(pszPath, false);
     AssertReturn(*pszPath, false);
+    Assert(RTPATH_F_IS_VALID(fFlags, 0));
 
     /*
@@ -802,5 +842,9 @@
     {
         struct stat Stat;
-        if (!stat(pszNativePath, &Stat))
+        if (fFlags & RTPATH_F_FOLLOW_LINK)
+            rc = stat(pszNativePath, &Stat);
+        else
+            rc = lstat(pszNativePath, &Stat);
+        if (!rc)
             rc = VINF_SUCCESS;
         else
Index: /trunk/src/VBox/Runtime/r3/win/path-win.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/win/path-win.cpp	(revision 23290)
+++ /trunk/src/VBox/Runtime/r3/win/path-win.cpp	(revision 23291)
@@ -188,23 +188,21 @@
 RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
 {
+    return RTPathQueryInfoEx(pszPath, pObjInfo, enmAdditionalAttribs, RTPATH_F_ON_LINK);
+}
+
+
+RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
+{
     /*
      * Validate input.
      */
-    if (!pszPath)
-    {
-        AssertMsgFailed(("Invalid pszPath=%p\n", pszPath));
-        return VERR_INVALID_PARAMETER;
-    }
-    if (!pObjInfo)
-    {
-        AssertMsgFailed(("Invalid pObjInfo=%p\n", pObjInfo));
-        return VERR_INVALID_PARAMETER;
-    }
-    if (    enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
-        ||  enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
-    {
-        AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
-        return VERR_INVALID_PARAMETER;
-    }
+    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+    AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
+    AssertMsgReturn(    enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING
+                    &&  enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
+                    ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs),
+                    VERR_INVALID_PARAMETER);
+    AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
 
     /*
@@ -250,22 +248,27 @@
     {
         /* Fallback to FindFileFirst in case of sharing violation. */
-        if (GetLastError() == ERROR_SHARING_VIOLATION)
-        {
-            WIN32_FIND_DATAA FindData;
-            HANDLE hDir = FindFirstFileA(pszPath, &FindData);
-            if (hDir == INVALID_HANDLE_VALUE)
-                return RTErrConvertFromWin32(GetLastError());
-            FindClose(hDir);
-            Data.dwFileAttributes = FindData.dwFileAttributes;
-            Data.ftCreationTime = FindData.ftCreationTime;
-            Data.ftLastAccessTime = FindData.ftLastAccessTime;
-            Data.ftLastWriteTime = FindData.ftLastWriteTime;
-            Data.nFileSizeHigh = FindData.nFileSizeHigh;
-            Data.nFileSizeLow = FindData.nFileSizeLow;
-        }
-        else
+        if (GetLastError() != ERROR_SHARING_VIOLATION)
             return RTErrConvertFromWin32(GetLastError());
+        WIN32_FIND_DATAA FindData;
+        HANDLE hDir = FindFirstFileA(pszPath, &FindData);
+        if (hDir == INVALID_HANDLE_VALUE)
+            return RTErrConvertFromWin32(GetLastError());
+        FindClose(hDir);
+        Data.dwFileAttributes = FindData.dwFileAttributes;
+        Data.ftCreationTime = FindData.ftCreationTime;
+        Data.ftLastAccessTime = FindData.ftLastAccessTime;
+        Data.ftLastWriteTime = FindData.ftLastWriteTime;
+        Data.nFileSizeHigh = FindData.nFileSizeHigh;
+        Data.nFileSizeLow = FindData.nFileSizeLow;
     }
 #endif
+    if (   (fFlags & RTPATH_F_FOLLOW_LINK)
+        && (Data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
+    {
+        AssertFailed();
+        /** @todo Symlinks: RTPathQueryInfoEx is not handling symbolic links
+         *        correctly on Windows.  (Both GetFileAttributesEx and FileFindFirst
+         *        will return info about the symlink.) */
+    }
 
     /*
@@ -323,13 +326,21 @@
                              PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
 {
+    return RTPathSetTimesEx(pszPath, pAccessTime, pModificationTime, pChangeTime, pBirthTime, RTPATH_F_ON_LINK);
+}
+
+
+RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+                               PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags)
+{
     /*
      * Validate input.
      */
-    AssertMsgReturn(VALID_PTR(pszPath), ("%p\n", pszPath), VERR_INVALID_POINTER);
-    AssertMsgReturn(*pszPath, ("%p\n", pszPath), VERR_INVALID_PARAMETER);
-    AssertMsgReturn(!pAccessTime || VALID_PTR(pAccessTime), ("%p\n", pAccessTime), VERR_INVALID_POINTER);
-    AssertMsgReturn(!pModificationTime || VALID_PTR(pModificationTime), ("%p\n", pModificationTime), VERR_INVALID_POINTER);
-    AssertMsgReturn(!pChangeTime || VALID_PTR(pChangeTime), ("%p\n", pChangeTime), VERR_INVALID_POINTER);
-    AssertMsgReturn(!pBirthTime || VALID_PTR(pBirthTime), ("%p\n", pBirthTime), VERR_INVALID_POINTER);
+    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+    AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
+    AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
+    AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
 
     /*
@@ -340,11 +351,36 @@
     if (RT_SUCCESS(rc))
     {
-        HANDLE hFile = CreateFileW(pwszPath,
-                                   FILE_WRITE_ATTRIBUTES,   /* dwDesiredAccess */
-                                   FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */
-                                   NULL,                    /* security attribs */
-                                   OPEN_EXISTING,           /* dwCreationDisposition */
-                                   FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
-                                   NULL);
+        HANDLE hFile;
+        if (fOpen & RTPATH_F_FOLLOW_LINK)
+            hFile = CreateFileW(pwszPath,
+                                FILE_WRITE_ATTRIBUTES,   /* dwDesiredAccess */
+                                FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */
+                                NULL,                    /* security attribs */
+                                OPEN_EXISTING,           /* dwCreationDisposition */
+                                FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
+                                NULL);
+        else
+        {
+/** @todo Symlink: Test RTPathSetTimesEx on Windows. (The code is disabled
+ *        because it's not tested yet.) */
+#if 0 //def FILE_FLAG_OPEN_REPARSE_POINT
+            hFile = CreateFileW(pwszPath,
+                                FILE_WRITE_ATTRIBUTES,   /* dwDesiredAccess */
+                                FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */
+                                NULL,                    /* security attribs */
+                                OPEN_EXISTING,           /* dwCreationDisposition */
+                                FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT,
+                                NULL);
+
+            if (hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_PARAMETER)
+#endif
+                hFile = CreateFileW(pwszPath,
+                                    FILE_WRITE_ATTRIBUTES,   /* dwDesiredAccess */
+                                    FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */
+                                    NULL,                    /* security attribs */
+                                    OPEN_EXISTING,           /* dwCreationDisposition */
+                                    FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
+                                    NULL);
+        }
         if (hFile != INVALID_HANDLE_VALUE)
         {
@@ -485,13 +521,11 @@
 
 
-/**
- * Checks if the path exists.
- *
- * Symbolic links will all be attempted resolved.
- *
- * @returns true if it exists and false if it doesn't
- * @param   pszPath     The path to check.
- */
 RTDECL(bool) RTPathExists(const char *pszPath)
+{
+    return RTPathExistsEx(pszPath, RTPATH_F_FOLLOW_LINK);
+}
+
+
+RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags)
 {
     /*
@@ -500,8 +534,10 @@
     AssertPtrReturn(pszPath, false);
     AssertReturn(*pszPath, false);
+    Assert(RTPATH_F_IS_VALID(fFlags, 0));
 
     /*
      * Try query file info.
      */
+    DWORD dwAttr;
 #ifndef RT_DONT_CONVERT_FILENAMES
     PRTUTF16 pwszPath;
@@ -509,15 +545,27 @@
     if (RT_SUCCESS(rc))
     {
-        if (GetFileAttributesW(pwszPath) == INVALID_FILE_ATTRIBUTES)
-            rc = VERR_GENERAL_FAILURE;
+        dwAttr = GetFileAttributesW(pwszPath);
         RTUtf16Free(pwszPath);
     }
+    else
+        dwAttr = INVALID_FILE_ATTRIBUTES;
 #else
-    int rc = VINF_SUCCESS;
-    if (GetFileAttributesExA(pszPath) == INVALID_FILE_ATTRIBUTES)
-        rc = VERR_GENERAL_FAILURE;
+    dwAttr = GetFileAttributesA(pszPath);
 #endif
 
-    return RT_SUCCESS(rc);
+    if (dwAttr == INVALID_FILE_ATTRIBUTES)
+        return false;
+
+#ifdef FILE_ATTRIBUTE_REPARSE_POINT
+    if (   (fFlags & RTPATH_F_FOLLOW_LINK)
+        && (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT))
+    {
+        AssertFailed();
+        /** @todo Symlinks: RTPathExists+RTPathExistsEx is misbehaving on symbolic
+         *        links on Windows. */
+    }
+#endif
+
+    return true;
 }
 
