Skip to content
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

[Win32] long path name support [Bug #12551] #4505

Merged
merged 3 commits into from May 16, 2021

Conversation

GabrielNagy
Copy link
Contributor

@GabrielNagy GabrielNagy commented May 15, 2021

Implement long path support on Windows by applying Microsoft's recommended application manifest.

To make this work on both Visual C++ and MinGW, include the manifest as a resource when generating the resource files. This way it will be embedded into the executables/libraries generated by both compilers.

It's important for the manifest resource to have ID 1, otherwise GCC will embed a default manifest. Resource type 24 corresponds to manifest resources.1

Note that in addition to this, the user needs to have long paths enabled either by modifying the registry or by enabling a group policy.2

@GabrielNagy
Copy link
Contributor Author

I tested this using the following steps:

  1. Enable long paths either via Registry or Group Policy: https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later
  2. Reboot (not sure if necessary)
  3. Run a Ruby script located in a long path (over 260 chars) - this fails without the PR
  4. Require a Ruby file located in a long path (over 260 chars) - this fails without the PR
  5. Run Dir.mkdir with a long path - this fails without the PR

@GabrielNagy
Copy link
Contributor Author

This can alternatively be done by adding the manifest resource to https://github.com/ruby/ruby/blob/master/win32/resource.rb, so this will also work with MinGW builds. I'll test some more.

Implement long path support on Windows by applying Microsoft's
recommended application manifest.

To make this work on both Visual C++ and MinGW, include the manifest as
a resource when generating the resource files. This way it will be
embedded into the executables/libraries generated by both compilers.

It's important for the manifest resource to have ID 1, otherwise GCC
will embed a default manifest. Resource type 24 corresponds to manifest
resources.[1]

Note that in addition to this, the user needs to have long paths enabled
either by modifying the registry or by enabling a group policy.[2]

[1] https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types
[2] https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later
@GabrielNagy
Copy link
Contributor Author

This works for me with Visual Studio 2019 and GCC 10 (MinGW). I think AppVeyor compiles from a different directory so that's why it can't find the manifest, I'll try to see if I can get the basedir somehow.

win32/resource.rb Outdated Show resolved Hide resolved
@GabrielNagy
Copy link
Contributor Author

Works! Nice!

There was a failing test when I first pushed the PR: https://github.com/ruby/ruby/runs/2591987561?check_suite_focus=true. It seems related but I think it confirms that long paths work:

  1) Failure:
TestProcess#test_spawn_too_long_path [D:/a/ruby/ruby/src/test/ruby/test_process.rb:1758]:
[ruby-core:34842].
[Errno::ENOENT, Errno::E2BIG] exception expected, not #<Errno::EINVAL: Invalid argument - echoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoechoecho>.

Should EINVAL be included in the allowed exceptions?

Even with long paths, filenames on Windows are limited to 255
characters. Anything up to 255 raises ENOENT, higher values raise
EINVAL.
@nobu nobu merged commit 229cb0f into ruby:master May 16, 2021
@michaeltlombardi
Copy link

@nobu what versions of ruby will this land in? 👀

larskanis added a commit to oneclick/rubyinstaller2-packages that referenced this pull request Jun 10, 2021
larskanis added a commit to oneclick/rubyinstaller2-packages that referenced this pull request Jun 10, 2021
larskanis added a commit to oneclick/rubyinstaller2-packages that referenced this pull request Jun 11, 2021
@KostyaSha
Copy link

@larskanis @nobu what ruby versions will include this path fixes?

@larskanis
Copy link
Contributor

I added the patch to all ruby branches of RubyInstaller here. That means that all versions of the next release series from 2.5 to 3.0 will include it. And it's already present in RubyInstaller-head.

@Inversion-des
Copy link

I just got this Errno::ENOENT problem in the development
and a small minute upgrade from v3.0.1 to v3.0.2 solved the problem — it was fantastic 😲!

Thank you so much! 👍❤

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
6 participants