[PATCH] Cygwin: document a recent bug fix

2021-01-15 Thread Ken Brown via Cygwin-patches
This documents commit aec64798, "Cygwin: add flag to indicate reparse
points unknown to WinAPI".
---
 winsup/cygwin/release/3.2.0 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/winsup/cygwin/release/3.2.0 b/winsup/cygwin/release/3.2.0
index 132d5c810..c18a848de 100644
--- a/winsup/cygwin/release/3.2.0
+++ b/winsup/cygwin/release/3.2.0
@@ -43,5 +43,8 @@ Bug Fixes
 - Fix return value of sqrtl on negative infinity.
   Addresses: https://cygwin.com/pipermail/cygwin/2020-October/246606.html
 
+- Fix a path handling problem if there is a WSL symlink in PATH.
+  Addresses: https://cygwin.com/pipermail/cygwin/2020-December/246938.html
+
 - Fix a bug in fstatat(2) on 32 bit that could cause it to return garbage.
   Addresses: https://cygwin.com/pipermail/cygwin/2021-January/247399.html
-- 
2.30.0



Re: [PATCH] Cygwin: document a recent bug fix

2021-01-15 Thread Ken Brown via Cygwin-patches

On 1/15/2021 12:42 PM, Ken Brown via Cygwin-patches wrote:

This documents commit b951adce, "Cygwin: add flag to indicate reparse
points unknown to WinAPI".


Sorry, there's a mistake in the commit message.  A corrected version is on the 
way.

Ken


[PATCH] Cygwin: document a recent bug fix

2021-01-15 Thread Ken Brown via Cygwin-patches
This documents commit b951adce, "Cygwin: add flag to indicate reparse
points unknown to WinAPI".
---
 winsup/cygwin/release/3.2.0 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/winsup/cygwin/release/3.2.0 b/winsup/cygwin/release/3.2.0
index 132d5c810..c18a848de 100644
--- a/winsup/cygwin/release/3.2.0
+++ b/winsup/cygwin/release/3.2.0
@@ -43,5 +43,8 @@ Bug Fixes
 - Fix return value of sqrtl on negative infinity.
   Addresses: https://cygwin.com/pipermail/cygwin/2020-October/246606.html
 
+- Fix a path handling problem if there is a WSL symlink in PATH.
+  Addresses: https://cygwin.com/pipermail/cygwin/2020-December/246938.html
+
 - Fix a bug in fstatat(2) on 32 bit that could cause it to return garbage.
   Addresses: https://cygwin.com/pipermail/cygwin/2021-January/247399.html
-- 
2.30.0



[PATCH 11/11] dir.cc: Try unlink_nt first

2021-01-15 Thread Ben Wijen
Speedup deletion of directories.
---
 winsup/cygwin/dir.cc | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc
index f912a9e47..2e7da3638 100644
--- a/winsup/cygwin/dir.cc
+++ b/winsup/cygwin/dir.cc
@@ -22,6 +22,8 @@ details. */
 #include "cygtls.h"
 #include "tls_pbuf.h"
 
+extern NTSTATUS unlink_nt (const char *ourname, ULONG eflags);
+
 extern "C" int
 dirfd (DIR *dir)
 {
@@ -398,6 +400,10 @@ rmdir (const char *dir)
  if (msdos && p == dir + 1 && isdrive (dir))
p[1] = '\\';
}
+  if(NT_SUCCESS(unlink_nt (dir, FILE_DIRECTORY_FILE))) {
+res = 0;
+__leave;
+  }
   if (!(fh = build_fh_name (dir, PC_SYM_NOFOLLOW)))
__leave;   /* errno already set */;
 
-- 
2.29.2



[PATCH 08/11] path.cc: Allow to skip filesystem checks

2021-01-15 Thread Ben Wijen
When file attributes are of no concern,
there is no point to query them.
---
 winsup/cygwin/path.cc | 3 +++
 winsup/cygwin/path.h  | 1 +
 2 files changed, 4 insertions(+)

diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index abd3687df..f00707e86 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -931,7 +931,10 @@ path_conv::check (const char *src, unsigned opt,
 
 is_fs_via_procsys:
 
+   if (!(opt & PC_SKIP_SYM_CHECK))
+   {
  symlen = sym.check (full_path, suff, fs, conv_handle);
+   }
 
 is_virtual_symlink:
 
diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h
index 62bd5ddd5..56855e1c9 100644
--- a/winsup/cygwin/path.h
+++ b/winsup/cygwin/path.h
@@ -59,6 +59,7 @@ enum pathconv_arg
   PC_KEEP_HANDLE= _BIT (12),   /* keep handle for later stat calls */
   PC_NO_ACCESS_CHECK= _BIT (13),   /* helper flag for error check */
   PC_SYM_NOFOLLOW_DIR   = _BIT (14),   /* don't follow a trailing slash */
+  PC_SKIP_SYM_CHECK = _BIT (15),   /* skip symlink_info::check */
   PC_DONT_USE   = _BIT (31)/* conversion to signed happens. */
 };
 
-- 
2.29.2



[PATCH 09/11] mount.cc: Implement poor-man's cache

2021-01-15 Thread Ben Wijen
Try to avoid NtQueryVolumeInformationFile.
---
 winsup/cygwin/mount.cc | 78 --
 winsup/cygwin/mount.h  |  2 +-
 winsup/cygwin/path.cc  |  2 +-
 winsup/cygwin/path.h   |  1 +
 4 files changed, 56 insertions(+), 27 deletions(-)

diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc
index e0349815d..1d2b3a61a 100644
--- a/winsup/cygwin/mount.cc
+++ b/winsup/cygwin/mount.cc
@@ -82,6 +82,32 @@ win32_device_name (const char *src_path, char *win32_path, 
device& dev)
   return true;
 }
 
+static uint32_t
+hash_prefix (const PUNICODE_STRING upath)
+{
+  UNICODE_STRING prefix;
+  WCHAR *p;
+
+  if (upath->Buffer[5] == L':' && upath->Buffer[6] == L'\\')
+p = upath->Buffer + 6;
+  else
+{
+  /* We're expecting an UNC path.  Move p to the backslash after
+   "\??\UNC\server\share" or the trailing NUL. */
+  p = upath->Buffer + 7; /* Skip "\??\UNC" */
+  int bs_cnt = 0;
+
+  while (*++p)
+if (*p == L'\\')
+  if (++bs_cnt > 1)
+break;
+}
+  RtlInitCountedUnicodeString (, upath->Buffer,
+   (p - upath->Buffer) * sizeof(WCHAR));
+
+  return hash_path_name ((ino_t) 0, );
+}
+
 /* Beginning with Samba 3.0.28a, Samba allows to get version information using
the ExtendedInfo member returned by a FileFsObjectIdInformation request.
We just store the samba_version information for now.  Older versions than
@@ -106,14 +132,16 @@ class fs_info_cache
   struct {
 fs_info fsi;
 uint32_t hash;
+uint32_t prefix_hash;
   } entry[MAX_FS_INFO_CNT];
 
   uint32_t genhash (PFILE_FS_VOLUME_INFORMATION);
 
 public:
   fs_info_cache () : count (0) { fsi_lock.init ("fsi_lock"); }
+  fs_info *search (uint32_t);
   fs_info *search (PFILE_FS_VOLUME_INFORMATION, uint32_t &);
-  void add (uint32_t, fs_info *);
+  void add (uint32_t, fs_info *, uint32_t);
 };
 
 static fs_info_cache fsi_cache;
@@ -142,22 +170,31 @@ fs_info_cache::search (PFILE_FS_VOLUME_INFORMATION pffvi, 
uint32_t )
   return [i].fsi;
   return NULL;
 }
+fs_info*
+fs_info_cache::search (uint32_t prefix_hash)
+{
+  for (uint32_t i = 0; i < count; ++i)
+if (entry[i].prefix_hash == prefix_hash)
+  return [i].fsi;
+  return NULL;
+}
 
 void
-fs_info_cache::add (uint32_t hashval, fs_info *new_fsi)
+fs_info_cache::add (uint32_t hashval, fs_info *new_fsi, uint32_t prefix_hash)
 {
   fsi_lock.acquire ();
   if (count < MAX_FS_INFO_CNT)
 {
   entry[count].fsi = *new_fsi;
   entry[count].hash = hashval;
+  entry[count].prefix_hash = prefix_hash;
   ++count;
 }
   fsi_lock.release ();
 }
 
 bool
-fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
+fs_info::update (PUNICODE_STRING upath, HANDLE in_vol, bool use_prefix_hash)
 {
   NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
   HANDLE vol;
@@ -178,6 +215,17 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
   UNICODE_STRING fsname;
 
   clear ();
+
+  if (use_prefix_hash)
+{
+  fs_info *fsi = fsi_cache.search (hash_prefix (upath));
+  if (fsi)
+{
+  *this = *fsi;
+  return true;
+}
+}
+
   /* Always caseinsensitive.  We really just need access to the drive. */
   InitializeObjectAttributes (, upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
   if (in_vol)
@@ -233,27 +281,7 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
 a unique per-drive/share hash. */
   if (ffvi_buf.ffvi.VolumeSerialNumber == 0)
{
- UNICODE_STRING path_prefix;
- WCHAR *p;
-
- if (upath->Buffer[5] == L':' && upath->Buffer[6] == L'\\')
-   p = upath->Buffer + 6;
- else
-   {
- /* We're expecting an UNC path.  Move p to the backslash after
-"\??\UNC\server\share" or the trailing NUL. */
- p = upath->Buffer + 7;  /* Skip "\??\UNC" */
- int bs_cnt = 0;
-
- while (*++p)
-   if (*p == L'\\')
-   if (++bs_cnt > 1)
- break;
-   }
- RtlInitCountedUnicodeString (_prefix, upath->Buffer,
-  (p - upath->Buffer) * sizeof (WCHAR));
- ffvi_buf.ffvi.VolumeSerialNumber = hash_path_name ((ino_t) 0,
-_prefix);
+ ffvi_buf.ffvi.VolumeSerialNumber = hash_prefix(upath);
}
   fs_info *fsi = fsi_cache.search (_buf.ffvi, hash);
   if (fsi)
@@ -460,7 +488,7 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
 
   if (!in_vol)
 NtClose (vol);
-  fsi_cache.add (hash, this);
+  fsi_cache.add (hash, this, hash_prefix (upath));
   return true;
 }
 
diff --git a/winsup/cygwin/mount.h b/winsup/cygwin/mount.h
index 122a679a8..86b72fb4c 100644
--- a/winsup/cygwin/mount.h
+++ b/winsup/cygwin/mount.h
@@ -124,7 +124,7 @@ class fs_info
 
   const char *fsname () const { return fsn[0] ? fsn : "unknown"; }
 
-  bool __reg3 update 

[PATCH 10/11] syscalls.cc: Expose shallow-pathconv unlink_nt

2021-01-15 Thread Ben Wijen
Not having to query file information improves unlink speed.
---
 winsup/cygwin/syscalls.cc | 68 ---
 1 file changed, 42 insertions(+), 26 deletions(-)

diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 79e4a4422..8aecdf453 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1305,6 +1305,18 @@ _unlink_ntpc_ (path_conv& pc, bool shareable)
   return status;
 }
 
+NTSTATUS
+unlink_nt (const char *ourname, ULONG eflags)
+{
+  path_conv pc (ourname, PC_SYM_NOFOLLOW | PC_FS_USE_PREFIX_HASH | 
PC_SKIP_SYM_CHECK, NULL);
+  dev_t devn = pc.get_device ();
+  if (pc.error || isproc_dev (devn))
+return STATUS_CANNOT_DELETE;
+
+  PUNICODE_STRING ntpath = pc.get_nt_native_path ();
+  return _unlink_nt (ntpath, eflags, 0);
+}
+
 NTSTATUS
 unlink_ntpc (path_conv )
 {
@@ -1322,37 +1334,41 @@ unlink (const char *ourname)
 {
   int res = -1;
   dev_t devn;
-  NTSTATUS status;
+  NTSTATUS status = unlink_nt (ourname, FILE_NON_DIRECTORY_FILE);
 
-  path_conv win32_name (ourname, PC_SYM_NOFOLLOW, stat_suffixes);
+  if (!NT_SUCCESS (status))
+  {
+path_conv win32_name (ourname, PC_SYM_NOFOLLOW, stat_suffixes);
 
-  if (win32_name.error)
-{
-  set_errno (win32_name.error);
-  goto done;
-}
+if (win32_name.error)
+  {
+set_errno (win32_name.error);
+goto done;
+  }
 
-  devn = win32_name.get_device ();
-  if (isproc_dev (devn))
-{
-  set_errno (EROFS);
-  goto done;
-}
+devn = win32_name.get_device ();
+if (isproc_dev (devn))
+  {
+set_errno (EROFS);
+goto done;
+  }
 
-  if (!win32_name.exists ())
-{
-  debug_printf ("unlinking a nonexistent file");
-  set_errno (ENOENT);
-  goto done;
-}
-  else if (win32_name.isdir ())
-{
-  debug_printf ("unlinking a directory");
-  set_errno (EISDIR);
-  goto done;
-}
+if (!win32_name.exists ())
+  {
+debug_printf ("unlinking a nonexistent file");
+set_errno (ENOENT);
+goto done;
+  }
+else if (win32_name.isdir ())
+  {
+debug_printf ("unlinking a directory");
+set_errno (EISDIR);
+goto done;
+  }
+
+status = unlink_ntpc (win32_name);
+  }
 
-  status = unlink_ntpc (win32_name);
   if (NT_SUCCESS (status))
 res = 0;
   else
-- 
2.29.2



[PATCH 06/11] cxx.cc: Fix dynamic initialization for static local variables

2021-01-15 Thread Ben Wijen
The old implementation for __cxa_guard_acquire did not return 1,
therefore dynamic initialization was never performed.

If concurrent-safe dynamic initialisation is ever needed, CXX ABI
must be followed when re-implementing __cxa_guard_acquire (et al.)
---
 winsup/cygwin/Makefile.in |  2 +-
 winsup/cygwin/cxx.cc  | 10 --
 2 files changed, 1 insertion(+), 11 deletions(-)

diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index a840f2b83..73d9b37fd 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -69,7 +69,7 @@ COMMON_CFLAGS=-MMD ${$(*F)_CFLAGS} -Wimplicit-fallthrough=5 
-Werror -fmerge-cons
 ifeq ($(target_cpu),x86_64)
 COMMON_CFLAGS+=-mcmodel=small
 endif
-COMPILE.cc+=${COMMON_CFLAGS} # -std=gnu++14
+COMPILE.cc+=${COMMON_CFLAGS} -fno-threadsafe-statics # -std=gnu++14
 COMPILE.c+=${COMMON_CFLAGS}
 
 AR:=@AR@
diff --git a/winsup/cygwin/cxx.cc b/winsup/cygwin/cxx.cc
index be3268549..b69524aca 100644
--- a/winsup/cygwin/cxx.cc
+++ b/winsup/cygwin/cxx.cc
@@ -83,16 +83,6 @@ __cxa_pure_virtual (void)
   api_fatal ("pure virtual method called");
 }
 
-extern "C" void
-__cxa_guard_acquire ()
-{
-}
-
-extern "C" void
-__cxa_guard_release ()
-{
-}
-
 /* These routines are made available as last-resort fallbacks
for the application.  Should not be used in practice; the
entries in this struct get overwritten by each DLL as it
-- 
2.29.2



[PATCH 07/11] syscalls.cc: Implement non-path_conv dependent _unlink_nt

2021-01-15 Thread Ben Wijen
Implement _unlink_nt: wich does not depend on patch_conv
---
 winsup/cygwin/fhandler_disk_file.cc |   4 +-
 winsup/cygwin/forkable.cc   |   4 +-
 winsup/cygwin/syscalls.cc   | 239 ++--
 3 files changed, 228 insertions(+), 19 deletions(-)

diff --git a/winsup/cygwin/fhandler_disk_file.cc 
b/winsup/cygwin/fhandler_disk_file.cc
index 07f9c513a..fe04f832b 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -1837,7 +1837,7 @@ fhandler_disk_file::mkdir (mode_t mode)
 int
 fhandler_disk_file::rmdir ()
 {
-  extern NTSTATUS unlink_nt (path_conv );
+  extern NTSTATUS unlink_ntpc (path_conv );
 
   if (!pc.isdir ())
 {
@@ -1850,7 +1850,7 @@ fhandler_disk_file::rmdir ()
   return -1;
 }
 
-  NTSTATUS status = unlink_nt (pc);
+  NTSTATUS status = unlink_ntpc (pc);
 
   if (!NT_SUCCESS (status))
 {
diff --git a/winsup/cygwin/forkable.cc b/winsup/cygwin/forkable.cc
index 350a95c3e..bd7421bf5 100644
--- a/winsup/cygwin/forkable.cc
+++ b/winsup/cygwin/forkable.cc
@@ -29,7 +29,7 @@ details. */
 
 /* Allow concurrent processes to use the same dll or exe
  * via their hardlink while we delete our hardlink. */
-extern NTSTATUS unlink_nt_shareable (path_conv );
+extern NTSTATUS unlink_ntpc_shareable (path_conv );
 
 #define MUTEXSEP L"@"
 #define PATHSEP L"\\"
@@ -132,7 +132,7 @@ rmdirs (WCHAR ntmaxpathbuf[NT_MAX_PATH])
  RtlInitUnicodeString (, ntmaxpathbuf);
 
  path_conv pc ();
- unlink_nt_shareable (pc); /* move to bin */
+ unlink_ntpc_shareable (pc); /* move to bin */
}
 
  if (!pfdi->NextEntryOffset)
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index f86a93825..79e4a4422 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -491,7 +491,7 @@ try_to_bin (path_conv , HANDLE , ACCESS_MASK access, 
ULONG flags)
   break;
 case STATUS_DIRECTORY_NOT_EMPTY:
   /* Uh oh!  This was supposed to be avoided by the check_dir_not_empty
-test in unlink_nt, but given that the test isn't atomic, this *can*
+test in unlink_ntpc, but given that the test isn't atomic, this *can*
 happen.  Try to move the dir back ASAP. */
   pfri->RootDirectory = NULL;
   pfri->FileNameLength = pc.get_nt_native_path ()->Length;
@@ -501,7 +501,7 @@ try_to_bin (path_conv , HANDLE , ACCESS_MASK access, 
ULONG flags)
   if (NT_SUCCESS (NtSetInformationFile (fh, , pfri, frisiz,
FileRenameInformation)))
{
- /* Give notice to unlink_nt and leave immediately.  This avoids
+ /* Give notice to unlink_ntpc and leave immediately.  This avoids
 closing the handle, which might still be used if called from
 the rm -r workaround code. */
  bin_stat = dir_not_empty;
@@ -545,7 +545,7 @@ try_to_bin (path_conv , HANDLE , ACCESS_MASK access, 
ULONG flags)
   if ((access & FILE_WRITE_ATTRIBUTES) && NT_SUCCESS (status) && !pc.isdir ())
 NtSetAttributesFile (fh, pc.file_attributes ());
   NtClose (fh);
-  fh = NULL; /* So unlink_nt doesn't close the handle twice. */
+  fh = NULL; /* So unlink_ntpc doesn't close the handle twice. */
   /* On success or when trying to unlink a directory we just return here.
  The below code only works for files.  It also fails on NFS. */
   if (NT_SUCCESS (status) || pc.isdir () || pc.fs_is_nfs ())
@@ -671,7 +671,187 @@ check_dir_not_empty (HANDLE dir, path_conv )
 }
 
 static NTSTATUS
-_unlink_nt (path_conv , bool shareable)
+_unlink_nt (PUNICODE_STRING ntpath, ULONG eflags, ULONG oattr)
+{
+  //Available as of Redstone 1 (Win10_17_09)
+  static bool has_posix_unlink_semantics =
+  wincap.has_posix_unlink_semantics ();
+  //Available as of Redstone 5 (Win10_18_09) (As were POSIX rename semantics)
+  static bool has_posix_unlink_semantics_with_ignore_readonly =
+  wincap.has_posix_rename_semantics ();
+
+  HANDLE fh;
+  ACCESS_MASK access = DELETE;
+  OBJECT_ATTRIBUTES attr;
+  IO_STATUS_BLOCK io;
+  ULONG flags = FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT
+  | FILE_DELETE_ON_CLOSE | eflags;
+  NTSTATUS fstatus, istatus = STATUS_SUCCESS;
+
+  syscall_printf("Trying to delete %S, isdir = %d", ntpath,
+ eflags == FILE_DIRECTORY_FILE);
+
+  InitializeObjectAttributes(, ntpath, oattr, NULL, NULL);
+
+  //FILE_DELETE_ON_CLOSE icw FILE_DIRECTORY_FILE only works when directory is 
empty
+  //-> We must assume directory not empty, therefore only do this for regular 
files.
+  if (eflags & FILE_NON_DIRECTORY_FILE)
+{
+  //Step 1
+  //If the file is not 'in use' and not 'readonly', this should just work.
+  fstatus = NtOpenFile (, access, , , FILE_SHARE_DELETE, flags);
+  debug_printf("NtOpenFile %S: %y", ntpath, fstatus);
+}
+
+  if (!(eflags & FILE_NON_DIRECTORY_FILE) || // Workaround for the 
non-empty-dir issue
+  fstatus == 

[PATCH 04/11] syscalls.cc: Use EISDIR

2021-01-15 Thread Ben Wijen
This is the non-POSIX value returned by Linux since 2.1.132.
---
 winsup/cygwin/syscalls.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 227d1a911..043ccdb99 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1118,7 +1118,7 @@ unlink (const char *ourname)
   else if (win32_name.isdir ())
 {
   debug_printf ("unlinking a directory");
-  set_errno (EPERM);
+  set_errno (EISDIR);
   goto done;
 }
 
-- 
2.29.2



[PATCH 03/11] syscalls.cc: Fix num_links

2021-01-15 Thread Ben Wijen
NtQueryInformationFile on fh_ro needs FILE_READ_ATTRIBUTES
to succeed.
---
 winsup/cygwin/syscalls.cc | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 0e89b4f44..227d1a911 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -767,8 +767,9 @@ _unlink_nt (path_conv , bool shareable)
   if ((pc.fs_flags () & FILE_SUPPORTS_TRANSACTIONS))
start_transaction (old_trans, trans);
 retry_open:
-  status = NtOpenFile (_ro, FILE_WRITE_ATTRIBUTES, , ,
-  FILE_SHARE_VALID_FLAGS, flags);
+  status = NtOpenFile (_ro,
+   FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
+   , , FILE_SHARE_VALID_FLAGS, flags);
   if (NT_SUCCESS (status))
{
  debug_printf ("Opening %S for removing R/O succeeded",
-- 
2.29.2



[PATCH 01/11] syscalls.cc: unlink_nt: Try FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE first

2021-01-15 Thread Ben Wijen
---
 winsup/cygwin/ntdll.h |  3 ++-
 winsup/cygwin/syscalls.cc | 20 
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index d4f6aaf45..7eee383dd 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -497,7 +497,8 @@ enum {
   FILE_DISPOSITION_DELETE  = 0x01,
   FILE_DISPOSITION_POSIX_SEMANTICS = 0x02,
   FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK   = 0x04,
-  FILE_DISPOSITION_ON_CLOSE= 0x08
+  FILE_DISPOSITION_ON_CLOSE= 0x08,
+  FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE   = 0x10,
 };
 
 enum
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 525efecf3..ce4e9c65c 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -709,11 +709,23 @@ _unlink_nt (path_conv , bool shareable)
   flags);
   if (!NT_SUCCESS (status))
goto out;
-  /* Why didn't the devs add a FILE_DELETE_IGNORE_READONLY_ATTRIBUTE
-flag just like they did with FILE_LINK_IGNORE_READONLY_ATTRIBUTE
-and FILE_LINK_IGNORE_READONLY_ATTRIBUTE???
+  /* Try FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE first
+ it was added with Redstone 5 (Win10 18_09) (as were POSIX rename 
semantics)
+ If it fails: fall-back to usual trickery */
+  if (wincap.has_posix_rename_semantics ())
+{
+  fdie.Flags = FILE_DISPOSITION_DELETE | 
FILE_DISPOSITION_POSIX_SEMANTICS;
+  fdie.Flags|= FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE;
+  status = NtSetInformationFile (fh, , , sizeof fdie,
+ FileDispositionInformationEx);
+  if (NT_SUCCESS (status))
+{
+  NtClose (fh);
+  goto out;
+}
+}
 
- POSIX unlink semantics are nice, but they still fail if the file
+  /* POSIX unlink semantics are nice, but they still fail if the file
 has the R/O attribute set.  Removing the file is very much a safe
 bet afterwards, so, no transaction. */
   if (pc.file_attributes () & FILE_ATTRIBUTE_READONLY)
-- 
2.29.2



[PATCH] Cygwin: pty: Set input_available_event only for cygwin pipe.

2021-01-15 Thread Takashi Yano via Cygwin-patches
- cat exits immediately in the following senario.
1) Execute env CYGWIN=disable_pcon script
2) Execute cmd.exe
3) Execute cat in cmd.exe.
  This is caused by setting input_available_event for the pipe for
  non-cygwin app. This patch fixes the issue.
---
 winsup/cygwin/fhandler_tty.cc | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index e4993bf31..0b9901974 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -394,7 +394,8 @@ fhandler_pty_master::accept_input ()
}
 }
 
-  SetEvent (input_available_event);
+  if (write_to == get_output_handle ())
+SetEvent (input_available_event);
   ReleaseMutex (input_mutex);
   return ret;
 }
-- 
2.30.0



[PATCH 5/5] Cygwin: pty: Make master thread functions be static.

2021-01-15 Thread Takashi Yano via Cygwin-patches
- The functions pty_master_thread() and pty_master_fwd_thread()
  should be static (i.e. should not access class member) because
  the instance is deleted if the master is dup()'ed and the first
  master is closed. In this case, because the dup()'ed instance
  still exists, these master threads are also still alive even
  though the instance has been deleted. As a result, accesing
  class members in these functions causes accessi violation.

  Addresses:
  https://cygwin.com/pipermail/cygwin-developers/2021-January/012030.html
---
 winsup/cygwin/fhandler.h  |  30 ++-
 winsup/cygwin/fhandler_tty.cc | 154 ++
 2 files changed, 128 insertions(+), 56 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index ffd19a590..d134b180c 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2274,8 +2274,9 @@ class fhandler_pty_common: public fhandler_termios
   void resize_pseudo_console (struct winsize *);
 
  protected:
-  BOOL process_opost_output (HANDLE h,
-const void *ptr, ssize_t& len, bool is_echo);
+  static BOOL process_opost_output (HANDLE h, const void *ptr, ssize_t& len,
+   bool is_echo, tty *ttyp,
+   bool is_nonblocking);
 };
 
 class fhandler_pty_slave: public fhandler_pty_common
@@ -2352,6 +2353,24 @@ class fhandler_pty_slave: public fhandler_pty_common
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
 class fhandler_pty_master: public fhandler_pty_common
 {
+public:
+  /* Parameter set for the static function pty_master_thread() */
+  struct master_thread_param_t {
+HANDLE from_master;
+HANDLE from_master_cyg;
+HANDLE to_master;
+HANDLE to_master_cyg;
+HANDLE master_ctl;
+HANDLE input_available_event;
+  };
+  /* Parameter set for the static function pty_master_fwd_thread() */
+  struct master_fwd_thread_param_t {
+HANDLE to_master_cyg;
+HANDLE from_slave;
+HANDLE output_mutex;
+tty *ttyp;
+  };
+private:
   int pktmode; // non-zero if pty in a packet mode.
   HANDLE master_ctl;   // Control socket for handle duplication
   cygthread *master_thread;// Master control thread
@@ -2360,14 +2379,15 @@ class fhandler_pty_master: public fhandler_pty_common
   DWORD dwProcessId;   // Owner of master handles
   HANDLE to_master_cyg, from_master_cyg;
   cygthread *master_fwd_thread;// Master forwarding thread
+  HANDLE thread_param_copied_event;
 
 public:
   HANDLE get_echo_handle () const { return echo_r; }
   /* Constructor */
   fhandler_pty_master (int);
 
-  DWORD pty_master_thread ();
-  DWORD pty_master_fwd_thread ();
+  static DWORD pty_master_thread (const master_thread_param_t *p);
+  static DWORD pty_master_fwd_thread (const master_fwd_thread_param_t *p);
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
@@ -2410,6 +2430,8 @@ public:
 return fh;
   }
   bool to_be_read_from_pcon (void);
+  void get_master_thread_param (master_thread_param_t *p);
+  void get_master_fwd_thread_param (master_fwd_thread_param_t *p);
 };
 
 class fhandler_dev_null: public fhandler_base
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 789bcdfdf..e4993bf31 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -301,7 +301,8 @@ fhandler_pty_master::doecho (const void *str, DWORD len)
 {
   ssize_t towrite = len;
   acquire_output_mutex (INFINITE);
-  if (!process_opost_output (echo_w, str, towrite, true))
+  if (!process_opost_output (echo_w, str, towrite, true,
+get_ttyp (), is_nonblocking ()))
 termios_printf ("Write to echo pipe failed, %E");
   release_output_mutex ();
 }
@@ -874,7 +875,8 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
   reset_switch_to_pcon ();
 
   acquire_output_mutex (INFINITE);
-  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false))
+  if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false,
+get_ttyp (), is_nonblocking ()))
 {
   DWORD err = GetLastError ();
   termios_printf ("WriteFile failed, %E");
@@ -1955,8 +1957,15 @@ fhandler_pty_slave::fixup_after_exec ()
calls to CallNamedPipe should have a big enough timeout value.  For now this
is 500ms.  Hope that's enough. */
 
+/* The function pty_master_thread() should be static because the instance
+   is deleted if the master is dup()'ed and the original is closed. In
+   this case, dup()'ed instance still exists, therefore, master thread
+   is also still alive even though the instance has been deleted. As a
+   result, accesing member variables in this function causes access
+   violation. */
+
 DWORD
-fhandler_pty_master::pty_master_thread ()
+fhandler_pty_master::pty_master_thread 

[PATCH 4/5] Cygwin: pty: Prevent pty from changing code page of parent console.

2021-01-15 Thread Takashi Yano via Cygwin-patches
- After commit 232fde0e, pty changes console code page when the first
  non-cygwin app is executed. If pty is started in real console device,
  pty changes the code page of root console. This causes very annoying
  result because changing code page changes the font of command prompt
  if console is in legacy mode. This patch avoids this by creating a
  new invisible console for the first pty started in console device.
---
 winsup/cygwin/fhandler.h  |   5 +-
 winsup/cygwin/fhandler_console.cc |  38 +++--
 winsup/cygwin/fhandler_tty.cc | 126 +-
 winsup/cygwin/spawn.cc|   1 +
 winsup/cygwin/tty.cc  |   2 +
 winsup/cygwin/tty.h   |   2 +
 6 files changed, 163 insertions(+), 11 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 2077b5245..ffd19a590 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2127,7 +2127,7 @@ private:
   int input_tcsetattr (int a, const struct termios *t);
   void set_cursor_maybe ();
   static bool create_invisible_console (HWINSTA);
-  static bool create_invisible_console_workaround ();
+  static bool create_invisible_console_workaround (bool force);
   static console_state *open_shared_console (HWND, HANDLE&, bool&);
   void fix_tab_position (void);
 
@@ -2185,7 +2185,7 @@ private:
   bool send_winch_maybe ();
   void setup ();
   bool set_unit ();
-  static bool need_invisible ();
+  static bool need_invisible (bool force=false);
   static void free_console ();
   static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *);
 
@@ -2346,6 +2346,7 @@ class fhandler_pty_slave: public fhandler_pty_common
   void mask_switch_to_pcon_in (bool mask);
   void setup_locale (void);
   tty *get_ttyp () { return (tty *) tc (); } /* Override as public */
+  void create_invisible_console (void);
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_console.cc 
b/winsup/cygwin/fhandler_console.cc
index a4c054e24..dd00079fa 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -53,6 +53,23 @@ fhandler_console::console_state NO_COPY 
*fhandler_console::shared_console_info;
 
 bool NO_COPY fhandler_console::invisible_console;
 
+/* Mutex for AttachConsole()/FreeConsole() in fhandler_tty.cc */
+HANDLE NO_COPY attach_mutex;
+
+static inline void
+acquire_attach_mutex (DWORD t)
+{
+  if (attach_mutex)
+WaitForSingleObject (attach_mutex, t);
+}
+
+static inline void
+release_attach_mutex ()
+{
+  if (attach_mutex)
+ReleaseMutex (attach_mutex);
+}
+
 /* con_ra is shared in the same process.
Only one console can exist in a process, therefore, static is suitable. */
 static struct fhandler_base::rabuf_t con_ra;
@@ -599,6 +616,8 @@ fhandler_console::process_input_message (void)
   if (!shared_console_info)
 return input_error;
 
+  acquire_attach_mutex (INFINITE);
+
   termios *ti = &(get_ttyp ()->ti);
 
   fhandler_console::input_states stat = input_processing;
@@ -608,6 +627,7 @@ fhandler_console::process_input_message (void)
   if (!PeekConsoleInputW (get_handle (), input_rec, INREC_SIZE, _read))
 {
   termios_printf ("PeekConsoleInput failed, %E");
+  release_attach_mutex ();
   return input_error;
 }
 
@@ -972,6 +992,7 @@ out:
   /* Discard processed recored. */
   DWORD dummy;
   ReadConsoleInputW (get_handle (), input_rec, min (total_read, i+1), );
+  release_attach_mutex ();
   return stat;
 }
 
@@ -2973,6 +2994,7 @@ fhandler_console::write (const void *vsrc, size_t len)
   if (bg <= bg_eof)
 return (ssize_t) bg;
 
+  acquire_attach_mutex (INFINITE);
   push_process_state process_state (PID_TTYOU);
   acquire_output_mutex (INFINITE);
 
@@ -3298,6 +3320,7 @@ fhandler_console::write (const void *vsrc, size_t len)
 
   syscall_printf ("%ld = fhandler_console::write(...)", len);
 
+  release_attach_mutex ();
   return len;
 }
 
@@ -3469,12 +3492,13 @@ fhandler_console::create_invisible_console (HWINSTA 
horig)
function is currently only called at startup and during exec, it shouldn't
be a big deal.  */
 bool
-fhandler_console::create_invisible_console_workaround ()
+fhandler_console::create_invisible_console_workaround (bool force)
 {
-  if (!AttachConsole (-1))
+  /* If force is set, avoid to reattach to existing console. */
+  if (force || !AttachConsole (-1))
 {
   bool taskbar;
-  DWORD err = GetLastError ();
+  DWORD err = force ? 0 : GetLastError ();
   path_conv helper ("/bin/cygwin-console-helper.exe");
   HANDLE hello = NULL;
   HANDLE goodbye = NULL;
@@ -3559,10 +3583,12 @@ fhandler_console::free_console ()
 }
 
 bool
-fhandler_console::need_invisible ()
+fhandler_console::need_invisible (bool force)
 {
   BOOL b = false;
-  if (exists ())
+  /* If force is set, forcibly create a new invisible console
+ even if a console device already exists. */
+  if (exists () && !force)
 

[PATCH 3/5] Cygwin: pty: Make close_pseudoconsole() be a static member function.

2021-01-15 Thread Takashi Yano via Cygwin-patches
- The function close_pseudoconsole() should be static so that it
  can be safely called in spawn.cc even after the fhandler_pty_slave
  instance has been deleted. That is, there is a problem with the
  current code. This patch fixes the issue.
---
 winsup/cygwin/fhandler.h  |  3 ++-
 winsup/cygwin/fhandler_tty.cc | 22 --
 winsup/cygwin/spawn.cc|  6 --
 3 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 45ac17af2..2077b5245 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2339,12 +2339,13 @@ class fhandler_pty_slave: public fhandler_pty_common
 return fh;
   }
   bool setup_pseudoconsole (STARTUPINFOEXW *si, bool nopcon);
-  void close_pseudoconsole (void);
+  static void close_pseudoconsole (tty *ttyp);
   bool term_has_pcon_cap (const WCHAR *env);
   void set_switch_to_pcon (void);
   void reset_switch_to_pcon (void);
   void mask_switch_to_pcon_in (bool mask);
   void setup_locale (void);
+  tty *get_ttyp () { return (tty *) tc (); } /* Override as public */
 };
 
 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit))
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 8ff74cdde..0c92f41d4 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -2563,21 +2563,23 @@ fallback:
   return false;
 }
 
+/* The function close_pseudoconsole() should be static so that it can
+   be called even after the fhandler_pty_slave instance is deleted. */
 void
-fhandler_pty_slave::close_pseudoconsole (void)
+fhandler_pty_slave::close_pseudoconsole (tty *ttyp)
 {
-  if (get_ttyp ()->h_pseudo_console)
+  if (ttyp->h_pseudo_console)
 {
-  get_ttyp ()->wait_pcon_fwd ();
-  HPCON_INTERNAL *hp = (HPCON_INTERNAL *) get_ttyp ()->h_pseudo_console;
+  ttyp->wait_pcon_fwd ();
+  HPCON_INTERNAL *hp = (HPCON_INTERNAL *) ttyp->h_pseudo_console;
   HANDLE tmp = hp->hConHostProcess;
-  ClosePseudoConsole (get_ttyp ()->h_pseudo_console);
+  ClosePseudoConsole (ttyp->h_pseudo_console);
   CloseHandle (tmp);
-  get_ttyp ()->h_pseudo_console = NULL;
-  get_ttyp ()->switch_to_pcon_in = false;
-  get_ttyp ()->pcon_pid = 0;
-  get_ttyp ()->pcon_start = false;
-  get_ttyp ()->do_not_resize_pcon = false;
+  ttyp->h_pseudo_console = NULL;
+  ttyp->switch_to_pcon_in = false;
+  ttyp->pcon_pid = 0;
+  ttyp->pcon_start = false;
+  ttyp->do_not_resize_pcon = false;
 }
 }
 
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 94909df4c..bf1b08057 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -664,6 +664,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
init_console_handler (myself->ctty > 0);
 
   bool enable_pcon = false;
+  tty *ptys_ttyp = NULL;
   STARTUPINFOEXW si_pcon;
   ZeroMemory (_pcon, sizeof (si_pcon));
   STARTUPINFOW *si_tmp = 
@@ -677,6 +678,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
  c_flags |= EXTENDED_STARTUPINFO_PRESENT;
  si_tmp = _pcon.StartupInfo;
  enable_pcon = true;
+ ptys_ttyp = ptys_primary->get_ttyp ();
}
}
 
@@ -954,7 +956,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
  if (enable_pcon)
{
  WaitForSingleObject (pi.hProcess, INFINITE);
- ptys_primary->close_pseudoconsole ();
+ fhandler_pty_slave::close_pseudoconsole (ptys_ttyp);
}
  else if (cons_native)
{
@@ -973,7 +975,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
  if (waitpid (cygpid, , 0) != cygpid)
res = -1;
  if (enable_pcon)
-   ptys_primary->close_pseudoconsole ();
+   fhandler_pty_slave::close_pseudoconsole (ptys_ttyp);
  else if (cons_native)
{
  fhandler_console::request_xterm_mode_output (true,
-- 
2.30.0



[PATCH 2/5] Cygwin: console: Revise the code to switch xterm mode.

2021-01-15 Thread Takashi Yano via Cygwin-patches
- If application changes the console mode, mode management introduced
  by commit 10d8c278 will be corrupted. For example, stdout of jansi
  v2.0.1 or later is piped to less, jansi resets the xterm mode flag
  ENABLE_VIRTUAL_TERMINA_PROCESSING when jansi is terminated. This
  causes garbled output in less because less needs this flag enabled.
  This patch fixes the issue.
---
 winsup/cygwin/fhandler.h  |  18 -
 winsup/cygwin/fhandler_console.cc | 121 +++---
 winsup/cygwin/select.cc   |  15 +---
 winsup/cygwin/spawn.cc|  35 -
 4 files changed, 127 insertions(+), 62 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index fe76c0781..45ac17af2 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2048,8 +2048,6 @@ class dev_console
   bool raw_win32_keyboard_mode;
   char cons_rabuf[40];  // cannot get longer than char buf[40] in char_command
   char *cons_rapoi;
-  LONG xterm_mode_input;
-  LONG xterm_mode_output;
   bool cursor_key_app_mode;
 
   inline UINT get_console_cp ();
@@ -2086,11 +2084,19 @@ public:
 input_signalled = 2,
 input_winch = 3
   };
+  struct handle_set_t
+  {
+HANDLE input_handle;
+HANDLE output_handle;
+HANDLE input_mutex;
+HANDLE output_mutex;
+  };
 private:
   static const unsigned MAX_WRITE_CHARS;
   static console_state *shared_console_info;
   static bool invisible_console;
   HANDLE input_mutex, output_mutex;
+  handle_set_t handle_set;
 
   /* Used when we encounter a truncated multi-byte sequence.  The
  lead bytes are stored here and revisited in the next write call. */
@@ -2212,8 +2218,12 @@ private:
   size_t  ();
   size_t  ();
 
-  void request_xterm_mode_input (bool);
-  void request_xterm_mode_output (bool);
+  const handle_set_t *get_handle_set (void) {return _set;}
+  void get_duplicated_handle_set (handle_set_t *p);
+  static void close_handle_set (handle_set_t *p);
+
+  static void request_xterm_mode_input (bool, const handle_set_t *p);
+  static void request_xterm_mode_output (bool, const handle_set_t *p);
 
   friend tty_min * tty_list::get_cttyp ();
 };
diff --git a/winsup/cygwin/fhandler_console.cc 
b/winsup/cygwin/fhandler_console.cc
index 41cac37e6..a4c054e24 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -187,11 +187,7 @@ fhandler_console::set_unit ()
  tty_min_state.setntty (DEV_CONS_MAJOR, console_unit (me));
   devset = (fh_devices) shared_console_info->tty_min_state.getntty ();
   if (created)
-   {
- con.owner = myself->pid;
- con.xterm_mode_input = 0;
- con.xterm_mode_output = 0;
-   }
+   con.owner = myself->pid;
 }
   if (!created && shared_console_info)
 {
@@ -279,60 +275,65 @@ fhandler_console::rabuflen ()
   return con_ra.rabuflen;
 }
 
+/* The function request_xterm_mode_{in,out}put() should be static so that
+   they can be called even after the fhandler_console instance is deleted. */
 void
-fhandler_console::request_xterm_mode_input (bool req)
+fhandler_console::request_xterm_mode_input (bool req, const handle_set_t *p)
 {
   if (con_is_legacy)
 return;
+  WaitForSingleObject (p->input_mutex, INFINITE);
+  DWORD dwMode;
+  GetConsoleMode (p->input_handle, );
   if (req)
 {
-  if (InterlockedExchange (_mode_input, 1) == 0)
+  if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_INPUT))
{
- DWORD dwMode;
- GetConsoleMode (get_handle (), );
  dwMode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
- SetConsoleMode (get_handle (), dwMode);
+ SetConsoleMode (p->input_handle, dwMode);
  if (con.cursor_key_app_mode) /* Restore DECCKM */
-   WriteConsoleW (get_output_handle (), L"\033[?1h", 5, NULL, 0);
+   {
+ request_xterm_mode_output (true, p);
+ WriteConsoleW (p->output_handle, L"\033[?1h", 5, NULL, 0);
+   }
}
 }
   else
 {
-  if (InterlockedExchange (_mode_input, 0) == 1)
+  if (dwMode & ENABLE_VIRTUAL_TERMINAL_INPUT)
{
- DWORD dwMode;
- GetConsoleMode (get_handle (), );
  dwMode &= ~ENABLE_VIRTUAL_TERMINAL_INPUT;
- SetConsoleMode (get_handle (), dwMode);
+ SetConsoleMode (p->input_handle, dwMode);
}
 }
+  ReleaseMutex (p->input_mutex);
 }
 
 void
-fhandler_console::request_xterm_mode_output (bool req)
+fhandler_console::request_xterm_mode_output (bool req, const handle_set_t *p)
 {
   if (con_is_legacy)
 return;
+  WaitForSingleObject (p->output_mutex, INFINITE);
+  DWORD dwMode;
+  GetConsoleMode (p->output_handle, );
   if (req)
 {
-  if (InterlockedExchange (_mode_output, 1) == 0)
+  if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
{
- DWORD dwMode;
- GetConsoleMode (get_output_handle (), );
  dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
- SetConsoleMode (get_output_handle 

[PATCH 1/5] Cygwin: pty: Add workaround for rlwrap 0.40 or later.

2021-01-15 Thread Takashi Yano via Cygwin-patches
- The workaround for rlwrap introduced by commit 8199b0cc does not
  take effect for rlwrap 0.40 or later. This patch add a workaround
  for rlwrap 0.40 or later as well.
---
 winsup/cygwin/fhandler_tty.cc | 5 +
 1 file changed, 5 insertions(+)

diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 77f7bfe43..8ff74cdde 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -1720,6 +1720,11 @@ int
 fhandler_pty_master::tcgetattr (struct termios *t)
 {
   *t = cygwin_shared->tty[get_minor ()]->ti;
+  /* Workaround for rlwrap v0.40 or later */
+  if (get_ttyp ()->pcon_start)
+t->c_lflag &= ~(ICANON | ECHO);
+  if (get_ttyp ()->h_pseudo_console)
+t->c_iflag &= ~ICRNL;
   return 0;
 }
 
-- 
2.30.0



[PATCH 0/5] Some revisions for pty and console code.

2021-01-15 Thread Takashi Yano via Cygwin-patches
Takashi Yano (5):
  Cygwin: pty: Add workaround for rlwrap 0.40 or later.
  Cygwin: console: Revise the code to switch xterm mode.
  Cygwin: pty: Make close_pseudoconsole() be a static member function.
  Cygwin: pty: Prevent pty from changing code page of parent console.
  Cygwin: pty: Make master thread functions be static.

 winsup/cygwin/fhandler.h  |  56 --
 winsup/cygwin/fhandler_console.cc | 159 +++-
 winsup/cygwin/fhandler_tty.cc | 305 +++---
 winsup/cygwin/select.cc   |  15 +-
 winsup/cygwin/spawn.cc|  42 +++-
 winsup/cygwin/tty.cc  |   2 +
 winsup/cygwin/tty.h   |   2 +
 7 files changed, 440 insertions(+), 141 deletions(-)

-- 
2.30.0