On Mon, Aug 22, 2016 at 5:24 PM, Chris Angelico <ros...@gmail.com> wrote:
> On Tue, Aug 23, 2016 at 3:13 AM, eryk sun <eryk...@gmail.com> wrote:
>> On Mon, Aug 22, 2016 at 4:18 PM, Chris Angelico <ros...@gmail.com> wrote:
>>>
>>>> The CON device should work if the process is attached to a console
>>>> (i.e. a conhost.exe instance).
>>>
>>> No, I used Pike (to avoid any specifically-Python issues or
>>> protections) running in a console. Attempting to write to "Logs/con"
>>> wrote to the console, so I know the console device is active.
>>> Attempting to write to "Logs/con.txt" failed as described.
>>
>> What version of Windows is this? If it's Windows 7 I'll have to check
>> that later. If "Logs" is an existing directory, then both "Logs/con"
>> and "Logs/con.txt" should refer to the console. If "Logs" doesn't
>> exist, then both should fail. Virtual DOS devices only exist in
>> existing directories.
>
> Yes, it was Windows 7 (running in a VM under Debian Jessie, though I
> doubt that makes any difference). The Logs directory did exist (that's
> why I used that otherwise-odd choice of name).

I discovered why "Logs/con.txt" isn't working right in Windows 7,
while "Logs/nul.txt" does get redirected correctly to r"\\.\nul".
Prior to Windows 8 the console doesn't use an NT device, so the base
API has a function named BaseIsThisAConsoleName that looks for names
such as r"\\.CON", r"\\.CONIN$", "CON", or r"C:\Temp\con.txt" and
returns either "CONIN$" or "CONOUT$" if there's a match. A match for
just "CON" maps to one or the other of the latter depending on whether
read or write access is desired.

If there's a match, then a CreateFile call gets routed to
OpenConsoleW, which uses the process ConsoleHandle to send the request
to the attached instance of conhost.exe, which replies with a console
pseudohandle. Note that the handle value is flagged by setting the
lower 2 bits, i.e. 3, 7, 11, which allows routing to special console
functions, such as WriteFile => WriteConsoleA. In Windows 8+ console
handles are regular File handles (e.g. 24, 28, 32).

When debugging this I observed that there's a performance hack in
BaseIsThisAConsoleName. It only calls RtlIsDosDeviceName_U, which does
a full check for "CON" in the path, if the name starts with '\\' ,
'c', or 'C', or if it ends with 'n', 'N', ':', or '$'. This means
r"C:\whatever\con.txt" works (the base path doesn't even have to
exist), but not r"D:\whatever\con.txt". In your case the name starts
with 'L', so BaseIsThisAConsoleName returns false and the code falls
through to calling DosPathNameToRelativeNtPathName_U_WithStatus. This
returns r"\??\con", which NtCreateFile fails to open.

r"\??" is a virtual directory starting in Windows XP. For this
directory the object manager first checks the logon session's DOS
devices in r"\Sessions\0\DosDevices\[Logon Id]" and then the global
DOS devices in r"\GLOBAL??". This is an improvement over the less
flexible way that Windows 2000 managed DOS devices for terminal
services and logon sessions. A DOS 'device' is an object symbolic link
to the real NT device in the r"\Device" directory. In Windows 8+,
r"\GLOBAL??\CON" is a link to r"\Device\ConDrv\Console", which is why
opening "Logs/con.txt" worked 'correctly' for me in Windows 10.
-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to