GetFinalPathNameByHandleW添加FILE_NAME_NORMALIZED支持(感谢 清泠)

This commit is contained in:
mingkuang
2021-05-14 16:38:59 +08:00
parent 98ddb6ef0e
commit 0f362cbcd3
3 changed files with 171 additions and 110 deletions
+2 -1
View File
@@ -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参数处理错误。
+118 -109
View File
@@ -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)
{
+51
View File
@@ -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