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(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 RtlFreeHeap(RtlGetProcessHeap(),
73 if (!NT_SUCCESS(errCode
))
75 SetLastErrorByStatus (errCode
);
76 return INVALID_HANDLE_VALUE
;
86 GetLogicalDriveStringsA(DWORD nBufferLength
,
92 dwDriveMap
= GetLogicalDrives();
94 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
96 if (dwDriveMap
& (1<<drive
))
101 if (count
* 4 * sizeof(char) <= nBufferLength
)
105 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
106 if (dwDriveMap
& (1<<drive
))
115 return (count
* 4 * sizeof(char));
123 GetLogicalDriveStringsW(DWORD nBufferLength
,
129 dwDriveMap
= GetLogicalDrives();
131 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
133 if (dwDriveMap
& (1<<drive
))
137 if (count
* 4 * sizeof(WCHAR
) <= nBufferLength
)
140 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
141 if (dwDriveMap
& (1<<drive
))
143 *p
++ = (WCHAR
)('A' + drive
);
150 return (count
* 4 * sizeof(WCHAR
));
158 GetLogicalDrives(VOID
)
161 PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo
;
163 /* Get the Device Map for this Process */
164 Status
= NtQueryInformationProcess(NtCurrentProcess(),
166 &ProcessDeviceMapInfo
,
167 sizeof(ProcessDeviceMapInfo
),
170 /* Return the Drive Map */
171 if (!NT_SUCCESS(Status
))
173 SetLastErrorByStatus(Status
);
177 return ProcessDeviceMapInfo
.Query
.DriveMap
;
186 LPCSTR lpRootPathName
,
187 LPDWORD lpSectorsPerCluster
,
188 LPDWORD lpBytesPerSector
,
189 LPDWORD lpNumberOfFreeClusters
,
190 LPDWORD lpTotalNumberOfClusters
193 PWCHAR RootPathNameW
=NULL
;
197 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
201 return GetDiskFreeSpaceW (RootPathNameW
,
204 lpNumberOfFreeClusters
,
205 lpTotalNumberOfClusters
);
214 LPCWSTR lpRootPathName
,
215 LPDWORD lpSectorsPerCluster
,
216 LPDWORD lpBytesPerSector
,
217 LPDWORD lpNumberOfFreeClusters
,
218 LPDWORD lpTotalNumberOfClusters
221 FILE_FS_SIZE_INFORMATION FileFsSize
;
222 IO_STATUS_BLOCK IoStatusBlock
;
223 WCHAR RootPathName
[MAX_PATH
];
229 wcsncpy (RootPathName
, lpRootPathName
, 3);
233 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
237 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
238 if (INVALID_HANDLE_VALUE
== hFile
)
240 SetLastError(ERROR_PATH_NOT_FOUND
);
244 errCode
= NtQueryVolumeInformationFile(hFile
,
247 sizeof(FILE_FS_SIZE_INFORMATION
),
248 FileFsSizeInformation
);
249 if (!NT_SUCCESS(errCode
))
252 SetLastErrorByStatus (errCode
);
256 *lpBytesPerSector
= FileFsSize
.BytesPerSector
;
257 *lpSectorsPerCluster
= FileFsSize
.SectorsPerAllocationUnit
;
258 *lpNumberOfFreeClusters
= FileFsSize
.AvailableAllocationUnits
.u
.LowPart
;
259 *lpTotalNumberOfClusters
= FileFsSize
.TotalAllocationUnits
.u
.LowPart
;
270 GetDiskFreeSpaceExA (
271 LPCSTR lpDirectoryName OPTIONAL
,
272 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
273 PULARGE_INTEGER lpTotalNumberOfBytes
,
274 PULARGE_INTEGER lpTotalNumberOfFreeBytes
277 PWCHAR DirectoryNameW
=NULL
;
281 if (!(DirectoryNameW
= FilenameA2W(lpDirectoryName
, FALSE
)))
285 return GetDiskFreeSpaceExW (DirectoryNameW
,
286 lpFreeBytesAvailableToCaller
,
287 lpTotalNumberOfBytes
,
288 lpTotalNumberOfFreeBytes
);
297 LPCWSTR lpDirectoryName OPTIONAL
,
298 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
299 PULARGE_INTEGER lpTotalNumberOfBytes
,
300 PULARGE_INTEGER lpTotalNumberOfFreeBytes
303 FILE_FS_SIZE_INFORMATION FileFsSize
;
304 IO_STATUS_BLOCK IoStatusBlock
;
305 ULARGE_INTEGER BytesPerCluster
;
306 WCHAR RootPathName
[MAX_PATH
];
311 FIXME: this is obviously wrong for UNC paths, symbolic directories etc.
316 wcsncpy (RootPathName
, lpDirectoryName
, 3);
320 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
324 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
325 if (INVALID_HANDLE_VALUE
== hFile
)
330 errCode
= NtQueryVolumeInformationFile(hFile
,
333 sizeof(FILE_FS_SIZE_INFORMATION
),
334 FileFsSizeInformation
);
335 if (!NT_SUCCESS(errCode
))
338 SetLastErrorByStatus (errCode
);
342 BytesPerCluster
.QuadPart
=
343 FileFsSize
.BytesPerSector
* FileFsSize
.SectorsPerAllocationUnit
;
345 // FIXME: Use quota information
346 if (lpFreeBytesAvailableToCaller
)
347 lpFreeBytesAvailableToCaller
->QuadPart
=
348 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
350 if (lpTotalNumberOfBytes
)
351 lpTotalNumberOfBytes
->QuadPart
=
352 BytesPerCluster
.QuadPart
* FileFsSize
.TotalAllocationUnits
.QuadPart
;
353 if (lpTotalNumberOfFreeBytes
)
354 lpTotalNumberOfFreeBytes
->QuadPart
=
355 BytesPerCluster
.QuadPart
* FileFsSize
.AvailableAllocationUnits
.QuadPart
;
367 GetDriveTypeA(LPCSTR lpRootPathName
)
369 PWCHAR RootPathNameW
;
371 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
372 return DRIVE_UNKNOWN
;
374 return GetDriveTypeW(RootPathNameW
);
382 GetDriveTypeW(LPCWSTR lpRootPathName
)
384 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
385 IO_STATUS_BLOCK IoStatusBlock
;
390 hFile
= InternalOpenDirW(lpRootPathName
, FALSE
);
391 if (hFile
== INVALID_HANDLE_VALUE
)
393 return DRIVE_NO_ROOT_DIR
; /* According to WINE regression tests */
396 errCode
= NtQueryVolumeInformationFile (hFile
,
399 sizeof(FILE_FS_DEVICE_INFORMATION
),
400 FileFsDeviceInformation
);
401 if (!NT_SUCCESS(errCode
))
404 SetLastErrorByStatus (errCode
);
409 switch (FileFsDevice
.DeviceType
)
411 case FILE_DEVICE_CD_ROM
:
412 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
414 case FILE_DEVICE_VIRTUAL_DISK
:
415 return DRIVE_RAMDISK
;
416 case FILE_DEVICE_NETWORK_FILE_SYSTEM
:
418 case FILE_DEVICE_DISK
:
419 case FILE_DEVICE_DISK_FILE_SYSTEM
:
420 if (FileFsDevice
.Characteristics
& FILE_REMOTE_DEVICE
)
422 if (FileFsDevice
.Characteristics
& FILE_REMOVABLE_MEDIA
)
423 return DRIVE_REMOVABLE
;
427 DPRINT1("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice
.DeviceType
);
429 return DRIVE_UNKNOWN
;
437 GetVolumeInformationA(
438 LPCSTR lpRootPathName
,
439 LPSTR lpVolumeNameBuffer
,
440 DWORD nVolumeNameSize
,
441 LPDWORD lpVolumeSerialNumber
,
442 LPDWORD lpMaximumComponentLength
,
443 LPDWORD lpFileSystemFlags
,
444 LPSTR lpFileSystemNameBuffer
,
445 DWORD nFileSystemNameSize
448 UNICODE_STRING FileSystemNameU
;
449 UNICODE_STRING VolumeNameU
= {0};
450 ANSI_STRING VolumeName
;
451 ANSI_STRING FileSystemName
;
452 PWCHAR RootPathNameW
;
455 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
458 if (lpVolumeNameBuffer
)
460 VolumeNameU
.MaximumLength
= nVolumeNameSize
* sizeof(WCHAR
);
461 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
463 VolumeNameU
.MaximumLength
);
464 if (VolumeNameU
.Buffer
== NULL
)
470 if (lpFileSystemNameBuffer
)
472 FileSystemNameU
.Length
= 0;
473 FileSystemNameU
.MaximumLength
= nFileSystemNameSize
* sizeof(WCHAR
);
474 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
476 FileSystemNameU
.MaximumLength
);
477 if (FileSystemNameU
.Buffer
== NULL
)
479 if (VolumeNameU
.Buffer
!= NULL
)
481 RtlFreeHeap(RtlGetProcessHeap(),
487 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
492 Result
= GetVolumeInformationW (RootPathNameW
,
493 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
495 lpVolumeSerialNumber
,
496 lpMaximumComponentLength
,
498 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
499 nFileSystemNameSize
);
503 if (lpVolumeNameBuffer
)
505 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
506 VolumeName
.Length
= 0;
507 VolumeName
.MaximumLength
= nVolumeNameSize
;
508 VolumeName
.Buffer
= lpVolumeNameBuffer
;
511 if (lpFileSystemNameBuffer
)
513 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
514 FileSystemName
.Length
= 0;
515 FileSystemName
.MaximumLength
= nFileSystemNameSize
;
516 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
519 /* convert unicode strings to ansi (or oem) */
522 if (lpVolumeNameBuffer
)
524 RtlUnicodeStringToAnsiString (&VolumeName
,
528 if (lpFileSystemNameBuffer
)
530 RtlUnicodeStringToAnsiString (&FileSystemName
,
537 if (lpVolumeNameBuffer
)
539 RtlUnicodeStringToOemString (&VolumeName
,
543 if (lpFileSystemNameBuffer
)
545 RtlUnicodeStringToOemString (&FileSystemName
,
552 if (lpVolumeNameBuffer
)
554 RtlFreeHeap (RtlGetProcessHeap (),
558 if (lpFileSystemNameBuffer
)
560 RtlFreeHeap (RtlGetProcessHeap (),
562 FileSystemNameU
.Buffer
);
568 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
570 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
576 GetVolumeInformationW(
577 LPCWSTR lpRootPathName
,
578 LPWSTR lpVolumeNameBuffer
,
579 DWORD nVolumeNameSize
,
580 LPDWORD lpVolumeSerialNumber
,
581 LPDWORD lpMaximumComponentLength
,
582 LPDWORD lpFileSystemFlags
,
583 LPWSTR lpFileSystemNameBuffer
,
584 DWORD nFileSystemNameSize
587 PFILE_FS_VOLUME_INFORMATION FileFsVolume
;
588 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
589 IO_STATUS_BLOCK IoStatusBlock
;
590 WCHAR RootPathName
[MAX_PATH
];
591 UCHAR Buffer
[max(FS_VOLUME_BUFFER_SIZE
, FS_ATTRIBUTE_BUFFER_SIZE
)];
596 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
597 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
599 DPRINT("FileFsVolume %p\n", FileFsVolume
);
600 DPRINT("FileFsAttribute %p\n", FileFsAttribute
);
602 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
604 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
608 wcsncpy (RootPathName
, lpRootPathName
, 3);
612 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
613 if (hFile
== INVALID_HANDLE_VALUE
)
618 DPRINT("hFile: %x\n", hFile
);
619 errCode
= NtQueryVolumeInformationFile(hFile
,
622 FS_VOLUME_BUFFER_SIZE
,
623 FileFsVolumeInformation
);
624 if ( !NT_SUCCESS(errCode
) )
626 DPRINT("Status: %x\n", errCode
);
628 SetLastErrorByStatus (errCode
);
632 if (lpVolumeSerialNumber
)
633 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
635 if (lpVolumeNameBuffer
)
637 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
639 memcpy(lpVolumeNameBuffer
,
640 FileFsVolume
->VolumeLabel
,
641 FileFsVolume
->VolumeLabelLength
);
642 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
647 SetLastError(ERROR_MORE_DATA
);
652 errCode
= NtQueryVolumeInformationFile (hFile
,
655 FS_ATTRIBUTE_BUFFER_SIZE
,
656 FileFsAttributeInformation
);
658 if (!NT_SUCCESS(errCode
))
660 DPRINT("Status: %x\n", errCode
);
661 SetLastErrorByStatus (errCode
);
665 if (lpFileSystemFlags
)
666 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
667 if (lpMaximumComponentLength
)
668 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
669 if (lpFileSystemNameBuffer
)
671 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
673 memcpy(lpFileSystemNameBuffer
,
674 FileFsAttribute
->FileSystemName
,
675 FileFsAttribute
->FileSystemNameLength
);
676 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
680 SetLastError(ERROR_MORE_DATA
);
694 LPCSTR lpRootPathName
,
695 LPCSTR lpVolumeName
/* NULL if deleting label */
698 PWCHAR RootPathNameW
;
699 PWCHAR VolumeNameW
= NULL
;
702 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
707 if (!(VolumeNameW
= FilenameA2W(lpVolumeName
, TRUE
)))
711 Result
= SetVolumeLabelW (RootPathNameW
,
716 RtlFreeHeap (RtlGetProcessHeap (),
730 LPCWSTR lpRootPathName
,
731 LPCWSTR lpVolumeName
/* NULL if deleting label */
734 PFILE_FS_LABEL_INFORMATION LabelInfo
;
735 IO_STATUS_BLOCK IoStatusBlock
;
740 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
741 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
743 sizeof(FILE_FS_LABEL_INFORMATION
) +
745 if (LabelInfo
== NULL
)
747 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
750 LabelInfo
->VolumeLabelLength
= LabelLength
;
751 memcpy(LabelInfo
->VolumeLabel
,
755 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
756 if (INVALID_HANDLE_VALUE
== hFile
)
758 RtlFreeHeap(RtlGetProcessHeap(),
764 Status
= NtSetVolumeInformationFile(hFile
,
767 sizeof(FILE_FS_LABEL_INFORMATION
) +
769 FileFsLabelInformation
);
771 RtlFreeHeap(RtlGetProcessHeap(),
775 if (!NT_SUCCESS(Status
))
777 DPRINT("Status: %x\n", Status
);
779 SetLastErrorByStatus(Status
);
788 * @name GetVolumeNameForVolumeMountPointW
790 * Return an unique volume name for a drive root or mount point.
792 * @param VolumeMountPoint
793 * Pointer to string that contains either root drive name or
796 * Pointer to buffer that is filled with resulting unique
797 * volume name on success.
798 * @param VolumeNameLength
799 * Size of VolumeName buffer in TCHARs.
802 * TRUE when the function succeeds and the VolumeName buffer is filled,
807 GetVolumeNameForVolumeMountPointW(
808 IN LPCWSTR VolumeMountPoint
,
809 OUT LPWSTR VolumeName
,
810 IN DWORD VolumeNameLength
)
812 UNICODE_STRING NtFileName
;
813 OBJECT_ATTRIBUTES ObjectAttributes
;
815 IO_STATUS_BLOCK Iosb
;
817 PMOUNTDEV_NAME MountDevName
;
818 PMOUNTMGR_MOUNT_POINT MountPoint
;
819 ULONG MountPointSize
;
820 PMOUNTMGR_MOUNT_POINTS MountPoints
;
822 PUCHAR SymbolicLinkName
;
827 * First step is to convert the passed volume mount point name to
828 * an NT acceptable name.
831 if (!RtlDosPathNameToNtPathName_U(VolumeMountPoint
, &NtFileName
, NULL
, NULL
))
833 SetLastError(ERROR_PATH_NOT_FOUND
);
837 if (NtFileName
.Length
> sizeof(WCHAR
) &&
838 NtFileName
.Buffer
[(NtFileName
.Length
/ sizeof(WCHAR
)) - 1] == '\\')
840 NtFileName
.Length
-= sizeof(WCHAR
);
844 * Query mount point device name which we will later use for determining
848 InitializeObjectAttributes(&ObjectAttributes
, &NtFileName
, 0, NULL
, NULL
);
849 Status
= NtOpenFile(&FileHandle
, FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
850 &ObjectAttributes
, &Iosb
,
851 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
852 FILE_SYNCHRONOUS_IO_NONALERT
);
853 RtlFreeUnicodeString(&NtFileName
);
854 if (!NT_SUCCESS(Status
))
856 SetLastErrorByStatus(Status
);
860 BufferLength
= sizeof(MOUNTDEV_NAME
) + 50 * sizeof(WCHAR
);
863 MountDevName
= RtlAllocateHeap(GetProcessHeap(), 0, BufferLength
);
864 if (MountDevName
== NULL
)
867 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
871 Status
= NtDeviceIoControlFile(FileHandle
, NULL
, NULL
, NULL
, &Iosb
,
872 IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
873 NULL
, 0, MountDevName
, BufferLength
);
874 if (!NT_SUCCESS(Status
))
876 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
877 if (Status
== STATUS_BUFFER_OVERFLOW
)
879 BufferLength
= sizeof(MOUNTDEV_NAME
) + MountDevName
->NameLength
;
885 SetLastErrorByStatus(Status
);
890 while (!NT_SUCCESS(Status
));
895 * Get the mount point information from mount manager.
898 MountPointSize
= MountDevName
->NameLength
+ sizeof(MOUNTMGR_MOUNT_POINT
);
899 MountPoint
= RtlAllocateHeap(GetProcessHeap(), 0, MountPointSize
);
900 if (MountPoint
== NULL
)
902 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
903 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
906 RtlZeroMemory(MountPoint
, sizeof(MOUNTMGR_MOUNT_POINT
));
907 MountPoint
->DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINT
);
908 MountPoint
->DeviceNameLength
= MountDevName
->NameLength
;
909 RtlCopyMemory(MountPoint
+ 1, MountDevName
->Name
, MountDevName
->NameLength
);
910 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
912 RtlInitUnicodeString(&NtFileName
, L
"\\??\\MountPointManager");
913 InitializeObjectAttributes(&ObjectAttributes
, &NtFileName
, 0, NULL
, NULL
);
914 Status
= NtOpenFile(&FileHandle
, FILE_GENERIC_READ
, &ObjectAttributes
,
915 &Iosb
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
916 FILE_SYNCHRONOUS_IO_NONALERT
);
917 if (!NT_SUCCESS(Status
))
919 SetLastErrorByStatus(Status
);
920 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
924 BufferLength
= sizeof(MOUNTMGR_MOUNT_POINTS
);
927 MountPoints
= RtlAllocateHeap(GetProcessHeap(), 0, BufferLength
);
928 if (MountPoints
== NULL
)
930 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
932 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
936 Status
= NtDeviceIoControlFile(FileHandle
, NULL
, NULL
, NULL
, &Iosb
,
937 IOCTL_MOUNTMGR_QUERY_POINTS
,
938 MountPoint
, MountPointSize
,
939 MountPoints
, BufferLength
);
940 if (!NT_SUCCESS(Status
))
942 RtlFreeHeap(GetProcessHeap(), 0, MountPoints
);
943 if (Status
== STATUS_BUFFER_OVERFLOW
)
945 BufferLength
= MountPoints
->Size
;
948 else if (!NT_SUCCESS(Status
))
950 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
952 SetLastErrorByStatus(Status
);
957 while (!NT_SUCCESS(Status
));
959 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
963 * Now we've gathered info about all mount points mapped to our device, so
964 * select the correct one and copy it into the output buffer.
967 for (Index
= 0; Index
< MountPoints
->NumberOfMountPoints
; Index
++)
969 MountPoint
= MountPoints
->MountPoints
+ Index
;
970 SymbolicLinkName
= (PUCHAR
)MountPoints
+ MountPoint
->SymbolicLinkNameOffset
;
973 * Check for "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
974 * (with the last slash being optional) style symbolic links.
977 if (MountPoint
->SymbolicLinkNameLength
== 48 * sizeof(WCHAR
) ||
978 (MountPoint
->SymbolicLinkNameLength
== 49 * sizeof(WCHAR
) &&
979 SymbolicLinkName
[48] == L
'\\'))
981 if (RtlCompareMemory(SymbolicLinkName
, L
"\\??\\Volume{",
982 11 * sizeof(WCHAR
)) == 11 * sizeof(WCHAR
) &&
983 SymbolicLinkName
[19] == L
'-' && SymbolicLinkName
[24] == L
'-' &&
984 SymbolicLinkName
[29] == L
'-' && SymbolicLinkName
[34] == L
'-' &&
985 SymbolicLinkName
[47] == L
'}')
987 if (VolumeNameLength
>= MountPoint
->SymbolicLinkNameLength
/ sizeof(WCHAR
))
989 RtlCopyMemory(VolumeName
,
990 (PUCHAR
)MountPoints
+ MountPoint
->SymbolicLinkNameOffset
,
991 MountPoint
->SymbolicLinkNameLength
);
992 VolumeName
[1] = L
'\\';
997 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
1001 RtlFreeHeap(GetProcessHeap(), 0, MountPoints
);
1008 RtlFreeHeap(GetProcessHeap(), 0, MountPoints
);
1009 SetLastError(ERROR_INVALID_PARAMETER
);