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
= {0};
448 ANSI_STRING VolumeName
;
449 ANSI_STRING FileSystemName
;
450 PWCHAR RootPathNameW
;
453 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
456 if (lpVolumeNameBuffer
)
458 VolumeNameU
.MaximumLength
= nVolumeNameSize
* sizeof(WCHAR
);
459 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
461 VolumeNameU
.MaximumLength
);
462 if (VolumeNameU
.Buffer
== NULL
)
468 if (lpFileSystemNameBuffer
)
470 FileSystemNameU
.Length
= 0;
471 FileSystemNameU
.MaximumLength
= nFileSystemNameSize
* sizeof(WCHAR
);
472 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
474 FileSystemNameU
.MaximumLength
);
475 if (FileSystemNameU
.Buffer
== NULL
)
477 if (VolumeNameU
.Buffer
!= NULL
)
479 RtlFreeHeap(RtlGetProcessHeap(),
485 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
490 Result
= GetVolumeInformationW (RootPathNameW
,
491 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
493 lpVolumeSerialNumber
,
494 lpMaximumComponentLength
,
496 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
497 nFileSystemNameSize
);
501 if (lpVolumeNameBuffer
)
503 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
504 VolumeName
.Length
= 0;
505 VolumeName
.MaximumLength
= nVolumeNameSize
;
506 VolumeName
.Buffer
= lpVolumeNameBuffer
;
509 if (lpFileSystemNameBuffer
)
511 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
512 FileSystemName
.Length
= 0;
513 FileSystemName
.MaximumLength
= nFileSystemNameSize
;
514 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
517 /* convert unicode strings to ansi (or oem) */
520 if (lpVolumeNameBuffer
)
522 RtlUnicodeStringToAnsiString (&VolumeName
,
526 if (lpFileSystemNameBuffer
)
528 RtlUnicodeStringToAnsiString (&FileSystemName
,
535 if (lpVolumeNameBuffer
)
537 RtlUnicodeStringToOemString (&VolumeName
,
541 if (lpFileSystemNameBuffer
)
543 RtlUnicodeStringToOemString (&FileSystemName
,
550 if (lpVolumeNameBuffer
)
552 RtlFreeHeap (RtlGetProcessHeap (),
556 if (lpFileSystemNameBuffer
)
558 RtlFreeHeap (RtlGetProcessHeap (),
560 FileSystemNameU
.Buffer
);
566 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
568 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
574 GetVolumeInformationW(
575 LPCWSTR lpRootPathName
,
576 LPWSTR lpVolumeNameBuffer
,
577 DWORD nVolumeNameSize
,
578 LPDWORD lpVolumeSerialNumber
,
579 LPDWORD lpMaximumComponentLength
,
580 LPDWORD lpFileSystemFlags
,
581 LPWSTR lpFileSystemNameBuffer
,
582 DWORD nFileSystemNameSize
585 PFILE_FS_VOLUME_INFORMATION FileFsVolume
;
586 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
587 IO_STATUS_BLOCK IoStatusBlock
;
588 WCHAR RootPathName
[MAX_PATH
];
589 UCHAR Buffer
[max(FS_VOLUME_BUFFER_SIZE
, FS_ATTRIBUTE_BUFFER_SIZE
)];
594 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
595 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
597 DPRINT("FileFsVolume %p\n", FileFsVolume
);
598 DPRINT("FileFsAttribute %p\n", FileFsAttribute
);
600 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
602 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
606 wcsncpy (RootPathName
, lpRootPathName
, 3);
610 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
611 if (hFile
== INVALID_HANDLE_VALUE
)
616 DPRINT("hFile: %x\n", hFile
);
617 errCode
= NtQueryVolumeInformationFile(hFile
,
620 FS_VOLUME_BUFFER_SIZE
,
621 FileFsVolumeInformation
);
622 if ( !NT_SUCCESS(errCode
) )
624 DPRINT("Status: %x\n", errCode
);
626 SetLastErrorByStatus (errCode
);
630 if (lpVolumeSerialNumber
)
631 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
633 if (lpVolumeNameBuffer
)
635 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
637 memcpy(lpVolumeNameBuffer
,
638 FileFsVolume
->VolumeLabel
,
639 FileFsVolume
->VolumeLabelLength
);
640 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
645 SetLastError(ERROR_MORE_DATA
);
650 errCode
= NtQueryVolumeInformationFile (hFile
,
653 FS_ATTRIBUTE_BUFFER_SIZE
,
654 FileFsAttributeInformation
);
656 if (!NT_SUCCESS(errCode
))
658 DPRINT("Status: %x\n", errCode
);
659 SetLastErrorByStatus (errCode
);
663 if (lpFileSystemFlags
)
664 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
665 if (lpMaximumComponentLength
)
666 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
667 if (lpFileSystemNameBuffer
)
669 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
671 memcpy(lpFileSystemNameBuffer
,
672 FileFsAttribute
->FileSystemName
,
673 FileFsAttribute
->FileSystemNameLength
);
674 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
678 SetLastError(ERROR_MORE_DATA
);
692 LPCSTR lpRootPathName
,
693 LPCSTR lpVolumeName
/* NULL if deleting label */
696 PWCHAR RootPathNameW
;
697 PWCHAR VolumeNameW
= NULL
;
700 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
705 if (!(VolumeNameW
= FilenameA2W(lpVolumeName
, TRUE
)))
709 Result
= SetVolumeLabelW (RootPathNameW
,
714 RtlFreeHeap (RtlGetProcessHeap (),
728 LPCWSTR lpRootPathName
,
729 LPCWSTR lpVolumeName
/* NULL if deleting label */
732 PFILE_FS_LABEL_INFORMATION LabelInfo
;
733 IO_STATUS_BLOCK IoStatusBlock
;
738 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
739 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
741 sizeof(FILE_FS_LABEL_INFORMATION
) +
743 if (LabelInfo
== NULL
)
745 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
748 LabelInfo
->VolumeLabelLength
= LabelLength
;
749 memcpy(LabelInfo
->VolumeLabel
,
753 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
754 if (INVALID_HANDLE_VALUE
== hFile
)
756 RtlFreeHeap(RtlGetProcessHeap(),
762 Status
= NtSetVolumeInformationFile(hFile
,
765 sizeof(FILE_FS_LABEL_INFORMATION
) +
767 FileFsLabelInformation
);
769 RtlFreeHeap(RtlGetProcessHeap(),
773 if (!NT_SUCCESS(Status
))
775 DPRINT("Status: %x\n", Status
);
777 SetLastErrorByStatus(Status
);
786 * @name GetVolumeNameForVolumeMountPointW
788 * Return an unique volume name for a drive root or mount point.
790 * @param VolumeMountPoint
791 * Pointer to string that contains either root drive name or
794 * Pointer to buffer that is filled with resulting unique
795 * volume name on success.
796 * @param VolumeNameLength
797 * Size of VolumeName buffer in TCHARs.
800 * TRUE when the function succeeds and the VolumeName buffer is filled,
805 GetVolumeNameForVolumeMountPointW(
806 IN LPCWSTR VolumeMountPoint
,
807 OUT LPWSTR VolumeName
,
808 IN DWORD VolumeNameLength
)
810 UNICODE_STRING NtFileName
;
811 OBJECT_ATTRIBUTES ObjectAttributes
;
813 IO_STATUS_BLOCK Iosb
;
815 PMOUNTDEV_NAME MountDevName
;
816 PMOUNTMGR_MOUNT_POINT MountPoint
;
817 ULONG MountPointSize
;
818 PMOUNTMGR_MOUNT_POINTS MountPoints
;
820 PUCHAR SymbolicLinkName
;
825 * First step is to convert the passed volume mount point name to
826 * an NT acceptable name.
829 if (!RtlDosPathNameToNtPathName_U(VolumeName
, &NtFileName
, NULL
, NULL
))
831 SetLastError(ERROR_PATH_NOT_FOUND
);
835 if (NtFileName
.Length
> sizeof(WCHAR
) &&
836 NtFileName
.Buffer
[(NtFileName
.Length
/ sizeof(WCHAR
)) - 1] == '\\')
838 NtFileName
.Length
-= sizeof(WCHAR
);
842 * Query mount point device name which we will later use for determining
846 InitializeObjectAttributes(&ObjectAttributes
, &NtFileName
, 0, NULL
, NULL
);
847 Status
= NtOpenFile(&FileHandle
, FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
848 &ObjectAttributes
, &Iosb
,
849 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
850 FILE_SYNCHRONOUS_IO_NONALERT
);
851 RtlFreeUnicodeString(&NtFileName
);
852 if (!NT_SUCCESS(Status
))
854 SetLastErrorByStatus(Status
);
858 BufferLength
= sizeof(MOUNTDEV_NAME
) + 50 * sizeof(WCHAR
);
861 MountDevName
= RtlAllocateHeap(GetProcessHeap(), 0, BufferLength
);
862 if (MountDevName
== NULL
)
865 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
869 Status
= NtDeviceIoControlFile(FileHandle
, NULL
, NULL
, NULL
, &Iosb
,
870 IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
871 NULL
, 0, MountDevName
, BufferLength
);
872 if (!NT_SUCCESS(Status
))
874 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
875 if (Status
== STATUS_BUFFER_OVERFLOW
)
877 BufferLength
= sizeof(MOUNTDEV_NAME
) + MountDevName
->NameLength
;
883 SetLastErrorByStatus(Status
);
888 while (!NT_SUCCESS(Status
));
893 * Get the mount point information from mount manager.
896 MountPointSize
= MountDevName
->NameLength
+ sizeof(MOUNTMGR_MOUNT_POINT
);
897 MountPoint
= RtlAllocateHeap(GetProcessHeap(), 0, MountPointSize
);
898 if (MountPoint
== NULL
)
900 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
901 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
904 RtlZeroMemory(MountPoint
, sizeof(MOUNTMGR_MOUNT_POINT
));
905 MountPoint
->DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINT
);
906 MountPoint
->DeviceNameLength
= MountDevName
->NameLength
;
907 RtlCopyMemory(MountPoint
+ 1, MountDevName
->Name
, MountDevName
->NameLength
);
908 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
910 RtlInitUnicodeString(&NtFileName
, L
"\\??\\MountPointManager");
911 InitializeObjectAttributes(&ObjectAttributes
, &NtFileName
, 0, NULL
, NULL
);
912 Status
= NtOpenFile(&FileHandle
, FILE_GENERIC_READ
, &ObjectAttributes
,
913 &Iosb
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
914 FILE_SYNCHRONOUS_IO_NONALERT
);
915 if (!NT_SUCCESS(Status
))
917 SetLastErrorByStatus(Status
);
918 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
922 BufferLength
= sizeof(MOUNTMGR_MOUNT_POINTS
);
925 MountPoints
= RtlAllocateHeap(GetProcessHeap(), 0, BufferLength
);
926 if (MountPoints
== NULL
)
928 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
930 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
934 Status
= NtDeviceIoControlFile(FileHandle
, NULL
, NULL
, NULL
, &Iosb
,
935 IOCTL_MOUNTMGR_QUERY_POINTS
,
936 MountPoint
, MountPointSize
,
937 MountPoints
, BufferLength
);
938 if (!NT_SUCCESS(Status
))
940 RtlFreeHeap(GetProcessHeap(), 0, MountPoints
);
941 if (Status
== STATUS_BUFFER_OVERFLOW
)
943 BufferLength
= MountPoints
->Size
;
946 else if (!NT_SUCCESS(Status
))
948 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
950 SetLastErrorByStatus(Status
);
955 while (!NT_SUCCESS(Status
));
957 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
961 * Now we've gathered info about all mount points mapped to our device, so
962 * select the correct one and copy it into the output buffer.
965 for (Index
= 0; Index
< MountPoints
->NumberOfMountPoints
; Index
++)
967 MountPoint
= MountPoints
->MountPoints
+ Index
;
968 SymbolicLinkName
= (PUCHAR
)MountPoints
+ MountPoint
->SymbolicLinkNameOffset
;
971 * Check for "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
972 * (with the last slash being optional) style symbolic links.
975 if (MountPoint
->SymbolicLinkNameLength
== 48 * sizeof(WCHAR
) ||
976 (MountPoint
->SymbolicLinkNameLength
== 49 * sizeof(WCHAR
) &&
977 SymbolicLinkName
[48] == L
'\\'))
979 if (RtlCompareMemory(SymbolicLinkName
, L
"\\??\\Volume{",
980 11 * sizeof(WCHAR
)) == 11 * sizeof(WCHAR
) &&
981 SymbolicLinkName
[19] == L
'-' && SymbolicLinkName
[24] == L
'-' &&
982 SymbolicLinkName
[29] == L
'-' && SymbolicLinkName
[34] == L
'-' &&
983 SymbolicLinkName
[47] == L
'}')
985 if (VolumeNameLength
>= MountPoint
->SymbolicLinkNameLength
/ sizeof(WCHAR
))
987 RtlCopyMemory(VolumeName
,
988 (PUCHAR
)MountPoints
+ MountPoint
->SymbolicLinkNameOffset
,
989 MountPoint
->SymbolicLinkNameLength
);
990 VolumeName
[1] = L
'\\';
995 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
999 RtlFreeHeap(GetProcessHeap(), 0, MountPoints
);
1006 RtlFreeHeap(GetProcessHeap(), 0, MountPoints
);
1007 SetLastError(ERROR_INVALID_PARAMETER
);