[GHC] #13373: Handle long file paths on Windows

#13373: Handle long file paths on Windows ----------------------------------------+--------------------------------- Reporter: ezyang | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: libraries/base | Version: 8.1 Keywords: | Operating System: Windows Architecture: Unknown/Multiple | Type of failure: None/Unknown Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: ----------------------------------------+--------------------------------- In the past, Cabal and GHC have run into Windows' PATH_MAX path size limitation, which caps the length of file system paths at 260 characters. Examples: * https://github.com/haskell/cabal/issues/3972 * https://ghc.haskell.org/trac/ghc/ticket/10777 It would be really great if Haskell's base libraries handled long file system paths correctly. There are a few possibilities for achieving this: * Call GetShortPathName https://msdn.microsoft.com/en- us/library/windows/desktop/aa364989(v=vs.85).aspx before calling any Windows API function, if we notice the file path is too long. The bad: Windows has to store the alias, and this aliasing mechanism may be disabled (but maybe this never happens in practice). * Rewrite the core libraries to use the Unicode versions of functions, which support longer paths. We need to add the `\\?\` prefix in this case. However, this prefix is not supported by all functions, and it turns off automatic expansion in the path string (so `..` is not interpreted.) Care would need to be taken to not break existing code. * For Windows 10 only, opt into transparent long path support using a manifest. See the bottom of https://msdn.microsoft.com/en- us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath Downside: this only works for Windows 10 An alternative plan is to build and publish an alternative Windows IO library, which is a drop-in replacement for the IO functionality implemented in base but is long paths. We can use this to test paths and provide better functionality to old versions of GHC, before merging the changes back into base proper. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13373 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13373: Handle long file paths on Windows -------------------------------------+------------------------------------- Reporter: ezyang | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: libraries/base | Version: 8.1 Resolution: | Keywords: Operating System: Windows | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by awson): ''but maybe this never happens in practice'' All my Windows machines have short path names generation disabled. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13373#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13373: Handle long file paths on Windows -------------------------------------+------------------------------------- Reporter: ezyang | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: libraries/base | Version: 8.1 Resolution: | Keywords: Operating System: Windows | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Old description:
In the past, Cabal and GHC have run into Windows' PATH_MAX path size limitation, which caps the length of file system paths at 260 characters. Examples:
* https://github.com/haskell/cabal/issues/3972 * https://ghc.haskell.org/trac/ghc/ticket/10777
It would be really great if Haskell's base libraries handled long file system paths correctly. There are a few possibilities for achieving this:
* Call GetShortPathName https://msdn.microsoft.com/en- us/library/windows/desktop/aa364989(v=vs.85).aspx before calling any Windows API function, if we notice the file path is too long. The bad: Windows has to store the alias, and this aliasing mechanism may be disabled (but maybe this never happens in practice). * Rewrite the core libraries to use the Unicode versions of functions, which support longer paths. We need to add the `\\?\` prefix in this case. However, this prefix is not supported by all functions, and it turns off automatic expansion in the path string (so `..` is not interpreted.) Care would need to be taken to not break existing code. * For Windows 10 only, opt into transparent long path support using a manifest. See the bottom of https://msdn.microsoft.com/en- us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath Downside: this only works for Windows 10
An alternative plan is to build and publish an alternative Windows IO library, which is a drop-in replacement for the IO functionality implemented in base but is long paths. We can use this to test paths and provide better functionality to old versions of GHC, before merging the changes back into base proper.
New description: In the past, Cabal and GHC have run into Windows' PATH_MAX path size limitation, which caps the length of file system paths at 260 characters. Examples: * https://github.com/haskell/cabal/issues/3972 * https://ghc.haskell.org/trac/ghc/ticket/10777 It would be really great if Haskell's base libraries handled long file system paths correctly. There are a few possibilities for achieving this: * Call GetShortPathName https://msdn.microsoft.com/en- us/library/windows/desktop/aa364989(v=vs.85).aspx before calling any Windows API function, if we notice the file path is too long. The bad: Windows has to store the alias, and this aliasing mechanism may be disabled ~~(but maybe this never happens in practice).~~ * Rewrite the core libraries to use the Unicode versions of functions, which support longer paths. We need to add the `\\?\` prefix in this case. However, this prefix is not supported by all functions, and it turns off automatic expansion in the path string (so `..` is not interpreted.) Care would need to be taken to not break existing code. * For Windows 10 only, opt into transparent long path support using a manifest. See the bottom of https://msdn.microsoft.com/en- us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath Downside: this only works for Windows 10 An alternative plan is to build and publish an alternative Windows IO library, which is a drop-in replacement for the IO functionality implemented in base but is long paths. We can use this to test paths and provide better functionality to old versions of GHC, before merging the changes back into base proper. -- Comment (by ezyang): I stand corrected. :) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13373#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13373: Handle long file paths on Windows -------------------------------------+------------------------------------- Reporter: ezyang | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: libraries/base | Version: 8.1 Resolution: | Keywords: Operating System: Windows | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by ekmett): Using long paths would fix the sort of weird things that arise with `Con.hs` and the like on Windows as well. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13373#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13373: Handle long file paths on Windows -------------------------------------+------------------------------------- Reporter: ezyang | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: libraries/base | Version: 8.1 Resolution: | Keywords: Operating System: Windows | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by Rufflewind): I have a [https://github.com/haskell/directory/blob/b82ca0194767bf418330bd1ed89ea54171... helper function] which can be used to add `\\?\` to paths and takes care of the subtleties of `..` etc: So far I've managed to [https://github.com/haskell/directory/commit/f77655a2e17c6f7076c7cf9d7de83f5b... use this] for most of the direct Win32 API calls. However, `c_stat` (from GHC's `System.Posix.Internals`) is used quite a bit and does not support longer paths AFAIK, so that probably needs to be replaced somehow. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13373#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13373: Handle long file paths on Windows -------------------------------------+------------------------------------- Reporter: ezyang | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: libraries/base | Version: 8.1 Resolution: | Keywords: Operating System: Windows | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by YitzGale): How are other compilers dealing with this? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13373#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13373: Handle long file paths on Windows -------------------------------------+------------------------------------- Reporter: ezyang | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: libraries/base | Version: 8.1 Resolution: | Keywords: Operating System: Windows | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by Rufflewind): Turns out, despite what [https://msdn.microsoft.com/en- us/library/windows/desktop/aa365530.aspx MSDN] says, `SetCurrentDirectoryW` does not seem to support long paths through the `\\?\` prefix. I saw an [https://news.ycombinator.com/item?id=13093529 anecdote] that it ''does'' work if one opts-in through the Win10-only feature (through manifest and/or (?) registry tweak), as long as you append a backslash. Since it still did not work with the `\\?\` prefix even after appending a backslash, so I can only assume that `\\?\` is broken for `SetCurrentDirectoryW`, but the registry/manifest tweak likely does work. My guess is that because in the past `SetCurrentDirectoryW` never supported `\\?\` to begin with, when they added the Win10 feature, whoever updated the documentation probably copy-pasted that section throughout and forgot that `\\?\` was ''specifically not enabled'' for `SetCurrentDirectoryW` unlike many other functions, likely because it would make the counterpart `GetCurrentDirectoryW` risky for improperly written programs. TL;DR: It does not seem possible to set the current directory to a long path except through the Win-10 only mechanism. Also, a lot of Windows functions will choke on relative paths if the resulting path becomes too long, so users will have to use exclusively `\\?\`-style absolute paths. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13373#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

TL;DR: It does not seem possible to set the current directory to a long
#13373: Handle long file paths on Windows -------------------------------------+------------------------------------- Reporter: ezyang | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: libraries/base | Version: 8.1 Resolution: | Keywords: Operating System: Windows | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by hvr): Replying to [comment:6 Rufflewind]: path except through the Win-10 only mechanism. It cannot be set at once... but what about getting there in multiple steps as a workaround with multiple `SetCurrentDirectoryW` calls, where the first one uses an absolute path, and the subsequent ones use relative paths? I know... I'm two days late for such suggestions :-) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13373#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13373: Handle long file paths on Windows -------------------------------------+------------------------------------- Reporter: ezyang | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: libraries/base | Version: 8.1 Resolution: | Keywords: Operating System: Windows | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by joeyhess): My software is afflicted by this problem on Windows. While the manifest file approach is only a partial solution, it would be good to at least not have the problem on Windows 10. And, it seems fairly unintrusive to enable it. ghc already embeds a manifest on windows for https://ghc.haskell.org/trac/ghc/ticket/1271 , so could longPathAware be added to it? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13373#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13373: Handle long file paths on Windows -------------------------------------+------------------------------------- Reporter: ezyang | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: libraries/base | Version: 8.1 Resolution: | Keywords: Operating System: Windows | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by joeyhess): Due to https://ghc.haskell.org/trac/ghc/ticket/13796 it's hard to make ghc embed a custom manifest file to enable long filename support. However, use -fno-embed-manifest and when running foo.exe, windows will read a side-by- side foo.exe.manifest file. I tested this with a foo.hs containing main = writeFile (take 300 (cycle "a")) "hello" Despite the manifest enabling long file support, on Windows 10 that fails with "openFile: does not exist". Seems that long file support includes CreateFileW, but ghc's openFile uses _wsopen, which is not included in the long file support. This makes the manifest approach only useful for some subset of programs. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13373#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC