Cygwin CWD vs. Win32 CWD (was Re: [ANNOUNCEMENT] Updated: vim-7.3.003-1)

Corinna Vinschen corinna-cygwin@cygwin.com
Wed Aug 25 11:46:00 GMT 2010


On Aug 20 22:31, Corinna Vinschen wrote:
> On Aug 20 16:03, Christopher Faylor wrote:
> > On Fri, Aug 20, 2010 at 09:27:25PM +0200, Corinna Vinschen wrote:
> > >Erm... btw., how is that different from the message, if you need a
> > >valid Win32 CWD in your hybrid app, use cygwin_internal(CW_SYNC_WINCWD)?
> > 
> > My supposition is that the breakage for hybrid applications is much more
> > pervasive than for programs which want to delete directories that someone
> > has cd'ed to.
> > 
> > But, actually, I am liking the "just relink your app like this if that
> > is what you want" solution better.  That means minor tweaks to the
> > current Cygwin code.  A pure Cygwin app continues to behave like linux.
> > You just have to rebuild your hybrid app.
> > 
> > I think I'll work on a proof-of-concept for that.
> 
> That sounds good.  [...]

I have created a patch which implements both, a /usr/lib/winsynccwd.o
which you can link against, and a new environment setting CYGWIN=winsynccwd.

To implement this as configurable as possible, I changed the new
cygwin_internal (CW_SYNC_WINCWD) functionality to take an additional
parameter:

  cygwin_internal (CW_SYNC_WINCWD, 0)

  	Uncouple Win32 CWD from Cygwin CWD and immediately set
	Win32 CWD back to \\?\PIPE.

  cygwin_internal (CW_SYNC_WINCWD, 1)

  	Uncouple Win32 CWD from Cygwin CWD, but immediately set the
	Win32 CWD exactly once to the Cygwin CWD.

	This is practically identical to the former simple
	cygwin_internal (CW_SYNC_WINCWD) implementation.

  cygwin_internal (CW_SYNC_WINCWD, 2)
  
  	Couple Win32 CWD  to Cygwin CWD and immediately set
	the Win32 CWD to the Cygwn CWD.

	Every chdir() call will keep the Win32 CWD in sync with the
	Cygwin CWD now, unless the Cygwin CWD is an invalid CWD for
	Win32, in which case it will set the Win32 CWD to \\?\PIPE.

Usage of the new CYGWIN setting "winsynccwd":

   CYGWIN="nowinsynccwd" ==> cygwin_internal (CW_SYNC_WINCWD, 0)
   CYGWIN="winsynccwd"   ==> cygwin_internal (CW_SYNC_WINCWD, 2)
   CYGWIN="winsynccwd:X" ==> cygwin_internal (CW_SYNC_WINCWD, X)

Linking against /usr/lib/winsynccwd.o is equivalent to

  cygwin_internal (CW_SYNC_WINCWD, 2)

Please see the patch below.  Comments are highly welcome.  Alternatively
we just drop the entire jumble and keep the Win32 always in sync.  I'm
still wondering what other guys on the list think...

Btw., linking against libwinsynccwd.a (for instance with -lwinsynccwd)
does not work.  Same for libbinmode.a etc.  I don't see how this can
work at all.  The cygwin_premainX functions are requested by
libcygwin.a which already satisfies the requierment by itself using
its own empty cygwin_premainX functions.  The -lwinsynccwd prior ro
-lcygwin does not provide the function, because it hasn't been requested
at that time.  Unless I'm missing something, it looks to me like the
libbinmode, etc files are just useless.


Corinna


	* Makefile.in (EXTRALIBS): Add libwinsynccwd.a
	(INSTOBJS)(: Add winsynccwd.o
	* environ.cc (set_winsynccwd): New function.
	(parse_thing): Add "winsynccwd".
	* external.cc (sync_wincwd): Redefine to take a parameter.
	Explain what we do with it.
	(cygwin_internal): Fetch one unsigned long parameter for
	CW_SYNC_WINCWD.
	* globals.cc (allow_winsynccwd): New global variable.
	* path.cc (cwdstuff::set): Keep Win32 CWD in sync if allow_winsynccwd
	is set to true.
	* winsynccwd.c: New file.


Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/Makefile.in,v
retrieving revision 1.237
diff -u -p -r1.237 Makefile.in
--- Makefile.in	21 Aug 2010 18:57:36 -0000	1.237
+++ Makefile.in	25 Aug 2010 11:42:52 -0000
@@ -228,8 +228,8 @@ API_VER:=$(srcdir)/include/cygwin/versio
 LIB_NAME:=libcygwin.a
 LIBSERVER:=@LIBSERVER@
 SUBLIBS:=libpthread.a libutil.a ${CURDIR}/libm.a ${CURDIR}/libc.a libdl.a libresolv.a librt.a
-EXTRALIBS:=libautomode.a libbinmode.a libtextmode.a libtextreadmode.a
-INSTOBJS:=automode.o binmode.o textmode.o textreadmode.o
+EXTRALIBS:=libautomode.a libbinmode.a libtextmode.a libtextreadmode.a libwinsynccwd.a
+INSTOBJS:=automode.o binmode.o textmode.o textreadmode.o winsynccwd.o
 TARGET_LIBS:=$(LIB_NAME) $(CYGWIN_START) $(GMON_START) $(LIBGMON_A) $(SUBLIBS) $(INSTOBJS) $(EXTRALIBS)
 
 ifneq "${filter -O%,$(CFLAGS)}" ""
Index: environ.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/environ.cc,v
retrieving revision 1.183
diff -u -p -r1.183 environ.cc
--- environ.cc	18 May 2010 14:30:50 -0000	1.183
+++ environ.cc	25 Aug 2010 11:42:52 -0000
@@ -569,6 +569,12 @@ set_proc_retry (const char *buf)
   child_info::retry_count = strtoul (buf, NULL, 0);
 }
 
+static void
+set_winsynccwd (const char *buf)
+{
+  cygwin_internal (CW_SYNC_WINCWD, buf ? strtol (buf, NULL, 0) : 2);
+}
+
 /* The structure below is used to set up an array which is used to
    parse the CYGWIN environment variable or, if enabled, options from
    the registry.  */
@@ -605,6 +611,7 @@ static struct parse_thing
   {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
   {"upcaseenv", {&create_upcaseenv}, justset, NULL, {{false}, {true}}},
   {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}},
+  {"winsynccwd", {func: set_winsynccwd}, isfunc, NULL, {{s: "0"}, {s: "2"}}},
   {NULL, {0}, justset, 0, {{0}, {0}}}
 };
 
Index: external.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/external.cc,v
retrieving revision 1.119
diff -u -p -r1.119 external.cc
--- external.cc	24 Aug 2010 15:11:24 -0000	1.119
+++ external.cc	25 Aug 2010 11:42:52 -0000
@@ -165,9 +165,33 @@ sync_winenv ()
 /* Synchronize Win32 CWD with Cygwin CWD.  Return -1 and set errno if
    setting the Win32 CWD fails. */
 static unsigned long
-sync_wincwd ()
+sync_wincwd (unsigned long what)
 {
   unsigned long ret = (unsigned long) -1;
+  /* First, set allow_winsynccwd according to what:
+     what == 0 -> Decouple Win32 CWD from Cygwin CWD -> allow_winsynccwd = false
+     what == 1 -> Couple CWDs exactly once -> allow_winsynccwd = false
+     what == 2 -> Couple CWDs and stick to it -> allow_winsynccwd = true
+  */
+  switch (what)
+    {
+    case 0:
+      allow_winsynccwd = false;
+      if (!SetCurrentDirectoryW (L"\\\\?\\PIPE\\"))
+	__seterrno ();
+      else
+	ret = 0;
+      return ret;
+    case 1:
+      allow_winsynccwd = false;
+      break;
+    case 2:
+      allow_winsynccwd = true;
+      break;
+    default:
+      set_errno (EINVAL);
+      return ret;
+    }
   /* Lock cwd.  We're accessing it directly here. */
   cygheap->cwd.cwd_lock.acquire ();
   /* First check if the path can work at all.  Fortunately we already have
@@ -538,7 +562,10 @@ cygwin_internal (cygwin_getinfo_types t,
 	}
 	break;
       case CW_SYNC_WINCWD:
-	res = sync_wincwd ();
+	{
+	  unsigned long what = va_arg (arg, unsigned long);
+	  res = sync_wincwd (what);
+	}
 	break;
 
       default:
Index: globals.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/globals.cc,v
retrieving revision 1.18
diff -u -p -r1.18 globals.cc
--- globals.cc	7 May 2010 21:25:18 -0000	1.18
+++ globals.cc	25 Aug 2010 11:42:52 -0000
@@ -54,6 +54,7 @@ int NO_COPY dynamically_loaded;
 bool display_title;
 bool strip_title_path;
 bool allow_glob = true;
+bool allow_winsynccwd = false;
 bool NO_COPY in_forkee;
 
 int __argc_safe;
Index: path.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/path.cc,v
retrieving revision 1.603
diff -u -p -r1.603 path.cc
--- path.cc	20 Aug 2010 14:29:56 -0000	1.603
+++ path.cc	25 Aug 2010 11:42:53 -0000
@@ -3468,6 +3468,14 @@ cwdstuff::set (path_conv *nat_cwd, const
       else
 	error = 0;
     }
+  /* If we have been instructed to keep the Win32 CWD in sync, do it.
+     Don't check for error, other than to add it to strace output. */
+  if (allow_winsynccwd)
+    {
+      const WCHAR *wcwd = error ? L"\\\\?\\PIPE\\" : win32.Buffer;
+      if (!SetCurrentDirectoryW (wcwd))
+	debug_printf ("SetCurrentDirectoryW(%W) failed, %E", wcwd);
+    }
 
   /* Eventually, create POSIX path if it's not set on entry. */
   tmp_pathbuf tp;
Index: winsynccwd.c
===================================================================
RCS file: winsynccwd.c
diff -N winsynccwd.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ winsynccwd.c	25 Aug 2010 11:42:53 -0000
@@ -0,0 +1,18 @@
+/* winsyncenv.c
+
+   Copyright 2010 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <windows.h>
+#include <sys/cygwin.h>
+
+void
+cygwin_premain1 (int argc, char **argv, struct per_process *myself)
+{
+  cygwin_internal (CW_SYNC_WINCWD, 2);
+}


-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat



More information about the Cygwin-developers mailing list