testsuite tests for Cygwin<->Win32 process interaction

Corinna Vinschen corinna-cygwin@cygwin.com
Thu Jun 26 08:21:26 GMT 2025


On Jun 25 16:15, Jeremy Drake via Cygwin-developers wrote:
> On Wed, 25 Jun 2025, Jon Turney wrote:
> 
> > On 25/06/2025 20:52, Jeremy Drake via Cygwin-developers wrote:
> > > I would like to add tests of invoking non-Cygwin processes using
> > > posix_spawn and making sure their stdin/out/err and cwd are as expected.
> > > I see that there is a mingw directory for building with the cross-mingw
> > > compiler, and I could make a test child process built through that which
> > > uses GetFileInformationByHandleEx and GetCurrentDirectoryW.
> 
> This turned out to be more complicated than I expected,
> GetFileInformationByHandleEx(FileNameInfo) sucks badly, and seems to only
> actually work for regular files.

This is unexpected.  GetFileInformationByHandleEx is basically just a
wrapper for NtQueryInformationFile and that goes especially for the
FileNameInfo class which even neglects to prepend a drive letter or
UNC path to make the result useful in a DOS Path environment.

But naturally it should work for files and dirs the same.

I attached a Q&D(*) STC.  The output shows that it works the same for
files and dirs:

$ tests/x86_64/ntfilename xxx
NtOpenFile(\??\C:\cygwin64\home\corinna\xxx)
NtQueryObject: "\Device\HarddiskVolume3\cygwin64\home\corinna\xxx"
FileNameInformation: "\cygwin64\home\corinna\xxx"
FileNormalizedNameInformation: "\cygwin64\home\corinna\xxx"
FileNameInfo: "\cygwin64\home\corinna\xxx"

$ tests/x86_64/ntfilename .
NtOpenFile(\??\C:\cygwin64\home\corinna)
NtQueryObject: "\Device\HarddiskVolume3\cygwin64\home\corinna"
FileNameInformation: "\cygwin64\home\corinna"
FileNormalizedNameInformation: "\cygwin64\home\corinna"
FileNameInfo: "\cygwin64\home\corinna"

So, my question at this point would be, what is the *real* problem here?

> Which is probably why Cygwin uses
> NtQueryObject(ObjectNameInformation) instead, which I switched to

Uh, we use NtQueryObject in cases where we want valid return values
for real NT objects or device paths like \Device\Null.

> This
> has the downside of giving NT native paths (\Device\HarddiskVolumeN\path).

Downside? *grin*


Corinna

(*) Don't use non-ASCII chars in the filename when testing...
-------------- next part --------------
#define _WIN32_WINNT 0x0a00
#include <stdio.h>
#include <windows.h>
#include <winternl.h>
#include <locale.h>
#include <wchar.h>
#include <wctype.h>

int
main (int argc, char **argv)
{
  UNICODE_STRING wpath;
  UNICODE_STRING upath;
  HANDLE h;
  OBJECT_ATTRIBUTES attr;
  IO_STATUS_BLOCK io;
  NTSTATUS status;
  ULONG size;
  POBJECT_NAME_INFORMATION poni = (POBJECT_NAME_INFORMATION) alloca (32000);
  PFILE_NAME_INFORMATION pfni = (PFILE_NAME_INFORMATION) alloca (32000);
  PFILE_NAME_INFO pfni2 = (PFILE_NAME_INFO) pfni;

  setlocale (LC_ALL, "");

  if (argc < 2)
    {
      fprintf (stderr, "usage: %s DOS-PATH\n", argv[0]);
      return 1;
    }
  if (!RtlCreateUnicodeStringFromAsciiz (&wpath, argv[1]))
    {
      fprintf (stderr, "RtlCreateUnicodeStringFromAsciiz failed\n");
      return 1;
    }

  if (!RtlDosPathNameToNtPathName_U (wpath.Buffer, &upath, NULL, NULL))
    {
      fprintf (stderr, "RtlDosPathNameToNtPathName_U failed\n");
      RtlFreeUnicodeString (&wpath);
      return 1;
    }
  InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
  fprintf (stderr, "NtOpenFile(%ls)\n", upath.Buffer);
  status = NtOpenFile (&h, GENERIC_READ | SYNCHRONIZE,
		       &attr, &io, FILE_SHARE_VALID_FLAGS,
		       FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
  if (!NT_SUCCESS (status))
    {
      fprintf (stderr, "NtOpenFile(%ls): 0x%08X\n", upath.Buffer, status);
      return 1;
    }

  status = NtQueryObject (h, ObjectNameInformation, poni, 32000, &size);
  if (!NT_SUCCESS (status))
    fprintf (stderr, "NtQueryObject: 0x%08X\n", status);
  else
    printf ("NtQueryObject: \"%*ls\"\n",
	    poni->Name.Length / sizeof (WCHAR),
	    poni->Name.Buffer);

  status = NtQueryInformationFile (h, &io, pfni, 32000, FileNameInformation);
  if (!NT_SUCCESS (status))
      fprintf (stderr, "FileNameInformation: 0x%08X\n", status);
  else
    printf ("FileNameInformation: \"%*ls\"\n",
	    pfni->FileNameLength / sizeof (WCHAR),
	    pfni->FileName);

  status = NtQueryInformationFile (h, &io, pfni, 32000,
				   FileNormalizedNameInformation);
  if (!NT_SUCCESS (status))
    fprintf (stderr, "FileNormalizedNameInformation: 0x%08X\n", status);
  else
    printf ("FileNormalizedNameInformation: \"%*ls\"\n",
	    pfni->FileNameLength / sizeof (WCHAR),
	    pfni->FileName);

  if (!GetFileInformationByHandleEx (h, FileNameInfo, pfni2, 32000))
    fprintf (stderr, "FileNameInfo: Win32 error %u\n", GetLastError ());
  else
    printf ("FileNameInfo: \"%*ls\"\n",
	    pfni2->FileNameLength / sizeof (WCHAR),
	    pfni2->FileName);


  NtClose (h);
  return 0;
}


More information about the Cygwin-developers mailing list