-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Windows: implement getCorrectCasing #9435
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -781,5 +781,61 @@ bool GetCwd(std::wstring* result, DWORD* err_code) { | |
} | ||
} | ||
|
||
std::wstring GetCorrectCasing(const std::wstring& abs_path) { | ||
if (!HasDriveSpecifierPrefix(abs_path.c_str())) { | ||
return L""; | ||
} | ||
std::wstring path = Normalize(abs_path); | ||
std::unique_ptr<wchar_t[]> result(new wchar_t[4 + path.size() + 1]); | ||
// Ensure path starts with UNC prefix, so we can use long paths in | ||
// FindFirstFileW. | ||
wcscpy(result.get(), L"\\\\?\\"); | ||
// Copy the rest of the normalized path. (Must be normalized and use `\` | ||
// separators, for the UNC prefix to work.) | ||
wcscpy(result.get() + 4, path.c_str()); | ||
// Ensure drive letter is upper case. | ||
result[4] = towupper(result[4]); | ||
// Start at index 7, which is after the UNC prefix and drive segment (i.e. | ||
// past `\\?\C:\`). | ||
wchar_t* start = result.get() + 7; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a lot of implicit knowledge in this code which makes it hard to read, e.g. where does the 7 come from? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this from UNC (if so make it conditional)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added comment. |
||
// Fix the casing of each segment, from left to right. | ||
while (true) { | ||
// Find current segment end. | ||
wchar_t* seg_end = wcschr(start, L'\\'); | ||
// Pretend the whole path ends at the current segment. | ||
if (seg_end) { | ||
*seg_end = 0; | ||
} | ||
// Find this path from the filesystem. The lookup is case-insensitive, but | ||
// the result shows the correct casing. Because we fix the casing from left | ||
// to right, only the last segment needs fixing, so we look up that | ||
// particular directory (or file). | ||
WIN32_FIND_DATAW metadata; | ||
HANDLE handle = FindFirstFileW(result.get(), &metadata); | ||
if (handle != INVALID_HANDLE_VALUE) { | ||
// Found the child. The correct casing is in metadata.cFileName | ||
wcscpy(start, metadata.cFileName); | ||
FindClose(handle); | ||
if (seg_end) { | ||
// There are more path segments to fix. Restore the `\` separator. | ||
*seg_end = L'\\'; | ||
start = seg_end + 1; | ||
} else { | ||
// This was the last segment. | ||
break; | ||
} | ||
} else { | ||
// Path does not exist. Restore the `\` separator and leave the rest of | ||
// the path unchanged. | ||
if (seg_end) { | ||
*seg_end = L'\\'; | ||
} | ||
break; | ||
} | ||
} | ||
// Return the case-corrected path without the `\\?\` prefix. | ||
return result.get() + 4; | ||
} | ||
|
||
} // namespace windows | ||
} // namespace bazel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please a comment here that explains what "correct" refers to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.