aboutsummaryrefslogtreecommitdiff
path: root/winsup/cygwin/fhandler
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/fhandler')
-rw-r--r--winsup/cygwin/fhandler/base.cc48
-rw-r--r--winsup/cygwin/fhandler/console.cc56
-rw-r--r--winsup/cygwin/fhandler/pty.cc30
-rw-r--r--winsup/cygwin/fhandler/socket_local.cc2
-rw-r--r--winsup/cygwin/fhandler/termios.cc31
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;
+ }
+}