Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: dll/win32/kernel32/client/file/disk.c * PURPOSE: Disk and Drive functions * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) * Erik Bos, Alexandre Julliard : * GetLogicalDriveStringsA, * GetLogicalDriveStringsW, GetLogicalDrives * UPDATE HISTORY: * Created 01/11/98 *///WINE copyright notice:/* * DOS drives handling functions * * Copyright 1993 Erik Bos * Copyright 1996 Alexandre Julliard */
#include <k32.h>
#define NDEBUG#include <debug.h>
#define MAX_DOS_DRIVES 26
/* * @implemented *//* Synced to Wine-2008/12/28 */DWORDWINAPIGetLogicalDriveStringsA(IN DWORD nBufferLength, IN LPSTR lpBuffer){ DWORD drive, count; DWORD dwDriveMap; LPSTR p;
dwDriveMap = GetLogicalDrives();
for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++) { if (dwDriveMap & (1<<drive)) count++; }
if ((count * 4) + 1 > nBufferLength) return ((count * 4) + 1);
p = lpBuffer;
for (drive = 0; drive < MAX_DOS_DRIVES; drive++) if (dwDriveMap & (1<<drive)) { *p++ = 'A' + (UCHAR)drive; *p++ = ':'; *p++ = '\\'; *p++ = '\0'; } *p = '\0';
return (count * 4);}
/* * @implemented *//* Synced to Wine-2008/12/28 */DWORDWINAPIGetLogicalDriveStringsW(IN DWORD nBufferLength, IN LPWSTR lpBuffer){ DWORD drive, count; DWORD dwDriveMap; LPWSTR p;
dwDriveMap = GetLogicalDrives();
for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++) { if (dwDriveMap & (1<<drive)) count++; }
if ((count * 4) + 1 > nBufferLength) return ((count * 4) + 1);
p = lpBuffer; for (drive = 0; drive < MAX_DOS_DRIVES; drive++) if (dwDriveMap & (1<<drive)) { *p++ = (WCHAR)('A' + drive); *p++ = (WCHAR)':'; *p++ = (WCHAR)'\\'; *p++ = (WCHAR)'\0'; } *p = (WCHAR)'\0';
return (count * 4);}
/* * @implemented *//* Synced to Wine-? */DWORDWINAPIGetLogicalDrives(VOID){ NTSTATUS Status; PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
/* Get the Device Map for this Process */ Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessDeviceMap, &ProcessDeviceMapInfo.Query, sizeof(ProcessDeviceMapInfo.Query), NULL);
/* Return the Drive Map */ if (!NT_SUCCESS(Status)) { BaseSetLastNTError(Status); return 0; }
if (ProcessDeviceMapInfo.Query.DriveMap == 0) { SetLastError(ERROR_SUCCESS); }
return ProcessDeviceMapInfo.Query.DriveMap;}
/* * @implemented */BOOLWINAPIGetDiskFreeSpaceA(IN LPCSTR lpRootPathName, OUT LPDWORD lpSectorsPerCluster, OUT LPDWORD lpBytesPerSector, OUT LPDWORD lpNumberOfFreeClusters, OUT LPDWORD lpTotalNumberOfClusters){ PCSTR RootPath; PUNICODE_STRING RootPathU;
RootPath = lpRootPathName; if (RootPath == NULL) { RootPath = "\\"; }
RootPathU = Basep8BitStringToStaticUnicodeString(RootPath); if (RootPathU == NULL) { return FALSE; }
return GetDiskFreeSpaceW(RootPathU->Buffer, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters);}
/* * @implemented */BOOLWINAPIGetDiskFreeSpaceW(IN LPCWSTR lpRootPathName, OUT LPDWORD lpSectorsPerCluster, OUT LPDWORD lpBytesPerSector, OUT LPDWORD lpNumberOfFreeClusters, OUT LPDWORD lpTotalNumberOfClusters){ BOOL Below2GB; PCWSTR RootPath; NTSTATUS Status; HANDLE RootHandle; UNICODE_STRING FileName; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; FILE_FS_SIZE_INFORMATION FileFsSize;
/* If no path provided, get root path */ RootPath = lpRootPathName; if (lpRootPathName == NULL) { RootPath = L"\\"; }
/* Convert the path to NT path */ if (!RtlDosPathNameToNtPathName_U(RootPath, &FileName, NULL, NULL)) { SetLastError(ERROR_PATH_NOT_FOUND); return FALSE; }
/* 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)) { BaseSetLastNTError(Status); RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer); if (lpBytesPerSector != NULL) { *lpBytesPerSector = 0; }
return FALSE; }
/* 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; }
if (lpBytesPerSector != NULL) { *lpBytesPerSector = FileFsSize.BytesPerSector; }
if (lpNumberOfFreeClusters != NULL) { 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;}
/* * @implemented */BOOLWINAPIGetDiskFreeSpaceExA(IN LPCSTR lpDirectoryName OPTIONAL, OUT PULARGE_INTEGER lpFreeBytesAvailableToCaller, OUT PULARGE_INTEGER lpTotalNumberOfBytes, OUT PULARGE_INTEGER lpTotalNumberOfFreeBytes){ PCSTR RootPath; PUNICODE_STRING RootPathU;
RootPath = lpDirectoryName; if (RootPath == NULL) { RootPath = "\\"; }
RootPathU = Basep8BitStringToStaticUnicodeString(RootPath); if (RootPathU == NULL) { return FALSE; }
return GetDiskFreeSpaceExW(RootPathU->Buffer, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes);}
/* * @implemented */BOOLWINAPIGetDiskFreeSpaceExW(IN LPCWSTR lpDirectoryName OPTIONAL, OUT PULARGE_INTEGER lpFreeBytesAvailableToCaller, OUT PULARGE_INTEGER lpTotalNumberOfBytes, OUT PULARGE_INTEGER lpTotalNumberOfFreeBytes){ PCWSTR RootPath; 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) { RootPath = L"\\"; }
/* Convert the path to NT path */ if (!RtlDosPathNameToNtPathName_U(RootPath, &FileName, NULL, NULL)) { SetLastError(ERROR_PATH_NOT_FOUND); return FALSE; }
/* 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)) { BaseSetLastNTError(Status); /* If error conversion lead to file not found, override to use path not found * which is more accurate */ if (GetLastError() == ERROR_FILE_NOT_FOUND) { SetLastError(ERROR_PATH_NOT_FOUND); }
RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer);
return FALSE; }
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); /* If it succeed, complete out buffers */ if (NT_SUCCESS(Status)) { /* We can close here, we'll return */ NtClose(RootHandle);
/* Compute the size of an AU */ BytesPerAllocationUnit = FileFsFullSize.SectorsPerAllocationUnit * FileFsFullSize.BytesPerSector;
/* And then return what was asked */ if (lpFreeBytesAvailableToCaller != NULL) { lpFreeBytesAvailableToCaller->QuadPart = FileFsFullSize.CallerAvailableAllocationUnits.QuadPart * BytesPerAllocationUnit; }
if (lpTotalNumberOfBytes != NULL) { lpTotalNumberOfBytes->QuadPart = FileFsFullSize.TotalAllocationUnits.QuadPart * BytesPerAllocationUnit; }
/* No need to check for nullness ;-) */ lpTotalNumberOfFreeBytes->QuadPart = FileFsFullSize.ActualAvailableAllocationUnits.QuadPart * BytesPerAllocationUnit;
return TRUE; } }
/* Otherwise, fallback to normal size information */ Status = NtQueryVolumeInformationFile(RootHandle, &IoStatusBlock, &FileFsSize, sizeof(FILE_FS_SIZE_INFORMATION), FileFsSizeInformation); NtClose(RootHandle); if (!NT_SUCCESS(Status)) { BaseSetLastNTError(Status); return FALSE; }
/* Compute the size of an AU */ BytesPerAllocationUnit = FileFsSize.SectorsPerAllocationUnit * FileFsSize.BytesPerSector;
/* And then return what was asked, available is free, the same! */ if (lpFreeBytesAvailableToCaller != NULL) { lpFreeBytesAvailableToCaller->QuadPart = FileFsSize.AvailableAllocationUnits.QuadPart * BytesPerAllocationUnit; }
if (lpTotalNumberOfBytes != NULL) { lpTotalNumberOfBytes->QuadPart = FileFsSize.TotalAllocationUnits.QuadPart * BytesPerAllocationUnit; }
if (lpTotalNumberOfFreeBytes != NULL) { lpTotalNumberOfFreeBytes->QuadPart = FileFsSize.AvailableAllocationUnits.QuadPart * BytesPerAllocationUnit; }
return TRUE;}
/* * @implemented */UINTWINAPIGetDriveTypeA(IN LPCSTR lpRootPathName){ PWSTR RootPathU;
if (lpRootPathName != NULL) { PUNICODE_STRING RootPathUStr;
RootPathUStr = Basep8BitStringToStaticUnicodeString(lpRootPathName); if (RootPathUStr == NULL) { return DRIVE_NO_ROOT_DIR; }
RootPathU = RootPathUStr->Buffer; } else { RootPathU = NULL; }
return GetDriveTypeW(RootPathU);}
/* * @implemented */UINTWINAPIGetDriveTypeW(IN LPCWSTR lpRootPathName){ BOOL RetryOpen; PCWSTR RootPath; NTSTATUS Status; WCHAR DriveLetter; HANDLE RootHandle; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING PathName, VolumeString; FILE_FS_DEVICE_INFORMATION FileFsDevice; WCHAR Buffer[MAX_PATH], VolumeName[MAX_PATH];
/* If no path, get one */ if (lpRootPathName == NULL) { RootPath = Buffer; /* This will be current drive (<letter>:\ - drop the rest)*/ if (RtlGetCurrentDirectory_U(sizeof(Buffer), Buffer) > 3 * sizeof(WCHAR)) { Buffer[3] = UNICODE_NULL; } } else { /* Handle broken value */ if (lpRootPathName == (PVOID)-1) { return DRIVE_UNKNOWN; }
RootPath = lpRootPathName; /* If provided path is 2-len, it might be a drive letter... */ if (wcslen(lpRootPathName) == 2) { /* Check it! */ DriveLetter = RtlUpcaseUnicodeChar(lpRootPathName[0]); /* That's a drive letter! */ if (DriveLetter >= L'A' && DriveLetter <= L'Z' && lpRootPathName[1] == L':') { /* Make it a volume */ Buffer[0] = DriveLetter; Buffer[1] = L':'; Buffer[2] = L'\\'; Buffer[3] = UNICODE_NULL; RootPath = Buffer; } } }
/* If the provided looks like a DOS device... Like <letter>:\<0> */ DriveLetter = RtlUpcaseUnicodeChar(RootPath[0]); /* We'll take the quick path! * We'll find the device type looking at the device map (and types ;-)) * associated with the current process */ if (DriveLetter >= L'A' && DriveLetter <= L'Z' && RootPath[1] == L':' && RootPath[2] == L'\\' && RootPath[3] == UNICODE_NULL) { USHORT Index; PROCESS_DEVICEMAP_INFORMATION DeviceMap;
/* Query the device map */ Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessDeviceMap, &DeviceMap.Query, sizeof(DeviceMap.Query), NULL); /* Zero output if we failed */ if (!NT_SUCCESS(Status)) { RtlZeroMemory(&DeviceMap, sizeof(PROCESS_DEVICEMAP_INFORMATION)); }
/* Get our index in the device map */ Index = DriveLetter - L'A'; /* Check we're in the device map (bit set) */ if (((1 << Index) & DeviceMap.Query.DriveMap) != 0) { /* Validate device type and return it */ if (DeviceMap.Query.DriveType[Index] >= DRIVE_REMOVABLE && DeviceMap.Query.DriveType[Index] <= DRIVE_RAMDISK) { return DeviceMap.Query.DriveType[Index]; } /* Otherwise, return we don't know the type */ else { return DRIVE_UNKNOWN; } }
/* We couldn't find ourselves, do it the slow way */ }
/* No path provided, use root */ if (lpRootPathName == NULL) { RootPath = L"\\"; }
/* Convert to NT path */ if (!RtlDosPathNameToNtPathName_U(RootPath, &PathName, NULL, NULL)) { return DRIVE_NO_ROOT_DIR; }
/* If not a directory, fail, we need a volume */ if (PathName.Buffer[(PathName.Length / sizeof(WCHAR)) - 1] != L'\\') { RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer); return DRIVE_NO_ROOT_DIR; }
/* We will work with a device object, so trim the trailing backslash now */ PathName.Length -= sizeof(WCHAR);
/* Let's probe for it, by forcing open failure! */ RetryOpen = TRUE; InitializeObjectAttributes(&ObjectAttributes, &PathName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&RootHandle, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); /* It properly failed! */ if (Status == STATUS_FILE_IS_A_DIRECTORY) { /* It might be a mount point, then, query for target */ if (BasepGetVolumeNameFromReparsePoint(lpRootPathName, VolumeName, MAX_PATH, NULL)) { /* We'll reopen the target */ RtlInitUnicodeString(&VolumeString, VolumeName); VolumeName[1] = L'?'; VolumeString.Length -= sizeof(WCHAR); InitializeObjectAttributes(&ObjectAttributes, &VolumeString, OBJ_CASE_INSENSITIVE, NULL, NULL); } } else { /* heh. It worked? Or failed for whatever other reason? * Check we have a directory if we get farther in path */ PathName.Length += sizeof(WCHAR); if (IsThisARootDirectory(0, &PathName)) { /* Yes? Heh, then it's fine, keep our current handle */ RetryOpen = FALSE; } else { /* Then, retry to open without forcing non directory type */ PathName.Length -= sizeof(WCHAR); if (NT_SUCCESS(Status)) { NtClose(RootHandle); } } }
/* Now, we retry without forcing file type - should work now */ if (RetryOpen) { Status = NtOpenFile(&RootHandle, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); }
/* We don't need path any longer */ RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer); if (!NT_SUCCESS(Status)) { return DRIVE_NO_ROOT_DIR; }
/* Query the device for its type */ Status = NtQueryVolumeInformationFile(RootHandle, &IoStatusBlock, &FileFsDevice, sizeof(FILE_FS_DEVICE_INFORMATION), FileFsDeviceInformation); /* No longer required */ NtClose(RootHandle); if (!NT_SUCCESS(Status)) { return DRIVE_UNKNOWN; }
/* Do we have a remote device? Return so! */ if ((FileFsDevice.Characteristics & FILE_REMOTE_DEVICE) == FILE_REMOTE_DEVICE) { return DRIVE_REMOTE; }
/* Check the device type */ switch (FileFsDevice.DeviceType) { /* CDROM, easy */ case FILE_DEVICE_CD_ROM: case FILE_DEVICE_CD_ROM_FILE_SYSTEM: return DRIVE_CDROM;
/* Disk... */ case FILE_DEVICE_DISK: case FILE_DEVICE_DISK_FILE_SYSTEM: /* Removable media? Floppy is one */ if ((FileFsDevice.Characteristics & FILE_REMOVABLE_MEDIA) == FILE_REMOVABLE_MEDIA || (FileFsDevice.Characteristics & FILE_FLOPPY_DISKETTE) == FILE_FLOPPY_DISKETTE) { return DRIVE_REMOVABLE; } else { return DRIVE_FIXED; }
/* Easy cases */ case FILE_DEVICE_NETWORK: case FILE_DEVICE_NETWORK_FILE_SYSTEM: return DRIVE_REMOTE;
case FILE_DEVICE_VIRTUAL_DISK: return DRIVE_RAMDISK; }
/* Nothing matching, just fail */ return DRIVE_UNKNOWN;}
/* EOF */