mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
Enable long path names on Windows without the registry value
Windows applies the `longPathAware` manifest setting only when `LongPathsEnabled` is set in the registry, so paths longer than 260 characters still fail on a stock machine. Set the undocumented `IsLongPathAwareProcess` bit in the PEB at startup instead, which is what `RtlAreLongPathsEnabled` reads and what Go's runtime does since 1.23. [Bug #18947] [Bug #18923] Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
21ed8de7fd
commit
bb847847ae
3 files changed
+61
Notes:
git
2026-08-19 07:31:45 +00:00
No files matched your search
@@ -244,6 +244,11 @@ Ruby 4.0 bundled RubyGems and Bundler version 4. see the following links for det
|
||||
* SunOS 4 (Solaris, i.e. SunOS 5, is unaffected)
|
||||
* BSD/OS (BSDi)
|
||||
|
||||
* Windows 10 1703 or later no longer needs the `LongPathsEnabled` registry
|
||||
value to use paths longer than 260 characters. Each path component is still
|
||||
limited to 255 characters, and a child process still starts with the
|
||||
`MAX_PATH` limited current directory. [[Bug #18947]]
|
||||
|
||||
## Compatibility issues
|
||||
|
||||
* `Kernel#at_exit` and `END {}` now raise `Ractor::IsolationError` when called
|
||||
@@ -327,6 +332,7 @@ A lot of work has gone into making Ractors more stable, performant, and usable.
|
||||
|
||||
## JIT
|
||||
|
||||
[Bug #18947]: https://bugs.ruby-lang.org/issues/18947
|
||||
[Feature #8948]: https://bugs.ruby-lang.org/issues/8948
|
||||
[Feature #9779]: https://bugs.ruby-lang.org/issues/9779
|
||||
[Feature #15330]: https://bugs.ruby-lang.org/issues/15330
|
||||
|
||||
@@ -590,6 +590,22 @@ class TestDir < Test::Unit::TestCase
|
||||
assert_empty(entries - Dir.glob("#{wild}/Common*", File::FNM_SHORTNAME), bug10819)
|
||||
end
|
||||
|
||||
def test_glob_long_path
|
||||
bug18923 = '[Bug #18923]'
|
||||
# the whole path is longer than MAX_PATH, while each component is
|
||||
# within the 255 chars limit of NTFS
|
||||
deep = File.join(@root, "a" * 200, "b" * 200)
|
||||
begin
|
||||
FileUtils.mkdir_p(deep)
|
||||
rescue SystemCallError
|
||||
omit "long path names are not available"
|
||||
end
|
||||
file = File.join(deep, "c.txt")
|
||||
File.write(file, "")
|
||||
assert_equal([file], Dir.glob(File.join(@root, "**", "*.txt")), bug18923)
|
||||
assert_equal(["c.txt"], Dir.children(deep), bug18923)
|
||||
end
|
||||
|
||||
def test_home_windows
|
||||
setup_envs(%w[HOME USERPROFILE HOMEDRIVE HOMEPATH])
|
||||
|
||||
|
||||
@@ -843,6 +843,44 @@ static int w32_cmdvector(const WCHAR *, char ***, UINT, rb_encoding *);
|
||||
//
|
||||
// Initialization stuff
|
||||
//
|
||||
|
||||
/* License: Ruby's */
|
||||
/* Enable long path names for this process, whatever the registry value
|
||||
* HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled is. The
|
||||
* loader sets the same PEB bit for longPathAware in the manifest, but only
|
||||
* when that registry value is set, so the manifest alone is not enough on a
|
||||
* stock machine. Undocumented, and taken from initLongPathSupport in Go's
|
||||
* runtime <https://go.dev/src/runtime/os_windows.go>, whose maintainers have
|
||||
* proposed to drop it <https://github.com/golang/go/issues/66560>. */
|
||||
static void
|
||||
init_long_path_support(void)
|
||||
{
|
||||
/* PEB.BitField, and the IsLongPathAwareProcess bit in it */
|
||||
enum {peb_bit_field_offset = 3, is_long_path_aware_process = 0x80};
|
||||
typedef long (WINAPI version_func)(OSVERSIONINFOW *);
|
||||
typedef void *(WINAPI peb_func)(void);
|
||||
version_func *pRtlGetVersion;
|
||||
peb_func *pRtlGetCurrentPeb;
|
||||
OSVERSIONINFOW osvi;
|
||||
BYTE *bit_field;
|
||||
|
||||
pRtlGetVersion = (version_func *)get_proc_address("ntdll.dll", "RtlGetVersion", NULL);
|
||||
if (!pRtlGetVersion) return;
|
||||
memset(&osvi, 0, sizeof(osvi));
|
||||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||||
if (pRtlGetVersion(&osvi)) return;
|
||||
|
||||
/* the PEB bit is honored since Windows 10 1703 (10.0.15063) */
|
||||
if (osvi.dwMajorVersion < 10) return;
|
||||
if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 &&
|
||||
osvi.dwBuildNumber < 15063) return;
|
||||
|
||||
pRtlGetCurrentPeb = (peb_func *)get_proc_address("ntdll.dll", "RtlGetCurrentPeb", NULL);
|
||||
if (!pRtlGetCurrentPeb) return;
|
||||
bit_field = (BYTE *)pRtlGetCurrentPeb() + peb_bit_field_offset;
|
||||
*bit_field |= is_long_path_aware_process;
|
||||
}
|
||||
|
||||
/* License: Ruby's */
|
||||
void
|
||||
rb_w32_sysinit(int *argc, char ***argv)
|
||||
@@ -854,6 +892,7 @@ rb_w32_sysinit(int *argc, char ***argv)
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX);
|
||||
|
||||
get_version();
|
||||
init_long_path_support();
|
||||
|
||||
//
|
||||
// subvert cmd.exe's feeble attempt at command line parsing
|
||||
|
||||
Reference in new issue
Block a user