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
23 #include <wine/debug.h>
25 WINE_DEFAULT_DEBUG_CHANNEL(kernel32file
);
27 #define MAX_DOS_DRIVES 26
31 InternalOpenDirW(LPCWSTR DirName
,
34 UNICODE_STRING NtPathU
;
35 OBJECT_ATTRIBUTES ObjectAttributes
;
37 IO_STATUS_BLOCK IoStatusBlock
;
40 if (!RtlDosPathNameToNtPathName_U(DirName
,
45 WARN("Invalid path\n");
46 SetLastError(ERROR_BAD_PATHNAME
);
47 return INVALID_HANDLE_VALUE
;
50 InitializeObjectAttributes(&ObjectAttributes
,
56 errCode
= NtCreateFile (&hFile
,
57 Write
? FILE_GENERIC_WRITE
: FILE_GENERIC_READ
,
62 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
68 RtlFreeHeap(RtlGetProcessHeap(),
72 if (!NT_SUCCESS(errCode
))
74 SetLastErrorByStatus (errCode
);
75 return INVALID_HANDLE_VALUE
;
84 /* Synced to Wine-2008/12/28 */
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) + 1 > nBufferLength
) return ((count
* 4) + 1);
105 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
106 if (dwDriveMap
& (1<<drive
))
108 *p
++ = 'A' + (UCHAR
)drive
;
122 /* Synced to Wine-2008/12/28 */
124 GetLogicalDriveStringsW(DWORD nBufferLength
,
130 dwDriveMap
= GetLogicalDrives();
132 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
134 if (dwDriveMap
& (1<<drive
))
138 if ((count
* 4) + 1 > nBufferLength
) return ((count
* 4) + 1);
141 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
142 if (dwDriveMap
& (1<<drive
))
144 *p
++ = (WCHAR
)('A' + drive
);
158 /* Synced to Wine-? */
160 GetLogicalDrives(VOID
)
163 PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo
;
165 /* Get the Device Map for this Process */
166 Status
= NtQueryInformationProcess(NtCurrentProcess(),
168 &ProcessDeviceMapInfo
,
169 sizeof(ProcessDeviceMapInfo
),
172 /* Return the Drive Map */
173 if (!NT_SUCCESS(Status
))
175 SetLastErrorByStatus(Status
);
179 return ProcessDeviceMapInfo
.Query
.DriveMap
;
188 LPCSTR lpRootPathName
,
189 LPDWORD lpSectorsPerCluster
,
190 LPDWORD lpBytesPerSector
,
191 LPDWORD lpNumberOfFreeClusters
,
192 LPDWORD lpTotalNumberOfClusters
195 PWCHAR RootPathNameW
=NULL
;
199 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
203 return GetDiskFreeSpaceW (RootPathNameW
,
206 lpNumberOfFreeClusters
,
207 lpTotalNumberOfClusters
);
216 LPCWSTR lpRootPathName
,
217 LPDWORD lpSectorsPerCluster
,
218 LPDWORD lpBytesPerSector
,
219 LPDWORD lpNumberOfFreeClusters
,
220 LPDWORD lpTotalNumberOfClusters
223 FILE_FS_SIZE_INFORMATION FileFsSize
;
224 IO_STATUS_BLOCK IoStatusBlock
;
225 WCHAR RootPathName
[MAX_PATH
];
231 wcsncpy (RootPathName
, lpRootPathName
, 3);
235 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
239 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
240 if (INVALID_HANDLE_VALUE
== hFile
)
242 SetLastError(ERROR_PATH_NOT_FOUND
);
246 errCode
= NtQueryVolumeInformationFile(hFile
,
249 sizeof(FILE_FS_SIZE_INFORMATION
),
250 FileFsSizeInformation
);
251 if (!NT_SUCCESS(errCode
))
254 SetLastErrorByStatus (errCode
);
258 if (lpSectorsPerCluster
)
259 *lpSectorsPerCluster
= FileFsSize
.SectorsPerAllocationUnit
;
260 if (lpBytesPerSector
)
261 *lpBytesPerSector
= FileFsSize
.BytesPerSector
;
262 if (lpNumberOfFreeClusters
)
263 *lpNumberOfFreeClusters
= FileFsSize
.AvailableAllocationUnits
.u
.LowPart
;
264 if (lpTotalNumberOfClusters
)
265 *lpTotalNumberOfClusters
= FileFsSize
.TotalAllocationUnits
.u
.LowPart
;
276 GetDiskFreeSpaceExA (
277 LPCSTR lpDirectoryName OPTIONAL
,
278 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
279 PULARGE_INTEGER lpTotalNumberOfBytes
,
280 PULARGE_INTEGER lpTotalNumberOfFreeBytes
283 PWCHAR DirectoryNameW
=NULL
;
287 if (!(DirectoryNameW
= FilenameA2W(lpDirectoryName
, FALSE
)))
291 return GetDiskFreeSpaceExW (DirectoryNameW
,
292 lpFreeBytesAvailableToCaller
,
293 lpTotalNumberOfBytes
,
294 lpTotalNumberOfFreeBytes
);
303 LPCWSTR lpDirectoryName OPTIONAL
,
304 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
305 PULARGE_INTEGER lpTotalNumberOfBytes
,
306 PULARGE_INTEGER lpTotalNumberOfFreeBytes
311 FILE_FS_SIZE_INFORMATION FsSize
;
312 FILE_FS_FULL_SIZE_INFORMATION FsFullSize
;
314 IO_STATUS_BLOCK IoStatusBlock
;
315 ULARGE_INTEGER BytesPerCluster
;
319 if (lpDirectoryName
== NULL
)
320 lpDirectoryName
= L
"\\";
322 hFile
= InternalOpenDirW(lpDirectoryName
, FALSE
);
323 if (INVALID_HANDLE_VALUE
== hFile
)
328 if (lpFreeBytesAvailableToCaller
!= NULL
|| lpTotalNumberOfBytes
!= NULL
)
330 /* To get the free space available to the user associated with the
331 current thread, try FileFsFullSizeInformation. If this is not
332 supported by the file system, fall back to FileFsSize */
334 Status
= NtQueryVolumeInformationFile(hFile
,
337 sizeof(FsInfo
.FsFullSize
),
338 FileFsFullSizeInformation
);
340 if (NT_SUCCESS(Status
))
342 /* Close the handle before returning data
343 to avoid a handle leak in case of a fault! */
346 BytesPerCluster
.QuadPart
=
347 FsInfo
.FsFullSize
.BytesPerSector
* FsInfo
.FsFullSize
.SectorsPerAllocationUnit
;
349 if (lpFreeBytesAvailableToCaller
!= NULL
)
351 lpFreeBytesAvailableToCaller
->QuadPart
=
352 BytesPerCluster
.QuadPart
* FsInfo
.FsFullSize
.CallerAvailableAllocationUnits
.QuadPart
;
355 if (lpTotalNumberOfBytes
!= NULL
)
357 lpTotalNumberOfBytes
->QuadPart
=
358 BytesPerCluster
.QuadPart
* FsInfo
.FsFullSize
.TotalAllocationUnits
.QuadPart
;
361 if (lpTotalNumberOfFreeBytes
!= NULL
)
363 lpTotalNumberOfFreeBytes
->QuadPart
=
364 BytesPerCluster
.QuadPart
* FsInfo
.FsFullSize
.ActualAvailableAllocationUnits
.QuadPart
;
371 Status
= NtQueryVolumeInformationFile(hFile
,
374 sizeof(FsInfo
.FsSize
),
375 FileFsSizeInformation
);
377 /* Close the handle before returning data
378 to avoid a handle leak in case of a fault! */
381 if (!NT_SUCCESS(Status
))
383 SetLastErrorByStatus (Status
);
387 BytesPerCluster
.QuadPart
=
388 FsInfo
.FsSize
.BytesPerSector
* FsInfo
.FsSize
.SectorsPerAllocationUnit
;
390 if (lpFreeBytesAvailableToCaller
)
392 lpFreeBytesAvailableToCaller
->QuadPart
=
393 BytesPerCluster
.QuadPart
* FsInfo
.FsSize
.AvailableAllocationUnits
.QuadPart
;
396 if (lpTotalNumberOfBytes
)
398 lpTotalNumberOfBytes
->QuadPart
=
399 BytesPerCluster
.QuadPart
* FsInfo
.FsSize
.TotalAllocationUnits
.QuadPart
;
402 if (lpTotalNumberOfFreeBytes
)
404 lpTotalNumberOfFreeBytes
->QuadPart
=
405 BytesPerCluster
.QuadPart
* FsInfo
.FsSize
.AvailableAllocationUnits
.QuadPart
;
416 GetDriveTypeA(LPCSTR lpRootPathName
)
418 PWCHAR RootPathNameW
;
420 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
421 return DRIVE_UNKNOWN
;
423 return GetDriveTypeW(RootPathNameW
);
431 GetDriveTypeW(LPCWSTR lpRootPathName
)
433 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
434 IO_STATUS_BLOCK IoStatusBlock
;
439 hFile
= InternalOpenDirW(lpRootPathName
, FALSE
);
440 if (hFile
== INVALID_HANDLE_VALUE
)
442 return DRIVE_NO_ROOT_DIR
; /* According to WINE regression tests */
445 errCode
= NtQueryVolumeInformationFile (hFile
,
448 sizeof(FILE_FS_DEVICE_INFORMATION
),
449 FileFsDeviceInformation
);
450 if (!NT_SUCCESS(errCode
))
453 SetLastErrorByStatus (errCode
);
458 switch (FileFsDevice
.DeviceType
)
460 case FILE_DEVICE_CD_ROM
:
461 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
463 case FILE_DEVICE_VIRTUAL_DISK
:
464 return DRIVE_RAMDISK
;
465 case FILE_DEVICE_NETWORK_FILE_SYSTEM
:
467 case FILE_DEVICE_DISK
:
468 case FILE_DEVICE_DISK_FILE_SYSTEM
:
469 if (FileFsDevice
.Characteristics
& FILE_REMOTE_DEVICE
)
471 if (FileFsDevice
.Characteristics
& FILE_REMOVABLE_MEDIA
)
472 return DRIVE_REMOVABLE
;
476 ERR("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice
.DeviceType
);
478 return DRIVE_UNKNOWN
;
486 GetVolumeInformationA(
487 LPCSTR lpRootPathName
,
488 LPSTR lpVolumeNameBuffer
,
489 DWORD nVolumeNameSize
,
490 LPDWORD lpVolumeSerialNumber
,
491 LPDWORD lpMaximumComponentLength
,
492 LPDWORD lpFileSystemFlags
,
493 LPSTR lpFileSystemNameBuffer
,
494 DWORD nFileSystemNameSize
497 UNICODE_STRING FileSystemNameU
;
498 UNICODE_STRING VolumeNameU
= { 0, 0, NULL
};
499 ANSI_STRING VolumeName
;
500 ANSI_STRING FileSystemName
;
501 PWCHAR RootPathNameW
;
504 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
507 if (lpVolumeNameBuffer
)
509 VolumeNameU
.MaximumLength
= (USHORT
)nVolumeNameSize
* sizeof(WCHAR
);
510 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
512 VolumeNameU
.MaximumLength
);
513 if (VolumeNameU
.Buffer
== NULL
)
519 if (lpFileSystemNameBuffer
)
521 FileSystemNameU
.Length
= 0;
522 FileSystemNameU
.MaximumLength
= (USHORT
)nFileSystemNameSize
* sizeof(WCHAR
);
523 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
525 FileSystemNameU
.MaximumLength
);
526 if (FileSystemNameU
.Buffer
== NULL
)
528 if (VolumeNameU
.Buffer
!= NULL
)
530 RtlFreeHeap(RtlGetProcessHeap(),
536 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
541 Result
= GetVolumeInformationW (RootPathNameW
,
542 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
544 lpVolumeSerialNumber
,
545 lpMaximumComponentLength
,
547 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
548 nFileSystemNameSize
);
552 if (lpVolumeNameBuffer
)
554 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
555 VolumeName
.Length
= 0;
556 VolumeName
.MaximumLength
= (USHORT
)nVolumeNameSize
;
557 VolumeName
.Buffer
= lpVolumeNameBuffer
;
560 if (lpFileSystemNameBuffer
)
562 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
563 FileSystemName
.Length
= 0;
564 FileSystemName
.MaximumLength
= (USHORT
)nFileSystemNameSize
;
565 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
568 /* convert unicode strings to ansi (or oem) */
571 if (lpVolumeNameBuffer
)
573 RtlUnicodeStringToAnsiString (&VolumeName
,
577 if (lpFileSystemNameBuffer
)
579 RtlUnicodeStringToAnsiString (&FileSystemName
,
586 if (lpVolumeNameBuffer
)
588 RtlUnicodeStringToOemString (&VolumeName
,
592 if (lpFileSystemNameBuffer
)
594 RtlUnicodeStringToOemString (&FileSystemName
,
601 if (lpVolumeNameBuffer
)
603 RtlFreeHeap (RtlGetProcessHeap (),
607 if (lpFileSystemNameBuffer
)
609 RtlFreeHeap (RtlGetProcessHeap (),
611 FileSystemNameU
.Buffer
);
617 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
619 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
625 GetVolumeInformationW(
626 LPCWSTR lpRootPathName
,
627 LPWSTR lpVolumeNameBuffer
,
628 DWORD nVolumeNameSize
,
629 LPDWORD lpVolumeSerialNumber
,
630 LPDWORD lpMaximumComponentLength
,
631 LPDWORD lpFileSystemFlags
,
632 LPWSTR lpFileSystemNameBuffer
,
633 DWORD nFileSystemNameSize
636 PFILE_FS_VOLUME_INFORMATION FileFsVolume
;
637 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
638 IO_STATUS_BLOCK IoStatusBlock
;
639 WCHAR RootPathName
[MAX_PATH
];
640 UCHAR Buffer
[max(FS_VOLUME_BUFFER_SIZE
, FS_ATTRIBUTE_BUFFER_SIZE
)];
645 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
646 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
648 TRACE("FileFsVolume %p\n", FileFsVolume
);
649 TRACE("FileFsAttribute %p\n", FileFsAttribute
);
651 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
653 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
657 wcsncpy (RootPathName
, lpRootPathName
, 3);
661 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
662 if (hFile
== INVALID_HANDLE_VALUE
)
667 TRACE("hFile: %x\n", hFile
);
668 errCode
= NtQueryVolumeInformationFile(hFile
,
671 FS_VOLUME_BUFFER_SIZE
,
672 FileFsVolumeInformation
);
673 if ( !NT_SUCCESS(errCode
) )
675 WARN("Status: %x\n", errCode
);
677 SetLastErrorByStatus (errCode
);
681 if (lpVolumeSerialNumber
)
682 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
684 if (lpVolumeNameBuffer
)
686 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
688 memcpy(lpVolumeNameBuffer
,
689 FileFsVolume
->VolumeLabel
,
690 FileFsVolume
->VolumeLabelLength
);
691 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
696 SetLastError(ERROR_MORE_DATA
);
701 errCode
= NtQueryVolumeInformationFile (hFile
,
704 FS_ATTRIBUTE_BUFFER_SIZE
,
705 FileFsAttributeInformation
);
707 if (!NT_SUCCESS(errCode
))
709 WARN("Status: %x\n", errCode
);
710 SetLastErrorByStatus (errCode
);
714 if (lpFileSystemFlags
)
715 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
716 if (lpMaximumComponentLength
)
717 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
718 if (lpFileSystemNameBuffer
)
720 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
722 memcpy(lpFileSystemNameBuffer
,
723 FileFsAttribute
->FileSystemName
,
724 FileFsAttribute
->FileSystemNameLength
);
725 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
729 SetLastError(ERROR_MORE_DATA
);
743 LPCSTR lpRootPathName
,
744 LPCSTR lpVolumeName
/* NULL if deleting label */
747 PWCHAR RootPathNameW
;
748 PWCHAR VolumeNameW
= NULL
;
751 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
756 if (!(VolumeNameW
= FilenameA2W(lpVolumeName
, TRUE
)))
760 Result
= SetVolumeLabelW (RootPathNameW
,
765 RtlFreeHeap (RtlGetProcessHeap (),
779 LPCWSTR lpRootPathName
,
780 LPCWSTR lpVolumeName
/* NULL if deleting label */
783 PFILE_FS_LABEL_INFORMATION LabelInfo
;
784 IO_STATUS_BLOCK IoStatusBlock
;
789 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
790 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
792 sizeof(FILE_FS_LABEL_INFORMATION
) +
794 if (LabelInfo
== NULL
)
796 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
799 LabelInfo
->VolumeLabelLength
= LabelLength
;
800 memcpy(LabelInfo
->VolumeLabel
,
804 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
805 if (INVALID_HANDLE_VALUE
== hFile
)
807 RtlFreeHeap(RtlGetProcessHeap(),
813 Status
= NtSetVolumeInformationFile(hFile
,
816 sizeof(FILE_FS_LABEL_INFORMATION
) +
818 FileFsLabelInformation
);
820 RtlFreeHeap(RtlGetProcessHeap(),
824 if (!NT_SUCCESS(Status
))
826 WARN("Status: %x\n", Status
);
828 SetLastErrorByStatus(Status
);
837 * @name GetVolumeNameForVolumeMountPointW
839 * Return an unique volume name for a drive root or mount point.
841 * @param VolumeMountPoint
842 * Pointer to string that contains either root drive name or
845 * Pointer to buffer that is filled with resulting unique
846 * volume name on success.
847 * @param VolumeNameLength
848 * Size of VolumeName buffer in TCHARs.
851 * TRUE when the function succeeds and the VolumeName buffer is filled,
856 GetVolumeNameForVolumeMountPointW(
857 IN LPCWSTR VolumeMountPoint
,
858 OUT LPWSTR VolumeName
,
859 IN DWORD VolumeNameLength
)
861 UNICODE_STRING NtFileName
;
862 OBJECT_ATTRIBUTES ObjectAttributes
;
864 IO_STATUS_BLOCK Iosb
;
866 PMOUNTDEV_NAME MountDevName
;
867 PMOUNTMGR_MOUNT_POINT MountPoint
;
868 ULONG MountPointSize
;
869 PMOUNTMGR_MOUNT_POINTS MountPoints
;
871 PUCHAR SymbolicLinkName
;
875 if (!VolumeMountPoint
|| !VolumeMountPoint
[0])
877 SetLastError(ERROR_PATH_NOT_FOUND
);
882 * First step is to convert the passed volume mount point name to
883 * an NT acceptable name.
886 if (!RtlDosPathNameToNtPathName_U(VolumeMountPoint
, &NtFileName
, NULL
, NULL
))
888 SetLastError(ERROR_PATH_NOT_FOUND
);
892 if (NtFileName
.Length
> sizeof(WCHAR
) &&
893 NtFileName
.Buffer
[(NtFileName
.Length
/ sizeof(WCHAR
)) - 1] == '\\')
895 NtFileName
.Length
-= sizeof(WCHAR
);
899 * Query mount point device name which we will later use for determining
903 InitializeObjectAttributes(&ObjectAttributes
, &NtFileName
, 0, NULL
, NULL
);
904 Status
= NtOpenFile(&FileHandle
, FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
905 &ObjectAttributes
, &Iosb
,
906 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
907 FILE_SYNCHRONOUS_IO_NONALERT
);
908 RtlFreeUnicodeString(&NtFileName
);
909 if (!NT_SUCCESS(Status
))
911 SetLastErrorByStatus(Status
);
915 BufferLength
= sizeof(MOUNTDEV_NAME
) + 50 * sizeof(WCHAR
);
918 MountDevName
= RtlAllocateHeap(GetProcessHeap(), 0, BufferLength
);
919 if (MountDevName
== NULL
)
922 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
926 Status
= NtDeviceIoControlFile(FileHandle
, NULL
, NULL
, NULL
, &Iosb
,
927 IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
928 NULL
, 0, MountDevName
, BufferLength
);
929 if (!NT_SUCCESS(Status
))
931 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
932 if (Status
== STATUS_BUFFER_OVERFLOW
)
934 BufferLength
= sizeof(MOUNTDEV_NAME
) + MountDevName
->NameLength
;
940 SetLastErrorByStatus(Status
);
945 while (!NT_SUCCESS(Status
));
950 * Get the mount point information from mount manager.
953 MountPointSize
= MountDevName
->NameLength
+ sizeof(MOUNTMGR_MOUNT_POINT
);
954 MountPoint
= RtlAllocateHeap(GetProcessHeap(), 0, MountPointSize
);
955 if (MountPoint
== NULL
)
957 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
958 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
961 RtlZeroMemory(MountPoint
, sizeof(MOUNTMGR_MOUNT_POINT
));
962 MountPoint
->DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINT
);
963 MountPoint
->DeviceNameLength
= MountDevName
->NameLength
;
964 RtlCopyMemory(MountPoint
+ 1, MountDevName
->Name
, MountDevName
->NameLength
);
965 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
967 RtlInitUnicodeString(&NtFileName
, L
"\\??\\MountPointManager");
968 InitializeObjectAttributes(&ObjectAttributes
, &NtFileName
, 0, NULL
, NULL
);
969 Status
= NtOpenFile(&FileHandle
, FILE_GENERIC_READ
, &ObjectAttributes
,
970 &Iosb
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
971 FILE_SYNCHRONOUS_IO_NONALERT
);
972 if (!NT_SUCCESS(Status
))
974 SetLastErrorByStatus(Status
);
975 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
979 BufferLength
= sizeof(MOUNTMGR_MOUNT_POINTS
);
982 MountPoints
= RtlAllocateHeap(GetProcessHeap(), 0, BufferLength
);
983 if (MountPoints
== NULL
)
985 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
987 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
991 Status
= NtDeviceIoControlFile(FileHandle
, NULL
, NULL
, NULL
, &Iosb
,
992 IOCTL_MOUNTMGR_QUERY_POINTS
,
993 MountPoint
, MountPointSize
,
994 MountPoints
, BufferLength
);
995 if (!NT_SUCCESS(Status
))
997 RtlFreeHeap(GetProcessHeap(), 0, MountPoints
);
998 if (Status
== STATUS_BUFFER_OVERFLOW
)
1000 BufferLength
= MountPoints
->Size
;
1003 else if (!NT_SUCCESS(Status
))
1005 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
1006 NtClose(FileHandle
);
1007 SetLastErrorByStatus(Status
);
1012 while (!NT_SUCCESS(Status
));
1014 RtlFreeHeap(GetProcessHeap(), 0, MountPoint
);
1015 NtClose(FileHandle
);
1018 * Now we've gathered info about all mount points mapped to our device, so
1019 * select the correct one and copy it into the output buffer.
1022 for (Index
= 0; Index
< MountPoints
->NumberOfMountPoints
; Index
++)
1024 MountPoint
= MountPoints
->MountPoints
+ Index
;
1025 SymbolicLinkName
= (PUCHAR
)MountPoints
+ MountPoint
->SymbolicLinkNameOffset
;
1028 * Check for "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
1029 * (with the last slash being optional) style symbolic links.
1032 if (MountPoint
->SymbolicLinkNameLength
== 48 * sizeof(WCHAR
) ||
1033 (MountPoint
->SymbolicLinkNameLength
== 49 * sizeof(WCHAR
) &&
1034 SymbolicLinkName
[48] == L
'\\'))
1036 if (RtlCompareMemory(SymbolicLinkName
, L
"\\??\\Volume{",
1037 11 * sizeof(WCHAR
)) == 11 * sizeof(WCHAR
) &&
1038 SymbolicLinkName
[19] == L
'-' && SymbolicLinkName
[24] == L
'-' &&
1039 SymbolicLinkName
[29] == L
'-' && SymbolicLinkName
[34] == L
'-' &&
1040 SymbolicLinkName
[47] == L
'}')
1042 if (VolumeNameLength
>= MountPoint
->SymbolicLinkNameLength
/ sizeof(WCHAR
))
1044 RtlCopyMemory(VolumeName
,
1045 (PUCHAR
)MountPoints
+ MountPoint
->SymbolicLinkNameOffset
,
1046 MountPoint
->SymbolicLinkNameLength
);
1047 VolumeName
[1] = L
'\\';
1052 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
1056 RtlFreeHeap(GetProcessHeap(), 0, MountPoints
);
1063 RtlFreeHeap(GetProcessHeap(), 0, MountPoints
);
1064 SetLastError(ERROR_INVALID_PARAMETER
);
1070 * @implemented (Wine 13 sep 2008)
1074 GetVolumeNameForVolumeMountPointA(
1075 LPCSTR lpszVolumeMountPoint
,
1076 LPSTR lpszVolumeName
,
1077 DWORD cchBufferLength
1081 WCHAR volumeW
[50], *pathW
= NULL
;
1082 DWORD len
= min( sizeof(volumeW
) / sizeof(WCHAR
), cchBufferLength
);
1084 TRACE("(%s, %p, %x)\n", debugstr_a(lpszVolumeMountPoint
), lpszVolumeName
, cchBufferLength
);
1086 if (!lpszVolumeMountPoint
|| !(pathW
= FilenameA2W( lpszVolumeMountPoint
, TRUE
)))
1089 if ((ret
= GetVolumeNameForVolumeMountPointW( pathW
, volumeW
, len
)))
1090 FilenameW2A_N( lpszVolumeName
, len
, volumeW
, -1 );
1092 RtlFreeHeap( GetProcessHeap(), 0, pathW
);
1097 * @implemented (Wine 13 sep 2008)
1107 HANDLE mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
1108 NULL
, OPEN_EXISTING
, 0, 0 );
1109 if (mgr
== INVALID_HANDLE_VALUE
) return INVALID_HANDLE_VALUE
;
1113 MOUNTMGR_MOUNT_POINT input
;
1114 MOUNTMGR_MOUNT_POINTS
*output
;
1116 if (!(output
= RtlAllocateHeap( GetProcessHeap(), 0, size
)))
1118 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1121 memset( &input
, 0, sizeof(input
) );
1123 if (!DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_POINTS
, &input
, sizeof(input
),
1124 output
, size
, NULL
, NULL
))
1126 if (GetLastError() != ERROR_MORE_DATA
) break;
1127 size
= output
->Size
;
1128 RtlFreeHeap( GetProcessHeap(), 0, output
);
1132 /* abuse the Size field to store the current index */
1134 if (!FindNextVolumeW( output
, volume
, len
))
1136 RtlFreeHeap( GetProcessHeap(), 0, output
);
1137 return INVALID_HANDLE_VALUE
;
1139 return (HANDLE
)output
;
1142 return INVALID_HANDLE_VALUE
;
1146 * @implemented (Wine 13 sep 2008)
1155 WCHAR
*buffer
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1156 HANDLE handle
= FindFirstVolumeW( buffer
, len
);
1158 if (handle
!= INVALID_HANDLE_VALUE
)
1160 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
))
1162 FindVolumeClose( handle
);
1163 handle
= INVALID_HANDLE_VALUE
;
1166 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1171 * @implemented (Wine 13 sep 2008)
1179 return RtlFreeHeap(GetProcessHeap(), 0, hFindVolume
);