Windows: add fallback if canonicalize fails - #161951
Conversation
|
r? @clarfonthey rustbot has assigned @clarfonthey. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
This will probably need a libs discussion. But it isn't urgent. |
| let mut path = Vec::with_capacity(r"\\?\C:".len() + nt_path.len()); | ||
| // Create a verbatim drive root (e.g. \\?\C:) | ||
| path.extend_from_slice(&[b'\\', b'\\', b'?', b'\\', letter, b':']); | ||
| path.extend(OsString::from_wide(nt_path).into_encoded_bytes()); |
There was a problem hiding this comment.
Perhaps OsStr::new(nt_path).encode_wide()?
|
In terms of the current version: I have no blocking concerns and the rest looks good, so, I'll say r=me and you can merge whether you decide to make the changes I mention or not. |
9dcab79 to
7be5641
Compare
|
@bors r=clarfonthey rollup |
… r=clarfonthey Windows: add fallback if `canonicalize` fails This attempts a partial workaround for issues such as: rust-lang#59392, rust-lang#79449, rust-lang#59107, rust-lang#54875, rust-lang#52440, rust-lang#52377, rust-lang#48249, rust-lang#74327, rust-lang#55812 This may require a bit of explanation depending on how familiar you are with Windows paths, I'll try to keep it brief. The short version is that the above issues are cases where third party devices don't integrate with the system sufficiently so Windows isn't aware of the canonical drive for a particular path, causing our `canonicalize` function to fail. This PR works around it by manually search for the drive letter that corresponds to the root of the path. This only works in cases where there is a drive letter assigned but that is the majority of cases. It won't work when the device is only mounted to a directory in another filesystem or isn't mounted at all. To explain the implementation of this PR you should be aware that Windows on Windows NT is more like WINE on Linux then many people realise. You have a kernel (NT) and then you have an implementation of the Win32 APIs on top (this is why `kernel32.dll` is nothing to do with the real kernel, it's like an implementation of Win95's kernel API on top of another OS). Admittedly the boundaries have become fuzzier over the years but there still remains a clear distinction between the Win32 API and the NT kernel API in many places. Paths are one place where this distinction is made clear. You have the familiar Win32 paths like `C:\path\to\file` that date back to the time of DOS. And then you have the low-level NT kernel paths that look like `\Device\HarddiskVolume6\path\to\file` (which aren't really meant to be user-visible). To bridge the gap, the NT namespace has a special `??` directory containing mappings (i.e. symlinks) from drives like `C:` to paths like `\Device\HarddiskVolume6`. In that way translating between Win32 and NT paths is made simpler as you can replace `C:` with `\??\C:` and it'll get resolved to the right path and vice versa (the actual translation from win32 to NT is more complicated but I've already spent too many words on this). So back to canonicalisation. Resolving the canonical NT path should always succeed. The problem comes when mapping that to a Win32 drive path. When the drive is managed by the system then when resolving paths it knows which drive to pick. However, if the drive mapping is added manually then it doesn't. So the way to workaround this is to manually look at the drive mappings and see which one is the root of the NT path we have.
Rollup of 29 pull requests Successful merges: - #161694 (add `Complex` ABI run-make test) - #162014 (Move more `rustdoc-html` tests using `--test` into the right folder) - #162164 (Revert "Implement Debug for C-like enums with a concatenated string") - #160564 (volatile: allow accesses to non-AM memory to trap) - #161579 (suggest calling a fn item used as the iterator of a `for` loop) - #162044 (coverage: Resolve spans to file-coordinates in a separate step) - #162120 (Introduce `PerOwnerLoweringState`) - #162132 (std: improve safety documentation in UNIX stack overflow code) - #162151 (Test itanium mangling of `f16` and `f128`) - #162162 (Don't special-case `!` in stability checks anymore) - #162181 (Remove wrong UnusedBraces lint for iterator loop in edition 2024 ) - #162187 (Rename `thir::ExprKind::Use` to `ValueExpr`) - #158401 (mgca: Don't ICE when evaluating ValTrees that contain error constants) - #159873 (fuchsia: Add safestack as a supported sanitizer for x86_64 fuchsia) - #161847 (Preserve visibility in nested macro import suggestions) - #161951 (Windows: add fallback if `canonicalize` fails) - #161972 (Improve tests for `#[track_caller]` in async) - #162008 (Render the `box` pattern removal diagnostic more actionable & remove `box` expression recovery) - #162065 (std: don't reference `libc::O_NOFOLLOW` on VxWorks in `set_perm_nofollow`) - #162076 (docs(num): clarify conditions under which error occurs in `impl TryFrom<int> for int`) - #162152 (Revert "retrieve supported GCC targets from the sysroot") - #162153 (Prefer `LLVMGetVersion` for runtime info) - #162168 (fix ICE in project_goals/inherent) - #162171 (Explain LoongArch f16 NaN-boxing in inline asm) - #162173 (fix supposedly unreachable `bug!` being reachable) - #162180 (remove outdated next-solver FIXMEs) - #162191 (core: mark float `ClampBounds` methods as `#[inline]`) - #162195 (docs(time): clarify exact seconds for week and day) - #162199 (docs(time): clarify exact seconds for hour and minute)
|
Failed in a rollup: #162221 (comment) @bors r- |
|
This pull request was unapproved. This PR was contained in a rollup (#162221), which was unapproved. |
Get the NT path then search for a drive that links to a prefix of it.
7be5641 to
29776c0
Compare
|
Sorry, fixed docs and tested them locally. @bors r=clarfonthey |
|
Though in case it puts rollupers mind at ease: @bors try jobs=dist-aarch64-msvc |
This comment has been minimized.
This comment has been minimized.
Windows: add fallback if `canonicalize` fails try-job: dist-aarch64-msvc
… r=clarfonthey Windows: add fallback if `canonicalize` fails This attempts a partial workaround for issues such as: rust-lang#59392, rust-lang#79449, rust-lang#59107, rust-lang#54875, rust-lang#52440, rust-lang#52377, rust-lang#48249, rust-lang#74327, rust-lang#55812 This may require a bit of explanation depending on how familiar you are with Windows paths, I'll try to keep it brief. The short version is that the above issues are cases where third party devices don't integrate with the system sufficiently so Windows isn't aware of the canonical drive for a particular path, causing our `canonicalize` function to fail. This PR works around it by manually search for the drive letter that corresponds to the root of the path. This only works in cases where there is a drive letter assigned but that is the majority of cases. It won't work when the device is only mounted to a directory in another filesystem or isn't mounted at all. To explain the implementation of this PR you should be aware that Windows on Windows NT is more like WINE on Linux then many people realise. You have a kernel (NT) and then you have an implementation of the Win32 APIs on top (this is why `kernel32.dll` is nothing to do with the real kernel, it's like an implementation of Win95's kernel API on top of another OS). Admittedly the boundaries have become fuzzier over the years but there still remains a clear distinction between the Win32 API and the NT kernel API in many places. Paths are one place where this distinction is made clear. You have the familiar Win32 paths like `C:\path\to\file` that date back to the time of DOS. And then you have the low-level NT kernel paths that look like `\Device\HarddiskVolume6\path\to\file` (which aren't really meant to be user-visible). To bridge the gap, the NT namespace has a special `??` directory containing mappings (i.e. symlinks) from drives like `C:` to paths like `\Device\HarddiskVolume6`. In that way translating between Win32 and NT paths is made simpler as you can replace `C:` with `\??\C:` and it'll get resolved to the right path and vice versa (the actual translation from win32 to NT is more complicated but I've already spent too many words on this). So back to canonicalisation. Resolving the canonical NT path should always succeed. The problem comes when mapping that to a Win32 drive path. When the drive is managed by the system then when resolving paths it knows which drive to pick. However, if the drive mapping is added manually then it doesn't. So the way to workaround this is to manually look at the drive mappings and see which one is the root of the NT path we have.
… r=clarfonthey Windows: add fallback if `canonicalize` fails This attempts a partial workaround for issues such as: rust-lang#59392, rust-lang#79449, rust-lang#59107, rust-lang#54875, rust-lang#52440, rust-lang#52377, rust-lang#48249, rust-lang#74327, rust-lang#55812 This may require a bit of explanation depending on how familiar you are with Windows paths, I'll try to keep it brief. The short version is that the above issues are cases where third party devices don't integrate with the system sufficiently so Windows isn't aware of the canonical drive for a particular path, causing our `canonicalize` function to fail. This PR works around it by manually search for the drive letter that corresponds to the root of the path. This only works in cases where there is a drive letter assigned but that is the majority of cases. It won't work when the device is only mounted to a directory in another filesystem or isn't mounted at all. To explain the implementation of this PR you should be aware that Windows on Windows NT is more like WINE on Linux then many people realise. You have a kernel (NT) and then you have an implementation of the Win32 APIs on top (this is why `kernel32.dll` is nothing to do with the real kernel, it's like an implementation of Win95's kernel API on top of another OS). Admittedly the boundaries have become fuzzier over the years but there still remains a clear distinction between the Win32 API and the NT kernel API in many places. Paths are one place where this distinction is made clear. You have the familiar Win32 paths like `C:\path\to\file` that date back to the time of DOS. And then you have the low-level NT kernel paths that look like `\Device\HarddiskVolume6\path\to\file` (which aren't really meant to be user-visible). To bridge the gap, the NT namespace has a special `??` directory containing mappings (i.e. symlinks) from drives like `C:` to paths like `\Device\HarddiskVolume6`. In that way translating between Win32 and NT paths is made simpler as you can replace `C:` with `\??\C:` and it'll get resolved to the right path and vice versa (the actual translation from win32 to NT is more complicated but I've already spent too many words on this). So back to canonicalisation. Resolving the canonical NT path should always succeed. The problem comes when mapping that to a Win32 drive path. When the drive is managed by the system then when resolving paths it knows which drive to pick. However, if the drive mapping is added manually then it doesn't. So the way to workaround this is to manually look at the drive mappings and see which one is the root of the NT path we have.
…uwer Rollup of 12 pull requests Successful merges: - #161227 (implement `Add` and `Sub` for `Complex`) - #161280 (make target feature ABI check a hard error on ARM) - #161893 (Add custom allocator support to `(try_)map` on `UniqueArc` and `UniqueRc`) - #162154 (fix[154166]: closure debug capture print) - #161951 (Windows: add fallback if `canonicalize` fails) - #162173 (fix supposedly unreachable `bug!` being reachable) - #162180 (remove outdated next-solver handling) - #162191 (core: mark float `ClampBounds` methods as `#[inline]`) - #162195 (docs(time): clarify exact seconds for week and day) - #162199 (docs(time): clarify exact seconds for hour and minute) - #162222 (coverage: Small cleanups in `extract_hir_info`) - #162230 (Pass -Z merge-functions=disabled in tests/codegen-llvm/intrinsics/unchecked_math.rs)
…uwer Rollup of 12 pull requests Successful merges: - #161227 (implement `Add` and `Sub` for `Complex`) - #161280 (make target feature ABI check a hard error on ARM) - #161893 (Add custom allocator support to `(try_)map` on `UniqueArc` and `UniqueRc`) - #162154 (fix[154166]: closure debug capture print) - #161951 (Windows: add fallback if `canonicalize` fails) - #162173 (fix supposedly unreachable `bug!` being reachable) - #162180 (remove outdated next-solver handling) - #162191 (core: mark float `ClampBounds` methods as `#[inline]`) - #162195 (docs(time): clarify exact seconds for week and day) - #162199 (docs(time): clarify exact seconds for hour and minute) - #162222 (coverage: Small cleanups in `extract_hir_info`) - #162230 (Pass -Z merge-functions=disabled in tests/codegen-llvm/intrinsics/unchecked_math.rs)
Rollup merge of #161951 - ChrisDenton:canonicalize-boogaloo, r=clarfonthey Windows: add fallback if `canonicalize` fails This attempts a partial workaround for issues such as: #59392, #79449, #59107, #54875, #52440, #52377, #48249, #74327, #55812 This may require a bit of explanation depending on how familiar you are with Windows paths, I'll try to keep it brief. The short version is that the above issues are cases where third party devices don't integrate with the system sufficiently so Windows isn't aware of the canonical drive for a particular path, causing our `canonicalize` function to fail. This PR works around it by manually search for the drive letter that corresponds to the root of the path. This only works in cases where there is a drive letter assigned but that is the majority of cases. It won't work when the device is only mounted to a directory in another filesystem or isn't mounted at all. To explain the implementation of this PR you should be aware that Windows on Windows NT is more like WINE on Linux then many people realise. You have a kernel (NT) and then you have an implementation of the Win32 APIs on top (this is why `kernel32.dll` is nothing to do with the real kernel, it's like an implementation of Win95's kernel API on top of another OS). Admittedly the boundaries have become fuzzier over the years but there still remains a clear distinction between the Win32 API and the NT kernel API in many places. Paths are one place where this distinction is made clear. You have the familiar Win32 paths like `C:\path\to\file` that date back to the time of DOS. And then you have the low-level NT kernel paths that look like `\Device\HarddiskVolume6\path\to\file` (which aren't really meant to be user-visible). To bridge the gap, the NT namespace has a special `??` directory containing mappings (i.e. symlinks) from drives like `C:` to paths like `\Device\HarddiskVolume6`. In that way translating between Win32 and NT paths is made simpler as you can replace `C:` with `\??\C:` and it'll get resolved to the right path and vice versa (the actual translation from win32 to NT is more complicated but I've already spent too many words on this). So back to canonicalisation. Resolving the canonical NT path should always succeed. The problem comes when mapping that to a Win32 drive path. When the drive is managed by the system then when resolving paths it knows which drive to pick. However, if the drive mapping is added manually then it doesn't. So the way to workaround this is to manually look at the drive mappings and see which one is the root of the NT path we have.
View all comments
This attempts a partial workaround for issues such as: #59392, #79449, #59107, #54875, #52440, #52377, #48249, #74327, #55812
This may require a bit of explanation depending on how familiar you are with Windows paths, I'll try to keep it brief. The short version is that the above issues are cases where third party devices don't integrate with the system sufficiently so Windows isn't aware of the canonical drive for a particular path, causing our
canonicalizefunction to fail. This PR works around it by manually search for the drive letter that corresponds to the root of the path. This only works in cases where there is a drive letter assigned but that is the majority of cases. It won't work when the device is only mounted to a directory in another filesystem or isn't mounted at all.To explain the implementation of this PR you should be aware that Windows on Windows NT is more like WINE on Linux then many people realise. You have a kernel (NT) and then you have an implementation of the Win32 APIs on top (this is why
kernel32.dllis nothing to do with the real kernel, it's like an implementation of Win95's kernel API on top of another OS). Admittedly the boundaries have become fuzzier over the years but there still remains a clear distinction between the Win32 API and the NT kernel API in many places.Paths are one place where this distinction is made clear. You have the familiar Win32 paths like
C:\path\to\filethat date back to the time of DOS. And then you have the low-level NT kernel paths that look like\Device\HarddiskVolume6\path\to\file(which aren't really meant to be user-visible). To bridge the gap, the NT namespace has a special??directory containing mappings (i.e. symlinks) from drives likeC:to paths like\Device\HarddiskVolume6. In that way translating between Win32 and NT paths is made simpler as you can replaceC:with\??\C:and it'll get resolved to the right path and vice versa (the actual translation from win32 to NT is more complicated but I've already spent too many words on this).So back to canonicalisation. Resolving the canonical NT path should always succeed. The problem comes when mapping that to a Win32 drive path. When the drive is managed by the system then when resolving paths it knows which drive to pick. However, if the drive mapping is added manually then it doesn't.
So the way to workaround this is to manually look at the drive mappings and see which one is the root of the NT path we have.