diff --git a/mingw-w64-git/git-wrapper.c b/mingw-w64-git/git-wrapper.c index f8381fca67832..5f4caeeeaf9b1 100644 --- a/mingw-w64-git/git-wrapper.c +++ b/mingw-w64-git/git-wrapper.c @@ -9,7 +9,6 @@ #define UNICODE #define _UNICODE #include -#include #include #include #include @@ -42,196 +41,31 @@ static void print_error(LPCWSTR prefix, DWORD error_number) LocalFree((HLOCAL)buffer); } -#ifndef IO_REPARSE_TAG_APPEXECLINK -#define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL) -#endif - -// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/ns-ntifs-_reparse_data_buffer - -typedef struct _REPARSE_DATA_BUFFER { - ULONG ReparseTag; // Reparse tag type - USHORT ReparseDataLength; // Length of the reparse data - USHORT Reserved; // Used internally by NTFS to store remaining length - - union { - // Structure for IO_REPARSE_TAG_SYMLINK - // Handled by nt!IoCompleteRequest - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - - // Structure for IO_REPARSE_TAG_MOUNT_POINT - // Handled by nt!IoCompleteRequest - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - - // Structure for IO_REPARSE_TAG_WIM - // Handled by wimmount!FPOpenReparseTarget->wimserv.dll - // (wimsrv!ImageExtract) - struct { - GUID ImageGuid; // GUID of the mounted VIM image - BYTE ImagePathHash[0x14]; // Hash of the path to the file within the image - } WimImageReparseBuffer; - - // Structure for IO_REPARSE_TAG_WOF - // Handled by FSCTL_GET_EXTERNAL_BACKING, FSCTL_SET_EXTERNAL_BACKING in NTFS - // (Windows 10+) - struct { - //-- WOF_EXTERNAL_INFO -------------------- - ULONG Wof_Version; // Should be 1 (WOF_CURRENT_VERSION) - ULONG Wof_Provider; // Should be 2 (WOF_PROVIDER_FILE) - - //-- FILE_PROVIDER_EXTERNAL_INFO_V1 -------------------- - ULONG FileInfo_Version; // Should be 1 (FILE_PROVIDER_CURRENT_VERSION) - ULONG - FileInfo_Algorithm; // Usually 0 (FILE_PROVIDER_COMPRESSION_XPRESS4K) - } WofReparseBuffer; - - // Structure for IO_REPARSE_TAG_APPEXECLINK - struct { - ULONG StringCount; // Number of the strings in the StringList, separated - // by '\0' - WCHAR StringList[1]; // Multistring (strings separated by '\0', terminated - // by '\0\0') - } AppExecLinkReparseBuffer; - - // Dummy structure - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - } DUMMYUNIONNAME; -} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; - -BOOL win_readlink(LPCWSTR symfile, LPWSTR buf, DWORD maxsize) { - HANDLE hFile = INVALID_HANDLE_VALUE; - REPARSE_DATA_BUFFER *respbuf = NULL; - DWORD dwBytes = 0; - LPWSTR wstr = NULL; - int wlen = 0; - BOOL ret = FALSE; - hFile = CreateFileW( - symfile, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return FALSE; - } - respbuf = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - if (DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, respbuf, - MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwBytes, - NULL) != TRUE) { - CloseHandle(hFile); - free(respbuf); - return FALSE; - } - CloseHandle(hFile); - switch (respbuf->ReparseTag) { - case IO_REPARSE_TAG_SYMLINK: { - wstr = respbuf->SymbolicLinkReparseBuffer.PathBuffer + - (respbuf->SymbolicLinkReparseBuffer.SubstituteNameOffset / - sizeof(WCHAR)); - wlen = - respbuf->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR); - if (wlen >= 4 && wstr[0] == L'\\' && wstr[1] == L'?' && wstr[2] == L'?' && - wstr[3] == L'\\') { - /* Starts with \??\ */ - if (wlen >= 6 && - ((wstr[4] >= L'A' && wstr[4] <= L'Z') || - (wstr[4] >= L'a' && wstr[4] <= L'z')) && - wstr[5] == L':' && (wlen == 6 || wstr[6] == L'\\')) { - /* \??\:\ */ - wstr += 4; - wlen -= 4; - - } else if (wlen >= 8 && (wstr[4] == L'U' || wstr[4] == L'u') && - (wstr[5] == L'N' || wstr[5] == L'n') && - (wstr[6] == L'C' || wstr[6] == L'c') && wstr[7] == L'\\') { - /* \??\UNC\\\ - make sure the final path looks like */ - /* \\\\ */ - wstr += 6; - wstr[0] = L'\\'; - wlen -= 6; - } - } - if (wlen >= maxsize) { - break; - } - wcsncpy(buf, wstr, wlen); - ret = TRUE; - } break; - case IO_REPARSE_TAG_MOUNT_POINT: { - wstr = - respbuf->MountPointReparseBuffer.PathBuffer + - (respbuf->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)); - wlen = - respbuf->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR); - /* Only treat junctions that look like \??\:\ as symlink. */ - /* Junctions can also be used as mount points, like \??\Volume{}, */ - /* but that's confusing for programs since they wouldn't be able to */ - /* actually understand such a path when returned by uv_readlink(). */ - /* UNC paths are never valid for junctions so we don't care about them. */ - if (!(wlen >= 6 && wstr[0] == L'\\' && wstr[1] == L'?' && wstr[2] == L'?' && - wstr[3] == L'\\' && - ((wstr[4] >= L'A' && wstr[4] <= L'Z') || - (wstr[4] >= L'a' && wstr[4] <= L'z')) && - wstr[5] == L':' && (wlen == 6 || wstr[6] == L'\\'))) { - SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); - break; - } - - /* Remove leading \??\ */ - wstr += 4; - wlen -= 4; - if (wlen >= maxsize) { - break; - } - wcsncpy(buf, wstr, wlen); - ret = TRUE; - } break; - case IO_REPARSE_TAG_APPEXECLINK: { - if (respbuf->AppExecLinkReparseBuffer.StringCount != 0) { - LPWSTR szString = NULL, szTarget = NULL; - szString = (LPWSTR)respbuf->AppExecLinkReparseBuffer.StringList; - ULONG i = 0; - for (; i < respbuf->AppExecLinkReparseBuffer.StringCount; i++) { - if (i == 2) { - szTarget = szString; - } - szString += wcslen(szString) + 1; - } - if (wlen >= maxsize || szTarget == NULL) { - break; - } - wcsncpy(buf, szTarget, wlen); - ret = TRUE; - } - } break; - default: - break; - } - free(respbuf); - return ret; -} static void find_exe_realpath(LPWSTR exepath, int count) { - WCHAR mdexe[MAX_PATH]; + WCHAR mdexe[MAX_PATH], realexe[MAX_PATH]; + HANDLE hFile = INVALID_HANDLE_VALUE; + DWORD dwlen = 0; /* get the installation location */ - GetModuleFileName(NULL, mdexe, MAX_PATH); - if (win_readlink(mdexe, exepath, count)) { + GetModuleFileNameW(NULL, mdexe, MAX_PATH); + hFile = CreateFileW(mdexe, // file to open + GENERIC_READ, // open for reading + FILE_SHARE_READ, // share for reading + NULL, // default security + OPEN_EXISTING, // existing file only + FILE_ATTRIBUTE_NORMAL, // normal file + NULL); // no attr. template + if (hFile == INVALID_HANDLE_VALUE) { + wcscpy(exepath, mdexe); return; } - wcscpy(exepath, mdexe); - return; + dwlen = GetFinalPathNameByHandleW(hFile, realexe, MAX_PATH, VOLUME_NAME_DOS); + if (dwlen >= MAX_PATH) { + wcscpy(exepath, mdexe); + } else { + wcsncpy(exepath, realexe + 4, dwlen - 4); + } + CloseHandle(hFile); }