diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index adb84414e..8bcf83f0e 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -182,8 +182,9 @@ class fhandler_base size_t rabuflen; /* Used for advisory file locking. See flock.cc. */ - long long unique_id; + int64_t unique_id; void del_my_locks (del_lock_called_from); + void set_ino (ino_t i) { ino = i; } HANDLE read_state; @@ -304,7 +305,7 @@ class fhandler_base const char *get_win32_name () { return pc.get_win32 (); } virtual dev_t get_dev () { return get_device (); } ino_t get_ino () { return ino ?: ino = hash_path_name (0, pc.get_nt_native_path ()); } - long long get_unique_id () const { return unique_id; } + int64_t get_unique_id () const { return unique_id; } /* Returns name used for /proc//fd in buf. */ virtual char *get_proc_fd_name (char *buf); @@ -319,6 +320,7 @@ class fhandler_base int open_null (int flags); virtual int open (int, mode_t); virtual void open_setup (int flags); + void set_unique_id (int64_t u) { unique_id = u; } void set_unique_id () { NtAllocateLocallyUniqueId ((PLUID) &unique_id); } int close_with_arch (); @@ -731,13 +733,14 @@ public: int open (int flags, mode_t mode = 0); int dup (fhandler_base *child, int); int ioctl (unsigned int cmd, void *); + int __reg2 fstat (struct stat *buf); int __reg2 fstatvfs (struct statvfs *buf); int __reg3 fadvise (off_t, off_t, int); int __reg3 ftruncate (off_t, bool); - int init (HANDLE, DWORD, mode_t); + int init (HANDLE, DWORD, mode_t, int64_t); static int create (fhandler_pipe *[2], unsigned, int); static DWORD create (LPSECURITY_ATTRIBUTES, HANDLE *, HANDLE *, DWORD, - const char *, DWORD); + const char *, DWORD, int64_t *unique_id = NULL); fhandler_pipe (void *) {} void copyto (fhandler_base *x) diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 21bc7316e..094cc65e8 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -594,6 +594,7 @@ fhandler_socket::init_events () InterlockedIncrement (&socket_serial_number); if (!new_serial_number) /* 0 is reserved for global mutex */ InterlockedIncrement (&socket_serial_number); + set_ino (new_serial_number); RtlInitUnicodeString (&uname, sock_shared_name (name, new_serial_number)); InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF, get_session_parent_dir (), @@ -937,8 +938,8 @@ fhandler_socket::fstat (struct stat *buf) res = fhandler_base::fstat (buf); if (!res) { - buf->st_dev = 0; - buf->st_ino = (ino_t) ((uintptr_t) get_handle ()); + buf->st_dev = FHDEV (DEV_TCP_MAJOR, 0); + buf->st_ino = (ino_t) get_ino (); buf->st_mode = S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO; buf->st_size = 0; } diff --git a/winsup/cygwin/include/cygwin/signal.h b/winsup/cygwin/include/cygwin/signal.h index 350a91219..04ddb69d7 100644 --- a/winsup/cygwin/include/cygwin/signal.h +++ b/winsup/cygwin/include/cygwin/signal.h @@ -188,7 +188,7 @@ struct _sigcommune __extension__ union { int _si_fd; - void *_si_pipe_fhandler; + int64_t _si_pipe_unique_id; char *_si_str; }; }; diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index d0b4cd9a4..be32cfd59 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -622,11 +622,11 @@ commune_process (void *arg) case PICOM_PIPE_FHANDLER: { sigproc_printf ("processing PICOM_FDS"); - HANDLE hdl = si._si_commune._si_pipe_fhandler; + int64_t unique_id = si._si_commune._si_pipe_unique_id; unsigned int n = 0; cygheap_fdenum cfd; while (cfd.next () >= 0) - if (cfd->get_handle () == hdl) + if (cfd->get_unique_id () == unique_id) { fhandler_pipe *fh = cfd; n = sizeof *fh; @@ -701,7 +701,7 @@ _pinfo::commune_request (__uint32_t code, ...) switch (code) { case PICOM_PIPE_FHANDLER: - si._si_commune._si_pipe_fhandler = va_arg (args, HANDLE); + si._si_commune._si_pipe_unique_id = va_arg (args, int64_t); break; case PICOM_FD: @@ -781,13 +781,13 @@ out: } fhandler_pipe * -_pinfo::pipe_fhandler (HANDLE hdl, size_t &n) +_pinfo::pipe_fhandler (int64_t unique_id, size_t &n) { if (!this || !pid) return NULL; if (pid == myself->pid) return NULL; - commune_result cr = commune_request (PICOM_PIPE_FHANDLER, hdl); + commune_result cr = commune_request (PICOM_PIPE_FHANDLER, unique_id); n = cr.n; return (fhandler_pipe *) cr.s; } diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h index 1d6a72cfa..65a9e89ff 100644 --- a/winsup/cygwin/pinfo.h +++ b/winsup/cygwin/pinfo.h @@ -103,7 +103,7 @@ public: commune_result commune_request (__uint32_t, ...); bool alive (); - fhandler_pipe *pipe_fhandler (HANDLE, size_t &); + fhandler_pipe *pipe_fhandler (int64_t, 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 945c8fc24..4ec4fa48e 100644 --- a/winsup/cygwin/pipe.cc +++ b/winsup/cygwin/pipe.cc @@ -31,7 +31,7 @@ fhandler_pipe::fhandler_pipe () } int -fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode) +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 @@ -54,6 +54,8 @@ fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode) 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 @@ -66,27 +68,33 @@ extern "C" int sscanf (const char *, const char *, ...); int fhandler_pipe::open (int flags, mode_t mode) { - HANDLE proc, pipe_hdl, nio_hdl = NULL; - fhandler_pipe *fh = NULL; + 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; - sscanf (get_name (), "/proc/%d/fd/pipe:[%lu]", - &pid, (unsigned long *) &pipe_hdl); + sscanf (get_name (), "/proc/%d/fd/pipe:[%lld]", + &pid, (long long *) &uniq_id); if (pid == myself->pid) { cygheap_fdenum cfd (true); while (cfd.next () >= 0) { - if (cfd->get_handle () != pipe_hdl) + /* 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))) - { - set_errno (EACCES); - return 0; - } + continue; cfd->copyto (this); set_io_handle (NULL); pc.reset_conv_handle (); @@ -94,7 +102,9 @@ fhandler_pipe::open (int flags, mode_t mode) return 1; return 0; } - set_errno (ENOENT); + /* Found the pipe but access mode didn't match? EACCES. + Otherwise ENOENT */ + set_errno (got_one ? EACCES : ENOENT); return 0; } @@ -109,27 +119,30 @@ fhandler_pipe::open (int flags, mode_t mode) __seterrno (); return 0; } - if (!(fh = p->pipe_fhandler (pipe_hdl, size)) || !size) + fhr = p->pipe_fhandler (uniq_id, size); + if (fhr && rwflags == O_RDONLY) + fh = fhr; + else { - set_errno (ENOENT); - goto out; + fhw = p->pipe_fhandler (uniq_id + 1, size); + if (fhw && rwflags == O_WRONLY) + fh = fhw; } - /* 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))) + if (!fh) { - set_errno (EACCES); + /* 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, pipe_hdl, GetCurrentProcess (), &nio_hdl, - 0, inh, DUPLICATE_SAME_ACCESS)) + 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); + init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY, fh->get_ino ()); cfree (fh); CloseHandle (proc); return 1; @@ -168,7 +181,7 @@ fhandler_pipe::ftruncate (off_t length, bool allow_truncate) char * fhandler_pipe::get_proc_fd_name (char *buf) { - __small_sprintf (buf, "pipe:[%lu]", get_handle ()); + __small_sprintf (buf, "pipe:[%D]", get_ino ()); return buf; } @@ -199,7 +212,8 @@ fhandler_pipe::dup (fhandler_base *child, int flags) 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) + DWORD psize, const char *name, DWORD open_mode, + int64_t *unique_id) { /* Default to error. */ if (r) @@ -241,8 +255,12 @@ fhandler_pipe::create (LPSECURITY_ATTRIBUTES sa_ptr, PHANDLE r, PHANDLE w, { static volatile ULONG pipe_unique_id; if (!name) - __small_sprintf (pipename + len, "pipe-%p", - InterlockedIncrement ((LONG *) &pipe_unique_id)); + { + 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) @@ -341,8 +359,9 @@ 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); + 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) @@ -358,8 +377,10 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode) else { mode |= mode & O_TEXT ?: O_BINARY; - fhs[0]->init (r, FILE_CREATE_PIPE_INSTANCE | GENERIC_READ, mode); - fhs[1]->init (w, FILE_CREATE_PIPE_INSTANCE | GENERIC_WRITE, mode); + 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; } @@ -394,6 +415,21 @@ fhandler_pipe::ioctl (unsigned int cmd, void *p) return 0; } +int __reg2 +fhandler_pipe::fstat (struct stat *buf) +{ + int ret = fhandler_base::fstat (buf); + if (!ret) + { + buf->st_dev = FH_PIPE; + /* Don't use get_ino, it doesn't return 0 but a hash instead. */ + if (!(buf->st_ino = get_unique_id ())) + sscanf (get_name (), "/proc/%*d/fd/pipe:[%lld]", + (long long *) &buf->st_ino); + } + return ret; +} + int __reg2 fhandler_pipe::fstatvfs (struct statvfs *sfs) { @@ -410,10 +446,10 @@ pipe_worker (int filedes[2], unsigned int psize, int mode) { cygheap_fdnew fdin; cygheap_fdnew fdout (fdin, false); - char buf[sizeof ("/dev/fd/pipe:[2147483647]")]; - __small_sprintf (buf, "/dev/fd/pipe:[%d]", (int) fdin); + char buf[sizeof ("/dev/fd/pipe:[9223372036854775807]")]; + __small_sprintf (buf, "/dev/fd/pipe:[%D]", fhs[0]->get_ino ()); fhs[0]->pc.set_posix (buf); - __small_sprintf (buf, "pipe:[%d]", (int) fdout); + __small_sprintf (buf, "pipe:[%D]", fhs[1]->get_ino ()); fhs[1]->pc.set_posix (buf); fdin = fhs[0]; fdout = fhs[1]; diff --git a/winsup/cygwin/release/2.4.0 b/winsup/cygwin/release/2.4.0 index ed035af5c..6247fb8f4 100644 --- a/winsup/cygwin/release/2.4.0 +++ b/winsup/cygwin/release/2.4.0 @@ -81,3 +81,6 @@ Bug Fixes - *Always* zero out descriptor arrays when returning from select due to timeout, per POSIX. Addresses: https://cygwin.com/ml/cygwin/2015-12/msg00332.html + +- Return unique inode numbers when calling stat/fstat on pipes and IP sockets. + Addresses: https://cygwin.com/ml/cygwin/2015-12/msg00310.html