Cygwin: pipe: Revert to create() rather than nt_create().

This commit is contained in:
Takashi Yano 2021-08-29 17:23:57 +09:00 committed by Corinna Vinschen
parent b75d855fb0
commit cf3a7a9132
1 changed files with 21 additions and 171 deletions

View File

@ -463,13 +463,13 @@ fhandler_pipe::create (LPSECURITY_ATTRIBUTES sa_ptr, PHANDLE r, PHANDLE w,
if (name) if (name)
len += __small_sprintf (pipename + len, "%s", name); len += __small_sprintf (pipename + len, "%s", name);
open_mode |= PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE; open_mode |= PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE;
/* Retry CreateNamedPipe as long as the pipe name is in use. /* Retry CreateNamedPipe as long as the pipe name is in use.
Retrying will probably never be necessary, but we want Retrying will probably never be necessary, but we want
to be as robust as possible. */ to be as robust as possible. */
DWORD err = 0; DWORD err = 0;
while (r && !*r) while (w && !*w)
{ {
static volatile ULONG pipe_unique_id; static volatile ULONG pipe_unique_id;
if (!name) if (!name)
@ -498,12 +498,12 @@ fhandler_pipe::create (LPSECURITY_ATTRIBUTES sa_ptr, PHANDLE r, PHANDLE w,
definitely required for pty handling since fhandler_pty_master definitely required for pty handling since fhandler_pty_master
writes to the pipe in chunks, terminated by newline when CANON mode writes to the pipe in chunks, terminated by newline when CANON mode
is specified. */ is specified. */
*r = CreateNamedPipe (pipename, open_mode, pipe_mode, 1, psize, *w = CreateNamedPipe (pipename, open_mode, pipe_mode, 1, psize,
psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
if (*r != INVALID_HANDLE_VALUE) if (*w != INVALID_HANDLE_VALUE)
{ {
debug_printf ("pipe read handle %p", *r); debug_printf ("pipe write handle %p", *w);
err = 0; err = 0;
break; break;
} }
@ -516,14 +516,14 @@ fhandler_pipe::create (LPSECURITY_ATTRIBUTES sa_ptr, PHANDLE r, PHANDLE w,
Pick a new name and retry. */ Pick a new name and retry. */
debug_printf ("pipe busy", !name ? ", retrying" : ""); debug_printf ("pipe busy", !name ? ", retrying" : "");
if (!name) if (!name)
*r = NULL; *w = NULL;
break; break;
case ERROR_ACCESS_DENIED: case ERROR_ACCESS_DENIED:
/* The pipe is already open with incompatible parameters. /* The pipe is already open with incompatible parameters.
Pick a new name and retry. */ Pick a new name and retry. */
debug_printf ("pipe access denied%s", !name ? ", retrying" : ""); debug_printf ("pipe access denied%s", !name ? ", retrying" : "");
if (!name) if (!name)
*r = NULL; *w = NULL;
break; break;
default: default:
{ {
@ -535,60 +535,42 @@ fhandler_pipe::create (LPSECURITY_ATTRIBUTES sa_ptr, PHANDLE r, PHANDLE w,
if (err) if (err)
{ {
*r = NULL;
return err;
}
if (!w)
debug_printf ("pipe write handle NULL");
else
{
debug_printf ("CreateFile: name %s", pipename);
/* Open the named pipe for writing.
Be sure to permit FILE_READ_ATTRIBUTES access. */
DWORD access = GENERIC_WRITE | FILE_READ_ATTRIBUTES;
if ((open_mode & PIPE_ACCESS_DUPLEX) == PIPE_ACCESS_DUPLEX)
access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
*w = CreateFile (pipename, access, 0, sa_ptr, OPEN_EXISTING,
open_mode & FILE_FLAG_OVERLAPPED, 0);
if (!*w || *w == INVALID_HANDLE_VALUE)
{
/* Failure. */
DWORD err = GetLastError ();
debug_printf ("CreateFile failed, r %p, %E", r);
if (r)
CloseHandle (*r);
*w = NULL; *w = NULL;
return err; return err;
} }
debug_printf ("pipe write handle %p", *w); if (!r)
debug_printf ("pipe read handle NULL");
else
{
debug_printf ("CreateFile: name %s", pipename);
/* Open the named pipe for reading.
Be sure to permit FILE_WRITE_ATTRIBUTES access. */
DWORD access = GENERIC_READ | FILE_WRITE_ATTRIBUTES;
if ((open_mode & PIPE_ACCESS_DUPLEX) == PIPE_ACCESS_DUPLEX)
access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
*r = CreateFile (pipename, access, 0, sa_ptr, OPEN_EXISTING,
open_mode & FILE_FLAG_OVERLAPPED, 0);
if (!*r || *r == INVALID_HANDLE_VALUE)
{
/* Failure. */
DWORD err = GetLastError ();
debug_printf ("CreateFile failed, r %p, %E", r);
if (w)
CloseHandle (*w);
*r = NULL;
return err;
}
debug_printf ("pipe read handle %p", *r);
} }
/* Success. */ /* Success. */
return 0; return 0;
} }
/* The next version of fhandler_pipe::create used to call the previous
version. But the read handle created by the latter doesn't have
FILE_WRITE_ATTRIBUTES access unless the pipe is created with
PIPE_ACCESS_DUPLEX, and it doesn't seem possible to add that access
right. This causes set_pipe_non_blocking to fail.
To fix this we will define a helper function 'nt_create' that is
similar to the above fhandler_pipe::create but uses
NtCreateNamedPipeFile instead of CreateNamedPipe; this gives more
flexibility in setting the access rights. We will use this helper
function in the version of fhandler_pipe::create below, which
suffices for all of our uses of set_pipe_non_blocking. For
simplicity, nt_create will omit the 'open_mode' and 'name'
parameters, which aren't needed for our purposes. */
static int nt_create (LPSECURITY_ATTRIBUTES, PHANDLE, PHANDLE, DWORD,
int64_t *);
int int
fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode) fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode)
{ {
@ -597,7 +579,7 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode)
int res = -1; int res = -1;
int64_t unique_id; int64_t unique_id;
int ret = nt_create (sa, &r, &w, psize, &unique_id); int ret = create (sa, &r, &w, psize, NULL, 0, &unique_id);
if (ret) if (ret)
__seterrno_from_win_error (ret); __seterrno_from_win_error (ret);
else if ((fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev)) == NULL) else if ((fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev)) == NULL)
@ -624,138 +606,6 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode)
return res; return res;
} }
static int
nt_create (LPSECURITY_ATTRIBUTES sa_ptr, PHANDLE r, PHANDLE w,
DWORD psize, int64_t *unique_id)
{
NTSTATUS status;
HANDLE npfsh;
ACCESS_MASK access;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
LARGE_INTEGER timeout;
/* Default to error. */
if (r)
*r = NULL;
if (w)
*w = NULL;
status = fhandler_base::npfs_handle (npfsh);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
return GetLastError ();
}
/* Ensure that there is enough pipe buffer space for atomic writes. */
if (!psize)
psize = DEFAULT_PIPEBUFSIZE;
UNICODE_STRING pipename;
WCHAR pipename_buf[MAX_PATH];
size_t len = __small_swprintf (pipename_buf, L"%S-%u-",
&cygheap->installation_key,
GetCurrentProcessId ());
access = GENERIC_READ | FILE_WRITE_ATTRIBUTES;
ULONG pipe_type = pipe_byte ? FILE_PIPE_BYTE_STREAM_TYPE
: FILE_PIPE_MESSAGE_TYPE;
/* Retry NtCreateNamedPipeFile as long as the pipe name is in use.
Retrying will probably never be necessary, but we want
to be as robust as possible. */
DWORD err = 0;
while (r && !*r)
{
static volatile ULONG pipe_unique_id;
LONG id = InterlockedIncrement ((LONG *) &pipe_unique_id);
__small_swprintf (pipename_buf + len, L"pipe-nt-%p", id);
if (unique_id)
*unique_id = ((int64_t) id << 32 | GetCurrentProcessId ());
debug_printf ("name %W, size %u, mode %s", pipename_buf, psize,
(pipe_type & FILE_PIPE_MESSAGE_TYPE)
? "PIPE_TYPE_MESSAGE" : "PIPE_TYPE_BYTE");
RtlInitUnicodeString (&pipename, pipename_buf);
InitializeObjectAttributes (&attr, &pipename,
sa_ptr->bInheritHandle ? OBJ_INHERIT : 0,
npfsh, sa_ptr->lpSecurityDescriptor);
timeout.QuadPart = -500000;
status = NtCreateNamedPipeFile (r, access, &attr, &io,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE, 0, pipe_type,
FILE_PIPE_BYTE_STREAM_MODE,
0, 1, psize, psize, &timeout);
if (NT_SUCCESS (status))
{
debug_printf ("pipe read handle %p", *r);
err = 0;
break;
}
switch (status)
{
case STATUS_PIPE_BUSY:
case STATUS_INSTANCE_NOT_AVAILABLE:
case STATUS_PIPE_NOT_AVAILABLE:
/* The pipe is already open with compatible parameters.
Pick a new name and retry. */
debug_printf ("pipe busy, retrying");
*r = NULL;
break;
case STATUS_ACCESS_DENIED:
/* The pipe is already open with incompatible parameters.
Pick a new name and retry. */
debug_printf ("pipe access denied, retrying");
*r = NULL;
break;
default:
{
__seterrno_from_nt_status (status);
err = GetLastError ();
debug_printf ("failed, %E");
*r = INVALID_HANDLE_VALUE;
}
}
}
if (err)
{
*r = NULL;
return err;
}
if (!w)
debug_printf ("pipe write handle NULL");
else
{
debug_printf ("NtOpenFile: name %S", &pipename);
access = GENERIC_WRITE | FILE_READ_ATTRIBUTES;
status = NtOpenFile (w, access, &attr, &io, 0, 0);
if (!NT_SUCCESS (status))
{
DWORD err = GetLastError ();
debug_printf ("NtOpenFile failed, r %p, %E", r);
if (r)
CloseHandle (*r);
*w = NULL;
return err;
}
debug_printf ("pipe write handle %p", *w);
}
/* Success. */
return 0;
}
int int
fhandler_pipe::ioctl (unsigned int cmd, void *p) fhandler_pipe::ioctl (unsigned int cmd, void *p)
{ {