If the provided path or one of its parents points to a symbolic link, follow the symlink and return the path to its target. @param p_rPath Path to follow symlink for, if required. @return true if p_rPath or one of its parents pointed to a symlink.
| 143 | // @return true if p_rPath or one of its parents pointed to a symlink. |
| 144 | // |
| 145 | bool PluginUtils::FollowSymlinkIfRequired(std::wstring& p_rPath) |
| 146 | { |
| 147 | using namespace coveo::linq; |
| 148 | |
| 149 | // Check if path or one of its parent points to a symlink. |
| 150 | const auto isSymlink = [](const std::wstring& path) noexcept { |
| 151 | const auto attributes = ::GetFileAttributesW(path.c_str()); |
| 152 | return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; |
| 153 | }; |
| 154 | const bool symlink = from(coveo::enumerate_one(p_rPath)) |
| 155 | | concat(EnumerateParents(p_rPath)) |
| 156 | | any(isSymlink); |
| 157 | if (symlink) { |
| 158 | // In order to follow the symlink, we need a handle. |
| 159 | DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL; |
| 160 | if ((::GetFileAttributesW(p_rPath.c_str()) & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 161 | // Need this flag to open directory handles according to MSDN |
| 162 | flagsAndAttributes |= FILE_FLAG_BACKUP_SEMANTICS; |
| 163 | } |
| 164 | StHandle hFile = ::CreateFileW(p_rPath.c_str(), |
| 165 | GENERIC_READ, |
| 166 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 167 | nullptr, |
| 168 | OPEN_EXISTING, |
| 169 | flagsAndAttributes, |
| 170 | nullptr); |
| 171 | if (hFile != nullptr) { |
| 172 | const auto bufferSize = ::GetFinalPathNameByHandleW(hFile, nullptr, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); |
| 173 | if (bufferSize != 0) { |
| 174 | std::wstring finalPath(bufferSize + 1, L'\0'); |
| 175 | const auto finalPathRes = ::GetFinalPathNameByHandleW(hFile, |
| 176 | &*finalPath.begin(), |
| 177 | bufferSize + 1, |
| 178 | FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); |
| 179 | if (finalPathRes != 0) { |
| 180 | p_rPath = finalPath.c_str(); |
| 181 | |
| 182 | // Fetching symlink target probably left us with a weird path, fix it |
| 183 | // because Explorer can't handle paths with \\?\ in them. |
| 184 | StringUtils::ReplaceAll(p_rPath, UNC_DRIVE_SYMLINK_PREFIX, L""); |
| 185 | StringUtils::ReplaceAll(p_rPath, LOCAL_DRIVE_SYMLINK_PREFIX, L""); |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | return symlink; |
| 191 | } |
| 192 | |
| 193 | // |
| 194 | // Checks if the given path is a UNC path in the form |
nothing calls this directly
no test coverage detected