-
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: support long paths when calling WinAPI functions #2181
Comments
Bumping to P1 because this makes our CI flaky / failing. |
This way it's easier to find the functions we need to change to widechar version. See #2181 -- PiperOrigin-RevId: 141043389 MOS_MIGRATED_REVID=141043389
This change: - renames windows_error_handling.* to windows_util.* - moves most stuff except for the JNI method implementations into the new windows_util namespace - implements a jstring to wchar string converter - uses GetFileAttributesW in windows_file_operations.cc See #2181 -- PiperOrigin-RevId: 141187291 MOS_MIGRATED_REVID=141187291
Implement conversion methods between char strings and wchar_t strings. This is necessary to use widechar Windows functions. See #2181 -- PiperOrigin-RevId: 142009930 MOS_MIGRATED_REVID=142009930
In this change: - implement PrintErrorW (copy of PrintError but uses FormatMessageW) - use GetModuleFileNameW in GetSelfPath and do not worry about UNC paths, we'll automatically handle them in the future when we use widechar functions everywhere. Until then, if a path happens to have the "\\?\" prefix and that causes an error, we won't be worse off than today; today we just call `pdie` - use GetTempPathW in GetOutputRoot; in theory this might also return an UNC path but again that shouldn't be a problem - add comments for the arguments of CreateFileA and CreateProcessA calls, to make the code a bit more readable See #2181 -- PiperOrigin-RevId: 142118854 MOS_MIGRATED_REVID=142118854
Move GetJvmVersion from blaze_util to blaze_util_platform, and remove the RunProgram declaration from blaze_util.h. Since GetJvmVersion is the only user of RunProgram this is safe to do, and allows making RunProgram static as well as simplifying its implementation on Windows, while also changing it to use CreateProcessW instead of CreateProcessA. See #2181 -- PiperOrigin-RevId: 142122045 MOS_MIGRATED_REVID=142122045
This method can normalize paths with "." and ".." and multiple "/" characters. E.g. normalize("../foo/./bar/../baz") = "foo/baz" This method enables us implementing PathExists on Windows. If the path to check is too long, we need to prefix it with "\\?\" for the Windows API functions to work, but then the path must be fully normalized and in Windows format. We already have functions to convert a path to Windows format but that doesn't normalize; with this function we can finally convert paths like "/c/foo/../bar" to L"\\?\c:\foo" and check if it exists. See #2107 See #2181 -- PiperOrigin-RevId: 142648194 MOS_MIGRATED_REVID=142648194
Anything I can do to assist with this? It's one of the things that blocks our Windows adoption. |
Thanks, I think we're close to fixing this. I'm about to update the CreateFileA calls to CreateFileW in blaze_util_windows, then update the CreateProcessA ones to W, and that should do it. |
Checking if a path exists is surprisingly hard on Windows. The most convenient API functions are PathFileExists and GetFileAttributes but neither of them follows junctions. To check if a junction is dangling, we have to resolve it all the way. This change adds a JunctionResolver class to file_windows, which can resolve junctions (if they aren't dangling) and non-junctions (in this case just checks their existence). See #2107 See #2181 -- PiperOrigin-RevId: 143645274 MOS_MIGRATED_REVID=143645274
TIL: CreateProcessW doesn't support long paths, not even with "\\?\". (..a moment of silence..) Luckily, there's GetShortPathName so we can shorten those long paths and CreateProcess can spawn a process with them. |
Another poor soul who ran into this, and tried everything I tried and some more: |
Happy New Year...? |
Because CreateProcessW doesn't support long paths, not even with the "\\?\" prefix [1], we need to convert long paths to short ones to spawn processes. This change implements the corresponding function and uses it in blaze_util_windows. [1] #2181 (comment) See #2107 See #2181 -- PiperOrigin-RevId: 144062404 MOS_MIGRATED_REVID=144062404
Add a separate argument to nativeCreateProcess for argv[0] specifically, and another for the rest of the args. In a subsequent change I'll add code to compute the 8dot3 style short name of the argv[0] so we can use longer paths for executables in CreateProcessA than we normally could. This is the same approach as used in commit 44ecf9a See #2107 See #2181 -- PiperOrigin-RevId: 144311562 MOS_MIGRATED_REVID=144311562
Use CreateFileW in blaze_util_windows.cc when opening the "jvm.out" file. This allows supporting long paths. Also use AsWindowsPathWithUncPrefix instead of just AsWindowsPath plus manually adding the UNC prefix. Also fix a compilation error in file_windows_test.cc, I'm surprised the CI system didn't catch this, maybe we aren't running this test there. See #2107 See #2181 -- PiperOrigin-RevId: 144813245 MOS_MIGRATED_REVID=144813245
Add tests for the AsExecutablePathForCreateProcess method, since its logic is pretty complex. Unfortunately testing it also requires complex logic, as we need to test what exactly happens when the input path is shorter than MAX_PATH or when it's longer than it. To test that reliably, we need a base path that we know will not get shortened. Creating that base path under the temp directory is a nightmare, we need to: (1) retrieve the temp dir, shorten it so we know that it won't be shortened further (2) keep creating subdirectories that have a short name so they also won't get shortened, but keep the entire path below MAX_PATH while leaving enough space for a file name in the end (3) append a file name such that the path is just below MAX_PATH, or is exactly that long, or is longer than it. Because of steps (1) and (2) we can be sure that no other component in the path will get shortened, so we can test exactly what's going on with the shortener logic and its error handling. But oh boy is it complicated. Side note, we need to use the Widechar WinAPI functions to create/delete the directories and files, because the POSIX API on Windows appears to be backed by the ASCII API functions, so attempting to `mkdir` with a path longer than CreateDirectoryA's limit is going to fail. But on the positive side, adding tests caught two bugs in the method, so we have that going for us which is nice. See #2107 See #2181 -- PiperOrigin-RevId: 144823029 MOS_MIGRATED_REVID=144823029
*** Reason for rollback *** Breaks Bazel-Install-Trigger on CI. *** Original change description *** Bazel client, Windows: impl. ForEachDirectoryEntry Implement ForEachDirectoryEntry on Windows using FindFirstFileW / FindNextFileW. Supports long paths and traversing junctions. See #2107 See #2181 -- PiperOrigin-RevId: 145282158 MOS_MIGRATED_REVID=145282158
I have a change that fixes about 5 long path related bugs. Now I can build bazel with a long output_user_root. I'll break it down and start sending out. |
Fix blaze_util_windows.ConvertPath: in the MSVC version this is using the actual %PATH% value, we don't need to convert it. Fix blaze_util_windows.PathAsJvmFlag: shorten the path so we can pass it to the JVM process (long paths aren't understood by the shell), but also converrt backslashes to forward slashes so the JVM won't believe we are passing paths with escaped characters. See #2107 See #2181 -- PiperOrigin-RevId: 149396971 MOS_MIGRATED_REVID=149396971
Is there still work to do here? |
Not that I'm aware of. It's my great pleasure to hit "Close and comment". |
We're going to eagerly try this out this week as it's one of the things that blocks our use of Bazel on Windows. Thanks and we'll keep you posted! |
We're also going to start dogfooding the MSYS-less version with 0.5.0, stay tuned! |
Description of the problem / feature request / question:
We're hitting path length limitations because we use the ASCII version of Win32 functions and paths are limited to 260 characters (
MAX_PATH
).See for example #2178 (comment).
We have to use the widechar versions and prefix all long paths with
\\?\
.Caveats: such prefixed paths may not use
/
as the path separator, only\
. Using/
only works with the ASCII versions.If possible, provide a minimal example to reproduce the problem:
Environment info
Operating System: Windows (every version)
If
bazel info release
returns "development version" or "(@non-git)", please tell us what source tree you compiled Bazel from; git commit hash is appreciated (git rev-parse HEAD
):Have you found anything relevant by searching the web? (e.g. GitHub issues, email threads in the bazel-discuss@googlegroups.com archive)
Naupe.
Anything else, information or logs or outputs that would be helpful?
(If they are large, please upload as attachment or provide link).
The text was updated successfully, but these errors were encountered: