diff --git a/YY-Thunks.nuspec b/YY-Thunks.nuspec index aab34a2..d78926c 100644 --- a/YY-Thunks.nuspec +++ b/YY-Thunks.nuspec @@ -31,7 +31,8 @@ * 代ç �优化 - å‡�å°‘ GetDpiForSystemDownlevel 函数中 GetDeviceCaps 的调用次数(感谢 毛利)。 - å�ˆå¹¶[RP 11](https://github.com/Chuyu-Team/YY-Thunks/pull/11), 填充自旋é”�中那些Unknowå�˜é‡�的语义(感谢 zeroclear) - + - GetFinalPathNameByHandleW添加FILE_NAME_NORMALIZED支æŒ�(感谢 清泠) + * 解决[Bug 10](https://github.com/Chuyu-Team/YY-Thunks/issues/10), XP下BaseSetLastNTError转æ�¢STATUS_TIMEOUT会报错。 * 解决[Bug 12](https://github.com/Chuyu-Team/YY-Thunks/issues/12), XPä¸�支æŒ�SetFileInformationByHandleä¼ å…¥FileRenameInfo。 * 解决[Bug 13](https://github.com/Chuyu-Team/YY-Thunks/issues/13),RtlRunOnceBeginInitialize一处lpInitOnceå�‚数处ç�†é”™è¯¯ã€‚ diff --git a/src/Thunks/api-ms-win-core-file.hpp b/src/Thunks/api-ms-win-core-file.hpp index ce3d697..93a6186 100644 --- a/src/Thunks/api-ms-win-core-file.hpp +++ b/src/Thunks/api-ms-win-core-file.hpp @@ -398,6 +398,18 @@ GetFinalPathNameByHandleW( return 0; } + UNICODE_STRING VolumeNtName = {}; + + wchar_t szVolumeRoot[MAX_PATH]; + szVolumeRoot[0] = L'\0'; + + wchar_t* szLongPathNameBuffer = nullptr; + + //Ä¿±êËùÐèµÄ·ÖÇøÃû³Æ£¬²»°üº¬×îºóµÄ '\\' + UNICODE_STRING TargetVolumeName = {}; + //Ä¿±êËùÐèµÄÎļþÃû£¬¿ªÊ¼°üº¬ '\\' + UNICODE_STRING TargetFileName = {}; + const auto ProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; LSTATUS lStatus = ERROR_SUCCESS; DWORD cchReturn = 0; @@ -512,160 +524,157 @@ GetFinalPathNameByHandleW( goto __Exit; } - //µÍÓÚVistaƽ̨ÎÞ·¨Ö§³Ö FILE_NAME_OPENED£¬Òò´ËºöÂÔ + VolumeNtName.Buffer = pObjectName->Name.Buffer; + VolumeNtName.Length = VolumeNtName.MaximumLength = pObjectName->Name.Length - pFileNameInfo->FileNameLength + sizeof(wchar_t); + if (VOLUME_NAME_NT & dwFlags) { //·µ»ØNT·¾¶ - cchReturn = pObjectName->Name.Length / sizeof(lpszFilePath[0]); - - if (cchFilePath <= cchReturn) - { - //³¤¶È²»×ã¡­¡­ - - cchReturn += 1; - } - else - { - memcpy(lpszFilePath, pObjectName->Name.Buffer, cchReturn * sizeof(lpszFilePath[0])); - - lpszFilePath[cchReturn] = L'\0'; - } + TargetVolumeName.Buffer = VolumeNtName.Buffer; + TargetVolumeName.Length = TargetVolumeName.MaximumLength = VolumeNtName.Length - sizeof(wchar_t); } else if (VOLUME_NAME_NONE & dwFlags) { //½ö·µ»ØÎļþÃû - cchReturn = pFileNameInfo->FileNameLength / sizeof(lpszFilePath[0]); - - if (cchFilePath <= cchReturn) - { - //³¤¶È²»×ã¡­¡­ - - cchReturn += 1; - } - else - { - memcpy(lpszFilePath, pFileNameInfo->FileName, cchReturn * sizeof(lpszFilePath[0])); - lpszFilePath[cchReturn] = L'\0'; - } } else { - const wchar_t szGobal[] = L"\\\\?\\GLOBALROOT"; - - const DWORD cbVolumeName = pObjectName->Name.Length - pFileNameInfo->FileNameLength + sizeof(lpszFilePath[0]); - - auto szVolumeMountPoint = (wchar_t*)HeapAlloc(ProcessHeap, 0, cbVolumeName + sizeof(szGobal)); - if (!szVolumeMountPoint) - { - lStatus = ERROR_NOT_ENOUGH_MEMORY; - goto __Exit; - } - - DWORD cbVolumeMountPoint = sizeof(szGobal) - sizeof(szGobal[0]); - - memcpy(szVolumeMountPoint, szGobal, cbVolumeMountPoint); - - memcpy((byte*)szVolumeMountPoint + cbVolumeMountPoint, pObjectName->Name.Buffer, cbVolumeName); - cbVolumeMountPoint += cbVolumeName; - - szVolumeMountPoint[cbVolumeMountPoint / sizeof(szVolumeMountPoint[0])] = L'\0'; - - wchar_t szVolumeName[MAX_PATH]; - - if (!GetVolumeNameForVolumeMountPointW(szVolumeMountPoint, szVolumeName, _countof(szVolumeName))) - { - lStatus = GetLastError(); - HeapFree(ProcessHeap, 0, szVolumeMountPoint); - - goto __Exit; - } - - HeapFree(ProcessHeap, 0, szVolumeMountPoint); - - if (VOLUME_NAME_GUID & dwFlags) { //·µ»Ø·ÖÇøGUIDÃû³Æ - - auto cchVolumeName = wcslen(szVolumeName); - - if (cchVolumeName == 0) + if (!internal::BasepGetVolumeGUIDFromNTName(&VolumeNtName, szVolumeRoot)) { - //¶ºÎÒ£¿ - lStatus = ERROR_INVALID_FUNCTION; + lStatus = GetLastError(); goto __Exit; } - - --cchVolumeName; - - cchReturn = cchVolumeName + pFileNameInfo->FileNameLength / sizeof(pFileNameInfo->FileName[0]); - - if (cchFilePath <= cchReturn) - { - cchReturn += 1; - } - else - { - //¸´ÖÆVolumeName - memcpy(lpszFilePath, szVolumeName, cchVolumeName * sizeof(szVolumeName[0])); - - //¸´ÖÆÎļþÃû - memcpy(lpszFilePath + cchVolumeName, pFileNameInfo->FileName, pFileNameInfo->FileNameLength); - - //NULL±ß½ç - lpszFilePath[cchReturn] = L'\0'; - } } else { //·µ»ØDos·¾¶ - DWORD cchVolumePathName = 0; - - wchar_t VolumePathName[MAX_PATH + 4] = L"\\\\?\\"; - - if (!GetVolumePathNamesForVolumeNameW(szVolumeName, VolumePathName + 4, MAX_PATH, &cchVolumePathName)) + if (!internal::BasepGetVolumeDosLetterNameFromNTName(&VolumeNtName, szVolumeRoot)) { lStatus = GetLastError(); goto __Exit; } + } - cchVolumePathName = wcslen(VolumePathName); + TargetVolumeName.Buffer = szVolumeRoot; + TargetVolumeName.Length = TargetVolumeName.MaximumLength = (wcslen(szVolumeRoot) - 1) * sizeof(szVolumeRoot[0]); + } - if (cchVolumePathName == 0) + //½«Â·¾¶½øÐй淶»¯ + if ((FILE_NAME_OPENED & dwFlags) == 0) + { + //ÓÉÓÚ Windows XP²»Ö§³Ö FileNormalizedNameInformation£¬ËùÒÔÎÒÃÇÖ±½Óµ÷Óà GetLongPathNameW »ñÈ¡ÍêÕû·¾¶¡£ + + DWORD cbszVolumeRoot = TargetVolumeName.Length; + + if (szVolumeRoot[0] == L'\0') + { + //ת»»·ÖÇøÐÅÏ¢ + + if (!internal::BasepGetVolumeDosLetterNameFromNTName(&VolumeNtName, szVolumeRoot)) { - //¶ºÎÒ£¿ - lStatus = ERROR_INVALID_FUNCTION; - goto __Exit; + lStatus = GetLastError(); + + if(lStatus == ERROR_NOT_ENOUGH_MEMORY) + goto __Exit; + + if (!internal::BasepGetVolumeGUIDFromNTName(&VolumeNtName, szVolumeRoot)) + { + lStatus = GetLastError(); + goto __Exit; + } } - --cchVolumePathName; + cbszVolumeRoot = (wcslen(szVolumeRoot) - 1) * sizeof(szVolumeRoot[0]); + } - cchReturn = cchVolumePathName + pFileNameInfo->FileNameLength / sizeof(pFileNameInfo->FileName[0]); - if (cchFilePath <= cchReturn) + + auto cbLongPathNameBufferSize = cbszVolumeRoot + pFileNameInfo->FileNameLength + 1024; + + szLongPathNameBuffer = (wchar_t*)HeapAlloc(ProcessHeap, 0, cbLongPathNameBufferSize); + if (!szLongPathNameBuffer) + { + lStatus = ERROR_NOT_ENOUGH_MEMORY; + goto __Exit; + } + + auto cchLongPathNameBufferSize = cbLongPathNameBufferSize / sizeof(szLongPathNameBuffer[0]); + + memcpy(szLongPathNameBuffer, szVolumeRoot, cbszVolumeRoot); + memcpy((char*)szLongPathNameBuffer + cbszVolumeRoot, pFileNameInfo->FileName, pFileNameInfo->FileNameLength); + szLongPathNameBuffer[(cbszVolumeRoot + pFileNameInfo->FileNameLength) / sizeof(wchar_t)] = L'\0'; + + for (;;) + { + auto result = GetLongPathNameW(szLongPathNameBuffer, szLongPathNameBuffer, cchLongPathNameBufferSize); + + if (result == 0) { - cchReturn += 1; + //ʧ°Ü + lStatus = GetLastError(); + goto __Exit; + } + else if (result >= cchLongPathNameBufferSize) + { + cchLongPathNameBufferSize = result + 1; + + auto pNewLongPathName = (wchar_t*)HeapReAlloc(ProcessHeap, 0, szLongPathNameBuffer, cchLongPathNameBufferSize * sizeof(wchar_t)); + if (!pNewLongPathName) + { + lStatus = ERROR_NOT_ENOUGH_MEMORY; + goto __Exit; + } + + szLongPathNameBuffer = pNewLongPathName; + } else { - //¸´ÖÆVolumePathName - memcpy(lpszFilePath, VolumePathName, cchVolumePathName * sizeof(VolumePathName[0])); - - //¸´ÖÆÎļþÃû - memcpy(lpszFilePath + cchVolumePathName, pFileNameInfo->FileName, pFileNameInfo->FileNameLength); - - //NULL±ß½ç - lpszFilePath[cchReturn] = L'\0'; + //ת»»³É¹¦ + TargetFileName.Buffer = (wchar_t*)((char*)szLongPathNameBuffer + cbszVolumeRoot); + TargetFileName.Length = TargetFileName.MaximumLength = result * sizeof(wchar_t) - cbszVolumeRoot; + break; } } } + else + { + //Ö±½Ó·µ»ØÔ­Ê¼Â·¾¶ + TargetFileName.Buffer = pFileNameInfo->FileName; + TargetFileName.Length = TargetFileName.MaximumLength = pFileNameInfo->FileNameLength; + } + + + //·µ»Ø½á¹û£¬¸ùĿ¼ + ÎļþÃû µÄ³¤¶È + cchReturn = (TargetVolumeName.Length + TargetFileName.Length) / sizeof(wchar_t); + + if (cchFilePath <= cchReturn) + { + //³¤¶È²»×ã¡­¡­ + + cchReturn += 1; + } + else + { + //¸´ÖƸùĿ¼ + memcpy(lpszFilePath, TargetVolumeName.Buffer, TargetVolumeName.Length); + //¸´ÖÆÎļþÃû + memcpy((char*)lpszFilePath + TargetVolumeName.Length, TargetFileName.Buffer, TargetFileName.Length); + //±£Ö¤×Ö·û´® '\0' ½Ø¶Ï + lpszFilePath[cchReturn] = L'\0'; + } __Exit: if (pFileNameInfo) HeapFree(ProcessHeap, 0, pFileNameInfo); if (pObjectName) HeapFree(ProcessHeap, 0, pObjectName); + if (szLongPathNameBuffer) + HeapFree(ProcessHeap, 0, szLongPathNameBuffer); if (lStatus != ERROR_SUCCESS) { diff --git a/src/YY_Thunks.cpp b/src/YY_Thunks.cpp index 1ec3b21..6879240 100644 --- a/src/YY_Thunks.cpp +++ b/src/YY_Thunks.cpp @@ -185,6 +185,57 @@ namespace YY return ERROR_SUCCESS; } + static BOOL __fastcall BasepGetVolumeGUIDFromNTName(const UNICODE_STRING* NtName, wchar_t szVolumeGUID[MAX_PATH]) + { +#define __szVolumeMountPointPrefix__ L"\\\\?\\GLOBALROOT" + + //Ò»¸öÉ豸Ãû³Æ 512 ³¤¶È¹»¶àÁ˰ɣ¿ + wchar_t szVolumeMountPoint[512]; + + //¼ì²é»º³åÇøÊÇ·ñ³ä×ã + auto cbBufferNeed = sizeof(__szVolumeMountPointPrefix__) + NtName->Length; + + if (cbBufferNeed > sizeof(szVolumeMountPoint)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + memcpy(szVolumeMountPoint, __szVolumeMountPointPrefix__, sizeof(__szVolumeMountPointPrefix__) - sizeof(__szVolumeMountPointPrefix__[0])); + memcpy((char*)szVolumeMountPoint + sizeof(__szVolumeMountPointPrefix__) - sizeof(__szVolumeMountPointPrefix__[0]), NtName->Buffer, NtName->Length); + + szVolumeMountPoint[cbBufferNeed / 2 - 1] = L'\0'; + + + return GetVolumeNameForVolumeMountPointW(szVolumeMountPoint, szVolumeGUID, MAX_PATH); + +#undef __szVolumeMountPointPrefix__ + } + + static BOOL __fastcall BasepGetVolumeDosLetterNameFromNTName(const UNICODE_STRING* NtName, wchar_t szVolumeDosLetter[MAX_PATH]) + { + wchar_t szVolumeName[MAX_PATH]; + + if (!BasepGetVolumeGUIDFromNTName(NtName, szVolumeName)) + { + return FALSE; + } + + DWORD cchVolumePathName = 0; + + if (!GetVolumePathNamesForVolumeNameW(szVolumeName, szVolumeDosLetter + 4, MAX_PATH - 4, &cchVolumePathName)) + { + return FALSE; + } + + szVolumeDosLetter[0] = L'\\'; + szVolumeDosLetter[1] = L'\\'; + szVolumeDosLetter[2] = L'?'; + szVolumeDosLetter[3] = L'\\'; + + return TRUE; + } + } }//namespace Thunks