summaryrefslogtreecommitdiffstats
path: root/src/os_mswin.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-02-10 23:18:53 +0100
committerBram Moolenaar <Bram@vim.org>2019-02-10 23:18:53 +0100
commitdce1e89be4675bcdbc9785584d3da25295481e63 (patch)
treebf5df09169e99ed6f60d67e2da4c4d29569d18a2 /src/os_mswin.c
parent3615abb693ab2d9374ae72f0993128e32ffa3e1c (diff)
patch 8.1.0894: MS-Windows: resolve() does not return a reparse pointv8.1.0894
Problem: MS-Windows: resolve() does not return a reparse point. Solution: Improve resolve(). (Yasuhiro Matsumoto, closes #3896)
Diffstat (limited to 'src/os_mswin.c')
-rw-r--r--src/os_mswin.c182
1 files changed, 180 insertions, 2 deletions
diff --git a/src/os_mswin.c b/src/os_mswin.c
index 363dc4666e..8d46e53cf1 100644
--- a/src/os_mswin.c
+++ b/src/os_mswin.c
@@ -1823,13 +1823,181 @@ mch_print_set_fg(long_u fgcol)
# include <shlobj.h>
# endif
+typedef enum _FILE_INFO_BY_HANDLE_CLASS_ {
+ FileBasicInfo_,
+ FileStandardInfo_,
+ FileNameInfo_,
+ FileRenameInfo_,
+ FileDispositionInfo_,
+ FileAllocationInfo_,
+ FileEndOfFileInfo_,
+ FileStreamInfo_,
+ FileCompressionInfo_,
+ FileAttributeTagInfo_,
+ FileIdBothDirectoryInfo_,
+ FileIdBothDirectoryRestartInfo_,
+ FileIoPriorityHintInfo_,
+ FileRemoteProtocolInfo_,
+ FileFullDirectoryInfo_,
+ FileFullDirectoryRestartInfo_,
+ FileStorageInfo_,
+ FileAlignmentInfo_,
+ FileIdInfo_,
+ FileIdExtdDirectoryInfo_,
+ FileIdExtdDirectoryRestartInfo_,
+ FileDispositionInfoEx_,
+ FileRenameInfoEx_,
+ MaximumFileInfoByHandleClass_
+} FILE_INFO_BY_HANDLE_CLASS_;
+
+typedef struct _FILE_NAME_INFO_ {
+ DWORD FileNameLength;
+ WCHAR FileName[1];
+} FILE_NAME_INFO_;
+
+typedef BOOL (WINAPI *pfnGetFileInformationByHandleEx)(
+ HANDLE hFile,
+ FILE_INFO_BY_HANDLE_CLASS_ FileInformationClass,
+ LPVOID lpFileInformation,
+ DWORD dwBufferSize);
+static pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL;
+
+typedef BOOL (WINAPI *pfnGetVolumeInformationByHandleW)(
+ HANDLE hFile,
+ LPWSTR lpVolumeNameBuffer,
+ DWORD nVolumeNameSize,
+ LPDWORD lpVolumeSerialNumber,
+ LPDWORD lpMaximumComponentLength,
+ LPDWORD lpFileSystemFlags,
+ LPWSTR lpFileSystemNameBuffer,
+ DWORD nFileSystemNameSize);
+static pfnGetVolumeInformationByHandleW pGetVolumeInformationByHandleW = NULL;
+
+ char_u *
+resolve_reparse_point(char_u *fname)
+{
+ HANDLE h = INVALID_HANDLE_VALUE;
+ DWORD size;
+ char_u *rfname = NULL;
+ FILE_NAME_INFO_ *nameinfo = NULL;
+ WCHAR buff[MAX_PATH], *volnames = NULL;
+ HANDLE hv;
+ DWORD snfile, snfind;
+ static BOOL loaded = FALSE;
+
+ if (pGetFileInformationByHandleEx == NULL ||
+ pGetVolumeInformationByHandleW == NULL)
+ {
+ HMODULE hmod = GetModuleHandle("kernel32.dll");
+
+ if (loaded == TRUE)
+ return NULL;
+ pGetFileInformationByHandleEx = (pfnGetFileInformationByHandleEx)
+ GetProcAddress(hmod, "GetFileInformationByHandleEx");
+ pGetVolumeInformationByHandleW = (pfnGetVolumeInformationByHandleW)
+ GetProcAddress(hmod, "GetVolumeInformationByHandleW");
+ loaded = TRUE;
+ if (pGetFileInformationByHandleEx == NULL ||
+ pGetVolumeInformationByHandleW == NULL)
+ return NULL;
+ }
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *p;
+
+ p = enc_to_utf16(fname, NULL);
+ if (p == NULL)
+ goto fail;
+
+ if ((GetFileAttributesW(p) & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
+ {
+ vim_free(p);
+ goto fail;
+ }
+
+ h = CreateFileW(p, 0, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ vim_free(p);
+ }
+ else
+ {
+ if ((GetFileAttributes((char*) fname) &
+ FILE_ATTRIBUTE_REPARSE_POINT) == 0)
+ goto fail;
+
+ h = CreateFile((char*) fname, 0, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ }
+
+ if (h == INVALID_HANDLE_VALUE)
+ goto fail;
+
+ size = sizeof(FILE_NAME_INFO_) + sizeof(WCHAR) * (MAX_PATH - 1);
+ nameinfo = (FILE_NAME_INFO_*)alloc(size + sizeof(WCHAR));
+ if (nameinfo == NULL)
+ goto fail;
+
+ if (!pGetFileInformationByHandleEx(h, FileNameInfo_, nameinfo, size))
+ goto fail;
+
+ nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = 0;
+
+ if (!pGetVolumeInformationByHandleW(
+ h, NULL, 0, &snfile, NULL, NULL, NULL, 0))
+ goto fail;
+
+ hv = FindFirstVolumeW(buff, MAX_PATH);
+ if (hv == INVALID_HANDLE_VALUE)
+ goto fail;
+
+ do {
+ GetVolumeInformationW(
+ buff, NULL, 0, &snfind, NULL, NULL, NULL, 0);
+ if (snfind == snfile)
+ break;
+ } while (FindNextVolumeW(hv, buff, MAX_PATH));
+
+ FindVolumeClose(hv);
+
+ if (snfind != snfile)
+ goto fail;
+
+ size = 0;
+ if (!GetVolumePathNamesForVolumeNameW(buff, NULL, 0, &size) &&
+ GetLastError() != ERROR_MORE_DATA)
+ goto fail;
+
+ volnames = (WCHAR*)alloc(size * sizeof(WCHAR));
+ if (!GetVolumePathNamesForVolumeNameW(buff, volnames, size,
+ &size))
+ goto fail;
+
+ wcscpy(buff, volnames);
+ if (nameinfo->FileName[0] == '\\')
+ wcscat(buff, nameinfo->FileName + 1);
+ else
+ wcscat(buff, nameinfo->FileName);
+ rfname = utf16_to_enc(buff, NULL);
+
+fail:
+ if (h != INVALID_HANDLE_VALUE)
+ CloseHandle(h);
+ if (nameinfo != NULL)
+ vim_free(nameinfo);
+ if (volnames != NULL)
+ vim_free(volnames);
+
+ return rfname;
+}
+
/*
* When "fname" is the name of a shortcut (*.lnk) resolve the file it points
* to and return that name in allocated memory.
* Otherwise NULL is returned.
*/
- char_u *
-mch_resolve_shortcut(char_u *fname)
+ static char_u *
+resolve_shortcut(char_u *fname)
{
HRESULT hr;
IShellLink *psl = NULL;
@@ -1937,6 +2105,16 @@ shortcut_end:
CoUninitialize();
return rfname;
}
+
+ char_u *
+mch_resolve_path(char_u *fname, int reparse_point)
+{
+ char_u *path = resolve_shortcut(fname);
+
+ if (path == NULL && reparse_point)
+ path = resolve_reparse_point(fname);
+ return path;
+}
#endif
#if (defined(FEAT_EVAL) && !defined(FEAT_GUI)) || defined(PROTO)