mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 8.2.4875: MS-Windows: some .exe files are not recognized
Problem: MS-Windows: some .exe files are not recognized. Solution: Parse APPEXECLINK junctions. (closes #10302)
This commit is contained in:
@@ -439,6 +439,27 @@ slash_adjust(char_u *p)
|
||||
#define _wstat _wstat64
|
||||
#define _fstat _fstat64
|
||||
|
||||
static int
|
||||
read_reparse_point(const WCHAR *name, char_u *buf, DWORD *buf_len)
|
||||
{
|
||||
HANDLE h;
|
||||
BOOL ok;
|
||||
|
||||
h = CreateFileW(name, FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
NULL);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return FAIL;
|
||||
|
||||
ok = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buf, *buf_len,
|
||||
buf_len, NULL);
|
||||
CloseHandle(h);
|
||||
|
||||
return ok ? OK : FAIL;
|
||||
}
|
||||
|
||||
static int
|
||||
wstat_symlink_aware(const WCHAR *name, stat_T *stp)
|
||||
{
|
||||
@@ -491,6 +512,61 @@ wstat_symlink_aware(const WCHAR *name, stat_T *stp)
|
||||
return _wstat(name, (struct _stat *)stp);
|
||||
}
|
||||
|
||||
char_u *
|
||||
resolve_appexeclink(char_u *fname)
|
||||
{
|
||||
DWORD attr = 0;
|
||||
int idx;
|
||||
WCHAR *p, *end, *wname;
|
||||
// The buffer size is arbitrarily chosen to be "big enough" (TM), the
|
||||
// ceiling should be around 16k.
|
||||
char_u buf[4096];
|
||||
DWORD buf_len = sizeof(buf);
|
||||
REPARSE_DATA_BUFFER *rb = (REPARSE_DATA_BUFFER *)buf;
|
||||
|
||||
wname = enc_to_utf16(fname, NULL);
|
||||
if (wname == NULL)
|
||||
return NULL;
|
||||
|
||||
attr = GetFileAttributesW(wname);
|
||||
if (attr == INVALID_FILE_ATTRIBUTES ||
|
||||
(attr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
|
||||
{
|
||||
vim_free(wname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The applinks are similar to symlinks but with a huge difference: they can
|
||||
// only be executed, any other I/O operation on them is bound to fail with
|
||||
// ERROR_FILE_NOT_FOUND even though the file exists.
|
||||
if (read_reparse_point(wname, buf, &buf_len) == FAIL)
|
||||
{
|
||||
vim_free(wname);
|
||||
return NULL;
|
||||
}
|
||||
vim_free(wname);
|
||||
|
||||
if (rb->ReparseTag != IO_REPARSE_TAG_APPEXECLINK)
|
||||
return NULL;
|
||||
|
||||
// The (undocumented) reparse buffer contains a set of N null-terminated
|
||||
// Unicode strings, the application path is stored in the third one.
|
||||
if (rb->AppExecLinkReparseBuffer.StringCount < 3)
|
||||
return NULL;
|
||||
|
||||
p = rb->AppExecLinkReparseBuffer.StringList;
|
||||
end = p + rb->ReparseDataLength / sizeof(WCHAR);
|
||||
for (idx = 0; p < end
|
||||
&& idx < (int)rb->AppExecLinkReparseBuffer.StringCount
|
||||
&& idx != 2; )
|
||||
{
|
||||
if ((*p++ == L'\0'))
|
||||
++idx;
|
||||
}
|
||||
|
||||
return utf16_to_enc(p, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* stat() can't handle a trailing '/' or '\', remove it first.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user