|
12 | 12 | // See the License for the specific language governing permissions and |
13 | 13 | // limitations under the License. |
14 | 14 |
|
15 | | -#include "includes_normalize.h" |
16 | | - |
17 | | -#include "string_piece.h" |
18 | | -#include "string_piece_util.h" |
19 | | -#include "util.h" |
| 15 | +#include <string.h> |
| 16 | +#include <windows.h> |
20 | 17 |
|
21 | 18 | #include <algorithm> |
22 | 19 | #include <iterator> |
23 | 20 | #include <sstream> |
24 | 21 |
|
25 | | -#include <windows.h> |
| 22 | +#include "includes_normalize.h" |
| 23 | +#include "string_piece.h" |
| 24 | +#include "string_piece_util.h" |
| 25 | +#include "util.h" |
26 | 26 |
|
27 | 27 | namespace { |
28 | 28 |
|
29 | | -bool InternalGetFullPathName(const StringPiece& file_name, char* buffer, |
30 | | - size_t buffer_length, std::string* err) { |
31 | | - DWORD result_size = GetFullPathNameA(file_name.AsString().c_str(), |
32 | | - buffer_length, buffer, NULL); |
33 | | - if (result_size == 0) { |
34 | | - *err = "GetFullPathNameA(" + file_name.AsString() + "): " + |
35 | | - GetLastErrorString(); |
| 29 | +// Get the full path of a given filename. On success set |*path| and return |
| 30 | +// true. On failure, clear |path|, set |*err| then result false. |
| 31 | +bool InternalGetFullPathName(const StringPiece& file_name, std::string* path, |
| 32 | + std::string* err) { |
| 33 | + // IMPORTANT: Using GetFullPathNameA() with a long paths will fail with |
| 34 | + // "The filename or extension is too long" even if long path supported is |
| 35 | + // enabled. GetFullPathNameW() must be used for this function to work! |
| 36 | +#if 1 |
| 37 | + path->clear(); |
| 38 | + // Convert to wide filename first. |
| 39 | + std::string filename_str = file_name.AsString(); |
| 40 | + std::wstring wide_filename; |
| 41 | + if (!ConvertUTF8ToWin32Unicode(filename_str, &wide_filename, err)) |
| 42 | + return false; |
| 43 | + |
| 44 | + // Call GetFullPathNameW() |
| 45 | + DWORD wide_full_size = GetFullPathNameW(wide_filename.c_str(), 0, NULL, NULL); |
| 46 | + if (wide_full_size == 0) { |
| 47 | + *err = "GetFullPathNameW(" + |
| 48 | + std::string(wide_filename.begin(), wide_filename.end()) + |
| 49 | + "): " + GetLastErrorString(); |
| 50 | + return false; |
| 51 | + } |
| 52 | + |
| 53 | + // NOTE: wide_full_size includes the null-terminating character. |
| 54 | + std::wstring wide_path; |
| 55 | + wide_path.resize(static_cast<size_t>(wide_full_size - 1)); |
| 56 | + DWORD wide_full_size2 = |
| 57 | + GetFullPathNameW(wide_filename.c_str(), wide_full_size, |
| 58 | + const_cast<wchar_t*>(wide_path.data()), NULL); |
| 59 | + if (wide_full_size2 == 0) { |
| 60 | + *err = "GetFullPathNameA(" + filename_str + "): " + GetLastErrorString(); |
| 61 | + path->clear(); |
| 62 | + return false; |
| 63 | + } |
| 64 | + |
| 65 | + // Convert wide_path to Unicode. |
| 66 | + return ConvertWin32UnicodeToUTF8(wide_path, path, err); |
| 67 | +#else |
| 68 | + path->clear(); |
| 69 | + std::string filename_str = file_name.AsString(); |
| 70 | + DWORD full_size = GetFullPathNameA(filename_str.c_str(), 0, NULL, NULL); |
| 71 | + if (full_size == 0) { |
| 72 | + *err = "GetFullPathNameA(" + filename_str + "): " + GetLastErrorString(); |
36 | 73 | return false; |
37 | | - } else if (result_size > buffer_length) { |
38 | | - *err = "path too long"; |
| 74 | + } |
| 75 | +
|
| 76 | + // NOTE: full_size includes the null-terminating character. |
| 77 | + path->resize(static_cast<size_t>(full_size - 1)); |
| 78 | + DWORD result2 = GetFullPathNameA(filename_str.c_str(), full_size, |
| 79 | + const_cast<char*>(path->data()), NULL); |
| 80 | + if (result2 == 0) { |
| 81 | + *err = "GetFullPathNameA(" + filename_str + "): " + GetLastErrorString(); |
39 | 82 | return false; |
40 | 83 | } |
| 84 | +
|
| 85 | + path->resize(static_cast<size_t>(result2)); |
| 86 | + return true; |
| 87 | +#endif |
| 88 | +} |
| 89 | + |
| 90 | +// Get the drive prefix of a given filename. On success set |*drive| then return |
| 91 | +// true. On failure, clear |*drive|, set |*err| then return false. |
| 92 | +bool InternalGetDrive(const StringPiece& file_name, std::string* drive, |
| 93 | + std::string* err) { |
| 94 | + std::string path; |
| 95 | + if (!InternalGetFullPathName(file_name, &path, err)) |
| 96 | + return false; |
| 97 | + |
| 98 | + char drive_buffer[_MAX_DRIVE]; |
| 99 | + errno_t ret = _splitpath_s(path.data(), drive_buffer, sizeof(drive_buffer), |
| 100 | + NULL, 0, NULL, 0, NULL, 0); |
| 101 | + if (ret != 0) { |
| 102 | + *err = "_splitpath_s() returned " + std::string(strerror(ret)) + |
| 103 | + " for path: " + path; |
| 104 | + drive->clear(); |
| 105 | + return false; |
| 106 | + } |
| 107 | + drive->assign(drive_buffer); |
41 | 108 | return true; |
42 | 109 | } |
43 | 110 |
|
@@ -74,19 +141,13 @@ bool SameDrive(StringPiece a, StringPiece b, std::string* err) { |
74 | 141 | return true; |
75 | 142 | } |
76 | 143 |
|
77 | | - char a_absolute[_MAX_PATH]; |
78 | | - char b_absolute[_MAX_PATH]; |
79 | | - if (!InternalGetFullPathName(a, a_absolute, sizeof(a_absolute), err)) { |
80 | | - return false; |
81 | | - } |
82 | | - if (!InternalGetFullPathName(b, b_absolute, sizeof(b_absolute), err)) { |
| 144 | + std::string a_drive; |
| 145 | + std::string b_drive; |
| 146 | + if (!InternalGetDrive(a, &a_drive, err) || |
| 147 | + !InternalGetDrive(b, &b_drive, err)) { |
83 | 148 | return false; |
84 | 149 | } |
85 | | - char a_drive[_MAX_DIR]; |
86 | | - char b_drive[_MAX_DIR]; |
87 | | - _splitpath(a_absolute, a_drive, NULL, NULL, NULL); |
88 | | - _splitpath(b_absolute, b_drive, NULL, NULL, NULL); |
89 | | - return _stricmp(a_drive, b_drive) == 0; |
| 150 | + return _stricmp(a_drive.c_str(), b_drive.c_str()) == 0; |
90 | 151 | } |
91 | 152 |
|
92 | 153 | // Check path |s| is FullPath style returned by GetFullPathName. |
@@ -144,13 +205,14 @@ std::string IncludesNormalize::AbsPath(StringPiece s, std::string* err) { |
144 | 205 | return result; |
145 | 206 | } |
146 | 207 |
|
147 | | - char result[_MAX_PATH]; |
148 | | - if (!InternalGetFullPathName(s, result, sizeof(result), err)) { |
| 208 | + std::string result; |
| 209 | + if (!InternalGetFullPathName(s, &result, err)) { |
149 | 210 | return ""; |
150 | 211 | } |
151 | | - for (char* c = result; *c; ++c) |
152 | | - if (*c == '\\') |
153 | | - *c = '/'; |
| 212 | + for (char& c : result) { |
| 213 | + if (c == '\\') |
| 214 | + c = '/'; |
| 215 | + } |
154 | 216 | return result; |
155 | 217 | } |
156 | 218 |
|
@@ -183,24 +245,17 @@ std::string IncludesNormalize::Relativize( |
183 | 245 |
|
184 | 246 | bool IncludesNormalize::Normalize(const std::string& input, std::string* result, |
185 | 247 | std::string* err) const { |
186 | | - char copy[_MAX_PATH + 1]; |
187 | | - size_t len = input.size(); |
188 | | - if (len > _MAX_PATH) { |
189 | | - *err = "path too long"; |
190 | | - return false; |
191 | | - } |
192 | | - strncpy(copy, input.c_str(), input.size() + 1); |
| 248 | + std::string copy = input; |
193 | 249 | uint64_t slash_bits; |
194 | | - CanonicalizePath(copy, &len, &slash_bits); |
195 | | - StringPiece partially_fixed(copy, len); |
196 | | - std::string abs_input = AbsPath(partially_fixed, err); |
| 250 | + CanonicalizePath(©, &slash_bits); |
| 251 | + std::string abs_input = AbsPath(copy, err); |
197 | 252 | if (!err->empty()) |
198 | 253 | return false; |
199 | 254 |
|
200 | 255 | if (!SameDrive(abs_input, relative_to_, err)) { |
201 | 256 | if (!err->empty()) |
202 | 257 | return false; |
203 | | - *result = partially_fixed.AsString(); |
| 258 | + *result = copy; |
204 | 259 | return true; |
205 | 260 | } |
206 | 261 | *result = Relativize(abs_input, split_relative_to_, err); |
|
0 commit comments