diff options
author | Ron Yorston <rmy@pobox.com> | 2023-05-27 08:35:59 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2023-05-27 08:35:59 +0100 |
commit | 603af9bb92af6bc429d880df71618e96820967c5 (patch) | |
tree | 7100a2f8d93e7d133329906c2f0658c9cf5be171 | |
parent | 5adeafb91fe5d0fbfd2e4f773e64da9aa13d2f09 (diff) | |
download | busybox-w32-603af9bb92af6bc429d880df71618e96820967c5.tar.gz busybox-w32-603af9bb92af6bc429d880df71618e96820967c5.tar.bz2 busybox-w32-603af9bb92af6bc429d880df71618e96820967c5.zip |
win32: support "app exec link" reparse points
Reparse points with the tag IO_REPARSE_TAG_APPEXECLINK are present
in ~/AppData/Local/Microsoft/WindowsApps in Windows 10 and 11.
They are:
Used by Universal Windows Platform (UWP) packages to encode
information that allows the application to be launched by
CreateProcess.
Modify readlink(2) and lsattr(1) to treat them as symbolic links, in
much the same way as was done previously for junctions. They aren't
really symbolic links but they're similar.
Costs 128-160 bytes.
(GitHub issue #327)
-rw-r--r-- | e2fsprogs/e2fs_lib.c | 6 | ||||
-rw-r--r-- | e2fsprogs/lsattr.c | 1 | ||||
-rw-r--r-- | win32/mingw.c | 37 |
3 files changed, 43 insertions, 1 deletions
diff --git a/e2fsprogs/e2fs_lib.c b/e2fsprogs/e2fs_lib.c index 031f5e06b..4a4db1a13 100644 --- a/e2fsprogs/e2fs_lib.c +++ b/e2fsprogs/e2fs_lib.c | |||
@@ -135,6 +135,9 @@ void print_e2flags_long(struct stat *sb) | |||
135 | case IO_REPARSE_TAG_MOUNT_POINT: | 135 | case IO_REPARSE_TAG_MOUNT_POINT: |
136 | ln = "Junction"; | 136 | ln = "Junction"; |
137 | break; | 137 | break; |
138 | case IO_REPARSE_TAG_APPEXECLINK: | ||
139 | ln = "App_Exec_Link"; | ||
140 | break; | ||
138 | } | 141 | } |
139 | } | 142 | } |
140 | fputs(ln, stdout); | 143 | fputs(ln, stdout); |
@@ -174,6 +177,9 @@ void print_e2flags(struct stat *sb) | |||
174 | case IO_REPARSE_TAG_MOUNT_POINT: | 177 | case IO_REPARSE_TAG_MOUNT_POINT: |
175 | c = 'j'; | 178 | c = 'j'; |
176 | break; | 179 | break; |
180 | case IO_REPARSE_TAG_APPEXECLINK: | ||
181 | c = 'A'; | ||
182 | break; | ||
177 | } | 183 | } |
178 | } | 184 | } |
179 | #endif | 185 | #endif |
diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c index a6c4a27e9..87fdb78b3 100644 --- a/e2fsprogs/lsattr.c +++ b/e2fsprogs/lsattr.c | |||
@@ -47,6 +47,7 @@ | |||
47 | //usage: "\n\nAttributes:\n" | 47 | //usage: "\n\nAttributes:\n" |
48 | //usage: "\n j Junction" | 48 | //usage: "\n j Junction" |
49 | //usage: "\n l Symbolic link" | 49 | //usage: "\n l Symbolic link" |
50 | //usage: "\n A App exec link" | ||
50 | //usage: "\n R Reparse point" | 51 | //usage: "\n R Reparse point" |
51 | //usage: "\n o Offline" | 52 | //usage: "\n o Offline" |
52 | //usage: "\n e Encrypted" | 53 | //usage: "\n e Encrypted" |
diff --git a/win32/mingw.c b/win32/mingw.c index 9e1cf5eea..be4fc7aa1 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -593,6 +593,7 @@ static DWORD get_symlink_data(DWORD attr, const char *pathname, | |||
593 | switch (fbuf->dwReserved0) { | 593 | switch (fbuf->dwReserved0) { |
594 | case IO_REPARSE_TAG_SYMLINK: | 594 | case IO_REPARSE_TAG_SYMLINK: |
595 | case IO_REPARSE_TAG_MOUNT_POINT: | 595 | case IO_REPARSE_TAG_MOUNT_POINT: |
596 | case IO_REPARSE_TAG_APPEXECLINK: | ||
596 | return fbuf->dwReserved0; | 597 | return fbuf->dwReserved0; |
597 | } | 598 | } |
598 | } | 599 | } |
@@ -1602,6 +1603,23 @@ static wchar_t *normalize_ntpath(wchar_t *wbuf) | |||
1602 | return wbuf; | 1603 | return wbuf; |
1603 | } | 1604 | } |
1604 | 1605 | ||
1606 | /* | ||
1607 | * This is the stucture required for reparse points with the tag | ||
1608 | * IO_REPARSE_TAG_APPEXECLINK. The Buffer member contains four | ||
1609 | * NUL-terminated, concatentated strings: | ||
1610 | * | ||
1611 | * package id, entry point, executable path and application type. | ||
1612 | * | ||
1613 | * https://www.tiraniddo.dev/2019/09/overview-of-windows-execution-aliases.html | ||
1614 | */ | ||
1615 | typedef struct { | ||
1616 | DWORD ReparseTag; | ||
1617 | USHORT ReparseDataLength; | ||
1618 | USHORT Reserved; | ||
1619 | ULONG Version; | ||
1620 | WCHAR Buffer[1]; | ||
1621 | } APPEXECLINK_BUFFER; | ||
1622 | |||
1605 | #define SRPB rptr->SymbolicLinkReparseBuffer | 1623 | #define SRPB rptr->SymbolicLinkReparseBuffer |
1606 | ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) | 1624 | ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) |
1607 | { | 1625 | { |
@@ -1613,9 +1631,11 @@ ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) | |||
1613 | DWORD nbytes; | 1631 | DWORD nbytes; |
1614 | BYTE rbuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; | 1632 | BYTE rbuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; |
1615 | PREPARSE_DATA_BUFFER rptr = (PREPARSE_DATA_BUFFER)rbuf; | 1633 | PREPARSE_DATA_BUFFER rptr = (PREPARSE_DATA_BUFFER)rbuf; |
1634 | APPEXECLINK_BUFFER *aptr = (APPEXECLINK_BUFFER *)rptr; | ||
1616 | BOOL status; | 1635 | BOOL status; |
1617 | size_t len; | 1636 | size_t len; |
1618 | WCHAR *name = NULL; | 1637 | WCHAR *name = NULL, *str[4], *s; |
1638 | int i; | ||
1619 | 1639 | ||
1620 | status = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, | 1640 | status = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, |
1621 | rptr, sizeof(rbuf), &nbytes, NULL); | 1641 | rptr, sizeof(rbuf), &nbytes, NULL); |
@@ -1627,6 +1647,21 @@ ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) | |||
1627 | } else if (status && rptr->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { | 1647 | } else if (status && rptr->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { |
1628 | len = MRPB.SubstituteNameLength/sizeof(WCHAR); | 1648 | len = MRPB.SubstituteNameLength/sizeof(WCHAR); |
1629 | name = MRPB.PathBuffer + MRPB.SubstituteNameOffset/sizeof(WCHAR); | 1649 | name = MRPB.PathBuffer + MRPB.SubstituteNameOffset/sizeof(WCHAR); |
1650 | } else if (status && rptr->ReparseTag == IO_REPARSE_TAG_APPEXECLINK) { | ||
1651 | // We only need the executable path but we determine all of | ||
1652 | // the strings as a sanity check. | ||
1653 | i = 0; | ||
1654 | s = aptr->Buffer; | ||
1655 | do { | ||
1656 | str[i] = s; | ||
1657 | while (*s++) | ||
1658 | ; | ||
1659 | } while (++i < 4); | ||
1660 | |||
1661 | if (s - aptr->Buffer < MAXIMUM_REPARSE_DATA_BUFFER_SIZE) { | ||
1662 | len = wcslen(str[2]); | ||
1663 | name = str[2]; | ||
1664 | } | ||
1630 | } | 1665 | } |
1631 | 1666 | ||
1632 | if (name) { | 1667 | if (name) { |