3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/volume.c
6 * PURPOSE: File volume functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Erik Bos, Alexandre Julliard :
9 * GetLogicalDriveStringsA,
10 * GetLogicalDriveStringsW, GetLogicalDrives
14 //WINE copyright notice:
16 * DOS drives handling functions
18 * Copyright 1993 Erik Bos
19 * Copyright 1996 Alexandre Julliard
25 #include "../include/debug.h"
28 #define MAX_DOS_DRIVES 26
32 InternalOpenDirW(LPCWSTR DirName
,
35 UNICODE_STRING NtPathU
;
36 OBJECT_ATTRIBUTES ObjectAttributes
;
38 IO_STATUS_BLOCK IoStatusBlock
;
41 if (!RtlDosPathNameToNtPathName_U((LPWSTR
)DirName
,
46 DPRINT("Invalid path\n");
47 SetLastError(ERROR_BAD_PATHNAME
);
48 return INVALID_HANDLE_VALUE
;
51 InitializeObjectAttributes(&ObjectAttributes
,
53 Write
? FILE_WRITE_ATTRIBUTES
: FILE_READ_ATTRIBUTES
,
57 errCode
= NtCreateFile (&hFile
,
58 Write
? FILE_GENERIC_WRITE
: FILE_GENERIC_READ
,
63 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
69 RtlFreeUnicodeString(&NtPathU
);
71 if (!NT_SUCCESS(errCode
))
73 SetLastErrorByStatus (errCode
);
74 return INVALID_HANDLE_VALUE
;
84 GetLogicalDriveStringsA(DWORD nBufferLength
,
90 dwDriveMap
= GetLogicalDrives();
92 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
94 if (dwDriveMap
& (1<<drive
))
99 if (count
* 4 * sizeof(char) <= nBufferLength
)
103 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
104 if (dwDriveMap
& (1<<drive
))
113 return (count
* 4 * sizeof(char));
121 GetLogicalDriveStringsW(DWORD nBufferLength
,
127 dwDriveMap
= GetLogicalDrives();
129 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
131 if (dwDriveMap
& (1<<drive
))
135 if (count
* 4 * sizeof(WCHAR
) <= nBufferLength
)
138 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
139 if (dwDriveMap
& (1<<drive
))
141 *p
++ = (WCHAR
)('A' + drive
);
148 return (count
* 4 * sizeof(WCHAR
));
156 GetLogicalDrives(VOID
)
159 PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo
;
161 /* Get the Device Map for this Process */
162 Status
= NtQueryInformationProcess(NtCurrentProcess(),
164 &ProcessDeviceMapInfo
,
165 sizeof(ProcessDeviceMapInfo
),
168 /* Return the Drive Map */
169 if (!NT_SUCCESS(Status
))
171 SetLastErrorByStatus(Status
);
175 return ProcessDeviceMapInfo
.Query
.DriveMap
;
184 LPCSTR lpRootPathName
,
185 LPDWORD lpSectorsPerCluster
,
186 LPDWORD lpBytesPerSector
,
187 LPDWORD lpNumberOfFreeClusters
,
188 LPDWORD lpTotalNumberOfClusters
191 PWCHAR RootPathNameW
=NULL
;
195 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
199 return GetDiskFreeSpaceW (RootPathNameW
,
202 lpNumberOfFreeClusters
,
203 lpTotalNumberOfClusters
);
212 LPCWSTR lpRootPathName
,
213 LPDWORD lpSectorsPerCluster
,
214 LPDWORD lpBytesPerSector
,
215 LPDWORD lpNumberOfFreeClusters
,
216 LPDWORD lpTotalNumberOfClusters
219 FILE_FS_SIZE_INFORMATION FileFsSize
;
220 IO_STATUS_BLOCK IoStatusBlock
;
221 WCHAR RootPathName
[MAX_PATH
];
227 wcsncpy (RootPathName
, lpRootPathName
, 3);
231 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
235 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
236 if (INVALID_HANDLE_VALUE
== hFile
)
238 SetLastError(ERROR_PATH_NOT_FOUND
);
242 errCode
= NtQueryVolumeInformationFile(hFile
,
245 sizeof(FILE_FS_SIZE_INFORMATION
),
246 FileFsSizeInformation
);
247 if (!NT_SUCCESS(errCode
))
250 SetLastErrorByStatus (errCode
);
254 *lpBytesPerSector
= FileFsSize
.BytesPerSector
;
255 *lpSectorsPerCluster
= FileFsSize
.SectorsPerAllocationUnit
;
256 *lpNumberOfFreeClusters
= FileFsSize
.AvailableAllocationUnits
.u
.LowPart
;
257 *lpTotalNumberOfClusters
= FileFsSize
.TotalAllocationUnits
.u
.LowPart
;
268 GetDiskFreeSpaceExA (
269 LPCSTR lpDirectoryName OPTIONAL
,
270 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
271 PULARGE_INTEGER lpTotalNumberOfBytes
,
272 PULARGE_INTEGER lpTotalNumberOfFreeBytes
275 PWCHAR DirectoryNameW
=NULL
;
279 if (!(DirectoryNameW
= FilenameA2W(lpDirectoryName
, FALSE
)))
283 return GetDiskFreeSpaceExW (DirectoryNameW
,
284 lpFreeBytesAvailableToCaller
,
285 lpTotalNumberOfBytes
,
286 lpTotalNumberOfFreeBytes
);
295 LPCWSTR lpDirectoryName OPTIONAL
,
296 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
297 PULARGE_INTEGER lpTotalNumberOfBytes
,
298 PULARGE_INTEGER lpTotalNumberOfFreeBytes
301 FILE_FS_SIZE_INFORMATION FileFsSize
;
302 IO_STATUS_BLOCK IoStatusBlock
;
303 ULARGE_INTEGER BytesPerCluster
;
304 WCHAR RootPathName
[MAX_PATH
];
309 FIXME: this is obviously wrong for UNC paths, symbolic directories etc.
314 wcsncpy (RootPathName
, lpDirectoryName
, 3);
318 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
322 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
323 if (INVALID_HANDLE_VALUE
== hFile
)
328 errCode
= NtQueryVolumeInformationFile(hFile
,
331 sizeof(FILE_FS_SIZE_INFORMATION
),
332 FileFsSizeInformation
);
333 if (!NT_SUCCESS(errCode
))
336 SetLastErrorByStatus (errCode
);
340 BytesPerCluster
.QuadPart
=
341 FileFsSize
.BytesPerSector
* FileFsSize
.SectorsPerAllocationUnit
;
343 // FIXME: Use quota information
344 if (lpFreeBytesAvailableToCaller
)
345 lpFreeBytesAvailableToCaller
->QuadPart
=
346 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
348 if (lpTotalNumberOfBytes
)
349 lpTotalNumberOfBytes
->QuadPart
=
350 BytesPerCluster
.QuadPart
* FileFsSize
.TotalAllocationUnits
.QuadPart
;
351 if (lpTotalNumberOfFreeBytes
)
352 lpTotalNumberOfFreeBytes
->QuadPart
=
353 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
365 GetDriveTypeA(LPCSTR lpRootPathName
)
367 PWCHAR RootPathNameW
;
369 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
370 return DRIVE_UNKNOWN
;
372 return GetDriveTypeW(RootPathNameW
);
380 GetDriveTypeW(LPCWSTR lpRootPathName
)
382 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
383 IO_STATUS_BLOCK IoStatusBlock
;
388 hFile
= InternalOpenDirW(lpRootPathName
, FALSE
);
389 if (hFile
== INVALID_HANDLE_VALUE
)
391 return DRIVE_NO_ROOT_DIR
; /* According to WINE regression tests */
394 errCode
= NtQueryVolumeInformationFile (hFile
,
397 sizeof(FILE_FS_DEVICE_INFORMATION
),
398 FileFsDeviceInformation
);
399 if (!NT_SUCCESS(errCode
))
402 SetLastErrorByStatus (errCode
);
407 switch (FileFsDevice
.DeviceType
)
409 case FILE_DEVICE_CD_ROM
:
410 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
412 case FILE_DEVICE_VIRTUAL_DISK
:
413 return DRIVE_RAMDISK
;
414 case FILE_DEVICE_NETWORK_FILE_SYSTEM
:
416 case FILE_DEVICE_DISK
:
417 case FILE_DEVICE_DISK_FILE_SYSTEM
:
418 if (FileFsDevice
.Characteristics
& FILE_REMOTE_DEVICE
)
420 if (FileFsDevice
.Characteristics
& FILE_REMOVABLE_MEDIA
)
421 return DRIVE_REMOVABLE
;
425 DPRINT1("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice
.DeviceType
);
427 return DRIVE_UNKNOWN
;
435 GetVolumeInformationA(
436 LPCSTR lpRootPathName
,
437 LPSTR lpVolumeNameBuffer
,
438 DWORD nVolumeNameSize
,
439 LPDWORD lpVolumeSerialNumber
,
440 LPDWORD lpMaximumComponentLength
,
441 LPDWORD lpFileSystemFlags
,
442 LPSTR lpFileSystemNameBuffer
,
443 DWORD nFileSystemNameSize
446 UNICODE_STRING FileSystemNameU
;
447 UNICODE_STRING VolumeNameU
;
448 ANSI_STRING VolumeName
;
449 ANSI_STRING FileSystemName
;
450 PWCHAR RootPathNameW
;
453 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
456 if (lpVolumeNameBuffer
)
458 VolumeNameU
.Length
= 0;
459 VolumeNameU
.MaximumLength
= nVolumeNameSize
* sizeof(WCHAR
);
460 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
462 VolumeNameU
.MaximumLength
);
465 if (lpFileSystemNameBuffer
)
467 FileSystemNameU
.Length
= 0;
468 FileSystemNameU
.MaximumLength
= nFileSystemNameSize
* sizeof(WCHAR
);
469 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
471 FileSystemNameU
.MaximumLength
);
474 Result
= GetVolumeInformationW (RootPathNameW
,
475 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
477 lpVolumeSerialNumber
,
478 lpMaximumComponentLength
,
480 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
481 nFileSystemNameSize
);
485 if (lpVolumeNameBuffer
)
487 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
488 VolumeName
.Length
= 0;
489 VolumeName
.MaximumLength
= nVolumeNameSize
;
490 VolumeName
.Buffer
= lpVolumeNameBuffer
;
493 if (lpFileSystemNameBuffer
)
495 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
496 FileSystemName
.Length
= 0;
497 FileSystemName
.MaximumLength
= nFileSystemNameSize
;
498 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
501 /* convert unicode strings to ansi (or oem) */
504 if (lpVolumeNameBuffer
)
506 RtlUnicodeStringToAnsiString (&VolumeName
,
510 if (lpFileSystemNameBuffer
)
512 RtlUnicodeStringToAnsiString (&FileSystemName
,
519 if (lpVolumeNameBuffer
)
521 RtlUnicodeStringToOemString (&VolumeName
,
525 if (lpFileSystemNameBuffer
)
527 RtlUnicodeStringToOemString (&FileSystemName
,
534 if (lpVolumeNameBuffer
)
536 RtlFreeHeap (RtlGetProcessHeap (),
540 if (lpFileSystemNameBuffer
)
542 RtlFreeHeap (RtlGetProcessHeap (),
544 FileSystemNameU
.Buffer
);
550 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
552 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
558 GetVolumeInformationW(
559 LPCWSTR lpRootPathName
,
560 LPWSTR lpVolumeNameBuffer
,
561 DWORD nVolumeNameSize
,
562 LPDWORD lpVolumeSerialNumber
,
563 LPDWORD lpMaximumComponentLength
,
564 LPDWORD lpFileSystemFlags
,
565 LPWSTR lpFileSystemNameBuffer
,
566 DWORD nFileSystemNameSize
569 PFILE_FS_VOLUME_INFORMATION FileFsVolume
;
570 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
571 IO_STATUS_BLOCK IoStatusBlock
;
572 WCHAR RootPathName
[MAX_PATH
];
573 UCHAR Buffer
[max(FS_VOLUME_BUFFER_SIZE
, FS_ATTRIBUTE_BUFFER_SIZE
)];
578 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
579 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
581 DPRINT("FileFsVolume %p\n", FileFsVolume
);
582 DPRINT("FileFsAttribute %p\n", FileFsAttribute
);
584 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
586 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
590 wcsncpy (RootPathName
, lpRootPathName
, 3);
594 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
595 if (hFile
== INVALID_HANDLE_VALUE
)
600 DPRINT("hFile: %x\n", hFile
);
601 errCode
= NtQueryVolumeInformationFile(hFile
,
604 FS_VOLUME_BUFFER_SIZE
,
605 FileFsVolumeInformation
);
606 if ( !NT_SUCCESS(errCode
) )
608 DPRINT("Status: %x\n", errCode
);
610 SetLastErrorByStatus (errCode
);
614 if (lpVolumeSerialNumber
)
615 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
617 if (lpVolumeNameBuffer
)
619 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
621 memcpy(lpVolumeNameBuffer
,
622 FileFsVolume
->VolumeLabel
,
623 FileFsVolume
->VolumeLabelLength
);
624 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
629 SetLastError(ERROR_MORE_DATA
);
634 errCode
= NtQueryVolumeInformationFile (hFile
,
637 FS_ATTRIBUTE_BUFFER_SIZE
,
638 FileFsAttributeInformation
);
640 if (!NT_SUCCESS(errCode
))
642 DPRINT("Status: %x\n", errCode
);
643 SetLastErrorByStatus (errCode
);
647 if (lpFileSystemFlags
)
648 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
649 if (lpMaximumComponentLength
)
650 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
651 if (lpFileSystemNameBuffer
)
653 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
655 memcpy(lpFileSystemNameBuffer
,
656 FileFsAttribute
->FileSystemName
,
657 FileFsAttribute
->FileSystemNameLength
);
658 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
662 SetLastError(ERROR_MORE_DATA
);
676 LPCSTR lpRootPathName
,
677 LPCSTR lpVolumeName
/* NULL if deleting label */
680 PWCHAR RootPathNameW
;
681 PWCHAR VolumeNameW
= NULL
;
684 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
689 if (!(VolumeNameW
= FilenameA2W(lpVolumeName
, TRUE
)))
693 Result
= SetVolumeLabelW (RootPathNameW
,
698 RtlFreeHeap (RtlGetProcessHeap (),
712 LPCWSTR lpRootPathName
,
713 LPCWSTR lpVolumeName
/* NULL if deleting label */
716 PFILE_FS_LABEL_INFORMATION LabelInfo
;
717 IO_STATUS_BLOCK IoStatusBlock
;
722 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
723 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
725 sizeof(FILE_FS_LABEL_INFORMATION
) +
727 LabelInfo
->VolumeLabelLength
= LabelLength
;
728 memcpy(LabelInfo
->VolumeLabel
,
732 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
733 if (INVALID_HANDLE_VALUE
== hFile
)
735 RtlFreeHeap(RtlGetProcessHeap(),
741 Status
= NtSetVolumeInformationFile(hFile
,
744 sizeof(FILE_FS_LABEL_INFORMATION
) +
746 FileFsLabelInformation
);
748 RtlFreeHeap(RtlGetProcessHeap(),
752 if (!NT_SUCCESS(Status
))
754 DPRINT("Status: %x\n", Status
);
756 SetLastErrorByStatus(Status
);