2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/client/file/disk.c
5 * PURPOSE: Disk and Drive functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Erik Bos, Alexandre Julliard :
8 * GetLogicalDriveStringsA,
9 * GetLogicalDriveStringsW, GetLogicalDrives
13 //WINE copyright notice:
15 * DOS drives handling functions
17 * Copyright 1993 Erik Bos
18 * Copyright 1996 Alexandre Julliard
26 DEBUG_CHANNEL(kernel32file
);
28 #define MAX_DOS_DRIVES 26
29 HANDLE WINAPI
InternalOpenDirW(IN LPCWSTR DirName
, IN BOOLEAN Write
);
34 /* Synced to Wine-2008/12/28 */
37 GetLogicalDriveStringsA(IN DWORD nBufferLength
,
44 dwDriveMap
= GetLogicalDrives();
46 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
48 if (dwDriveMap
& (1<<drive
))
53 if ((count
* 4) + 1 > nBufferLength
) return ((count
* 4) + 1);
57 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
58 if (dwDriveMap
& (1<<drive
))
60 *p
++ = 'A' + (UCHAR
)drive
;
73 /* Synced to Wine-2008/12/28 */
76 GetLogicalDriveStringsW(IN DWORD nBufferLength
,
83 dwDriveMap
= GetLogicalDrives();
85 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
87 if (dwDriveMap
& (1<<drive
))
91 if ((count
* 4) + 1 > nBufferLength
) return ((count
* 4) + 1);
94 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
95 if (dwDriveMap
& (1<<drive
))
97 *p
++ = (WCHAR
)('A' + drive
);
110 /* Synced to Wine-? */
113 GetLogicalDrives(VOID
)
116 PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo
;
118 /* Get the Device Map for this Process */
119 Status
= NtQueryInformationProcess(NtCurrentProcess(),
121 &ProcessDeviceMapInfo
,
122 sizeof(ProcessDeviceMapInfo
),
125 /* Return the Drive Map */
126 if (!NT_SUCCESS(Status
))
128 BaseSetLastNTError(Status
);
132 return ProcessDeviceMapInfo
.Query
.DriveMap
;
140 GetDiskFreeSpaceA(IN LPCSTR lpRootPathName
,
141 OUT LPDWORD lpSectorsPerCluster
,
142 OUT LPDWORD lpBytesPerSector
,
143 OUT LPDWORD lpNumberOfFreeClusters
,
144 OUT LPDWORD lpTotalNumberOfClusters
)
146 PWCHAR RootPathNameW
=NULL
;
150 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
154 return GetDiskFreeSpaceW (RootPathNameW
,
157 lpNumberOfFreeClusters
,
158 lpTotalNumberOfClusters
);
166 GetDiskFreeSpaceW(IN LPCWSTR lpRootPathName
,
167 OUT LPDWORD lpSectorsPerCluster
,
168 OUT LPDWORD lpBytesPerSector
,
169 OUT LPDWORD lpNumberOfFreeClusters
,
170 OUT LPDWORD lpTotalNumberOfClusters
)
172 FILE_FS_SIZE_INFORMATION FileFsSize
;
173 IO_STATUS_BLOCK IoStatusBlock
;
174 WCHAR RootPathName
[MAX_PATH
];
180 wcsncpy (RootPathName
, lpRootPathName
, 3);
184 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
188 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
189 if (INVALID_HANDLE_VALUE
== hFile
)
191 SetLastError(ERROR_PATH_NOT_FOUND
);
195 errCode
= NtQueryVolumeInformationFile(hFile
,
198 sizeof(FILE_FS_SIZE_INFORMATION
),
199 FileFsSizeInformation
);
200 if (!NT_SUCCESS(errCode
))
203 BaseSetLastNTError (errCode
);
207 if (lpSectorsPerCluster
)
208 *lpSectorsPerCluster
= FileFsSize
.SectorsPerAllocationUnit
;
209 if (lpBytesPerSector
)
210 *lpBytesPerSector
= FileFsSize
.BytesPerSector
;
211 if (lpNumberOfFreeClusters
)
212 *lpNumberOfFreeClusters
= FileFsSize
.AvailableAllocationUnits
.u
.LowPart
;
213 if (lpTotalNumberOfClusters
)
214 *lpTotalNumberOfClusters
= FileFsSize
.TotalAllocationUnits
.u
.LowPart
;
225 GetDiskFreeSpaceExA(IN LPCSTR lpDirectoryName OPTIONAL
,
226 OUT PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
227 OUT PULARGE_INTEGER lpTotalNumberOfBytes
,
228 OUT PULARGE_INTEGER lpTotalNumberOfFreeBytes
)
230 PWCHAR DirectoryNameW
=NULL
;
234 if (!(DirectoryNameW
= FilenameA2W(lpDirectoryName
, FALSE
)))
238 return GetDiskFreeSpaceExW (DirectoryNameW
,
239 lpFreeBytesAvailableToCaller
,
240 lpTotalNumberOfBytes
,
241 lpTotalNumberOfFreeBytes
);
249 GetDiskFreeSpaceExW(IN LPCWSTR lpDirectoryName OPTIONAL
,
250 OUT PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
251 OUT PULARGE_INTEGER lpTotalNumberOfBytes
,
252 OUT PULARGE_INTEGER lpTotalNumberOfFreeBytes
)
256 FILE_FS_SIZE_INFORMATION FsSize
;
257 FILE_FS_FULL_SIZE_INFORMATION FsFullSize
;
259 IO_STATUS_BLOCK IoStatusBlock
;
260 ULARGE_INTEGER BytesPerCluster
;
264 if (lpDirectoryName
== NULL
)
265 lpDirectoryName
= L
"\\";
267 hFile
= InternalOpenDirW(lpDirectoryName
, FALSE
);
268 if (INVALID_HANDLE_VALUE
== hFile
)
273 if (lpFreeBytesAvailableToCaller
!= NULL
|| lpTotalNumberOfBytes
!= NULL
)
275 /* To get the free space available to the user associated with the
276 current thread, try FileFsFullSizeInformation. If this is not
277 supported by the file system, fall back to FileFsSize */
279 Status
= NtQueryVolumeInformationFile(hFile
,
282 sizeof(FsInfo
.FsFullSize
),
283 FileFsFullSizeInformation
);
285 if (NT_SUCCESS(Status
))
287 /* Close the handle before returning data
288 to avoid a handle leak in case of a fault! */
291 BytesPerCluster
.QuadPart
=
292 FsInfo
.FsFullSize
.BytesPerSector
* FsInfo
.FsFullSize
.SectorsPerAllocationUnit
;
294 if (lpFreeBytesAvailableToCaller
!= NULL
)
296 lpFreeBytesAvailableToCaller
->QuadPart
=
297 BytesPerCluster
.QuadPart
* FsInfo
.FsFullSize
.CallerAvailableAllocationUnits
.QuadPart
;
300 if (lpTotalNumberOfBytes
!= NULL
)
302 lpTotalNumberOfBytes
->QuadPart
=
303 BytesPerCluster
.QuadPart
* FsInfo
.FsFullSize
.TotalAllocationUnits
.QuadPart
;
306 if (lpTotalNumberOfFreeBytes
!= NULL
)
308 lpTotalNumberOfFreeBytes
->QuadPart
=
309 BytesPerCluster
.QuadPart
* FsInfo
.FsFullSize
.ActualAvailableAllocationUnits
.QuadPart
;
316 Status
= NtQueryVolumeInformationFile(hFile
,
319 sizeof(FsInfo
.FsSize
),
320 FileFsSizeInformation
);
322 /* Close the handle before returning data
323 to avoid a handle leak in case of a fault! */
326 if (!NT_SUCCESS(Status
))
328 BaseSetLastNTError (Status
);
332 BytesPerCluster
.QuadPart
=
333 FsInfo
.FsSize
.BytesPerSector
* FsInfo
.FsSize
.SectorsPerAllocationUnit
;
335 if (lpFreeBytesAvailableToCaller
)
337 lpFreeBytesAvailableToCaller
->QuadPart
=
338 BytesPerCluster
.QuadPart
* FsInfo
.FsSize
.AvailableAllocationUnits
.QuadPart
;
341 if (lpTotalNumberOfBytes
)
343 lpTotalNumberOfBytes
->QuadPart
=
344 BytesPerCluster
.QuadPart
* FsInfo
.FsSize
.TotalAllocationUnits
.QuadPart
;
347 if (lpTotalNumberOfFreeBytes
)
349 lpTotalNumberOfFreeBytes
->QuadPart
=
350 BytesPerCluster
.QuadPart
* FsInfo
.FsSize
.AvailableAllocationUnits
.QuadPart
;
361 GetDriveTypeA(IN LPCSTR lpRootPathName
)
363 PWCHAR RootPathNameW
;
366 return GetDriveTypeW(NULL
);
368 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
369 return DRIVE_UNKNOWN
;
371 return GetDriveTypeW(RootPathNameW
);
379 GetDriveTypeW(IN LPCWSTR lpRootPathName
)
381 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
382 OBJECT_ATTRIBUTES ObjectAttributes
;
383 IO_STATUS_BLOCK IoStatusBlock
;
384 UNICODE_STRING PathName
;
387 PWSTR CurrentDir
= NULL
;
392 /* If NULL is passed, use current directory path */
393 DWORD BufferSize
= GetCurrentDirectoryW(0, NULL
);
394 CurrentDir
= HeapAlloc(GetProcessHeap(), 0, BufferSize
* sizeof(WCHAR
));
396 return DRIVE_UNKNOWN
;
397 if (!GetCurrentDirectoryW(BufferSize
, CurrentDir
))
399 HeapFree(GetProcessHeap(), 0, CurrentDir
);
400 return DRIVE_UNKNOWN
;
403 if (wcslen(CurrentDir
) > 3)
406 lpRootPath
= CurrentDir
;
410 size_t Length
= wcslen(lpRootPathName
);
412 TRACE("lpRootPathName: %S\n", lpRootPathName
);
414 lpRootPath
= lpRootPathName
;
417 WCHAR DriveLetter
= RtlUpcaseUnicodeChar(lpRootPathName
[0]);
419 if (DriveLetter
>= L
'A' && DriveLetter
<= L
'Z' && lpRootPathName
[1] == L
':')
421 Length
= (Length
+ 2) * sizeof(WCHAR
);
423 CurrentDir
= HeapAlloc(GetProcessHeap(), 0, Length
);
425 return DRIVE_UNKNOWN
;
427 StringCbPrintfW(CurrentDir
, Length
, L
"%s\\", lpRootPathName
);
429 lpRootPath
= CurrentDir
;
434 TRACE("lpRootPath: %S\n", lpRootPath
);
436 if (!RtlDosPathNameToNtPathName_U(lpRootPath
, &PathName
, NULL
, NULL
))
438 if (CurrentDir
!= NULL
)
439 HeapFree(GetProcessHeap(), 0, CurrentDir
);
441 return DRIVE_NO_ROOT_DIR
;
444 TRACE("PathName: %S\n", PathName
.Buffer
);
446 if (CurrentDir
!= NULL
)
447 HeapFree(GetProcessHeap(), 0, CurrentDir
);
449 if (PathName
.Buffer
[(PathName
.Length
>> 1) - 1] != L
'\\')
451 return DRIVE_NO_ROOT_DIR
;
454 InitializeObjectAttributes(&ObjectAttributes
,
456 OBJ_CASE_INSENSITIVE
,
460 Status
= NtOpenFile(&FileHandle
,
461 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
464 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
465 FILE_SYNCHRONOUS_IO_NONALERT
);
467 RtlFreeHeap(RtlGetProcessHeap(), 0, PathName
.Buffer
);
468 if (!NT_SUCCESS(Status
))
469 return DRIVE_NO_ROOT_DIR
; /* According to WINE regression tests */
471 Status
= NtQueryVolumeInformationFile(FileHandle
,
474 sizeof(FILE_FS_DEVICE_INFORMATION
),
475 FileFsDeviceInformation
);
477 if (!NT_SUCCESS(Status
))
482 switch (FileFsDevice
.DeviceType
)
484 case FILE_DEVICE_CD_ROM
:
485 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
487 case FILE_DEVICE_VIRTUAL_DISK
:
488 return DRIVE_RAMDISK
;
489 case FILE_DEVICE_NETWORK_FILE_SYSTEM
:
491 case FILE_DEVICE_DISK
:
492 case FILE_DEVICE_DISK_FILE_SYSTEM
:
493 if (FileFsDevice
.Characteristics
& FILE_REMOTE_DEVICE
)
495 if (FileFsDevice
.Characteristics
& FILE_REMOVABLE_MEDIA
)
496 return DRIVE_REMOVABLE
;
500 ERR("Returning DRIVE_UNKNOWN for device type %lu\n", FileFsDevice
.DeviceType
);
502 return DRIVE_UNKNOWN
;