This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Title: Inconsistent use of VOLUME_NAME_* with GetFinalPathNameByHandle
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.2, Python 3.3
Status: closed Resolution: out of date
Dependencies: Superseder: nt._getfinalpathname may use uninitialized memory
View: 33016
Assigned To: Nosy List: brian.curtin, erlendaasland, eryksun, jaraco, pitrou, tim.golden
Priority: low Keywords:

Created on 2011-08-18 14:32 by pitrou, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (6)
msg142325 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-08-18 14:32
In the implementation of nt._getfinalpathname() (in posixmodule.c) we have:

    /* We have a good handle to the target, use it to determine the
       target path name. */
    buf_size = Py_GetFinalPathNameByHandleW(hFile, 0, 0, VOLUME_NAME_NT);


    result_length = Py_GetFinalPathNameByHandleW(hFile, target_path,
                                                 buf_size, VOLUME_NAME_DOS);

There doesn't seem to be a good reason to use VOLUME_NAME_NT in the first call and VOLUME_NAME_DOS in the second. Especially given the second call might require more characters than the first call, and therefore return a truncated path.
msg142326 - (view) Author: Brian Curtin (brian.curtin) * (Python committer) Date: 2011-08-18 14:37
Adding Jason - I'll dig around for it, but I think I brought this up in the past and I seem to remember him having a justification for it. (apologies if I'm thinking of something else)
msg142330 - (view) Author: Jason R. Coombs (jaraco) * (Python committer) Date: 2011-08-18 14:56
I agree the two calls should probably be consistent, though I also suspect that VOLUME_NAME_NT is always longer than VOLUME_NAME_DOS.

My justification for using VOLUME_NAME_NT is that the final name might not be located on a DOS-accessible name. My suspicion was that VOLUME_NAME_NT was more general purpose (though somewhat less user-friendly), so preferable in the case that the name isn't exposed to the user. It's been a while since I've investigated it, but I think you can have symlinks to UNC paths as well as \\?\ paths, so my concern is VOLUME_NAME_DOS might not work with those paths. Some tests are probably called for.

In the case of nt._getfinalpathname(), it's not obvious to me how it might be used, so VOLUME_NAME_DOS may be more appropriate. Or perhaps _getfinalpathname should pass that parameter through.
msg142336 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-08-18 15:16
That's slightly off-topic, but is it enough to strip the leading '\\?\' (and replace 'UNC' with '\'), or are there other things to watch out for?
msg388725 - (view) Author: Erlend E. Aasland (erlendaasland) * (Python triager) Date: 2021-03-15 10:25
This seems to have been fixed in 2018 in bpo-33016 by GH-6010.
msg388754 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2021-03-15 17:39
bpo-33016 fixed the problem with the inconsistent dwFlags argument passed to GetFinalPathNameByHandleW().

We do need the ability to get the NT name in order to implement samefile() and sameopenfile() reliably in all cases -- i.e. when the volume serial number and/or file ID are 0 because the filesystem doesn't support them. A new issue needs to be opened to extend nt._getfinalpathname() to support passing either a file descriptor or a name and to add a parameter for the flags that defaults to 0.

> VOLUME_NAME_NT was more general purpose

The most broadly supported flags value is `VOLUME_NAME_NT | FILE_NAME_OPENED` -- e.g. "\Device\HarddiskVolume2\Windows\Temp\FILENA~1.TXT". 

For general use, the preferred form is `VOLUME_NAME_DOS | FILE_NAME_NORMALIZED` (dwFlags=0), which is the canonical DOS path with long component names -- e.g. "\\?\C:\Windows\Temp\filename_long.txt". This requires a volume device that supports the mountpoint manager; a registered or auto-assigned DOS drive-letter name; and a filesystem that supports normalizing names in the opened path.

GetFinalPathNameByHandleW() has special handling for the Multiple UNC Provider (MUP) device at the root of UNC paths (i.e. \\server\share -> \\?\UNC\server\share -> \Device\Mup\server\share). For the DOS 'volume' name, it returns the "\\?\UNC" form.


Substitute drives and mapped drives are never present in the final DOS path. They resolve to a filesystem directory, not to a volume device, and they're usually defined locally in a logon session. Such drives are not final, globally accessible paths.

A file/directory in a filesystem is required, such as a filesystem mounted on a volume device, the named-pipe filesystem implemented on \Device\NamedPipe, or the mailslot filesystem implemented on \Device\Mailslot. Non-filesystem devices are not supported, such as \\?\CON (i.e. \Device\ConDrv\Console) and \\?\NUL (i.e. \Device\Null).

> That's slightly off-topic, but is it enough to strip the leading
> '\\?\' (and replace 'UNC' with '\')

The \\?\ path prefix, which signifies an extended path (i.e. a verbatim local-device path), should not be removed without testing that it results in an equivalent, accessible path. An extended path may be required in order to access DOS paths that are longer than MAX_PATH. Also, the last path component of the final path may be a reserved DOS device name, or end with trailing dots and/or spaces, which is inaccessible without using an extended path.
Date User Action Args
2022-04-11 14:57:20adminsetgithub: 56986
2021-03-15 17:39:20eryksunsetstatus: open -> closed

superseder: nt._getfinalpathname may use uninitialized memory

nosy: + eryksun
messages: + msg388754
resolution: out of date
stage: resolved
2021-03-15 10:25:45erlendaaslandsetnosy: + erlendaasland
messages: + msg388725
2011-08-18 15:16:48pitrousetmessages: + msg142336
2011-08-18 14:56:24jaracosetmessages: + msg142330
2011-08-18 14:37:12brian.curtinsetnosy: + jaraco
messages: + msg142326
2011-08-18 14:32:26pitroucreate