| 286 | } |
| 287 | |
| 288 | std::string Path::RealPath(const std::string_view path) |
| 289 | { |
| 290 | // Resolve non-absolute paths first. |
| 291 | std::vector<std::string_view> components; |
| 292 | // We need to keep the full combined path in scope |
| 293 | // as SplitNativePath() returns string_views to it. |
| 294 | std::string buf; |
| 295 | if (!IsAbsolute(path)) |
| 296 | { |
| 297 | buf = Path::Combine(FileSystem::GetWorkingDirectory(), path); |
| 298 | components = Path::SplitNativePath(buf); |
| 299 | } |
| 300 | else |
| 301 | components = Path::SplitNativePath(path); |
| 302 | |
| 303 | std::string realpath; |
| 304 | if (components.empty()) |
| 305 | return realpath; |
| 306 | |
| 307 | // Different to path because relative. |
| 308 | realpath.reserve(std::accumulate(components.begin(), components.end(), static_cast<size_t>(0), |
| 309 | [](size_t l, const std::string_view& s) { return l + s.length(); }) + |
| 310 | components.size() + 1); |
| 311 | |
| 312 | #ifdef _WIN32 |
| 313 | std::wstring wrealpath; |
| 314 | std::vector<WCHAR> symlink_buf; |
| 315 | wrealpath.reserve(realpath.size()); |
| 316 | symlink_buf.resize(path.size() + 1); |
| 317 | |
| 318 | // Check for any symbolic links throughout the path while adding components. |
| 319 | const bool skip_first = IsUNCPath(path); |
| 320 | bool test_symlink = true; |
| 321 | for (const std::string_view& comp : components) |
| 322 | { |
| 323 | if (!realpath.empty()) |
| 324 | { |
| 325 | realpath.push_back(FS_OSPATH_SEPARATOR_CHARACTER); |
| 326 | realpath.append(comp); |
| 327 | } |
| 328 | else if (skip_first) |
| 329 | { |
| 330 | realpath.append(comp); |
| 331 | continue; |
| 332 | } |
| 333 | else |
| 334 | { |
| 335 | realpath.append(comp); |
| 336 | } |
| 337 | if (test_symlink) |
| 338 | { |
| 339 | DWORD attribs; |
| 340 | if (FileSystem::GetWin32Path(&wrealpath, realpath) && |
| 341 | (attribs = GetFileAttributesW(wrealpath.c_str())) != INVALID_FILE_ATTRIBUTES) |
| 342 | { |
| 343 | // if not a link, go to the next component |
| 344 | if (attribs & FILE_ATTRIBUTE_REPARSE_POINT) |
| 345 | { |
nothing calls this directly
no test coverage detected