Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-100809: Fix handling of drive-relative paths in pathlib.Path.absolute()#100812

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
zooba merged 11 commits intopython:mainfrombarneygale:gh-100809-path-absolute-nt
Feb 17, 2023

Conversation

@barneygale
Copy link
Contributor

@barneygalebarneygale commentedJan 6, 2023
edited by bedevere-bot
Loading

If it's available, usent._getfullpathname() to retrieve an absolute path. This allows paths such as 'X:' to be made absolute even whenos.getcwd() returns a path on another drive. It follows the behaviour ofos.path.abspath(), except that no path normalisation is performed.

….absolute()If it's available, use `nt._getfullpathname()` to retrieve an absolutepath. This allows paths such as 'X:' to be made absolute even when`os.getcwd()` returns a path on another drive. It follows the behaviour of`os.path.abspath()`, except that no path normalisation is performed.
@barneygalebarneygale marked this pull request as ready for reviewJanuary 6, 2023 23:53
@eryksun
Copy link
Contributor

Are you planning to also fix this in 3.10 and 3.11? That requires fixing_from_parts().

>>> pathlib.WindowsPath._from_parts(['C:\\spam', 'C:eggs'])WindowsPath('C:eggs')

Maybe the fix for_from_parts() should be a separate PR.

@barneygale
Copy link
ContributorAuthor

barneygale commentedJan 7, 2023
edited
Loading

Are you planning to also fix this in 3.10 and 3.11? That requires fixing_from_parts().

>>> pathlib.WindowsPath._from_parts(['C:\\spam', 'C:eggs'])WindowsPath('C:eggs')

Maybe the fix for_from_parts() should be a separate PR.

I fixed this in#95450 and we decided not to backport because it was seemed like quite an obscure bug. I'd like to do the same here as the bug seems equally obscure (there are no user-logged bugs on the tracker that I could find), but I don't mind backporting both if we collectively feel that it's important.

@barneygalebarneygale marked this pull request as draftJanuary 7, 2023 15:53
@barneygale
Copy link
ContributorAuthor

With fresher eyes I realise my tests don't exercise per-drive working directories.

One way to address this would be to add asubst() context manager toLib/test/support/os_helper.py and use it fromtest_absolute(). The context manager would callsubst to allocate a new drive letter on__enter__(), andsubst /d on__exit__(). But perhaps there's a better way,@eryksun?

@eryksun
Copy link
Contributor

I fixed this in#95450 and we decided not to backport because it was seemed like quite an obscure bug.

Maybe skip fixing this in 3.10, butabsolute() is a documented method in 3.11. It should be able to resolve relative drive paths such as "Z:spam", which date back to MS-DOS in the 1980s. Maybe there's a more surgical fix for handling relative drive paths in_from_parts() that doesn't require usingntpath.join().

@barneygale
Copy link
ContributorAuthor

barneygale commentedJan 7, 2023
edited
Loading

Maybe, but the bug is observable just fromPath('C:\\foo') / 'C:', and constructors have been documented the entire time. I don't think I can make the fix for#94909 much more surgical than#95450 because pathlib's original algorithm for joining segments (right-to-left scanning) doesn't lend itself well to the problem. Any fix I attemped resembledos.path.join().

I don't think the presence of this bug in 3.11 makesabsolute() so defective as to not warrant documentation.

Does that seem reasonable?

@eryksun
Copy link
Contributor

With fresher eyes I realise my tests don't exercise per-drive working directories.

BASE isos.path.realpath(TESTFN), which is in the initial current working directory. The_getfullpathname() branch is tested as long as this resolves to a real path on a drive-letter drive.

One way to address this would be to add asubst() context manager toLib/test/support/os_helper.py and use it fromtest_absolute(). The context manager would callsubst

The "subst.exe" app callsDefineDosDeviceW() without the flagDDD_NO_BROADCAST_SYSTEM. Without this flag, aWM_DEVICECHANGE message for eitherDBT_DEVICEARRIVAL orDBT_DEVICEREMOVECOMPLETE is broadcasted to the top-level windows of applications in the current session viaBroadCastSystemMessageW().

I wouldn't want to announce the new drive in the current session (i.e.DBT_DEVICEARRIVAL), particularly not to the desktop shell, Explorer1. Instead,QueryDosDeviceW() andDefineDosDeviceW() could be added to_winapi, or called usingctypes. For example:

try:importctypesexceptImportError:defsubst_drive(path):raiseNotImplementedError('ctypes is not available')else:importcontextlibimportstringERROR_FILE_NOT_FOUND=2DDD_REMOVE_DEFINITION=2DDD_EXACT_MATCH_ON_REMOVE=4DDD_NO_BROADCAST_SYSTEM=8kernel32=ctypes.WinDLL('kernel32',use_last_error=True)@contextlib.contextmanagerdefsubst_drive(path):"""Temporarily yield a substitute drive for a given path."""forcinreversed(string.ascii_uppercase):drive=f'{c}:'if (notkernel32.QueryDosDeviceW(drive,None,0)andctypes.get_last_error()==ERROR_FILE_NOT_FOUND):breakelse:raiseFileExistsError('no available logical drive')ifnotkernel32.DefineDosDeviceW(DDD_NO_BROADCAST_SYSTEM,drive,path):raisectypes.WinError(ctypes.get_last_error())try:yielddrivefinally:ifnotkernel32.DefineDosDeviceW(DDD_REMOVE_DEFINITION|DDD_EXACT_MATCH_ON_REMOVE,drive,path):raisectypes.WinError(ctypes.get_last_error())

Footnotes

  1. That said, we can't prevent the new drive from being visible to processes in the current logon session that callGetLogicalDrives() orGetLogicalDriveStringsW(). This is the case if an Explorer window is manually refreshed by pressing F5.

barneygale reacted with heart emoji

@barneygale
Copy link
ContributorAuthor

I wouldn't want to announce the new drive in the current session (i.e. DBT_DEVICEARRIVAL), particularly not to the desktop shell, Explorer

Could you expand on why this is a bad idea please? Thank you!

@eryksun
Copy link
Contributor

Could you expand on why this is a bad idea please?

This is a drive that we're creating for our own temporary use. I don't think it's appropriate to have Explorer windows automatically updated to include it. I also wouldn't want unknown complications from what any other application might do when sent aWM_DEVICECHANGE message forDBT_DEVICEARRIVAL.

Also, it's more efficient to directly callQueryDosDeviceW() in a loop when searching for an available drive than it is to repeatedly spawn a "subst.exe" process.

@barneygale
Copy link
ContributorAuthor

barneygale commentedJan 7, 2023
edited
Loading

Gotcha, thanks.

Is there a time-of-check to time-of-use issue with your code above? I wonder if we could skip theQueryDosDeviceW checks and instead callDefineDosDeviceW with different drive letters until it succeeds?

@eryksun
Copy link
Contributor

Is there a time-of-check to time-of-use issue with your code above? I wonder if we could skip theQueryDosDeviceW checks and instead callDefineDosDeviceW with different drive letters until it succeeds?

I don't know how to avoid the small race condition without resorting to the NT API. "subst.exe" doesn't handle this any better.

DefineDosDeviceW() tries to be clever. The device names are defined as symbolic link objects in NT, e.g. "\??\Z:" -> "\??\C:\Windows". The target path of the symbolic link is a counted string with a current length and a maximum length, like most strings in NT.DefineDosDeviceW() uses this to implement a scheme that allows defining a device multiple times. The most recent definition is the active one, and each definition can be individually removed from the target buffer. For example:

>>> flags=DDD_NO_BROADCAST_SYSTEM>>> kernel32.DefineDosDeviceW(flags,'Z:','C:\\Windows')1>>> kernel32.DefineDosDeviceW(flags,'Z:','C:\\ProgramData')1>>> kernel32.DefineDosDeviceW(flags,'Z:','C:\\Temp')1>>> os.path.samefile('Z:','C:\\Temp')True>>> flags=DDD_REMOVE_DEFINITION|DDD_EXACT_MATCH_ON_REMOVE>>> kernel32.DefineDosDeviceW(flags,'Z:','C:\\Temp')1>>> os.path.samefile('Z:','C:\\ProgramData')True>>> kernel32.DefineDosDeviceW(flags,'Z:','C:\\ProgramData')1>>> os.path.samefile('Z:','C:\\Windows')True

I think this is bad behavior. The new drive definition affects all processes in the current logon session (i.e. the local device context). I wouldn't want to mask an existing drive definition. At least redefining a system drive requires administrator access.

barneygale reacted with heart emoji

Co-authored-by: Eryk Sun <eryksun@gmail.com>
…697UT.rstCo-authored-by: Steve Dower <steve.dower@microsoft.com>
Copy link
Member

@zoobazooba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The macOS failure is known and unrelated, so this is good to merge if the rest of CI agrees.

@zoobazooba merged commit072011b intopython:mainFeb 17, 2023
@zoobazooba added needs backport to 3.10only security fixes needs backport to 3.11only security fixes labelsFeb 17, 2023
@miss-islington
Copy link
Contributor

Thanks@barneygale for the PR, and@zooba for merging it 🌮🎉.. I'm working now to backport this PR to: 3.10.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Thanks@barneygale for the PR, and@zooba for merging it 🌮🎉.. I'm working now to backport this PR to: 3.11.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Sorry,@barneygale and@zooba, I could not cleanly backport this to3.10 due to a conflict.
Please backport usingcherry_picker on command line.
cherry_picker 072011b3c38f871cdc3ab62630ea2234d09456d1 3.10

@miss-islington
Copy link
Contributor

Sorry@barneygale and@zooba, I had trouble checking out the3.11 backport branch.
Please retry by removing and re-adding the "needs backport to 3.11" label.
Alternatively, you can backport usingcherry_picker on the command line.
cherry_picker 072011b3c38f871cdc3ab62630ea2234d09456d1 3.11

@zoobazooba added needs backport to 3.11only security fixes and removed needs backport to 3.11only security fixes labelsFeb 17, 2023
@miss-islington
Copy link
Contributor

Thanks@barneygale for the PR, and@zooba for merging it 🌮🎉.. I'm working now to backport this PR to: 3.11.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Sorry,@barneygale and@zooba, I could not cleanly backport this to3.11 due to a conflict.
Please backport usingcherry_picker on command line.
cherry_picker 072011b3c38f871cdc3ab62630ea2234d09456d1 3.11

@zoobazooba removed their assignmentFeb 17, 2023
@zooba
Copy link
Member

@barneygale Can I leave the backports with you?

barneygale reacted with thumbs up emoji

@bedevere-bot
Copy link

GH-101993 is a backport of this pull request to the3.11 branch.

@bedevere-botbedevere-bot removed the needs backport to 3.11only security fixes labelFeb 17, 2023
barneygale added a commit to barneygale/cpython that referenced this pull requestFeb 17, 2023
…ib.Path.absolute() (pythonGH-100812)Resolving the drive independently uses the OS API, which ensures it starts from the current directory on that drive..(cherry picked from commit072011b)Co-authored-by: Barney Gale <barney.gale@gmail.com>
@barneygale
Copy link
ContributorAuthor

@zooba looks like this won't backport unless we also backport#95450. OK to skip?

@zooba
Copy link
Member

Yeah, skip it.

barneygale reacted with thumbs up emoji

@zoobazooba removed the needs backport to 3.10only security fixes labelFeb 20, 2023
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@eryksuneryksuneryksun left review comments

@zoobazoobazooba approved these changes

Assignees

No one assigned

Labels

3.12only security fixestopic-pathlibtype-bugAn unexpected behavior, bug, or error

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

6 participants

@barneygale@eryksun@miss-islington@zooba@bedevere-bot@hauntsaninja

[8]ページ先頭

©2009-2025 Movatter.jp