[KERNEL32]: Reimplement GetDiskFreeSpaceW() to fix various issues in it. It also brings support for appcompat

This commit is contained in:
Pierre Schweitzer 2017-10-04 22:27:14 +02:00
parent 55ae20931f
commit 5bee374c82

View file

@ -215,50 +215,131 @@ GetDiskFreeSpaceW(IN LPCWSTR lpRootPathName,
OUT LPDWORD lpNumberOfFreeClusters, OUT LPDWORD lpNumberOfFreeClusters,
OUT LPDWORD lpTotalNumberOfClusters) OUT LPDWORD lpTotalNumberOfClusters)
{ {
FILE_FS_SIZE_INFORMATION FileFsSize; BOOL Below2GB;
PCWSTR RootPath;
NTSTATUS Status;
HANDLE RootHandle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock; IO_STATUS_BLOCK IoStatusBlock;
WCHAR RootPathName[MAX_PATH]; OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hFile; FILE_FS_SIZE_INFORMATION FileFsSize;
NTSTATUS errCode;
if (lpRootPathName) /* If no path provided, get root path */
RootPath = lpRootPathName;
if (lpRootPathName == NULL)
{ {
wcsncpy (RootPathName, lpRootPathName, 3); RootPath = L"\\";
} }
else
{
GetCurrentDirectoryW (MAX_PATH, RootPathName);
}
RootPathName[3] = 0;
hFile = InternalOpenDirW(RootPathName, FALSE); /* Convert the path to NT path */
if (INVALID_HANDLE_VALUE == hFile) if (!RtlDosPathNameToNtPathName_U(RootPath, &FileName, NULL, NULL))
{ {
SetLastError(ERROR_PATH_NOT_FOUND); SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE; return FALSE;
} }
errCode = NtQueryVolumeInformationFile(hFile, /* Open it for disk space query! */
&IoStatusBlock, InitializeObjectAttributes(&ObjectAttributes, &FileName,
&FileFsSize, OBJ_CASE_INSENSITIVE, NULL, NULL);
sizeof(FILE_FS_SIZE_INFORMATION), Status = NtOpenFile(&RootHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock,
FileFsSizeInformation); FILE_SHARE_READ | FILE_SHARE_WRITE,
if (!NT_SUCCESS(errCode)) FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_FREE_SPACE_QUERY);
if (!NT_SUCCESS(Status))
{ {
CloseHandle(hFile); BaseSetLastNTError(Status);
BaseSetLastNTError (errCode); RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer);
if (lpBytesPerSector != NULL)
{
*lpBytesPerSector = 0;
}
return FALSE; return FALSE;
} }
if (lpSectorsPerCluster) /* We don't need the name any longer */
RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer);
/* Query disk space! */
Status = NtQueryVolumeInformationFile(RootHandle, &IoStatusBlock, &FileFsSize,
sizeof(FILE_FS_SIZE_INFORMATION),
FileFsSizeInformation);
NtClose(RootHandle);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError(Status);
return FALSE;
}
/* Are we in some compatibility mode where size must be below 2GB? */
Below2GB = ((NtCurrentPeb()->AppCompatFlags.LowPart & GetDiskFreeSpace2GB) == GetDiskFreeSpace2GB);
/* If we're to overflow output, make sure we return the maximum */
if (FileFsSize.TotalAllocationUnits.HighPart != 0)
{
FileFsSize.TotalAllocationUnits.LowPart = -1;
}
if (FileFsSize.AvailableAllocationUnits.HighPart != 0)
{
FileFsSize.AvailableAllocationUnits.LowPart = -1;
}
/* Return what user asked for */
if (lpSectorsPerCluster != NULL)
{
*lpSectorsPerCluster = FileFsSize.SectorsPerAllocationUnit; *lpSectorsPerCluster = FileFsSize.SectorsPerAllocationUnit;
if (lpBytesPerSector) }
if (lpBytesPerSector != NULL)
{
*lpBytesPerSector = FileFsSize.BytesPerSector; *lpBytesPerSector = FileFsSize.BytesPerSector;
if (lpNumberOfFreeClusters) }
*lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.u.LowPart;
if (lpTotalNumberOfClusters) if (lpNumberOfFreeClusters != NULL)
*lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.u.LowPart; {
CloseHandle(hFile); if (!Below2GB)
{
*lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.LowPart;
}
/* If we have to remain below 2GB... */
else
{
DWORD FreeClusters;
/* Compute how many clusters there are in less than 2GB: 2 * 1024 * 1024 * 1024- 1 */
FreeClusters = 0x7FFFFFFF / (FileFsSize.SectorsPerAllocationUnit * FileFsSize.BytesPerSector);
/* If that's higher than what was queried, then return the queried value, it's OK! */
if (FreeClusters > FileFsSize.AvailableAllocationUnits.LowPart)
{
FreeClusters = FileFsSize.AvailableAllocationUnits.LowPart;
}
*lpNumberOfFreeClusters = FreeClusters;
}
}
if (lpTotalNumberOfClusters != NULL)
{
if (!Below2GB)
{
*lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.LowPart;
}
/* If we have to remain below 2GB... */
else
{
DWORD TotalClusters;
/* Compute how many clusters there are in less than 2GB: 2 * 1024 * 1024 * 1024- 1 */
TotalClusters = 0x7FFFFFFF / (FileFsSize.SectorsPerAllocationUnit * FileFsSize.BytesPerSector);
/* If that's higher than what was queried, then return the queried value, it's OK! */
if (TotalClusters > FileFsSize.TotalAllocationUnits.LowPart)
{
TotalClusters = FileFsSize.TotalAllocationUnits.LowPart;
}
*lpTotalNumberOfClusters = TotalClusters;
}
}
return TRUE; return TRUE;
} }