delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2012/08/30/22:41:18

X-Recipient: archive-cygwin AT delorie DOT com
X-SWARE-Spam-Status: No, hits=-1.2 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_FN,TW_NV,TW_VF
X-Spam-Check-By: sourceware.org
Message-ID: <50402422.1020901@malth.us>
Date: Thu, 30 Aug 2012 19:40:34 -0700
From: "Gregory M. Turner" <gmt AT malth DOT us>
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:14.0) Gecko/20120713 Thunderbird/14.0
MIME-Version: 1.0
To: cygwin AT cygwin DOT com
Subject: [patch/rfc]: bash: fix globbing for executables without ".exe"
X-IsSubscribed: yes
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

--------------040100040408000706070406
Content-Type: text/plain; charset=windows-1252; format=flowed
Content-Transfer-Encoding: 7bit

The attached attempts to mitigate a nasty interaction between globbing 
in bash and the cygwin .exe hack (i.e.: "/bin/b*sh" fails to match 
/bin/bash).

I originally posted this (incorrectly) to the -apps ml.

To be clear, this version is slightly revised from what I originally 
posted to -apps: specifically, I optimized the code selecting filenames 
matching "?*.exe" a bit, since this will often have to run nearly as 
many times as there are total files in all directories (nontrivially) 
searched by a given glob-pattern.

-gmt


--------------040100040408000706070406
Content-Type: text/plain; charset=windows-1252;
 name="bash-4.2_p36-cygwin-exe-globfix-r1.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="bash-4.2_p36-cygwin-exe-globfix-r1.patch"

In cygwin, we have "the .exe hack" where both foo and foo.exe are treated as
hardlinks to the same thing if foo is an executable or a symlink to an
executable.

This doesn't present a problem when globbing for something that matches "foo.exe"
since readdir() always seems to tack the .exe on to the end.  However, when
globbing for "foo", we completely fail to find the file, for the same reason.
The only thing for it is to explicitly check for this circumstance and inject
a match into our results iff the glob matches "foo" but not "foo.exe".

-gmt

diff -urN bash-4.2.orig/lib/glob/glob.c bash-4.2/lib/glob/glob.c
--- bash-4.2.orig/lib/glob/glob.c	2012-08-29 14:04:40.707465500 -0700
+++ bash-4.2/lib/glob/glob.c	2012-08-29 14:51:45.275465500 -0700
@@ -675,6 +675,103 @@
 	      bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1);
 	      ++count;
 	    }
+#if __CYGWIN__
+	  /* if file i.e. foo.exe is executable, see if "foo" matches the glob */
+	  else if (convfn[0] != '\0' && convfn[1] != '\0' && convfn[2] != '\0' &&
+	           convfn[3] != '\0' && convfn[4] != '\0')
+	    {
+	      char *x = &convfn[0];
+	      /* if sanity checks pass, assume this is the cygwin .exe hack at work. */
+	      struct stat finfo;
+	      
+	      while (*++x != '\0') ;
+	      if (*--x == 'e' && *--x == 'x' && *--x == 'e' && *--x == '.')
+	        {
+		  subdir = sh_makepath (dir, dp->d_name, pflags);
+		  if (!subdir)
+		    {
+		      lose = 1;
+		      break;
+		    }
+	          if (stat (subdir, &finfo) == 0 &&
+		      ((S_ISREG (finfo.st_mode) || S_ISLNK (finfo.st_mode)) &&
+		       (finfo.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
+		    {
+		      size_t dnamlen = x - convfn;
+		      /* We can kind-of abuse nextname here -- that's where it's
+		         going, anyhow, if everything checks out OK */
+		      nextname = (char *) malloc (dnamlen + 1);
+		      if (!nextname)
+			{
+			  lose = 1;
+			  break;
+			}
+		      bcopy (dp->d_name, nextname, dnamlen);
+		      *(nextname + dnamlen) = '\0';
+		      convfn = fnx_fromfs (nextname, dnamlen);
+		      /* So, it's executable and ends in .exe -- does it match the
+		         pattern, now that we have stripped the ".exe" off the end? */
+		      if (strmatch (pat, convfn, mflags) != FNM_NOMATCH)
+		        {
+			  /* Great, it matches, but does it actually exist, and is it executable?
+			     Probably, yes.  This protects against some future cygwin that made
+			     the .exe hack optional or removed it, and against the possibility that
+			     I've failed to capture the conditions that trigger the .exe hack in
+			     general.  A better test might be to check if they have the same inode */
+			  free(subdir);
+			  subdir = sh_makepath (dir, convfn, pflags);
+			  if (!subdir)
+			    {
+			      lose = 1;
+			      break;
+			    }
+			  /* My tests indicate that we can stat() the executable bit of a valid
+			     symlink in cygwin, expecting to get the same result as we would get 
+			     stat()ing the link-target.  The .exe hack does apply to such links!
+			     I haven't tested various wierd corner cases.  Guessing incorrectly
+			     whether the .exe hack is operating will result in missed globs, or
+			     (if we inject but then encounter the real file) duplicate matches */
+			  if (stat (subdir, &finfo) == 0 &&
+			      ((S_ISREG (finfo.st_mode) || S_ISLNK (finfo.st_mode)) &&
+			       (finfo.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
+			    {
+			      /* All signs point to cygwin .exe hack.  Add it, it's a "match." */
+			      if (nalloca < ALLOCA_MAX)
+				{
+				  nextlink = (struct globval *) alloca (sizeof (struct globval));
+				  nalloca += sizeof (struct globval);
+				}
+			      else
+				{
+				  nextlink = (struct globval *) malloc (sizeof (struct globval));
+				  if (firstmalloc == 0)
+				  firstmalloc = nextlink;
+				}
+
+			      if (!nextlink)
+				{
+				  lose = 1;
+				  break;
+				}
+			      nextlink->next = lastlink;
+			      lastlink = nextlink;
+			      nextlink->name = nextname;
+			      ++count;
+			    }
+			  else
+			    {
+			      free(nextname);
+			    }
+			}
+		      else
+			{
+			  free (nextname);
+			}
+		    }
+		  free(subdir);
+	        }
+	    }
+#endif
 	}
 
       (void) closedir (d);


--------------040100040408000706070406
Content-Type: text/plain; charset=us-ascii

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
--------------040100040408000706070406--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019