Not sure if this belongs in the cygport, upstream or /dev/null. Fixes, i.e.: "ls /bin/b*sh" failing to show /bin/bash.

-gmt
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,102 @@
              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 (strmatch ("*.exe", convfn, mflags) != FNM_NOMATCH)
+           {
+             /* if sanity checks pass, assume this is the cygwin .exe hack at 
work. */
+             struct stat finfo;
+             
+             /* ".exe" matches *.exe so lets rule that out rather than match 
'\0' */
+             if (!(convfn[0] == '.' && convfn[1] == 'e' && convfn[2] == 'x' &&
+                   convfn[3] == 'e' && convfn[4] == '\0'))
+               {
+                 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 = D_NAMLEN (dp) - 4; /* length of ".exe" */
+                     /* 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);

Reply via email to