From 91ca95ae4a7ee353fb913d31da6c183b9b4a1656 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Mon, 7 Jan 2019 12:31:28 +0100 Subject: Cygwin: rename pipe.cc to fhandler_pipe.cc move pipe syscalls to syscalls.cc Signed-off-by: Corinna Vinschen --- winsup/cygwin/Makefile.in | 2 +- winsup/cygwin/fhandler_pipe.cc | 438 +++++++++++++++++++++++++++++++++++ winsup/cygwin/pipe.cc | 508 ----------------------------------------- winsup/cygwin/syscalls.cc | 70 ++++++ 4 files changed, 509 insertions(+), 509 deletions(-) create mode 100644 winsup/cygwin/fhandler_pipe.cc delete mode 100644 winsup/cygwin/pipe.cc diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index 733678e96..e4ce31fda 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -287,6 +287,7 @@ DLL_OFILES:= \ fhandler_floppy.o \ fhandler_netdrive.o \ fhandler_nodevice.o \ + fhandler_pipe.o \ fhandler_proc.o \ fhandler_process.o \ fhandler_process_fd.o \ @@ -349,7 +350,6 @@ DLL_OFILES:= \ passwd.o \ path.o \ pinfo.o \ - pipe.o \ poll.o \ posix_ipc.o \ pseudo-reloc.o \ diff --git a/winsup/cygwin/fhandler_pipe.cc b/winsup/cygwin/fhandler_pipe.cc new file mode 100644 index 000000000..eafaa8856 --- /dev/null +++ b/winsup/cygwin/fhandler_pipe.cc @@ -0,0 +1,438 @@ +/* pipe.cc: pipe for Cygwin. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* FIXME: Should this really be fhandler_pipe.cc? */ + +#include "winsup.h" +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" +#include "pinfo.h" +#include "shared_info.h" + +fhandler_pipe::fhandler_pipe () + : fhandler_base_overlapped (), popen_pid (0) +{ + max_atomic_write = DEFAULT_PIPEBUFSIZE; + need_fork_fixup (true); +} + +int +fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode, int64_t uniq_id) +{ + /* FIXME: Have to clean this up someday + FIXME: Do we have to check for both !get_win32_name() and + !*get_win32_name()? */ + if ((!get_win32_name () || !*get_win32_name ()) && get_name ()) + { + char *d; + const char *s; + char *hold_normalized_name = (char *) alloca (strlen (get_name ()) + 1); + for (s = get_name (), d = hold_normalized_name; *s; s++, d++) + if (*s == '/') + *d = '\\'; + else + *d = *s; + *d = '\0'; + set_name (hold_normalized_name); + } + + bool opened_properly = a & FILE_CREATE_PIPE_INSTANCE; + a &= ~FILE_CREATE_PIPE_INSTANCE; + fhandler_base::init (f, a, mode); + close_on_exec (mode & O_CLOEXEC); + set_ino (uniq_id); + set_unique_id (uniq_id | !!(mode & GENERIC_WRITE)); + if (opened_properly) + setup_overlapped (); + else + destroy_overlapped (); + return 1; +} + +extern "C" int sscanf (const char *, const char *, ...); + +int +fhandler_pipe::open (int flags, mode_t mode) +{ + HANDLE proc, nio_hdl = NULL; + int64_t uniq_id; + fhandler_pipe *fh = NULL, *fhr = NULL, *fhw = NULL; + size_t size; + int pid, rwflags = (flags & O_ACCMODE); + bool inh; + bool got_one = false; + + if (sscanf (get_name (), "/proc/self/fd/pipe:[%lld]", + (long long *) &uniq_id) == 1) + pid = myself->pid; + else if (sscanf (get_name (), "/proc/%d/fd/pipe:[%lld]", + &pid, (long long *) &uniq_id) < 2) + { + set_errno (ENOENT); + return 0; + } + if (pid == myself->pid) + { + cygheap_fdenum cfd (true); + while (cfd.next () >= 0) + { + /* Windows doesn't allow to copy a pipe HANDLE with another access + mode. So we check for read and write side of pipe and try to + find the one matching the requested access mode. */ + if (cfd->get_unique_id () == uniq_id) + got_one = true; + else if (cfd->get_unique_id () == uniq_id + 1) + got_one = true; + else + continue; + if ((rwflags == O_RDONLY && !(cfd->get_access () & GENERIC_READ)) + || (rwflags == O_WRONLY && !(cfd->get_access () & GENERIC_WRITE))) + continue; + cfd->copyto (this); + set_io_handle (NULL); + pc.reset_conv_handle (); + if (!cfd->dup (this, flags)) + return 1; + return 0; + } + /* Found the pipe but access mode didn't match? EACCES. + Otherwise ENOENT */ + set_errno (got_one ? EACCES : ENOENT); + return 0; + } + + pinfo p (pid); + if (!p) + { + set_errno (ESRCH); + return 0; + } + if (!(proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId))) + { + __seterrno (); + return 0; + } + fhr = p->pipe_fhandler (uniq_id, size); + if (fhr && rwflags == O_RDONLY) + fh = fhr; + else + { + fhw = p->pipe_fhandler (uniq_id + 1, size); + if (fhw && rwflags == O_WRONLY) + fh = fhw; + } + if (!fh) + { + /* Too bad, but Windows only allows the same access mode when dup'ing + the pipe. */ + set_errno (fhr || fhw ? EACCES : ENOENT); + goto out; + } + inh = !(flags & O_CLOEXEC); + if (!DuplicateHandle (proc, fh->get_handle (), GetCurrentProcess (), + &nio_hdl, 0, inh, DUPLICATE_SAME_ACCESS)) + { + __seterrno (); + goto out; + } + init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY, + fh->get_plain_ino ()); + cfree (fh); + CloseHandle (proc); + return 1; +out: + if (nio_hdl) + CloseHandle (nio_hdl); + if (fh) + free (fh); + if (proc) + CloseHandle (proc); + return 0; +} + +off_t +fhandler_pipe::lseek (off_t offset, int whence) +{ + debug_printf ("(%D, %d)", offset, whence); + set_errno (ESPIPE); + return -1; +} + +int +fhandler_pipe::fadvise (off_t offset, off_t length, int advice) +{ + return ESPIPE; +} + +int +fhandler_pipe::ftruncate (off_t length, bool allow_truncate) +{ + return allow_truncate ? EINVAL : ESPIPE; +} + +char * +fhandler_pipe::get_proc_fd_name (char *buf) +{ + __small_sprintf (buf, "pipe:[%D]", get_plain_ino ()); + return buf; +} + +int +fhandler_pipe::dup (fhandler_base *child, int flags) +{ + fhandler_pipe *ftp = (fhandler_pipe *) child; + ftp->set_popen_pid (0); + + int res; + if (get_handle () && fhandler_base_overlapped::dup (child, flags)) + res = -1; + else + res = 0; + + debug_printf ("res %d", res); + return res; +} + +#define PIPE_INTRO "\\\\.\\pipe\\cygwin-" + +/* Create a pipe, and return handles to the read and write ends, + just like CreatePipe, but ensure that the write end permits + FILE_READ_ATTRIBUTES access, on later versions of win32 where + this is supported. This access is needed by NtQueryInformationFile, + which is used to implement select and nonblocking writes. + Note that the return value is either 0 or GetLastError, + unlike CreatePipe, which returns a bool for success or failure. */ +DWORD +fhandler_pipe::create (LPSECURITY_ATTRIBUTES sa_ptr, PHANDLE r, PHANDLE w, + DWORD psize, const char *name, DWORD open_mode, + int64_t *unique_id) +{ + /* Default to error. */ + if (r) + *r = NULL; + if (w) + *w = NULL; + + /* Ensure that there is enough pipe buffer space for atomic writes. */ + if (!psize) + psize = DEFAULT_PIPEBUFSIZE; + + char pipename[MAX_PATH]; + size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-", + &cygheap->installation_key); + DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_REJECT_REMOTE_CLIENTS; + if (!name) + pipe_mode |= pipe_byte ? PIPE_TYPE_BYTE : PIPE_TYPE_MESSAGE; + else + pipe_mode |= PIPE_TYPE_MESSAGE; + + if (!name || (open_mode & PIPE_ADD_PID)) + { + len += __small_sprintf (pipename + len, "%u-", GetCurrentProcessId ()); + open_mode &= ~PIPE_ADD_PID; + } + + if (name) + len += __small_sprintf (pipename + len, "%s", name); + + open_mode |= PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE; + + /* Retry CreateNamedPipe 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; + if (!name) + { + LONG id = InterlockedIncrement ((LONG *) &pipe_unique_id); + __small_sprintf (pipename + len, "pipe-%p", id); + if (unique_id) + *unique_id = ((int64_t) id << 32 | GetCurrentProcessId ()); + } + + debug_printf ("name %s, size %u, mode %s", pipename, psize, + (pipe_mode & PIPE_TYPE_MESSAGE) + ? "PIPE_TYPE_MESSAGE" : "PIPE_TYPE_BYTE"); + + /* Use CreateNamedPipe instead of CreatePipe, because the latter + returns a write handle that does not permit FILE_READ_ATTRIBUTES + access, on versions of win32 earlier than WinXP SP2. + CreatePipe also stupidly creates a full duplex pipe, which is + a waste, since only a single direction is actually used. + It's important to only allow a single instance, to ensure that + the pipe was not created earlier by some other process, even if + the pid has been reused. + + Note that the write side of the pipe is opened as PIPE_TYPE_MESSAGE. + This *seems* to more closely mimic Linux pipe behavior and is + definitely required for pty handling since fhandler_pty_master + writes to the pipe in chunks, terminated by newline when CANON mode + is specified. */ + *r = CreateNamedPipe (pipename, open_mode, pipe_mode, 1, psize, + psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); + + if (*r != INVALID_HANDLE_VALUE) + { + debug_printf ("pipe read handle %p", *r); + err = 0; + break; + } + + err = GetLastError (); + switch (err) + { + case ERROR_PIPE_BUSY: + /* The pipe is already open with compatible parameters. + Pick a new name and retry. */ + debug_printf ("pipe busy", !name ? ", retrying" : ""); + if (!name) + *r = NULL; + break; + case ERROR_ACCESS_DENIED: + /* The pipe is already open with incompatible parameters. + Pick a new name and retry. */ + debug_printf ("pipe access denied%s", !name ? ", retrying" : ""); + if (!name) + *r = NULL; + break; + default: + { + err = GetLastError (); + debug_printf ("failed, %E"); + } + } + } + + 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; + return err; + } + + debug_printf ("pipe write handle %p", *w); + } + + /* Success. */ + return 0; +} + +int +fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode) +{ + HANDLE r, w; + SECURITY_ATTRIBUTES *sa = sec_none_cloexec (mode); + int res = -1; + int64_t unique_id; + + int ret = create (sa, &r, &w, psize, NULL, FILE_FLAG_OVERLAPPED, &unique_id); + if (ret) + __seterrno_from_win_error (ret); + else if ((fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev)) == NULL) + { + CloseHandle (r); + CloseHandle (w); + } + else if ((fhs[1] = (fhandler_pipe *) build_fh_dev (*pipew_dev)) == NULL) + { + delete fhs[0]; + CloseHandle (w); + } + else + { + mode |= mode & O_TEXT ?: O_BINARY; + fhs[0]->init (r, FILE_CREATE_PIPE_INSTANCE | GENERIC_READ, mode, + unique_id); + fhs[1]->init (w, FILE_CREATE_PIPE_INSTANCE | GENERIC_WRITE, mode, + unique_id); + res = 0; + } + + debug_printf ("%R = pipe([%p, %p], %d, %y)", res, fhs[0], fhs[1], psize, mode); + return res; +} + +int +fhandler_pipe::ioctl (unsigned int cmd, void *p) +{ + int n; + + switch (cmd) + { + case FIONREAD: + if (get_device () == FH_PIPEW) + { + set_errno (EINVAL); + return -1; + } + if (!PeekNamedPipe (get_handle (), NULL, 0, NULL, (DWORD *) &n, NULL)) + { + __seterrno (); + return -1; + } + break; + default: + return fhandler_base::ioctl (cmd, p); + break; + } + *(int *) p = n; + return 0; +} + +int __reg2 +fhandler_pipe::fstat (struct stat *buf) +{ + int ret = fhandler_base::fstat (buf); + if (!ret) + { + buf->st_dev = FH_PIPE; + if (!(buf->st_ino = get_plain_ino ())) + sscanf (get_name (), "/proc/%*d/fd/pipe:[%lld]", + (long long *) &buf->st_ino); + } + return ret; +} + +int __reg2 +fhandler_pipe::fstatvfs (struct statvfs *sfs) +{ + set_errno (EBADF); + return -1; +} diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc deleted file mode 100644 index a75275d7c..000000000 --- a/winsup/cygwin/pipe.cc +++ /dev/null @@ -1,508 +0,0 @@ -/* pipe.cc: pipe for Cygwin. - -This file is part of Cygwin. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -/* FIXME: Should this really be fhandler_pipe.cc? */ - -#include "winsup.h" -#include -#include -#include "cygerrno.h" -#include "security.h" -#include "path.h" -#include "fhandler.h" -#include "dtable.h" -#include "cygheap.h" -#include "pinfo.h" -#include "shared_info.h" - -fhandler_pipe::fhandler_pipe () - : fhandler_base_overlapped (), popen_pid (0) -{ - max_atomic_write = DEFAULT_PIPEBUFSIZE; - need_fork_fixup (true); -} - -int -fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode, int64_t uniq_id) -{ - /* FIXME: Have to clean this up someday - FIXME: Do we have to check for both !get_win32_name() and - !*get_win32_name()? */ - if ((!get_win32_name () || !*get_win32_name ()) && get_name ()) - { - char *d; - const char *s; - char *hold_normalized_name = (char *) alloca (strlen (get_name ()) + 1); - for (s = get_name (), d = hold_normalized_name; *s; s++, d++) - if (*s == '/') - *d = '\\'; - else - *d = *s; - *d = '\0'; - set_name (hold_normalized_name); - } - - bool opened_properly = a & FILE_CREATE_PIPE_INSTANCE; - a &= ~FILE_CREATE_PIPE_INSTANCE; - fhandler_base::init (f, a, mode); - close_on_exec (mode & O_CLOEXEC); - set_ino (uniq_id); - set_unique_id (uniq_id | !!(mode & GENERIC_WRITE)); - if (opened_properly) - setup_overlapped (); - else - destroy_overlapped (); - return 1; -} - -extern "C" int sscanf (const char *, const char *, ...); - -int -fhandler_pipe::open (int flags, mode_t mode) -{ - HANDLE proc, nio_hdl = NULL; - int64_t uniq_id; - fhandler_pipe *fh = NULL, *fhr = NULL, *fhw = NULL; - size_t size; - int pid, rwflags = (flags & O_ACCMODE); - bool inh; - bool got_one = false; - - if (sscanf (get_name (), "/proc/self/fd/pipe:[%lld]", - (long long *) &uniq_id) == 1) - pid = myself->pid; - else if (sscanf (get_name (), "/proc/%d/fd/pipe:[%lld]", - &pid, (long long *) &uniq_id) < 2) - { - set_errno (ENOENT); - return 0; - } - if (pid == myself->pid) - { - cygheap_fdenum cfd (true); - while (cfd.next () >= 0) - { - /* Windows doesn't allow to copy a pipe HANDLE with another access - mode. So we check for read and write side of pipe and try to - find the one matching the requested access mode. */ - if (cfd->get_unique_id () == uniq_id) - got_one = true; - else if (cfd->get_unique_id () == uniq_id + 1) - got_one = true; - else - continue; - if ((rwflags == O_RDONLY && !(cfd->get_access () & GENERIC_READ)) - || (rwflags == O_WRONLY && !(cfd->get_access () & GENERIC_WRITE))) - continue; - cfd->copyto (this); - set_io_handle (NULL); - pc.reset_conv_handle (); - if (!cfd->dup (this, flags)) - return 1; - return 0; - } - /* Found the pipe but access mode didn't match? EACCES. - Otherwise ENOENT */ - set_errno (got_one ? EACCES : ENOENT); - return 0; - } - - pinfo p (pid); - if (!p) - { - set_errno (ESRCH); - return 0; - } - if (!(proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId))) - { - __seterrno (); - return 0; - } - fhr = p->pipe_fhandler (uniq_id, size); - if (fhr && rwflags == O_RDONLY) - fh = fhr; - else - { - fhw = p->pipe_fhandler (uniq_id + 1, size); - if (fhw && rwflags == O_WRONLY) - fh = fhw; - } - if (!fh) - { - /* Too bad, but Windows only allows the same access mode when dup'ing - the pipe. */ - set_errno (fhr || fhw ? EACCES : ENOENT); - goto out; - } - inh = !(flags & O_CLOEXEC); - if (!DuplicateHandle (proc, fh->get_handle (), GetCurrentProcess (), - &nio_hdl, 0, inh, DUPLICATE_SAME_ACCESS)) - { - __seterrno (); - goto out; - } - init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY, - fh->get_plain_ino ()); - cfree (fh); - CloseHandle (proc); - return 1; -out: - if (nio_hdl) - CloseHandle (nio_hdl); - if (fh) - free (fh); - if (proc) - CloseHandle (proc); - return 0; -} - -off_t -fhandler_pipe::lseek (off_t offset, int whence) -{ - debug_printf ("(%D, %d)", offset, whence); - set_errno (ESPIPE); - return -1; -} - -int -fhandler_pipe::fadvise (off_t offset, off_t length, int advice) -{ - return ESPIPE; -} - -int -fhandler_pipe::ftruncate (off_t length, bool allow_truncate) -{ - return allow_truncate ? EINVAL : ESPIPE; -} - -char * -fhandler_pipe::get_proc_fd_name (char *buf) -{ - __small_sprintf (buf, "pipe:[%D]", get_plain_ino ()); - return buf; -} - -int -fhandler_pipe::dup (fhandler_base *child, int flags) -{ - fhandler_pipe *ftp = (fhandler_pipe *) child; - ftp->set_popen_pid (0); - - int res; - if (get_handle () && fhandler_base_overlapped::dup (child, flags)) - res = -1; - else - res = 0; - - debug_printf ("res %d", res); - return res; -} - -#define PIPE_INTRO "\\\\.\\pipe\\cygwin-" - -/* Create a pipe, and return handles to the read and write ends, - just like CreatePipe, but ensure that the write end permits - FILE_READ_ATTRIBUTES access, on later versions of win32 where - this is supported. This access is needed by NtQueryInformationFile, - which is used to implement select and nonblocking writes. - Note that the return value is either 0 or GetLastError, - unlike CreatePipe, which returns a bool for success or failure. */ -DWORD -fhandler_pipe::create (LPSECURITY_ATTRIBUTES sa_ptr, PHANDLE r, PHANDLE w, - DWORD psize, const char *name, DWORD open_mode, - int64_t *unique_id) -{ - /* Default to error. */ - if (r) - *r = NULL; - if (w) - *w = NULL; - - /* Ensure that there is enough pipe buffer space for atomic writes. */ - if (!psize) - psize = DEFAULT_PIPEBUFSIZE; - - char pipename[MAX_PATH]; - size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-", - &cygheap->installation_key); - DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_REJECT_REMOTE_CLIENTS; - if (!name) - pipe_mode |= pipe_byte ? PIPE_TYPE_BYTE : PIPE_TYPE_MESSAGE; - else - pipe_mode |= PIPE_TYPE_MESSAGE; - - if (!name || (open_mode & PIPE_ADD_PID)) - { - len += __small_sprintf (pipename + len, "%u-", GetCurrentProcessId ()); - open_mode &= ~PIPE_ADD_PID; - } - - if (name) - len += __small_sprintf (pipename + len, "%s", name); - - open_mode |= PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE; - - /* Retry CreateNamedPipe 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; - if (!name) - { - LONG id = InterlockedIncrement ((LONG *) &pipe_unique_id); - __small_sprintf (pipename + len, "pipe-%p", id); - if (unique_id) - *unique_id = ((int64_t) id << 32 | GetCurrentProcessId ()); - } - - debug_printf ("name %s, size %u, mode %s", pipename, psize, - (pipe_mode & PIPE_TYPE_MESSAGE) - ? "PIPE_TYPE_MESSAGE" : "PIPE_TYPE_BYTE"); - - /* Use CreateNamedPipe instead of CreatePipe, because the latter - returns a write handle that does not permit FILE_READ_ATTRIBUTES - access, on versions of win32 earlier than WinXP SP2. - CreatePipe also stupidly creates a full duplex pipe, which is - a waste, since only a single direction is actually used. - It's important to only allow a single instance, to ensure that - the pipe was not created earlier by some other process, even if - the pid has been reused. - - Note that the write side of the pipe is opened as PIPE_TYPE_MESSAGE. - This *seems* to more closely mimic Linux pipe behavior and is - definitely required for pty handling since fhandler_pty_master - writes to the pipe in chunks, terminated by newline when CANON mode - is specified. */ - *r = CreateNamedPipe (pipename, open_mode, pipe_mode, 1, psize, - psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); - - if (*r != INVALID_HANDLE_VALUE) - { - debug_printf ("pipe read handle %p", *r); - err = 0; - break; - } - - err = GetLastError (); - switch (err) - { - case ERROR_PIPE_BUSY: - /* The pipe is already open with compatible parameters. - Pick a new name and retry. */ - debug_printf ("pipe busy", !name ? ", retrying" : ""); - if (!name) - *r = NULL; - break; - case ERROR_ACCESS_DENIED: - /* The pipe is already open with incompatible parameters. - Pick a new name and retry. */ - debug_printf ("pipe access denied%s", !name ? ", retrying" : ""); - if (!name) - *r = NULL; - break; - default: - { - err = GetLastError (); - debug_printf ("failed, %E"); - } - } - } - - 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; - return err; - } - - debug_printf ("pipe write handle %p", *w); - } - - /* Success. */ - return 0; -} - -int -fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode) -{ - HANDLE r, w; - SECURITY_ATTRIBUTES *sa = sec_none_cloexec (mode); - int res = -1; - int64_t unique_id; - - int ret = create (sa, &r, &w, psize, NULL, FILE_FLAG_OVERLAPPED, &unique_id); - if (ret) - __seterrno_from_win_error (ret); - else if ((fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev)) == NULL) - { - CloseHandle (r); - CloseHandle (w); - } - else if ((fhs[1] = (fhandler_pipe *) build_fh_dev (*pipew_dev)) == NULL) - { - delete fhs[0]; - CloseHandle (w); - } - else - { - mode |= mode & O_TEXT ?: O_BINARY; - fhs[0]->init (r, FILE_CREATE_PIPE_INSTANCE | GENERIC_READ, mode, - unique_id); - fhs[1]->init (w, FILE_CREATE_PIPE_INSTANCE | GENERIC_WRITE, mode, - unique_id); - res = 0; - } - - debug_printf ("%R = pipe([%p, %p], %d, %y)", res, fhs[0], fhs[1], psize, mode); - return res; -} - -int -fhandler_pipe::ioctl (unsigned int cmd, void *p) -{ - int n; - - switch (cmd) - { - case FIONREAD: - if (get_device () == FH_PIPEW) - { - set_errno (EINVAL); - return -1; - } - if (!PeekNamedPipe (get_handle (), NULL, 0, NULL, (DWORD *) &n, NULL)) - { - __seterrno (); - return -1; - } - break; - default: - return fhandler_base::ioctl (cmd, p); - break; - } - *(int *) p = n; - return 0; -} - -int __reg2 -fhandler_pipe::fstat (struct stat *buf) -{ - int ret = fhandler_base::fstat (buf); - if (!ret) - { - buf->st_dev = FH_PIPE; - if (!(buf->st_ino = get_plain_ino ())) - sscanf (get_name (), "/proc/%*d/fd/pipe:[%lld]", - (long long *) &buf->st_ino); - } - return ret; -} - -int __reg2 -fhandler_pipe::fstatvfs (struct statvfs *sfs) -{ - set_errno (EBADF); - return -1; -} - -static int __reg3 -pipe_worker (int filedes[2], unsigned int psize, int mode) -{ - fhandler_pipe *fhs[2]; - int res = fhandler_pipe::create (fhs, psize, mode); - if (!res) - { - cygheap_fdnew fdin; - cygheap_fdnew fdout (fdin, false); - char buf[sizeof ("/proc/self/fd/pipe:[9223372036854775807]")]; - __small_sprintf (buf, "/proc/self/fd/pipe:[%D]", fhs[0]->get_plain_ino ()); - fhs[0]->pc.set_posix (buf); - __small_sprintf (buf, "pipe:[%D]", fhs[1]->get_plain_ino ()); - fhs[1]->pc.set_posix (buf); - fdin = fhs[0]; - fdout = fhs[1]; - filedes[0] = fdin; - filedes[1] = fdout; - } - return res; -} - -extern "C" int -_pipe (int filedes[2], unsigned int psize, int mode) -{ - int res = pipe_worker (filedes, psize, mode); - int read, write; - if (res != 0) - read = write = -1; - else - { - read = filedes[0]; - write = filedes[1]; - } - syscall_printf ("%R = _pipe([%d, %d], %u, %y)", res, read, write, psize, mode); - return res; -} - -extern "C" int -pipe (int filedes[2]) -{ - int res = pipe_worker (filedes, DEFAULT_PIPEBUFSIZE, O_BINARY); - int read, write; - if (res != 0) - read = write = -1; - else - { - read = filedes[0]; - write = filedes[1]; - } - syscall_printf ("%R = pipe([%d, %d])", res, read, write); - return res; -} - -extern "C" int -pipe2 (int filedes[2], int mode) -{ - int res = pipe_worker (filedes, DEFAULT_PIPEBUFSIZE, mode); - int read, write; - if (res != 0) - read = write = -1; - else - { - read = filedes[0]; - write = filedes[1]; - } - syscall_printf ("%R = pipe2([%d, %d], %y)", res, read, write, mode); - return res; -} diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 5bb33bf0a..b99a21e8e 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -4959,3 +4959,73 @@ unlinkat (int dirfd, const char *pathname, int flags) __endtry return -1; } + +static int __reg3 +pipe_worker (int filedes[2], unsigned int psize, int mode) +{ + fhandler_pipe *fhs[2]; + int res = fhandler_pipe::create (fhs, psize, mode); + if (!res) + { + cygheap_fdnew fdin; + cygheap_fdnew fdout (fdin, false); + char buf[sizeof ("/proc/self/fd/pipe:[9223372036854775807]")]; + __small_sprintf (buf, "/proc/self/fd/pipe:[%D]", fhs[0]->get_plain_ino ()); + fhs[0]->pc.set_posix (buf); + __small_sprintf (buf, "pipe:[%D]", fhs[1]->get_plain_ino ()); + fhs[1]->pc.set_posix (buf); + fdin = fhs[0]; + fdout = fhs[1]; + filedes[0] = fdin; + filedes[1] = fdout; + } + return res; +} + +extern "C" int +_pipe (int filedes[2], unsigned int psize, int mode) +{ + int res = pipe_worker (filedes, psize, mode); + int read, write; + if (res != 0) + read = write = -1; + else + { + read = filedes[0]; + write = filedes[1]; + } + syscall_printf ("%R = _pipe([%d, %d], %u, %y)", res, read, write, psize, mode); + return res; +} + +extern "C" int +pipe (int filedes[2]) +{ + int res = pipe_worker (filedes, DEFAULT_PIPEBUFSIZE, O_BINARY); + int read, write; + if (res != 0) + read = write = -1; + else + { + read = filedes[0]; + write = filedes[1]; + } + syscall_printf ("%R = pipe([%d, %d])", res, read, write); + return res; +} + +extern "C" int +pipe2 (int filedes[2], int mode) +{ + int res = pipe_worker (filedes, DEFAULT_PIPEBUFSIZE, mode); + int read, write; + if (res != 0) + read = write = -1; + else + { + read = filedes[0]; + write = filedes[1]; + } + syscall_printf ("%R = pipe2([%d, %d], %y)", res, read, write, mode); + return res; +} -- cgit v1.2.3