[PATCH v2 0/2] Handle "app execution aliases"

Johannes Schindelin johannes.schindelin@gmx.de
Mon Mar 22 15:51:29 GMT 2021


When installing e.g. Python via the Windows Store, it is common that the
`python3.exe` entry in the `PATH` is not actually an executable at all,
but an "app executaion alias" (i.e. a special class of reparse point).

These filesystem entries are presented as 0-size files, but they are not
readable, which is why Cygwin has problems to execute them, with the error
message "Permission denied".

This issue has been reported a couple of times in the Git for Windows and
in the MSYS2 project, and even in Cygwin
(https://cygwin.com/pipermail/cygwin/2020-May/244969.html, the thread
devolved into a discussion about Thunderbird vs Outlook before long,
though).

The second patch fixes that, and for good measure, the first patch teaches
Cygwin to treat these reparse points as symbolic links.

Changes since v1:

- Introduce and use `struct _REPARSE_APPEXECLINK_BUFFER`.

Johannes Schindelin (2):
  Treat Windows Store's "app execution aliases" as symbolic links
  Allow executing Windows Store's "app execution aliases"

 winsup/cygwin/path.cc  | 40 ++++++++++++++++++++++++++++++++++++++++
 winsup/cygwin/spawn.cc |  7 +++++++
 2 files changed, 47 insertions(+)

Range-diff against v1:
1:  218dc58e36 ! 1:  529cb4ad54 Treat Windows Store's "app execution aliases" as symbolic links
    @@ Commit message
         Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

      ## winsup/cygwin/path.cc ##
    +@@ winsup/cygwin/path.cc: symlink_info::check_sysfile (HANDLE h)
    +   return res;
    + }
    +
    ++typedef struct _REPARSE_APPEXECLINK_BUFFER
    ++{
    ++  DWORD ReparseTag;
    ++  WORD  ReparseDataLength;
    ++  WORD  Reserved;
    ++  struct {
    ++    DWORD Version;       /* Take member name with a grain of salt. */
    ++    WCHAR Strings[1];    /* Four serialized, NUL-terminated WCHAR strings:
    ++			   - Package ID
    ++			   - Entry Point
    ++			   - Executable Path
    ++			   - Application Type
    ++			   We're only interested in the Executable Path */
    ++  } AppExecLinkReparseBuffer;
    ++} REPARSE_APPEXECLINK_BUFFER,*PREPARSE_APPEXECLINK_BUFFER;
    ++
    + static bool
    + check_reparse_point_string (PUNICODE_STRING subst)
    + {
     @@ winsup/cygwin/path.cc: check_reparse_point_target (HANDLE h, bool remote, PREPARSE_DATA_BUFFER rp,
            if (check_reparse_point_string (psymbuf))
      	return PATH_SYMLINK | PATH_REP;
    @@ winsup/cygwin/path.cc: check_reparse_point_target (HANDLE h, bool remote, PREPAR
     +  else if (!remote && rp->ReparseTag == IO_REPARSE_TAG_APPEXECLINK)
     +    {
     +      /* App execution aliases are commonly used by Windows Store apps. */
    -+      WCHAR *buf = (WCHAR *)(rp->GenericReparseBuffer.DataBuffer + 4);
    -+      DWORD size = rp->ReparseDataLength / sizeof(WCHAR), n;
    ++      PREPARSE_APPEXECLINK_BUFFER rpl = (PREPARSE_APPEXECLINK_BUFFER) rp;
    ++      WCHAR *buf = rpl->Strings;
    ++      DWORD size = rp->ReparseDataLength / sizeof (WCHAR), n;
     +
    -+      /*
    -+         It seems that app execution aliases have a payload of four
    ++      /* It seems that app execution aliases have a payload of four
     +	 NUL-separated wide string: package id, entry point, executable
     +	 and application type. We're interested in the executable. */
     +      for (int i = 0; i < 3 && size > 0; i++)
    -+        {
    ++	{
     +	  n = wcsnlen (buf, size - 1);
     +	  if (i == 2 && n > 0 && n < size)
     +	    {
    -+	      RtlInitCountedUnicodeString (psymbuf, buf, n * sizeof(WCHAR));
    ++	      RtlInitCountedUnicodeString (psymbuf, buf, n * sizeof (WCHAR));
     +	      return PATH_SYMLINK | PATH_REP;
     +	    }
     +	  if (i == 2)
2:  647dff4c7a = 2:  1c2659f902 Allow executing Windows Store's "app execution aliases"
--
2.31.0



More information about the Cygwin-patches mailing list