From 9c3e6db6879015c2ac9abef685faf59fbd19613b Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Thu, 25 Feb 2021 22:52:37 -0500 Subject: [PATCH] Improve the check for whether global and local config_dir are the same Extend the string comparison of the two paths to include comparing their file information structure. (See Remarks under the MSDN docs for GetFileInformationByHandle) If the strings are identical we treat them as identical without checking further whether the paths are valid. This matches the current behaviour. Otherwise, the two paths are treated as identical if both exist, are accessible and point to the same object in the file system. Trac: #1359, #1376 Signed-off-by: Selva Nair --- openvpn_config.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/openvpn_config.c b/openvpn_config.c index c814797..347377a 100644 --- a/openvpn_config.c +++ b/openvpn_config.c @@ -337,6 +337,65 @@ BuildFileList0(const TCHAR *config_dir, int recurse_depth, int group, int flags) FindClose(find_handle); } +/* + * Open a path and get its file information structure. + * Returns true on success, false on error. + */ +static bool +GetFileInfo(const wchar_t *path, BY_HANDLE_FILE_INFORMATION *info) +{ + bool ret = false; + + /* FILE_FLAG_BACKUP_SEMANTICS required to open directories */ + HANDLE fd = CreateFileW(path, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + + if (fd == INVALID_HANDLE_VALUE) + { + MsgToEventLog(EVENTLOG_ERROR_TYPE, L"GetFileInfo: Error opening path <%ls> (status = %lu)", path, GetLastError()); + return ret; + } + + ret = GetFileInformationByHandle(fd, info); + if (!ret) + { + MsgToEventLog(EVENTLOG_ERROR_TYPE, L"GetFileInfo: Error accessing file information for path <%ls> (status = %lu)", path, GetLastError()); + } + else + { + PrintDebug(L"path = <%ls> volumeid = %lu file index = (%lu,%lu)", path, info->dwVolumeSerialNumber, info->nFileIndexLow, info->nFileIndexHigh); + } + CloseHandle(fd); + + return ret; +} + +/* + * Compare two paths by checking whether they point to the + * same object in the file system. Returns true if the paths + * are same, false otherwise. + * If the two paths are identical strings return true early. + * If any of the paths do not exist, are not accessible or + * fail to provide file information, we return false. + */ +static bool +IsSamePath(const wchar_t *path1, const wchar_t *path2) +{ + BOOL ret = false; + BY_HANDLE_FILE_INFORMATION info1, info2; + + if (_wcsicmp(path1, path2) == 0) return true; + + if (GetFileInfo(path1, &info1) && GetFileInfo(path2, &info2)) + { + ret = (info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber + && info1.nFileIndexLow == info2.nFileIndexLow + && info1.nFileIndexHigh == info2.nFileIndexHigh); + } + + return ret; +} + void BuildFileList() { @@ -372,7 +431,7 @@ BuildFileList() root = NewConfigGroup(L"System Profiles", root, flags); - if (_tcscmp (o.global_config_dir, o.config_dir)) + if (!IsSamePath(o.global_config_dir, o.config_dir)) BuildFileList0 (o.global_config_dir, recurse_depth, root, flags); if (o.num_configs == 0 && issue_warnings)