-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
'cmd/git.exe' not support launcher from symlink with other directory #1650
Comments
Oh, whoops! I missed this ticket. Is this no longer an issue, @fcharlie? |
@dscho This issue has not been resolved. But I have other solutions. We can create a launcher startup git process(wait git). Readlink impl Support #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;
struct ReparseBuffer {
ReparseBuffer() {
data = reinterpret_cast<REPARSE_DATA_BUFFER *>(
malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE));
}
~ReparseBuffer() {
if (data != nullptr) {
free(data);
}
}
REPARSE_DATA_BUFFER *data{nullptr};
};
bool Readlink(const std::wstring &symfile, std::wstring &realfile) {
auto hFile = CreateFileW(
symfile.c_str(), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
ErrorMessage err(GetLastError());
fwprintf(stderr, L"CreateFileW: %s\n", err.message());
return false;
}
ReparseBuffer rbuf;
DWORD dwBytes = 0;
if (DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, rbuf.data,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwBytes,
nullptr) != TRUE) {
ErrorMessage err(GetLastError());
fwprintf(stderr, L"DeviceIoControl: %s\n", err.message());
CloseHandle(hFile);
return false;
}
CloseHandle(hFile);
switch (rbuf.data->ReparseTag) {
case IO_REPARSE_TAG_SYMLINK: {
auto wstr = rbuf.data->SymbolicLinkReparseBuffer.PathBuffer +
(rbuf.data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
sizeof(WCHAR));
auto wlen = rbuf.data->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'\\')) {
/* \??\<drive>:\ */
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\<server>\<share>\ - make sure the final path looks like */
/* \\<server>\<share>\ */
wstr += 6;
wstr[0] = L'\\';
wlen -= 6;
}
}
realfile.assign(wstr, wlen);
} break;
case IO_REPARSE_TAG_MOUNT_POINT: {
auto wstr = rbuf.data->MountPointReparseBuffer.PathBuffer +
(rbuf.data->MountPointReparseBuffer.SubstituteNameOffset /
sizeof(WCHAR));
auto wlen =
rbuf.data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
/* Only treat junctions that look like \??\<drive>:\ as symlink. */
/* Junctions can also be used as mount points, like \??\Volume{<guid>}, */
/* 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);
return false;
}
/* Remove leading \??\ */
wstr += 4;
wlen -= 4;
realfile.assign(wstr, wlen);
} break;
case IO_REPARSE_TAG_APPEXECLINK: {
if (rbuf.data->AppExecLinkReparseBuffer.StringCount != 0) {
LPWSTR szString = (LPWSTR)rbuf.data->AppExecLinkReparseBuffer.StringList;
for (ULONG i = 0; i < rbuf.data->AppExecLinkReparseBuffer.StringCount;
i++) {
if (i == 2) {
realfile = szString;
}
szString += wcslen(szString) + 1;
}
}
} break;
default:
return false;
}
return true;
} |
@dscho Look like mingw-w64-git/git-wrapper.c doesn't resolve symbolic links. |
@dscho I added a PR to fix this issues git-for-windows/MINGW-packages#30 |
It is [now possible to call `cmd\git.exe` via a symbolic link](git-for-windows/git#1650). Signed-off-by: Johannes Schindelin <[email protected]>
Setup
defaults?
output:
I think this launcher doesn't consider the symbolic link that may be returned by GetModuleFileName.
The text was updated successfully, but these errors were encountered: