diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index bef06e22b..5bf6c4e6b 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,21 @@
+2006-02-05  Corinna Vinschen  <corinna@vinschen.de>
+
+	* environ.cc (struct parse_thing): Add transparent_exe option.
+	* fhandler_disk_file.cc (fhandler_disk_file::link): Accomodate
+	transparent_exe option.  Add .exe suffix for links to executable files,
+	if transparent_exe is set.
+	* fhandler_process.cc (fhandler_process::fill_filebuf): Remove .exe
+	suffix if transparent_exe option is set.
+	* path.cc (symlink_worker): Accomodate transparent_exe option.
+	(realpath): Don't tack on .exe suffix if transparent_exe is set.
+	* syscalls.cc (transparent_exe): New global variable.
+	(unlink): Accomodate transparent_exe option.
+	(open): Ditto.
+	(link): Ditto.
+	(rename): Ditto. Maybe add .exe suffix when renaming executable files.
+	(pathconf): Accomodate transparent_exe option.
+	* winsup.h: Declare transparent_exe.
+
 2006-02-05  Christopher Faylor  <cgf@timesys.com>
 	    Corinna Vinschen  <corinna@vinschen.de>
 
diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index 8c5e79dee..eb99d2b51 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -586,6 +586,7 @@ static struct parse_thing
   {"title", {&display_title}, justset, NULL, {{false}, {true}}},
   {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
   {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}},
+  {"transparent_exe", {&transparent_exe}, justset, NULL, {{false}, {true}}},
   {NULL, {0}, justset, 0, {{0}, {0}}}
 };
 
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index 048574c1e..b187de58b 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -734,9 +734,11 @@ fhandler_disk_file::ftruncate (_off64_t length)
 int
 fhandler_disk_file::link (const char *newpath)
 {
-  path_conv newpc (newpath, PC_SYM_NOFOLLOW | PC_POSIX);
   extern bool allow_winsymlinks;
+  extern suffix_info stat_suffixes[];
 
+  path_conv newpc (newpath, PC_SYM_NOFOLLOW | PC_POSIX,
+		   transparent_exe ? stat_suffixes : NULL);
   if (newpc.error)
     {
       set_errno (newpc.case_clash ? ECASECLASH : newpc.error);
@@ -757,14 +759,32 @@ fhandler_disk_file::link (const char *newpath)
       return -1;
     }
 
-  /* Shortcut hack. */
-  char new_lnk_buf[CYG_MAX_PATH + 5];
-  if (allow_winsymlinks && pc.is_lnk_special () && !newpc.case_clash)
+  char new_buf[CYG_MAX_PATH + 5];
+  if (!newpc.error && !newpc.case_clash)
     {
-      strcpy (new_lnk_buf, newpath);
-      strcat (new_lnk_buf, ".lnk");
-      newpath = new_lnk_buf;
-      newpc.check (newpath, PC_SYM_NOFOLLOW);
+      DWORD bintype;
+      int len;
+
+      if (allow_winsymlinks && pc.is_lnk_special ())
+	{
+	  /* Shortcut hack. */
+	  strcpy (new_buf, newpath);
+	  strcat (new_buf, ".lnk");
+	  newpath = new_buf;
+	  newpc.check (newpath, PC_SYM_NOFOLLOW);
+	}
+      else if (transparent_exe
+               && !pc.isdir ()
+               && GetBinaryType (pc, &bintype)
+               && (len = strlen (newpc)) > 4
+               && !strcasematch ((const char *) newpc + len - 4, ".exe"))
+        {
+          /* Executable hack. */
+          strcpy (new_buf, newpath);
+          strcat (new_buf, ".exe");
+          newpath = new_buf;
+          newpc.check (newpath, PC_SYM_NOFOLLOW);
+        }
     }
 
   query_open (query_write_attributes);
diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc
index cb0b80520..28fd28c39 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -451,19 +451,18 @@ fhandler_process::fill_filebuf ()
 	else
 	  {
 	    mount_table->conv_to_posix_path (p->progname, filebuf, 1);
-#if 0
-	    /* Temporarily disabled.  The link will have a suffix so that
-	       an open(2) call will succeed on /proc/$PID/exe now.  This
-	       might become unnecessary if open(2) handles the .exe suffix
-	       at one point. */
-	    int len = strlen (filebuf);
-	    if (len > 4)
+	    /* If transparent_exe isn't set, the link keeps its suffix so that
+	       an open(2) call will succeed on /proc/$PID/exe. */
+	    if (transparent_exe)
 	      {
-		char *s = filebuf + len - 4;
-		if (strcasematch (s, ".exe"))
-		  *s = 0;
+		int len = strlen (filebuf);
+		if (len > 4)
+		  {
+		    char *s = filebuf + len - 4;
+		    if (strcasematch (s, ".exe"))
+		      *s = 0;
+		  }
 	      }
-#endif
 	  }
 	filesize = strlen (filebuf);
 	break;
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 45dc57947..4029ec5eb 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -2675,6 +2675,8 @@ int
 symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
 		bool isdevice)
 {
+  extern suffix_info stat_suffixes[];
+
   HANDLE h;
   int res = -1;
   path_conv win32_path, win32_oldpath;
@@ -2704,7 +2706,8 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
       goto done;
     }
 
-  win32_path.check (newpath, PC_SYM_NOFOLLOW);
+  win32_path.check (newpath, PC_SYM_NOFOLLOW,
+		    transparent_exe ? stat_suffixes : NULL);
   if (use_winsym && !win32_path.exists ())
     {
       strcpy (from, newpath);
@@ -2753,7 +2756,8 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
 	     ITEMIDLIST field. */
 	  if (GetFileAttributes (reloldpath) == INVALID_FILE_ATTRIBUTES)
 	    {
-	      win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW);
+	      win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW,
+	      			   transparent_exe ? stat_suffixes : NULL);
 	      if (win32_oldpath.error != ENOENT)
 		strcpy (use_winsym ? reloldpath : w32oldpath, win32_oldpath);
 	    }
@@ -2761,7 +2765,8 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
 	    strcpy (w32oldpath, reloldpath);
 	  if (use_winsym)
 	    {
-	      win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW);
+	      win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW,
+	      			   transparent_exe ? stat_suffixes : NULL);
 	      strcpy (w32oldpath, win32_oldpath);
 	    }
 	  if (cp)
@@ -2772,7 +2777,8 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
 	}
       else
 	{
-	  win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW);
+	  win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW,
+			       transparent_exe ? stat_suffixes : NULL);
 	  strcpy (w32oldpath, win32_oldpath);
 	}
       create_how = CREATE_NEW;
@@ -3723,7 +3729,7 @@ realpath (const char *path, char *resolved)
     {
       /* Check for the suffix being tacked on. */
       int tack_on = 0;
-      if (real_path.known_suffix)
+      if (!transparent_exe && real_path.known_suffix)
         {
 	  char *c = strrchr (real_path.normalized_path, '.');
 	  if (!c || !strcasematch (c, real_path.known_suffix))
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 62ebf639f..66c5e38c4 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -84,6 +84,8 @@ suffix_info stat_suffixes[] =
   suffix_info (NULL)
 };
 
+bool transparent_exe = false;
+
 SYSTEM_INFO system_info;
 
 static int __stdcall mknod_worker (const char *, mode_t, mode_t, _major_t,
@@ -139,7 +141,8 @@ unlink (const char *ourname)
   int res = -1;
   DWORD devn;
 
-  path_conv win32_name (ourname, PC_SYM_NOFOLLOW);
+  path_conv win32_name (ourname, PC_SYM_NOFOLLOW,
+  			transparent_exe ? stat_suffixes : NULL);
 
   if (win32_name.error)
     {
@@ -598,7 +601,8 @@ open (const char *unix_path, int flags, ...)
       if (fd >= 0)
 	{
 	  if (!(fh = build_fh_name (unix_path, NULL, (flags & O_NOFOLLOW) ?
-				    PC_SYM_NOFOLLOW : PC_SYM_FOLLOW)))
+				    PC_SYM_NOFOLLOW : PC_SYM_FOLLOW,
+				    transparent_exe ? stat_suffixes : NULL)))
 	    res = -1;		// errno already set
 	  else if ((flags & O_NOFOLLOW) && fh->issymlink ())
 	    {
@@ -722,7 +726,8 @@ link (const char *oldpath, const char *newpath)
   int res = -1;
   fhandler_base *fh;
 
-  if (!(fh = build_fh_name (oldpath, NULL, PC_SYM_NOFOLLOW)))
+  if (!(fh = build_fh_name (oldpath, NULL, PC_SYM_NOFOLLOW,
+			    transparent_exe ? stat_suffixes : NULL)))
     goto error;
 
   if (fh->error ())
@@ -1171,7 +1176,8 @@ rename (const char *oldpath, const char *newpath)
   int res = 0;
   char *lnk_suffix = NULL;
 
-  path_conv real_old (oldpath, PC_SYM_NOFOLLOW);
+  path_conv real_old (oldpath, PC_SYM_NOFOLLOW,
+		      transparent_exe ? stat_suffixes : NULL);
 
   if (real_old.error)
     {
@@ -1180,16 +1186,35 @@ rename (const char *oldpath, const char *newpath)
       return -1;
     }
 
-  path_conv real_new (newpath, PC_SYM_NOFOLLOW);
+  path_conv real_new (newpath, PC_SYM_NOFOLLOW,
+		      transparent_exe ? stat_suffixes : NULL);
 
-  /* Shortcut hack. */
-  char new_lnk_buf[CYG_MAX_PATH + 5];
-  if (real_old.is_lnk_special () && !real_new.error && !real_new.case_clash)
+  char new_buf[CYG_MAX_PATH + 5];
+  if (!real_new.error && !real_new.case_clash)
     {
-      strcpy (new_lnk_buf, newpath);
-      strcat (new_lnk_buf, ".lnk");
-      newpath = new_lnk_buf;
-      real_new.check (newpath, PC_SYM_NOFOLLOW);
+      DWORD bintype;
+      int len;
+
+      if (real_old.is_lnk_special ())
+	{
+	  /* Shortcut hack. */
+	  strcpy (new_buf, newpath);
+	  strcat (new_buf, ".lnk");
+	  newpath = new_buf;
+	  real_new.check (newpath, PC_SYM_NOFOLLOW);
+	}
+      else if (transparent_exe
+	       && !real_old.isdir ()
+	       && GetBinaryType (real_old, &bintype)
+	       && (len = strlen (real_new)) > 4
+	       && !strcasematch ((const char *) real_new + len - 4, ".exe"))
+        {
+	  /* Executable hack. */
+	  strcpy (new_buf, newpath);
+	  strcat (new_buf, ".exe");
+	  newpath = new_buf;
+	  real_new.check (newpath, PC_SYM_NOFOLLOW);
+	}
     }
 
   if (real_new.error || real_new.case_clash)
@@ -1510,7 +1535,8 @@ pathconf (const char *file, int v)
     case _PC_POSIX_PERMISSIONS:
     case _PC_POSIX_SECURITY:
       {
-	path_conv full_path (file, PC_SYM_FOLLOW);
+	path_conv full_path (file, PC_SYM_FOLLOW,
+			     transparent_exe ? stat_suffixes : NULL);
 	if (full_path.error)
 	  {
 	    set_errno (full_path.error);
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index c0059ed44..3fd669fc8 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -347,6 +347,7 @@ extern SYSTEM_INFO system_info;
 extern char *old_title;
 extern bool display_title;
 extern bool in_forkee;
+extern bool transparent_exe;
 
 extern HANDLE hMainThread;
 extern HANDLE hMainProc;