Settings UI: Check that the starting directory is normalized #19622

Open
opened 2026-01-31 06:48:59 +00:00 by claunia · 13 comments
Owner

Originally created by @jtnord on GitHub (Apr 3, 2023).

Windows Terminal version

1.16.10262.0

Windows build number

10.0.22000.1696

Other Software

No response

Steps to reproduce

  • create a new profile
    • Command line - > cmd.exe
    • "Starting directory" -? enter an existing path using a lower case drive letter (e.g. c:\users)
  • start a new terminal session with the new profile

Expected Behavior

cmd.exe is started in C:\Users as drive letters are upper case and NTFS is by default case preserving.

in the case where NTFS was set to be case sensitive then I would expect cmd.exe to be started in C:\users as the drive letters are always case insensitive and canonically upper case.

Actual Behavior

the CWD is exactly as entered (all lower case)

This causes some subtle issues with some programs / developer environments where tests are asserting that some log was written containing a canonicalized path.

(also this is half way between an issue and a new feature :) )

Originally created by @jtnord on GitHub (Apr 3, 2023). ### Windows Terminal version 1.16.10262.0 ### Windows build number 10.0.22000.1696 ### Other Software _No response_ ### Steps to reproduce * create a new profile * Command line - > `cmd.exe` * "Starting directory" -? enter an existing path using a lower case drive letter (e.g. `c:\users`) * start a new terminal session with the new profile ### Expected Behavior cmd.exe is started in `C:\Users` as drive letters are upper case and NTFS is by default case preserving. in the case where NTFS was set to be case sensitive then I would expect cmd.exe to be started in `C:\users` as the drive letters are always case insensitive and canonically upper case. ### Actual Behavior the CWD is exactly as entered (all lower case) This causes some subtle issues with some programs / developer environments where tests are asserting that some log was written containing a canonicalized path. (also this is half way between an issue and a new feature :) )
claunia added the Help WantedIssue-BugProduct-TerminalArea-TerminalConnection labels 2026-01-31 06:48:59 +00:00
Author
Owner

@carlos-zamora commented on GitHub (Apr 26, 2023):

Yup! Good find! Thanks! Right now, CreateProcess() doesn't normalize the path, but we could before handing it over.

@carlos-zamora commented on GitHub (Apr 26, 2023): Yup! Good find! Thanks! Right now, `CreateProcess()` doesn't normalize the path, but we could before handing it over.
Author
Owner

@JacobOgle commented on GitHub (Jun 10, 2023):

@carlos-zamora @jtnord mind if I take a crack at this for a first issue?

@JacobOgle commented on GitHub (Jun 10, 2023): @carlos-zamora @jtnord mind if I take a crack at this for a first issue?
Author
Owner

@carlos-zamora commented on GitHub (Jun 10, 2023):

@carlos-zamora @jtnord mind if I take a crack at this for a first issue?

Go for it! Feel free to post any questions you have here or in your PR. The team is happy to help! 😊

@carlos-zamora commented on GitHub (Jun 10, 2023): > @carlos-zamora @jtnord mind if I take a crack at this for a first issue? Go for it! Feel free to post any questions you have here or in your PR. The team is happy to help! 😊
Author
Owner

@gautam376 commented on GitHub (Aug 22, 2023):

want to work on this issue , if you allow .

@gautam376 commented on GitHub (Aug 22, 2023): want to work on this issue , if you allow .
Author
Owner

@zadjii-msft commented on GitHub (Aug 22, 2023):

Go for it! Feel free to comment if you have any questions ☺️

@zadjii-msft commented on GitHub (Aug 22, 2023): Go for it! Feel free to comment if you have any questions ☺️
Author
Owner

@CyTechNomad commented on GitHub (Sep 1, 2023):

would it be safe to assume that if the second character in a path was a : that the first value is a drive letter that should be upper cased?

@CyTechNomad commented on GitHub (Sep 1, 2023): would it be safe to assume that if the second character in a path was a `:` that the first value is a drive letter that should be upper cased?
Author
Owner

@lhecker commented on GitHub (Sep 4, 2023):

Yes, although that doesn't solve the problem entirely, because of UNC paths (or fix the remaining parts of the path).

After thinking about it for a bit, in my personal opinion, I would not fix this. If we fixed it as proposed, someone might similarly complain that their tests failed because the lowercase path in the settings don't match the lowercase path in the test anymore. And they would be just as correct as jtnord, which then opens up the debate who is correct.

Furthermore, and to make matters worse, when you canonicalize a path on Windows, it resolves all symlinks and junction points (GetFinalPathNameByHandle, same behavior as on other OS). For instance, an application launched in C:\Users\All Users or C:\Users\All Users\Application Data would then launch in C:\ProgramData. This would break any application that writes with relative paths, because launching in C:\Users\All Users and writing to .\Application Data\MyApp\foo.txt would then actually write at the equivalent of .\Application Data\Application Data\MyApp\foo.txt. GetFinalPathNameByHandle is also what the STL uses for canonicalization. I'm not aware of another API that fixes casing but avoids this behavior.

@lhecker commented on GitHub (Sep 4, 2023): Yes, although that doesn't solve the problem entirely, because of UNC paths (or fix the remaining parts of the path). After thinking about it for a bit, in my personal opinion, I would not fix this. If we fixed it as proposed, someone might similarly complain that their tests failed because the lowercase path in the settings don't match the lowercase path in the test anymore. And they would be just as correct as jtnord, which then opens up the debate who is correct. Furthermore, and to make matters worse, when you canonicalize a path on Windows, it resolves all symlinks and junction points (`GetFinalPathNameByHandle`, same behavior as on other OS). For instance, an application launched in `C:\Users\All Users` or `C:\Users\All Users\Application Data` would then launch in `C:\ProgramData`. This would break any application that writes with relative paths, because launching in `C:\Users\All Users` and writing to `.\Application Data\MyApp\foo.txt` would then actually write at the equivalent of `.\Application Data\Application Data\MyApp\foo.txt`. `GetFinalPathNameByHandle` is also what the STL uses for canonicalization. I'm not aware of another API that fixes casing but avoids this behavior.
Author
Owner

@jtnord commented on GitHub (Sep 4, 2023):

Furthermore, and to make matters worse, when you canonicalize a path on Windows, it resolves all symlinks and junction points

that's a pain

I'm not aware of another API that fixes casing but avoids this behavior.

it is at least possible with code by iterating every component after ensuring it is absolute (what a relative path would mean in this context is just 😱 )

(yes below is java - but at the end of the day that calls C++ for platform integration).

jshell> File test = new File("c:\\users\\All users\\ApplicatION Data")
test ==> c:\users\All users\ApplicatION Data

jshell> test.getCanonicalPath()
$5 ==> "C:\\Users\\All Users\\Application Data"

5327f67b9e/src/java.base/windows/native/libjava/canonicalize_md.c (L230-L387)

and
5327f67b9e/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java (L156-L263)

After thinking about it for a bit, in my personal opinion, I would not fix this. If we fixed it as proposed, someone might similarly complain that their tests failed because the lowercase path in the settings don't match the lowercase path in the test anymore.

Possibly does not have to be fixed as proposed - but perhaps the UX in the settings you could be improved so that the next person does not encounter this with head scratching (e.g. add a warning to the UI that the path is not canonical).

And they would be just as correct as jtnord, which then opens up the debate who is correct.

The filesystem is the source of truth 😉

@jtnord commented on GitHub (Sep 4, 2023): > Furthermore, and to make matters worse, when you canonicalize a path on Windows, it resolves all symlinks and junction points that's a pain > I'm not aware of another API that fixes casing but avoids this behavior. it is at least possible with code by iterating every component after ensuring it is absolute (what a relative path would mean in this context is just 😱 ) (yes below is java - but at the end of the day that calls C++ for platform integration). ``` jshell> File test = new File("c:\\users\\All users\\ApplicatION Data") test ==> c:\users\All users\ApplicatION Data jshell> test.getCanonicalPath() $5 ==> "C:\\Users\\All Users\\Application Data" ``` https://github.com/openjdk/jdk11u-dev/blob/5327f67b9e40ad756c6616779f3a2a44cdd257f7/src/java.base/windows/native/libjava/canonicalize_md.c#L230-L387 and https://github.com/openjdk/jdk11u-dev/blob/5327f67b9e40ad756c6616779f3a2a44cdd257f7/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java#L156-L263 > After thinking about it for a bit, in my personal opinion, I would not fix this. If we fixed it as proposed, someone might similarly complain that their tests failed because the lowercase path in the settings don't match the lowercase path in the test anymore. Possibly does not have to be fixed as proposed - but perhaps the UX in the settings you could be improved so that the next person does not encounter this with head scratching (e.g. add a warning to the UI that the path is not canonical). > And they would be just as correct as jtnord, which then opens up the debate who is correct. The filesystem is the source of truth 😉
Author
Owner

@lhecker commented on GitHub (Sep 4, 2023):

it is at least possible with code by iterating every component after ensuring it is absolute (what a relative path would mean in this context is just 😱 )

Yes we could do that. If we want to do it that way, we should do this here:
5fb2518117/src/cascadia/TerminalApp/AppLogic.cpp (L272-L288)

That way we don't need to run the logic on every app launch, because the result will be cached (by overwriting the settings.json file for instance). It's expensive to do so when the filesystem is not local and we should avoid it when possible.

Also, I found that PowerShell has implemented similar code here: ec8c163369/src/System.Management.Automation/namespaces/FileSystemProvider.cs (L123-L198)

Possibly does not have to be fixed as proposed - but perhaps the UX in the settings you could be improved so that the next person does not encounter this with head scratching (e.g. add a warning to the UI that the path is not canonical).

That's a great idea! We could do both if we wanted to. If we already have a function to fix the casing of a path, we can use that same function to quickly detect if the path given by the user differs and even add a button to fix up the path with a single click!

The filesystem is the source of truth 😉

If the filesystem is the source of truth and the failing assertions you mentioned don't actually use the filesystem as a source of truth, how is it the application's fault that didn't fail to handle case insensitive file paths?
Basically, if case-insensitive filepaths fail an application that expects case-sensitive ones, then it will cut both ways: If we don't fix this, then it fails applications that expect \ThosePaths\ and if we do, we fail applications that expect \thosepaths\. Neither application is correct: The filesystem is the source of truth, not the given string.

I do 100% get where you're coming from though. The code that is failing might not be in your control anyways after all... I'm not against doing this in general, but I currently don't think it's a good idea to fix up paths any more than necessary. To me this would be similar to the quirks mode in browsers and I'm afraid it creates a situation where more software is written based on the quirk behavior, since we can't bring the same kind of awareness about these things. Additionally, personally speaking, if I tell my terminal to do something weird, I'd still expect it do the weird thing. If it didn't, that'd be kind of a surprise too.

To summarize, I don't mind making this change, but I'm cautious about it. I'm basically afraid of the fallout not being any better than the current problem. We could implement Java's or PowerShell's path fixing code first, then add it as a warning to the settings UI that the path is not canonical and maybe see where that leads to? That definitely can't have any negative consequences. If that still causes issues for some, maybe we should only then add it to AppLogic::_ProcessLazySettingsChanges?
Or maybe we just fix it up all the time. I'm genuinely not sure. 😅

@lhecker commented on GitHub (Sep 4, 2023): > it is at least possible with code by iterating every component after ensuring it is absolute (what a relative path would mean in this context is just 😱 ) Yes we could do that. If we want to do it that way, we should do this here: https://github.com/microsoft/terminal/blob/5fb2518117ddf14e05f67eed47e6e4d940a3c025/src/cascadia/TerminalApp/AppLogic.cpp#L272-L288 That way we don't need to run the logic on every app launch, because the result will be cached (by overwriting the settings.json file for instance). It's expensive to do so when the filesystem is not local and we should avoid it when possible. Also, I found that PowerShell has implemented similar code here: https://github.com/PowerShell/PowerShell/blob/ec8c163369ae44d45fbb7668ec216f94dc6ae8c9/src/System.Management.Automation/namespaces/FileSystemProvider.cs#L123-L198 > Possibly does not have to be fixed as proposed - but perhaps the UX in the settings you could be improved so that the next person does not encounter this with head scratching (e.g. add a warning to the UI that the path is not canonical). That's a great idea! We could do both if we wanted to. If we already have a function to fix the casing of a path, we can use that same function to quickly detect if the path given by the user differs and even add a button to fix up the path with a single click! > The filesystem is the source of truth 😉 If the filesystem is the source of truth and the failing assertions you mentioned don't actually use the filesystem as a source of truth, how is it the application's fault that didn't fail to handle case insensitive file paths? Basically, if case-insensitive filepaths fail an application that expects case-sensitive ones, then it will cut both ways: If we don't fix this, then it fails applications that expect `\ThosePaths\` and if we do, we fail applications that expect `\thosepaths\`. Neither application is correct: The filesystem is the source of truth, not the given string. I do 100% get where you're coming from though. The code that is failing might not be in your control anyways after all... I'm not against doing this in general, but I currently don't think it's a good idea to fix up paths any more than necessary. To me this would be similar to the quirks mode in browsers and I'm afraid it creates a situation where more software is written based on the quirk behavior, since we can't bring the same kind of awareness about these things. Additionally, personally speaking, if I tell my terminal to do something weird, I'd still expect it do the weird thing. If it didn't, that'd be kind of a surprise too. To summarize, I don't mind making this change, but I'm cautious about it. I'm basically afraid of the fallout not being any better than the current problem. We could implement Java's or PowerShell's path fixing code first, then add it as a warning to the settings UI that the path is not canonical and maybe see where that leads to? That definitely can't have any negative consequences. If that still causes issues for some, maybe we should only then add it to `AppLogic::_ProcessLazySettingsChanges`? Or maybe we just fix it up all the time. I'm genuinely not sure. 😅
Author
Owner

@jtnord commented on GitHub (Sep 4, 2023):

If the filesystem is the source of truth and the failing assertions you mentioned don't actually use the filesystem as a source of truth, how is it the application's fault that didn't fail to handle case insensitive file paths?

the test assumed that the cwd would be in the correct case not the application so the test is fully to blame here not the application!
as cmd.exe was started in c:\workarea any subsequent cd'ing to relative paths retained the bad drive case. (the application spat out the filesystem case - thus test failed as it was expecting a lower case drive letter and some others at the start of the path)

https://issues.apache.org/jira/browse/MINVOKER-334 if you are at all curious.

Whilst assuming anything is generally a bad idea that cwd is normalized its not a completely outlandish assumption to make! (especially if you in cmd.exe in C:\ and cd users - you will get C:\Users in your prompt!)

We could implement Java's or PowerShell's path fixing code first, then add it as a warning to the settings UI that the path is not canonical and maybe see where that leads to

Yup - there is currently no validation the the path exists - so I guess that would be the first step. Networked drives may make this problematic though :/

Or maybe we just fix it up all the time. I'm genuinely not sure. 😅

in the same vane if you close this as PEBKAC I wouldn't argue :)

@jtnord commented on GitHub (Sep 4, 2023): > If the filesystem is the source of truth and the failing assertions you mentioned don't actually use the filesystem as a source of truth, how is it the application's fault that didn't fail to handle case insensitive file paths? the **test** assumed that the `cwd` would be in the correct case not the application so the test is fully to blame here not the application! as `cmd.exe` was started in `c:\workarea` any subsequent cd'ing to relative paths retained the bad drive case. (the application spat out the filesystem case - thus test failed as it was expecting a lower case drive letter and some others at the start of the path) https://issues.apache.org/jira/browse/MINVOKER-334 if you are at all curious. Whilst assuming anything is generally a bad idea that cwd is normalized its not a completely outlandish assumption to make! (especially if you in `cmd.exe` in `C:\` and `cd users` - you will get `C:\Users` in your prompt!) > We could implement Java's or PowerShell's path fixing code first, then add it as a warning to the settings UI that the path is not canonical and maybe see where that leads to Yup - there is currently no validation the the path exists - so I guess that would be the first step. Networked drives may make this problematic though :/ > Or maybe we just fix it up all the time. I'm genuinely not sure. 😅 in the same vane if you close this as PEBKAC I wouldn't argue :)
Author
Owner

@lhecker commented on GitHub (Sep 18, 2023):

Adding a validation to the settings UI that the path exists and is normalized sounds like a great idea. We are not entirely sure when we would be able to work on this but until then we would be happy to accept any contributions that work towards this end. 🙂

@lhecker commented on GitHub (Sep 18, 2023): Adding a validation to the settings UI that the path exists and is normalized sounds like a great idea. We are not entirely sure when we would be able to work on this but until then we would be happy to accept any contributions that work towards this end. 🙂
Author
Owner

@kheif commented on GitHub (Jun 18, 2025):

Hi! I'd like to work on this issue as my first contribution to Windows Terminal. Could you assign me to solve the problem?

Thanks!

@kheif commented on GitHub (Jun 18, 2025): Hi! I'd like to work on this issue as my first contribution to Windows Terminal. Could you assign me to solve the problem? Thanks!
Author
Owner

@DHowett commented on GitHub (Jun 18, 2025):

@kheif You're welcome to work on it, even without an assignment!

@DHowett commented on GitHub (Jun 18, 2025): @kheif You're welcome to work on it, even without an assignment!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#19622