From bdf262a5e30279a5adbf6c0717f8561bf9dae7ef Mon Sep 17 00:00:00 2001 From: Demi Obenour Date: Tue, 24 Oct 2017 18:59:35 -0400 Subject: [PATCH 1/2] Initial RFC commit --- text/0000-long-paths-windows.md | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 text/0000-long-paths-windows.md diff --git a/text/0000-long-paths-windows.md b/text/0000-long-paths-windows.md new file mode 100644 index 00000000000..35c8e4b920c --- /dev/null +++ b/text/0000-long-paths-windows.md @@ -0,0 +1,45 @@ +- Feature Name: long_windows_paths +- Start Date: 2017-10-24 +- RFC PR: +- Rust Issue: + +# Summary +[summary]: #summary + +Rust programs currently cannot access files on Windows 8 and below with paths longer than `MAX_PATH`. This is a bug and should be fixed. + +# Motivation +[motivation]: #motivation + +Windows 8 and below make it difficult but not impossible for a program to access a file with a name longer than `MAX_PATH`. The kernel APIs have no problem with such paths at all, but the user-mode APIs do. They require that the path be prefixed with `\\?\`, which disables all normalization. + +Fortunately, there is a solution that gets back normalization: if (and only if) the file name *does not* begin with `\??\` or `\\?\`, one can pass it to the Windows API function `GetFullPathNameW`, which supports long paths just fine and can easily be called from Rust. The resulting path can safely have `\\?\` prepended and then be passed to the underlying Windows API calls. `GetFullPathNameW`’s documentation claims that it does not support long paths, but it does. CoreCLR now depends on it doing so, so that won’t change. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +This should require at most a brief mention in the Rust book. All that is needed is a note that while many programs do not support long paths on Windows 8 and below (or Windows 10 without proper manifest/registry settings), Rust’s standard library has no such problems, and will work on any path that the underlying NT API supports. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +Whenever Rust sends a path to an underlying NT API, it should use first check if the path length is less than 260 characters **or** begins with either `\\?\` or `\??\`, then pass it to the underlying Windows API function directly. Otherwise, pass it to `GetFullPathNameW`. If it fails, return; if not, pass the result to the underlying Windows API call. + +# Drawbacks +[drawbacks]: #drawbacks + +This adds a small amount of complexity to the standard library. This complexity should be more than compensated by the ability to handle long paths generated by e.g. NPM. + +# Rationale and alternatives +[alternatives]: #alternatives + +The alternatives are: + +- Do nothing. This is bad, because tools like NPM already support and generate long paths. +- Try to implement `GetFullPathNameW` in pure Rust. This is not easy, and does not guarantee compatibility with the Windows implementation. +- Use `GetFullPathNameW` to allow for long paths on Windows. This is the approach chosen here. + +# Unresolved questions +[unresolved]: #unresolved-questions + +None From b7f95dd3831c2f23a9f27344dfd4ca184b579b0d Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Thu, 26 Oct 2017 14:14:56 -0400 Subject: [PATCH 2/2] =?UTF-8?q?CoreFX=20doesn=E2=80=99t=20use=20GetFullPat?= =?UTF-8?q?hNameW?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I thought that CoreFX (.NET Core standard library) used `GetFullPathNameW`, but it doesn’t. --- text/0000-long-paths-windows.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-long-paths-windows.md b/text/0000-long-paths-windows.md index 35c8e4b920c..7eafb84ec7d 100644 --- a/text/0000-long-paths-windows.md +++ b/text/0000-long-paths-windows.md @@ -13,7 +13,7 @@ Rust programs currently cannot access files on Windows 8 and below with paths lo Windows 8 and below make it difficult but not impossible for a program to access a file with a name longer than `MAX_PATH`. The kernel APIs have no problem with such paths at all, but the user-mode APIs do. They require that the path be prefixed with `\\?\`, which disables all normalization. -Fortunately, there is a solution that gets back normalization: if (and only if) the file name *does not* begin with `\??\` or `\\?\`, one can pass it to the Windows API function `GetFullPathNameW`, which supports long paths just fine and can easily be called from Rust. The resulting path can safely have `\\?\` prepended and then be passed to the underlying Windows API calls. `GetFullPathNameW`’s documentation claims that it does not support long paths, but it does. CoreCLR now depends on it doing so, so that won’t change. +Fortunately, there is a solution that gets back normalization: if (and only if) the file name *does not* begin with `\??\` or `\\?\`, one can pass it to the Windows API function `GetFullPathNameW`, which supports long paths just fine and can easily be called from Rust. The resulting path can safely have `\\?\` prepended and then be passed to the underlying Windows API calls.  `GetFullPathNameW`’s documentation claims that it does not support long paths, but it in fact does. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation @@ -42,4 +42,4 @@ The alternatives are: # Unresolved questions [unresolved]: #unresolved-questions -None +None. This is a bug fix, pure and simple.