Work around case-insensitivity issues with cwd on Windows#54
Closed
dscho wants to merge 2 commits intogitgitgadget:mastergitgitgadget/git:masterfrom
Closed
Work around case-insensitivity issues with cwd on Windows#54dscho wants to merge 2 commits intogitgitgadget:mastergitgitgadget/git:masterfrom
dscho wants to merge 2 commits intogitgitgadget:mastergitgitgadget/git:masterfrom
Conversation
When switching the current working directory, say, in PowerShell, it is quite possible to use a different capitalization than the one that is recorded on disk. While doing the same in `cmd.exe` adjusts the capitalization magically, that does not happen in PowerShell so that `getcwd()` returns the current directory in a different way than is recorded on disk. Typically this creates no problems except when you call git log . in a subdirectory called, say, "GIT/" but you switched to "Git/" and your `getcwd()` reports the latter, then Git won't understand that you wanted to see the history as per the `GIT/` subdirectory but it thinks you wanted to see the history of some directory that may have existed in the past (but actually never did). So let's be extra careful to adjust the capitalization of the current directory before working with it. Reported by a few PowerShell power users ;-) Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
35 tasks
Member
Author
|
/submit |
|
An error occurred while submitting: Error: git fetch https://github.com/gitgitgadget/git -- +refs/notes/gitgitgadget:refs/notes/gitgitgadget +refs/pull/54/head:refs/pull/54/head +refs/heads/maint:refs/remotes/upstream/maint +refs/heads/master:refs/remotes/upstream/master +refs/heads/next:refs/remotes/upstream/next +refs/heads/pu:refs/remotes/upstream/pu failed: 1,
|
Member
Author
|
/submit |
|
Submitted as pull.54.git.gitgitgadget@gmail.com |
`GetLongPathName()` function may fail when it is unable to query
the parent directory of a path component to determine the long name
for that component. It happens, because it uses `FindFirstFile()`
function for each next short part of path. The `FindFirstFile()`
requires `List Directory` and `Synchronize` desired access for a calling
process.
In case of lacking such permission for some part of path,
the `GetLongPathName()` returns 0 as result and `GetLastError()`
returns ERROR_ACCESS_DENIED.
`GetFinalPathNameByHandle()` function can help in such cases, because
it requires `Read Attributes` and `Synchronize` desired access to the
target path only.
The `GetFinalPathNameByHandle()` function was introduced on
`Windows Server 2008/Windows Vista`. So we need to load it dynamically.
`CreateFile()` parameters:
`lpFileName` = path to the current directory
`dwDesiredAccess` = 0 (it means `Read Attributes` and `Synchronize`)
`dwShareMode` = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
(it prevents `Sharing Violation`)
`lpSecurityAttributes` = NULL (default security attributes)
`dwCreationDisposition` = OPEN_EXISTING
(required to obtain a directory handle)
`dwFlagsAndAttributes` = FILE_FLAG_BACKUP_SEMANTICS
(required to obtain a directory handle)
`hTemplateFile` = NULL (when opening an existing file or directory,
`CreateFile` ignores this parameter)
The string that is returned by `GetFinalPathNameByHandle()` function
uses the \\?\ syntax. To skip the prefix and convert backslashes
to slashes, the `normalize_ntpath()` mingw function will be used.
Note: `GetFinalPathNameByHandle()` function returns a final path.
It is the path that is returned when a path is fully resolved.
For example, for a symbolic link named "C:\tmp\mydir" that points to
"D:\yourdir", the final path would be "D:\yourdir".
Signed-off-by: Anton Serbulov <aserbulov@plesk.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Member
Author
|
/submit |
|
Submitted as pull.54.v2.git.gitgitgadget@gmail.com |
Member
Author
|
Merged via cc67487 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On Windows, file names are recorded case-sensitively, but looked up case-insensitively. Therefore, it is possible to switch to a directory by using incorrect case, e.g.
cd documentationwill still get you into theDocumentationsubdirectory.In Powershell, doing so will however report the current directory with the specified spelling rather than the one recorded on disk, and Git will get confused.
To remedy that, we fixed this in Git for Windows more than three years ago, and needed only a small fix a couple of months later to accommodate for the diverse scenarios encountered by the many Git for Windows users.
Not only to keep the story closer to what happened historically, but also to make it easier to follow, I refrained from squashing these two patches.
Side note: the second patch is technically not battle-tested for that long: it uses an API function that requires Windows Vista or later, and we only recently started to clean up Git for Windows' code to drop fallbacks for Windows XP. Read: this code used to load the
GetFinalPathNameByHandle()function dynamically, and that is the only difference to the code that has been "battle-tested" for close to three years.Changes since v1:
Cc: Stephen Smith ischis2@cox.net