diff options
Diffstat (limited to 'winsup')
-rw-r--r-- | winsup/cygwin/ChangeLog | 14 | ||||
-rw-r--r-- | winsup/cygwin/cygheap.h | 1 | ||||
-rw-r--r-- | winsup/cygwin/path.cc | 5 | ||||
-rw-r--r-- | winsup/cygwin/pinfo.cc | 79 | ||||
-rw-r--r-- | winsup/cygwin/pinfo.h | 6 | ||||
-rw-r--r-- | winsup/cygwin/pipe.cc | 119 |
6 files changed, 184 insertions, 40 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index a2936bf40..a612dfab3 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,17 @@ +2005-02-06 Corinna Vinschen <corinna@vinschen.de> + + * path.cc (path_conv::check): Leave symlink expansion loop in case + a not-ENOENT error happens. + + * cygheap.h (cygheap_fdmanip::fhandler_pipe *): New cast operator. + * pinfo.cc (_pinfo::commune_recv): Add PICOM_PIPE_FHANDLER handling. + (_pinfo::commune_send): Ditto. + (_pinfo::pipe_fhandler): New method. + * pinfo.h (enum picom): Add PICOM_PIPE_FHANDLER. + (_pinfo::pipe_fhandler): Declare. + * pipe.cc (fhandler_pipe::open): Rewrite. Allow to open foreign + pipe handles. + 2005-02-03 Christopher Faylor <cgf@timesys.com> * cygthread.h (cygthread::terminate_thread): Reflect return value. diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index 43723244d..e75afe9ce 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -321,6 +321,7 @@ class cygheap_fdmanip operator int &() {return fd;} operator fhandler_base* &() {return *fh;} operator fhandler_socket* () const {return reinterpret_cast<fhandler_socket *> (*fh);} + operator fhandler_pipe* () const {return reinterpret_cast<fhandler_pipe *> (*fh);} void operator = (fhandler_base *fh) {*this->fh = fh;} fhandler_base *operator -> () const {return *fh;} bool isopen () const diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 055aa1986..7294d2267 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -764,6 +764,11 @@ is_virtual_symlink: else break; } + else if (sym.error != ENOENT) /* E. g. EACCES */ + { + error = sym.error; + goto out; + } /* No existing file found. */ } diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index 69dcb142c..7805eb43d 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -506,6 +506,34 @@ _pinfo::commune_recv () } break; } + case PICOM_PIPE_FHANDLER: + { + HANDLE hdl; + if (!ReadFile (__fromthem, &hdl, sizeof hdl, &nr, NULL) + || nr != sizeof hdl) + { + sigproc_printf ("ReadFile hdl failed, %E"); + CloseHandle (hp); + goto out; + } + CloseHandle (__fromthem); __fromthem = NULL; + CloseHandle (hp); + unsigned int n = 0; + cygheap_fdenum cfd; + while (cfd.next () >= 0) + if (cfd->get_handle () == hdl) + { + fhandler_pipe *fh = cfd; + n = sizeof *fh; + if (!WriteFile (__tothem, &n, sizeof n, &nr, NULL)) + sigproc_printf ("WriteFile sizeof hdl failed, %E"); + else if (!WriteFile (__tothem, fh, n, &nr, NULL)) + sigproc_printf ("WriteFile hdl failed, %E"); + } + if (!n && !WriteFile (__tothem, &n, sizeof n, &nr, NULL)) + sigproc_printf ("WriteFile sizeof hdl failed, %E"); + break; + } case PICOM_FD: { int fd; @@ -518,7 +546,7 @@ _pinfo::commune_recv () } CloseHandle (__fromthem); __fromthem = NULL; CloseHandle (hp); - unsigned int n; + unsigned int n = 0; cygheap_fdget cfd (fd); if (cfd < 0) n = strlen (strcpy (path, "")) + 1; @@ -659,6 +687,17 @@ _pinfo::commune_send (DWORD code, ...) size_t n; switch (code) { + case PICOM_PIPE_FHANDLER: + { + HANDLE hdl = va_arg (args, HANDLE); + if (!WriteFile (tothem, &hdl, sizeof hdl, &nr, NULL) + || nr != sizeof hdl) + { + __seterrno (); + goto err; + } + } + goto business_as_usual; case PICOM_FD: { int fd = va_arg (args, int); @@ -669,25 +708,31 @@ _pinfo::commune_send (DWORD code, ...) goto err; } } - /*FALLTHRU*/ + goto business_as_usual; case PICOM_CMDLINE: case PICOM_CWD: case PICOM_ROOT: case PICOM_FDS: + business_as_usual: if (!ReadFile (fromthem, &n, sizeof n, &nr, NULL) || nr != sizeof n) { __seterrno (); goto err; } - res.s = (char *) malloc (n); - char *p; - for (p = res.s; ReadFile (fromthem, p, n, &nr, NULL); p += nr) - continue; - if ((unsigned) (p - res.s) != n) - { - __seterrno (); - goto err; - } + if (!n) + res.s = NULL; + else + { + res.s = (char *) malloc (n); + char *p; + for (p = res.s; ReadFile (fromthem, p, n, &nr, NULL); p += nr) + continue; + if ((unsigned) (p - res.s) != n) + { + __seterrno (); + goto err; + } + } res.n = n; break; case PICOM_FIFO: @@ -740,6 +785,18 @@ out: return res; } +fhandler_pipe * +_pinfo::pipe_fhandler (HANDLE hdl, size_t &n) +{ + if (!this || !pid) + return NULL; + if (pid == myself->pid) + return NULL; + commune_result cr = commune_send (PICOM_PIPE_FHANDLER, hdl); + n = cr.n; + return (fhandler_pipe *) cr.s; +} + char * _pinfo::fd (int fd, size_t &n) { diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h index 705a1a599..7a502c100 100644 --- a/winsup/cygwin/pinfo.h +++ b/winsup/cygwin/pinfo.h @@ -27,12 +27,15 @@ enum picom PICOM_CWD = 3, PICOM_ROOT = 4, PICOM_FDS = 5, - PICOM_FD = 6 + PICOM_FD = 6, + PICOM_PIPE_FHANDLER = 7 }; #define EXITCODE_SET 0x80000000 #define EXITCODE_NOSET 0x40000000 +class fhandler_pipe; + class _pinfo { public: @@ -110,6 +113,7 @@ public: void commune_recv (); commune_result commune_send (DWORD, ...); bool alive (); + fhandler_pipe *pipe_fhandler (HANDLE hdl, size_t &); char *fd (int fd, size_t &); char *fds (size_t &); char *root (size_t &); diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc index 58cf0109d..ee4b7ad6f 100644 --- a/winsup/cygwin/pipe.cc +++ b/winsup/cygwin/pipe.cc @@ -36,43 +36,106 @@ fhandler_pipe::fhandler_pipe () { } +extern "C" int sscanf (const char *, const char *, ...); + int fhandler_pipe::open (int flags, mode_t mode) { - const char *path = get_name (); - debug_printf ("path: %s", path); - if (!strncmp (get_name (), "/proc/", 6)) + HANDLE proc, pipe_hdl, nio_hdl = NULL, nwrp_hdl = NULL; + fhandler_pipe *fh = NULL; + size_t size; + int pid, rwflags = (flags & O_ACCMODE); + + if (flags & O_CREAT) + { + set_errno (EACCES); + return 0; + } + sscanf (get_name (), "/proc/%d/fd/pipe:[%d]", &pid, (int *) &pipe_hdl); + if (pid == myself->pid) { - char *c; - HANDLE hdl; - int pid = strtol (path += 6, &c, 10); - if (!pid || !c || *c != '/') - goto out; - path = c; - if (strncmp (path, "/fd/pipe:[", 10)) - goto out; - path += 10; - hdl = (HANDLE) atoi (path); - if (pid == myself->pid) - { - cygheap_fdenum cfd; - while (cfd.next () >= 0) + cygheap_fdenum cfd; + while (cfd.next () >= 0) + { + if (cfd->get_handle () != pipe_hdl) + continue; + if ((rwflags == O_RDONLY && !(cfd->get_access () & GENERIC_READ)) + || (rwflags == O_WRONLY && !(cfd->get_access () & GENERIC_WRITE))) { - if (cfd->get_handle () == hdl) - { - if (!cfd->dup (this)) - return 1; - return 0; - } + set_errno (EACCES); + return 0; } + if (!cfd->dup (this)) + return 1; + return 0; } - else - { - /* TODO: Open pipes of different process. Is that possible? */ - } + set_errno (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; + } + if (!(fh = p->pipe_fhandler (pipe_hdl, size)) || !size) + { + set_errno (ENOENT); + goto out; + } + /* Too bad, but Windows only allows the same access mode when dup'ing + the pipe. */ + if ((rwflags == O_RDONLY && !(fh->get_access () & GENERIC_READ)) + || (rwflags == O_WRONLY && !(fh->get_access () & GENERIC_WRITE))) + { + set_errno (EACCES); + goto out; + } + if (!DuplicateHandle (proc, pipe_hdl, hMainProc, &nio_hdl, + 0, false, DUPLICATE_SAME_ACCESS)) + { + __seterrno (); + goto out; + } + if (fh->writepipe_exists + && !DuplicateHandle (proc, fh->writepipe_exists, + hMainProc, &nwrp_hdl, + 0, false, DUPLICATE_SAME_ACCESS)) + { + __seterrno (); + goto out; + } + if (fh->read_state) + { + create_read_state (2); + need_fork_fixup (true); + ProtectHandle1 (read_state, read_state); } + if (fh->get_guard ()) + create_guard ((flags & O_NOINHERIT) ? &sec_none_nih : &sec_none); + init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY); + writepipe_exists = nwrp_hdl; + if (flags & O_NOINHERIT) + close_on_exec (true); + uninterruptible_io (fh->uninterruptible_io ()); + free (fh); + CloseHandle (proc); + return 1; out: - set_errno (ENXIO); + if (nwrp_hdl) + CloseHandle (nwrp_hdl); + if (nio_hdl) + CloseHandle (nio_hdl); + if (fh) + free (fh); + if (proc) + CloseHandle (proc); return 0; } |