|
1 | 1 | #include <string> |
2 | 2 | #include <cstddef> |
3 | | -#include <cstdlib> // for _MAX_PATH |
| 3 | +#include <cstdlib> |
| 4 | +#include <algorithm> // for std::replace |
4 | 5 |
|
5 | 6 | #define WIN32_LEAN_AND_MEAN |
6 | 7 | #include <windows.h> |
7 | 8 | #include <winioctl.h> |
8 | 9 |
|
| 10 | +#include "limits_fs.h" |
9 | 11 | #include "win32_fs.h" |
10 | 12 |
|
11 | 13 |
|
@@ -55,6 +57,18 @@ typedef struct _REPARSE_DATA_BUFFER |
55 | 57 | } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; |
56 | 58 |
|
57 | 59 |
|
| 60 | +std::string fs_as_posix(std::string path) |
| 61 | +{ |
| 62 | + std::string s(path); |
| 63 | + |
| 64 | +#if defined(_WIN32) |
| 65 | + std::replace(s.begin(), s.end(), '\\', '/'); |
| 66 | +#endif |
| 67 | + |
| 68 | + return s; |
| 69 | +} |
| 70 | + |
| 71 | + |
58 | 72 | static bool fs_win32_get_reparse_buffer(std::string path, std::byte* buffer) |
59 | 73 | { |
60 | 74 | // this function is adapted from |
@@ -97,6 +111,48 @@ static bool fs_win32_get_reparse_buffer(std::string path, std::byte* buffer) |
97 | 111 | } |
98 | 112 |
|
99 | 113 |
|
| 114 | +std::string fs_win32_final_path(std::string path) |
| 115 | +{ |
| 116 | + // resolves Windows symbolic links (reparse points and junctions) |
| 117 | + // it also resolves the case insensitivity of Windows paths to the disk case |
| 118 | + // PATH MUST EXIST |
| 119 | + // |
| 120 | + // References: |
| 121 | + // https://stackoverflow.com/a/50182947 |
| 122 | + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea |
| 123 | + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlea |
| 124 | + |
| 125 | +#if defined(_WIN32) |
| 126 | + // dwDesiredAccess=0 to allow getting parameters even without read permission |
| 127 | + // FILE_FLAG_BACKUP_SEMANTICS required to open a directory |
| 128 | + HANDLE h = CreateFileA(path.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, |
| 129 | + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); |
| 130 | + if(h == INVALID_HANDLE_VALUE) |
| 131 | + return {}; |
| 132 | + |
| 133 | + std::string r(fs_get_max_path(), '\0'); |
| 134 | + |
| 135 | + const DWORD L = GetFinalPathNameByHandleA(h, r.data(), static_cast<DWORD>(r.size()), FILE_NAME_NORMALIZED); |
| 136 | + CloseHandle(h); |
| 137 | + if(L == 0) |
| 138 | + return {}; |
| 139 | + |
| 140 | + r.resize(L); |
| 141 | + |
| 142 | +#ifdef __cpp_lib_starts_ends_with // C++20 |
| 143 | + if (r.starts_with("\\\\?\\")) |
| 144 | +#else // C++98 |
| 145 | + if (r.substr(0, 4) == "\\\\?\\") |
| 146 | +#endif |
| 147 | + r = r.substr(4); |
| 148 | + |
| 149 | + return fs_as_posix(r); |
| 150 | +#else |
| 151 | + return std::string(path); |
| 152 | +#endif |
| 153 | +} |
| 154 | + |
| 155 | + |
100 | 156 | bool fs_win32_is_symlink(std::string path) |
101 | 157 | { |
102 | 158 | // distinguish between Windows symbolic links and reparse points as |
@@ -126,7 +182,7 @@ std::string fs_shortname(std::string in) |
126 | 182 | // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getshortpathnamew |
127 | 183 | // the path must exist |
128 | 184 |
|
129 | | - std::string out(_MAX_PATH, '\0'); |
| 185 | + std::string out(fs_get_max_path(), '\0'); |
130 | 186 | // size does not include null terminator |
131 | 187 | if(auto L = GetShortPathNameA(in.data(), out.data(), static_cast<DWORD>(out.size())); |
132 | 188 | L > 0 && L < out.length()){ |
|
0 commit comments