diff options
Diffstat (limited to 'winsup/cygwin/fhandler')
-rw-r--r-- | winsup/cygwin/fhandler/base.cc | 48 | ||||
-rw-r--r-- | winsup/cygwin/fhandler/console.cc | 56 | ||||
-rw-r--r-- | winsup/cygwin/fhandler/pty.cc | 30 | ||||
-rw-r--r-- | winsup/cygwin/fhandler/socket_local.cc | 2 | ||||
-rw-r--r-- | winsup/cygwin/fhandler/termios.cc | 31 |
5 files changed, 140 insertions, 27 deletions
diff --git a/winsup/cygwin/fhandler/base.cc b/winsup/cygwin/fhandler/base.cc index a5d15c7..32aca2c 100644 --- a/winsup/cygwin/fhandler/base.cc +++ b/winsup/cygwin/fhandler/base.cc @@ -526,8 +526,9 @@ fhandler_base::open (int flags, mode_t mode) ULONG file_attributes = 0; ULONG shared = (get_major () == DEV_TAPE_MAJOR ? 0 : FILE_SHARE_VALID_FLAGS); ULONG create_disposition; + FILE_BASIC_INFORMATION fbi; OBJECT_ATTRIBUTES attr; - IO_STATUS_BLOCK io; + IO_STATUS_BLOCK io, io_bi; NTSTATUS status; PFILE_FULL_EA_INFORMATION p = NULL; ULONG plen = 0; @@ -719,16 +720,32 @@ fhandler_base::open (int flags, mode_t mode) goto done; } - if (io.Information == FILE_CREATED) - { - /* Correct file attributes are needed for later use in, e.g. fchmod. */ - FILE_BASIC_INFORMATION fbi; + /* Fix up file attributes, they are desperately needed later. + + Originally we only did that in the FILE_CREATED case below, but that's + insufficient: - if (!NT_SUCCESS (NtQueryInformationFile (fh, &io, &fbi, sizeof fbi, - FileBasicInformation))) - fbi.FileAttributes = file_attributes | FILE_ATTRIBUTE_ARCHIVE; - pc.file_attributes (fbi.FileAttributes); + If two threads try to create the same file at the same time, it's + possible that path_conv::check returns the file as non-existant, i. e., + pc.file_attributes () returns INVALID_FILE_ATTRIBUTES, 0xffffffff. + However, one of the NtCreateFile will beat the other, so only one of + them returns with FILE_CREATED. + The other fhandler_base::open() will instead run into the O_TRUNC + conditional (further below), blindly check for the SPARSE attribute + and remove that bit. The result is that the attributes will be + 0xfffffdff, i.e., everything but SPARSE. Most annoying is that + pc.isdir() will return TRUE. Hilarity ensues. + + Note that we use a different IO_STATUS_BLOCK, so as not to overwrite + io.Information... */ + if (!NT_SUCCESS (NtQueryInformationFile (fh, &io_bi, &fbi, sizeof fbi, + FileBasicInformation))) + fbi.FileAttributes = file_attributes | FILE_ATTRIBUTE_ARCHIVE; + pc.file_attributes (fbi.FileAttributes); + + if (io.Information == FILE_CREATED) + { /* Always create files using a NULL SD. Create correct permission bits afterwards, maintaining the owner and group information just like chmod. This is done for two reasons. @@ -752,18 +769,17 @@ fhandler_base::open (int flags, mode_t mode) set_created_file_access (fh, pc, mode); } - /* If you O_TRUNC a file on Linux, the data is truncated, but the EAs are - preserved. If you open a file on Windows with FILE_OVERWRITE{_IF} or - FILE_SUPERSEDE, all streams are truncated, including the EAs. So we don't - use the FILE_OVERWRITE{_IF} flags, but instead just open the file and set - the size of the data stream explicitely to 0. Apart from being more Linux - compatible, this implementation has the pleasant side-effect to be more - than 5% faster than using FILE_OVERWRITE{_IF} (tested on W7 32 bit). */ if ((flags & O_TRUNC) && (flags & O_ACCMODE) != O_RDONLY && io.Information != FILE_CREATED && get_device () == FH_FS) { + /* If you O_TRUNC a file on Linux, the data is truncated, but the EAs are + preserved. If you open a file on Windows with FILE_OVERWRITE{_IF} or + FILE_SUPERSEDE, all streams are truncated, including the EAs. So we + don't use FILE_OVERWRITE{_IF} but just open the file and truncate the + data stream to size 0. Apart from being more Linux compatible, this + has the pleasant side-effect to be more than 5% faster. */ FILE_END_OF_FILE_INFORMATION feofi = { EndOfFile:{ QuadPart:0 } }; status = NtSetInformationFile (fh, &io, &feofi, sizeof feofi, FileEndOfFileInformation); diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index f162698..2e19e0d 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -509,7 +509,7 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp) case not_signalled_but_done: case done_with_debugger: processed = true; - ttyp->output_stopped = false; + ttyp->output_stopped &= ~BY_VSTOP; if (ti.c_lflag & NOFLSH) goto remove_record; con.num_processed = 0; @@ -932,7 +932,7 @@ fhandler_console::cleanup_for_non_cygwin_app (handle_set_t *p) /* Cleaning-up console mode for non-cygwin app. */ /* conmode can be tty::restore when non-cygwin app is exec'ed from login shell. */ - tty::cons_mode conmode = cons_mode_on_close (); + tty::cons_mode conmode = cons_mode_on_close (p); set_output_mode (conmode, ti, p); set_input_mode (conmode, ti, p); set_disable_master_thread (con.owner == GetCurrentProcessId ()); @@ -1144,6 +1144,15 @@ fhandler_console::read (void *pv, size_t& buflen) push_process_state process_state (PID_TTYIN); + if (get_ttyp ()->input_stopped && is_nonblocking ()) + { + set_errno (EAGAIN); + buflen = (size_t) -1; + return; + } + while (get_ttyp ()->input_stopped) + cygwait (10); + size_t copied_chars = 0; DWORD timeout = is_nonblocking () ? 0 : @@ -1991,8 +2000,9 @@ fhandler_console::close (int flag) acquire_output_mutex (mutex_timeout); - if (shared_console_info[unit] && myself->ppid == 1 - && (dev_t) myself->ctty == get_device ()) + if (shared_console_info[unit] && con.curr_input_mode != tty::restore + && (dev_t) myself->ctty == get_device () + && cons_mode_on_close (&handle_set) == tty::restore) { set_output_mode (tty::restore, &get_ttyp ()->ti, &handle_set); set_input_mode (tty::restore, &get_ttyp ()->ti, &handle_set); @@ -2131,6 +2141,7 @@ fhandler_console::ioctl (unsigned int cmd, void *arg) release_output_mutex (); return -1; case FIONREAD: + case TIOCINQ: { DWORD n; int ret = 0; @@ -2183,6 +2194,14 @@ fhandler_console::ioctl (unsigned int cmd, void *arg) return 0; } break; + case TCXONC: + res = this->tcflow ((int)(intptr_t) arg); + release_output_mutex (); + return res; + case TCFLSH: + res = this->tcflush ((int)(intptr_t) arg); + release_output_mutex (); + return res; } release_output_mutex (); @@ -2215,6 +2234,8 @@ int fhandler_console::tcsetattr (int a, struct termios const *t) { get_ttyp ()->ti = *t; + set_input_mode (tty::cygwin, t, &handle_set); + set_output_mode (tty::cygwin, t, &handle_set); return 0; } @@ -4170,8 +4191,8 @@ fhandler_console::write (const void *vsrc, size_t len) void fhandler_console::doecho (const void *str, DWORD len) { - bool stopped = get_ttyp ()->output_stopped; - get_ttyp ()->output_stopped = false; + int stopped = get_ttyp ()->output_stopped; + get_ttyp ()->output_stopped = 0; write (str, len); get_ttyp ()->output_stopped = stopped; } @@ -4702,10 +4723,31 @@ fhandler_console::fstat (struct stat *st) } tty::cons_mode -fhandler_console::cons_mode_on_close () +fhandler_console::cons_mode_on_close (handle_set_t *p) { + int unit = p->unit; if (myself->ppid != 1) /* Execed from normal cygwin process. */ return tty::cygwin; + if (!process_alive (con.owner)) /* The Master process already died. */ + return tty::restore; + if (con.owner == GetCurrentProcessId ()) /* Master process */ + return tty::restore; + + PROCESS_BASIC_INFORMATION pbi; + NTSTATUS status = + NtQueryInformationProcess (GetCurrentProcess (), ProcessBasicInformation, + &pbi, sizeof (pbi), NULL); + if (NT_SUCCESS (status) + && !process_alive ((DWORD) pbi.InheritedFromUniqueProcessId)) + /* Execed from normal cygwin process and the parent has been exited. */ + return tty::cygwin; + return tty::restore; /* otherwise, restore */ } + +int +fhandler_console::tcdrain () +{ + return 0; +} diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index 3128b92..b882b90 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -1304,6 +1304,15 @@ fhandler_pty_slave::read (void *ptr, size_t& len) push_process_state process_state (PID_TTYIN); + if (get_ttyp ()->input_stopped && is_nonblocking ()) + { + set_errno (EAGAIN); + len = (size_t) -1; + return; + } + while (get_ttyp ()->input_stopped) + cygwait (10); + if (ptr) /* Indicating not tcflush(). */ mask_switch_to_nat_pipe (true, true); @@ -1650,6 +1659,7 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg) retval = this->tcsetpgrp ((pid_t) (intptr_t) arg); goto out; case FIONREAD: + case TIOCINQ: { DWORD n; if (!bytes_available (n)) @@ -1664,6 +1674,12 @@ fhandler_pty_slave::ioctl (unsigned int cmd, void *arg) } } goto out; + case TCXONC: + retval = this->tcflow ((int)(intptr_t) arg); + goto out; + case TCFLSH: + retval = this->tcflush ((int)(intptr_t) arg); + goto out; default: return fhandler_base::ioctl (cmd, arg); } @@ -2342,6 +2358,7 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg) case TIOCSPGRP: return this->tcsetpgrp ((pid_t) (intptr_t) arg); case FIONREAD: + case TIOCINQ: { DWORD n; if (!bytes_available (n)) @@ -2352,6 +2369,10 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg) *(int *) arg = (int) n; } break; + case TCXONC: + return this->tcflow ((int)(intptr_t) arg); + case TCFLSH: + return this->tcflush ((int)(intptr_t) arg); default: return fhandler_base::ioctl (cmd, arg); } @@ -4194,3 +4215,12 @@ fhandler_pty_common::resume_from_temporarily_attach (DWORD resume_pid) } release_attach_mutex (); } + +int +fhandler_pty_common::tcdrain () +{ + DWORD n; + while (bytes_available (n) && n > 0) + cygwait (10); + return 0; +} diff --git a/winsup/cygwin/fhandler/socket_local.cc b/winsup/cygwin/fhandler/socket_local.cc index 270a1ef..ea5ee67 100644 --- a/winsup/cygwin/fhandler/socket_local.cc +++ b/winsup/cygwin/fhandler/socket_local.cc @@ -87,6 +87,8 @@ get_inet_addr_local (const struct sockaddr *in, int inlen, addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); *outlen = sizeof addr; memcpy (out, &addr, *outlen); + if (type) + *type = SOCK_DGRAM; return 0; } diff --git a/winsup/cygwin/fhandler/termios.cc b/winsup/cygwin/fhandler/termios.cc index a3cecdb..19d6220 100644 --- a/winsup/cygwin/fhandler/termios.cc +++ b/winsup/cygwin/fhandler/termios.cc @@ -491,16 +491,16 @@ fhandler_termios::process_stop_start (char c, tty *ttyp) { if (CCEQ (ti.c_cc[VSTOP], c)) { - ttyp->output_stopped = true; + ttyp->output_stopped |= BY_VSTOP; return true; } else if (CCEQ (ti.c_cc[VSTART], c)) { restart_output: - ttyp->output_stopped = false; + ttyp->output_stopped &= ~BY_VSTOP; return true; } - else if ((ti.c_iflag & IXANY) && ttyp->output_stopped) + else if ((ti.c_iflag & IXANY) && (ttyp->output_stopped & BY_VSTOP)) goto restart_output; } if ((ti.c_lflag & ICANON) && (ti.c_lflag & IEXTEN) @@ -540,7 +540,7 @@ fhandler_termios::line_edit (const char *rptr, size_t nread, termios& ti, fallthrough; case not_signalled_but_done: case done_with_debugger: - get_ttyp ()->output_stopped = false; + get_ttyp ()->output_stopped &= ~BY_VSTOP; continue; case not_signalled_with_nat_reader: disable_eof_key = true; @@ -915,3 +915,26 @@ fhandler_termios::get_console_process_id (DWORD pid, bool match, } return res_pri ?: res; } + +int +fhandler_termios::tcflow (int action) +{ + switch (action) + { + case TCOOFF: + get_ttyp ()->output_stopped |= BY_TCFLOW; + return 0; + case TCOON: + get_ttyp ()->output_stopped = 0; + return 0; + case TCIOFF: + get_ttyp ()->input_stopped |= BY_TCFLOW; + return 0; + case TCION: + get_ttyp ()->input_stopped = 0; + return 0; + default: + set_errno (EINVAL); + return -1; + } +} |