[KERNEL32]: Refactor a bit GetDiskFreeSpaceExW(), no ground breaking changes

This commit is contained in:
Pierre Schweitzer 2017-10-04 23:00:12 +02:00
parent 87448f3d8b
commit 1e2424ee98

View file

@ -383,103 +383,117 @@ GetDiskFreeSpaceExW(IN LPCWSTR lpDirectoryName OPTIONAL,
OUT PULARGE_INTEGER lpTotalNumberOfBytes, OUT PULARGE_INTEGER lpTotalNumberOfBytes,
OUT PULARGE_INTEGER lpTotalNumberOfFreeBytes) OUT PULARGE_INTEGER lpTotalNumberOfFreeBytes)
{ {
union PCWSTR RootPath;
{
FILE_FS_SIZE_INFORMATION FsSize;
FILE_FS_FULL_SIZE_INFORMATION FsFullSize;
} FsInfo;
IO_STATUS_BLOCK IoStatusBlock;
ULARGE_INTEGER BytesPerCluster;
HANDLE hFile;
NTSTATUS Status; NTSTATUS Status;
HANDLE RootHandle;
UNICODE_STRING FileName;
DWORD BytesPerAllocationUnit;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
FILE_FS_SIZE_INFORMATION FileFsSize;
/* If no path provided, get root path */
RootPath = lpDirectoryName;
if (lpDirectoryName == NULL) if (lpDirectoryName == NULL)
lpDirectoryName = L"\\";
hFile = InternalOpenDirW(lpDirectoryName, FALSE);
if (INVALID_HANDLE_VALUE == hFile)
{ {
RootPath = L"\\";
}
/* Convert the path to NT path */
if (!RtlDosPathNameToNtPathName_U(RootPath, &FileName, NULL, NULL))
{
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE; return FALSE;
} }
if (lpFreeBytesAvailableToCaller != NULL || lpTotalNumberOfBytes != NULL) /* Open it for disk space query! */
InitializeObjectAttributes(&ObjectAttributes, &FileName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtOpenFile(&RootHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_FREE_SPACE_QUERY);
if (!NT_SUCCESS(Status))
{ {
/* To get the free space available to the user associated with the BaseSetLastNTError(Status);
current thread, try FileFsFullSizeInformation. If this is not /* If error conversion lead to file not found, override to use path not found
supported by the file system, fall back to FileFsSize */ * which is more accurate
*/
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
SetLastError(ERROR_PATH_NOT_FOUND);
}
Status = NtQueryVolumeInformationFile(hFile, RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer);
&IoStatusBlock,
&FsInfo.FsFullSize, return FALSE;
sizeof(FsInfo.FsFullSize), }
RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer);
/* If user asks for lpTotalNumberOfFreeBytes, try to use full size information */
if (lpTotalNumberOfFreeBytes != NULL)
{
FILE_FS_FULL_SIZE_INFORMATION FileFsFullSize;
/* Issue the full fs size request */
Status = NtQueryVolumeInformationFile(RootHandle, &IoStatusBlock, &FileFsFullSize,
sizeof(FILE_FS_FULL_SIZE_INFORMATION),
FileFsFullSizeInformation); FileFsFullSizeInformation);
/* If it succeed, complete out buffers */
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
/* Close the handle before returning data /* We can close here, we'll return */
to avoid a handle leak in case of a fault! */ NtClose(RootHandle);
CloseHandle(hFile);
BytesPerCluster.QuadPart = /* Compute the size of an AU */
FsInfo.FsFullSize.BytesPerSector * FsInfo.FsFullSize.SectorsPerAllocationUnit; BytesPerAllocationUnit = FileFsFullSize.SectorsPerAllocationUnit * FileFsFullSize.BytesPerSector;
/* And then return what was asked */
if (lpFreeBytesAvailableToCaller != NULL) if (lpFreeBytesAvailableToCaller != NULL)
{ {
lpFreeBytesAvailableToCaller->QuadPart = lpFreeBytesAvailableToCaller->QuadPart = FileFsFullSize.CallerAvailableAllocationUnits.QuadPart * BytesPerAllocationUnit;
BytesPerCluster.QuadPart * FsInfo.FsFullSize.CallerAvailableAllocationUnits.QuadPart;
} }
if (lpTotalNumberOfBytes != NULL) if (lpTotalNumberOfBytes != NULL)
{ {
lpTotalNumberOfBytes->QuadPart = lpTotalNumberOfBytes->QuadPart = FileFsFullSize.TotalAllocationUnits.QuadPart * BytesPerAllocationUnit;
BytesPerCluster.QuadPart * FsInfo.FsFullSize.TotalAllocationUnits.QuadPart;
} }
if (lpTotalNumberOfFreeBytes != NULL) /* No need to check for nullness ;-) */
{ lpTotalNumberOfFreeBytes->QuadPart = FileFsFullSize.ActualAvailableAllocationUnits.QuadPart * BytesPerAllocationUnit;
lpTotalNumberOfFreeBytes->QuadPart =
BytesPerCluster.QuadPart * FsInfo.FsFullSize.ActualAvailableAllocationUnits.QuadPart;
}
return TRUE; return TRUE;
} }
} }
Status = NtQueryVolumeInformationFile(hFile, /* Otherwise, fallback to normal size information */
&IoStatusBlock, Status = NtQueryVolumeInformationFile(RootHandle, &IoStatusBlock,
&FsInfo.FsSize, &FileFsSize, sizeof(FILE_FS_SIZE_INFORMATION),
sizeof(FsInfo.FsSize),
FileFsSizeInformation); FileFsSizeInformation);
NtClose(RootHandle);
/* Close the handle before returning data
to avoid a handle leak in case of a fault! */
CloseHandle(hFile);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
BaseSetLastNTError (Status); BaseSetLastNTError(Status);
return FALSE; return FALSE;
} }
BytesPerCluster.QuadPart = /* Compute the size of an AU */
FsInfo.FsSize.BytesPerSector * FsInfo.FsSize.SectorsPerAllocationUnit; BytesPerAllocationUnit = FileFsSize.SectorsPerAllocationUnit * FileFsSize.BytesPerSector;
if (lpFreeBytesAvailableToCaller) /* And then return what was asked, available is free, the same! */
if (lpFreeBytesAvailableToCaller != NULL)
{ {
lpFreeBytesAvailableToCaller->QuadPart = lpFreeBytesAvailableToCaller->QuadPart = FileFsSize.AvailableAllocationUnits.QuadPart * BytesPerAllocationUnit;
BytesPerCluster.QuadPart * FsInfo.FsSize.AvailableAllocationUnits.QuadPart;
} }
if (lpTotalNumberOfBytes) if (lpTotalNumberOfBytes != NULL)
{ {
lpTotalNumberOfBytes->QuadPart = lpTotalNumberOfBytes->QuadPart = FileFsSize.TotalAllocationUnits.QuadPart * BytesPerAllocationUnit;
BytesPerCluster.QuadPart * FsInfo.FsSize.TotalAllocationUnits.QuadPart;
} }
if (lpTotalNumberOfFreeBytes) if (lpTotalNumberOfFreeBytes != NULL)
{ {
lpTotalNumberOfFreeBytes->QuadPart = lpTotalNumberOfFreeBytes->QuadPart = FileFsSize.AvailableAllocationUnits.QuadPart * BytesPerAllocationUnit;
BytesPerCluster.QuadPart * FsInfo.FsSize.AvailableAllocationUnits.QuadPart;
} }
return TRUE; return TRUE;