Mercurial > vim
comparison src/os_mswin.c @ 15774:c4efa095f323 v8.1.0894
patch 8.1.0894: MS-Windows: resolve() does not return a reparse point
commit https://github.com/vim/vim/commit/dce1e89be4675bcdbc9785584d3da25295481e63
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Feb 10 23:18:53 2019 +0100
patch 8.1.0894: MS-Windows: resolve() does not return a reparse point
Problem: MS-Windows: resolve() does not return a reparse point.
Solution: Improve resolve(). (Yasuhiro Matsumoto, closes https://github.com/vim/vim/issues/3896)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 10 Feb 2019 23:30:08 +0100 |
parents | 639b8318472c |
children | 028c9fdb8469 |
comparison
equal
deleted
inserted
replaced
15773:e3c2762bc354 | 15774:c4efa095f323 |
---|---|
1821 #if defined(FEAT_SHORTCUT) || defined(PROTO) | 1821 #if defined(FEAT_SHORTCUT) || defined(PROTO) |
1822 # ifndef PROTO | 1822 # ifndef PROTO |
1823 # include <shlobj.h> | 1823 # include <shlobj.h> |
1824 # endif | 1824 # endif |
1825 | 1825 |
1826 typedef enum _FILE_INFO_BY_HANDLE_CLASS_ { | |
1827 FileBasicInfo_, | |
1828 FileStandardInfo_, | |
1829 FileNameInfo_, | |
1830 FileRenameInfo_, | |
1831 FileDispositionInfo_, | |
1832 FileAllocationInfo_, | |
1833 FileEndOfFileInfo_, | |
1834 FileStreamInfo_, | |
1835 FileCompressionInfo_, | |
1836 FileAttributeTagInfo_, | |
1837 FileIdBothDirectoryInfo_, | |
1838 FileIdBothDirectoryRestartInfo_, | |
1839 FileIoPriorityHintInfo_, | |
1840 FileRemoteProtocolInfo_, | |
1841 FileFullDirectoryInfo_, | |
1842 FileFullDirectoryRestartInfo_, | |
1843 FileStorageInfo_, | |
1844 FileAlignmentInfo_, | |
1845 FileIdInfo_, | |
1846 FileIdExtdDirectoryInfo_, | |
1847 FileIdExtdDirectoryRestartInfo_, | |
1848 FileDispositionInfoEx_, | |
1849 FileRenameInfoEx_, | |
1850 MaximumFileInfoByHandleClass_ | |
1851 } FILE_INFO_BY_HANDLE_CLASS_; | |
1852 | |
1853 typedef struct _FILE_NAME_INFO_ { | |
1854 DWORD FileNameLength; | |
1855 WCHAR FileName[1]; | |
1856 } FILE_NAME_INFO_; | |
1857 | |
1858 typedef BOOL (WINAPI *pfnGetFileInformationByHandleEx)( | |
1859 HANDLE hFile, | |
1860 FILE_INFO_BY_HANDLE_CLASS_ FileInformationClass, | |
1861 LPVOID lpFileInformation, | |
1862 DWORD dwBufferSize); | |
1863 static pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL; | |
1864 | |
1865 typedef BOOL (WINAPI *pfnGetVolumeInformationByHandleW)( | |
1866 HANDLE hFile, | |
1867 LPWSTR lpVolumeNameBuffer, | |
1868 DWORD nVolumeNameSize, | |
1869 LPDWORD lpVolumeSerialNumber, | |
1870 LPDWORD lpMaximumComponentLength, | |
1871 LPDWORD lpFileSystemFlags, | |
1872 LPWSTR lpFileSystemNameBuffer, | |
1873 DWORD nFileSystemNameSize); | |
1874 static pfnGetVolumeInformationByHandleW pGetVolumeInformationByHandleW = NULL; | |
1875 | |
1876 char_u * | |
1877 resolve_reparse_point(char_u *fname) | |
1878 { | |
1879 HANDLE h = INVALID_HANDLE_VALUE; | |
1880 DWORD size; | |
1881 char_u *rfname = NULL; | |
1882 FILE_NAME_INFO_ *nameinfo = NULL; | |
1883 WCHAR buff[MAX_PATH], *volnames = NULL; | |
1884 HANDLE hv; | |
1885 DWORD snfile, snfind; | |
1886 static BOOL loaded = FALSE; | |
1887 | |
1888 if (pGetFileInformationByHandleEx == NULL || | |
1889 pGetVolumeInformationByHandleW == NULL) | |
1890 { | |
1891 HMODULE hmod = GetModuleHandle("kernel32.dll"); | |
1892 | |
1893 if (loaded == TRUE) | |
1894 return NULL; | |
1895 pGetFileInformationByHandleEx = (pfnGetFileInformationByHandleEx) | |
1896 GetProcAddress(hmod, "GetFileInformationByHandleEx"); | |
1897 pGetVolumeInformationByHandleW = (pfnGetVolumeInformationByHandleW) | |
1898 GetProcAddress(hmod, "GetVolumeInformationByHandleW"); | |
1899 loaded = TRUE; | |
1900 if (pGetFileInformationByHandleEx == NULL || | |
1901 pGetVolumeInformationByHandleW == NULL) | |
1902 return NULL; | |
1903 } | |
1904 | |
1905 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) | |
1906 { | |
1907 WCHAR *p; | |
1908 | |
1909 p = enc_to_utf16(fname, NULL); | |
1910 if (p == NULL) | |
1911 goto fail; | |
1912 | |
1913 if ((GetFileAttributesW(p) & FILE_ATTRIBUTE_REPARSE_POINT) == 0) | |
1914 { | |
1915 vim_free(p); | |
1916 goto fail; | |
1917 } | |
1918 | |
1919 h = CreateFileW(p, 0, 0, NULL, OPEN_EXISTING, | |
1920 FILE_FLAG_BACKUP_SEMANTICS, NULL); | |
1921 vim_free(p); | |
1922 } | |
1923 else | |
1924 { | |
1925 if ((GetFileAttributes((char*) fname) & | |
1926 FILE_ATTRIBUTE_REPARSE_POINT) == 0) | |
1927 goto fail; | |
1928 | |
1929 h = CreateFile((char*) fname, 0, 0, NULL, OPEN_EXISTING, | |
1930 FILE_FLAG_BACKUP_SEMANTICS, NULL); | |
1931 } | |
1932 | |
1933 if (h == INVALID_HANDLE_VALUE) | |
1934 goto fail; | |
1935 | |
1936 size = sizeof(FILE_NAME_INFO_) + sizeof(WCHAR) * (MAX_PATH - 1); | |
1937 nameinfo = (FILE_NAME_INFO_*)alloc(size + sizeof(WCHAR)); | |
1938 if (nameinfo == NULL) | |
1939 goto fail; | |
1940 | |
1941 if (!pGetFileInformationByHandleEx(h, FileNameInfo_, nameinfo, size)) | |
1942 goto fail; | |
1943 | |
1944 nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = 0; | |
1945 | |
1946 if (!pGetVolumeInformationByHandleW( | |
1947 h, NULL, 0, &snfile, NULL, NULL, NULL, 0)) | |
1948 goto fail; | |
1949 | |
1950 hv = FindFirstVolumeW(buff, MAX_PATH); | |
1951 if (hv == INVALID_HANDLE_VALUE) | |
1952 goto fail; | |
1953 | |
1954 do { | |
1955 GetVolumeInformationW( | |
1956 buff, NULL, 0, &snfind, NULL, NULL, NULL, 0); | |
1957 if (snfind == snfile) | |
1958 break; | |
1959 } while (FindNextVolumeW(hv, buff, MAX_PATH)); | |
1960 | |
1961 FindVolumeClose(hv); | |
1962 | |
1963 if (snfind != snfile) | |
1964 goto fail; | |
1965 | |
1966 size = 0; | |
1967 if (!GetVolumePathNamesForVolumeNameW(buff, NULL, 0, &size) && | |
1968 GetLastError() != ERROR_MORE_DATA) | |
1969 goto fail; | |
1970 | |
1971 volnames = (WCHAR*)alloc(size * sizeof(WCHAR)); | |
1972 if (!GetVolumePathNamesForVolumeNameW(buff, volnames, size, | |
1973 &size)) | |
1974 goto fail; | |
1975 | |
1976 wcscpy(buff, volnames); | |
1977 if (nameinfo->FileName[0] == '\\') | |
1978 wcscat(buff, nameinfo->FileName + 1); | |
1979 else | |
1980 wcscat(buff, nameinfo->FileName); | |
1981 rfname = utf16_to_enc(buff, NULL); | |
1982 | |
1983 fail: | |
1984 if (h != INVALID_HANDLE_VALUE) | |
1985 CloseHandle(h); | |
1986 if (nameinfo != NULL) | |
1987 vim_free(nameinfo); | |
1988 if (volnames != NULL) | |
1989 vim_free(volnames); | |
1990 | |
1991 return rfname; | |
1992 } | |
1993 | |
1826 /* | 1994 /* |
1827 * When "fname" is the name of a shortcut (*.lnk) resolve the file it points | 1995 * When "fname" is the name of a shortcut (*.lnk) resolve the file it points |
1828 * to and return that name in allocated memory. | 1996 * to and return that name in allocated memory. |
1829 * Otherwise NULL is returned. | 1997 * Otherwise NULL is returned. |
1830 */ | 1998 */ |
1831 char_u * | 1999 static char_u * |
1832 mch_resolve_shortcut(char_u *fname) | 2000 resolve_shortcut(char_u *fname) |
1833 { | 2001 { |
1834 HRESULT hr; | 2002 HRESULT hr; |
1835 IShellLink *psl = NULL; | 2003 IShellLink *psl = NULL; |
1836 IPersistFile *ppf = NULL; | 2004 IPersistFile *ppf = NULL; |
1837 OLECHAR wsz[MAX_PATH]; | 2005 OLECHAR wsz[MAX_PATH]; |
1934 if (pslw != NULL) | 2102 if (pslw != NULL) |
1935 pslw->lpVtbl->Release(pslw); | 2103 pslw->lpVtbl->Release(pslw); |
1936 | 2104 |
1937 CoUninitialize(); | 2105 CoUninitialize(); |
1938 return rfname; | 2106 return rfname; |
2107 } | |
2108 | |
2109 char_u * | |
2110 mch_resolve_path(char_u *fname, int reparse_point) | |
2111 { | |
2112 char_u *path = resolve_shortcut(fname); | |
2113 | |
2114 if (path == NULL && reparse_point) | |
2115 path = resolve_reparse_point(fname); | |
2116 return path; | |
1939 } | 2117 } |
1940 #endif | 2118 #endif |
1941 | 2119 |
1942 #if (defined(FEAT_EVAL) && !defined(FEAT_GUI)) || defined(PROTO) | 2120 #if (defined(FEAT_EVAL) && !defined(FEAT_GUI)) || defined(PROTO) |
1943 /* | 2121 /* |