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
,
93 dwDriveMap
= GetLogicalDrives();
95 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
97 if (dwDriveMap
& (1<<drive
))
102 if ((count
* 4) + 1 > nBufferLength
) return ((count
* 4) + 1);
106 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
107 if (dwDriveMap
& (1<<drive
))
109 *p
++ = 'A' + (UCHAR
)drive
;
123 /* Synced to Wine-2008/12/28 */
125 GetLogicalDriveStringsW(DWORD nBufferLength
,
132 dwDriveMap
= GetLogicalDrives();
134 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
136 if (dwDriveMap
& (1<<drive
))
140 if ((count
* 4) + 1 > nBufferLength
) return ((count
* 4) + 1);
143 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
144 if (dwDriveMap
& (1<<drive
))
146 *p
++ = (WCHAR
)('A' + drive
);
160 /* Synced to Wine-? */
162 GetLogicalDrives(VOID
)
165 PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo
;
167 /* Get the Device Map for this Process */
168 Status
= NtQueryInformationProcess(NtCurrentProcess(),
170 &ProcessDeviceMapInfo
,
171 sizeof(ProcessDeviceMapInfo
),
174 /* Return the Drive Map */
175 if (!NT_SUCCESS(Status
))
177 SetLastErrorByStatus(Status
);
181 return ProcessDeviceMapInfo
.Query
.DriveMap
;
190 LPCSTR lpRootPathName
,
191 LPDWORD lpSectorsPerCluster
,
192 LPDWORD lpBytesPerSector
,
193 LPDWORD lpNumberOfFreeClusters
,
194 LPDWORD lpTotalNumberOfClusters
197 PWCHAR RootPathNameW
=NULL
;
201 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
205 return GetDiskFreeSpaceW (RootPathNameW
,
208 lpNumberOfFreeClusters
,
209 lpTotalNumberOfClusters
);
218 LPCWSTR lpRootPathName
,
219 LPDWORD lpSectorsPerCluster
,
220 LPDWORD lpBytesPerSector
,
221 LPDWORD lpNumberOfFreeClusters
,
222 LPDWORD lpTotalNumberOfClusters
225 FILE_FS_SIZE_INFORMATION FileFsSize
;
226 IO_STATUS_BLOCK IoStatusBlock
;
227 WCHAR RootPathName
[MAX_PATH
];
233 wcsncpy (RootPathName
, lpRootPathName
, 3);
237 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
241 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
242 if (INVALID_HANDLE_VALUE
== hFile
)
244 SetLastError(ERROR_PATH_NOT_FOUND
);
248 errCode
= NtQueryVolumeInformationFile(hFile
,
251 sizeof(FILE_FS_SIZE_INFORMATION
),
252 FileFsSizeInformation
);
253 if (!NT_SUCCESS(errCode
))
256 SetLastErrorByStatus (errCode
);
260 if (lpSectorsPerCluster
)
261 *lpSectorsPerCluster
= FileFsSize
.SectorsPerAllocationUnit
;
262 if (lpBytesPerSector
)
263 *lpBytesPerSector
= FileFsSize
.BytesPerSector
;
264 if (lpNumberOfFreeClusters
)
265 *lpNumberOfFreeClusters
= FileFsSize
.AvailableAllocationUnits
.u
.LowPart
;
266 if (lpTotalNumberOfClusters
)
267 *lpTotalNumberOfClusters
= FileFsSize
.TotalAllocationUnits
.u
.LowPart
;
278 GetDiskFreeSpaceExA (
279 LPCSTR lpDirectoryName OPTIONAL
,
280 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
281 PULARGE_INTEGER lpTotalNumberOfBytes
,
282 PULARGE_INTEGER lpTotalNumberOfFreeBytes
285 PWCHAR DirectoryNameW
=NULL
;
289 if (!(DirectoryNameW
= FilenameA2W(lpDirectoryName
, FALSE
)))
293 return GetDiskFreeSpaceExW (DirectoryNameW
,
294 lpFreeBytesAvailableToCaller
,
295 lpTotalNumberOfBytes
,
296 lpTotalNumberOfFreeBytes
);
305 LPCWSTR lpDirectoryName OPTIONAL
,
306 PULARGE_INTEGER lpFreeBytesAvailableToCaller
,
307 PULARGE_INTEGER lpTotalNumberOfBytes
,
308 PULARGE_INTEGER lpTotalNumberOfFreeBytes
313 FILE_FS_SIZE_INFORMATION FsSize
;
314 FILE_FS_FULL_SIZE_INFORMATION FsFullSize
;
316 IO_STATUS_BLOCK IoStatusBlock
;
317 ULARGE_INTEGER BytesPerCluster
;
321 if (lpDirectoryName
== NULL
)
322 lpDirectoryName
= L
"\\";
324 hFile
= InternalOpenDirW(lpDirectoryName
, FALSE
);
325 if (INVALID_HANDLE_VALUE
== hFile
)
330 if (lpFreeBytesAvailableToCaller
!= NULL
|| lpTotalNumberOfBytes
!= NULL
)
332 /* To get the free space available to the user associated with the
333 current thread, try FileFsFullSizeInformation. If this is not
334 supported by the file system, fall back to FileFsSize */
336 Status
= NtQueryVolumeInformationFile(hFile
,
339 sizeof(FsInfo
.FsFullSize
),
340 FileFsFullSizeInformation
);
342 if (NT_SUCCESS(Status
))
344 /* Close the handle before returning data
345 to avoid a handle leak in case of a fault! */
348 BytesPerCluster
.QuadPart
=
349 FsInfo
.FsFullSize
.BytesPerSector
* FsInfo
.FsFullSize
.SectorsPerAllocationUnit
;
351 if (lpFreeBytesAvailableToCaller
!= NULL
)
353 lpFreeBytesAvailableToCaller
->QuadPart
=
354 BytesPerCluster
.QuadPart
* FsInfo
.FsFullSize
.CallerAvailableAllocationUnits
.QuadPart
;
357 if (lpTotalNumberOfBytes
!= NULL
)
359 lpTotalNumberOfBytes
->QuadPart
=
360 BytesPerCluster
.QuadPart
* FsInfo
.FsFullSize
.TotalAllocationUnits
.QuadPart
;
363 if (lpTotalNumberOfFreeBytes
!= NULL
)
365 lpTotalNumberOfFreeBytes
->QuadPart
=
366 BytesPerCluster
.QuadPart
* FsInfo
.FsFullSize
.ActualAvailableAllocationUnits
.QuadPart
;
373 Status
= NtQueryVolumeInformationFile(hFile
,
376 sizeof(FsInfo
.FsSize
),
377 FileFsSizeInformation
);
379 /* Close the handle before returning data
380 to avoid a handle leak in case of a fault! */
383 if (!NT_SUCCESS(Status
))
385 SetLastErrorByStatus (Status
);
389 BytesPerCluster
.QuadPart
=
390 FsInfo
.FsSize
.BytesPerSector
* FsInfo
.FsSize
.SectorsPerAllocationUnit
;
392 if (lpFreeBytesAvailableToCaller
)
394 lpFreeBytesAvailableToCaller
->QuadPart
=
395 BytesPerCluster
.QuadPart
* FsInfo
.FsSize
.AvailableAllocationUnits
.QuadPart
;
398 if (lpTotalNumberOfBytes
)
400 lpTotalNumberOfBytes
->QuadPart
=
401 BytesPerCluster
.QuadPart
* FsInfo
.FsSize
.TotalAllocationUnits
.QuadPart
;
404 if (lpTotalNumberOfFreeBytes
)
406 lpTotalNumberOfFreeBytes
->QuadPart
=
407 BytesPerCluster
.QuadPart
* FsInfo
.FsSize
.AvailableAllocationUnits
.QuadPart
;
418 GetDriveTypeA(LPCSTR lpRootPathName
)
420 PWCHAR RootPathNameW
;
422 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
423 return DRIVE_UNKNOWN
;
425 return GetDriveTypeW(RootPathNameW
);
433 GetDriveTypeW(LPCWSTR lpRootPathName
)
435 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
436 IO_STATUS_BLOCK IoStatusBlock
;
441 hFile
= InternalOpenDirW(lpRootPathName
, FALSE
);
442 if (hFile
== INVALID_HANDLE_VALUE
)
444 return DRIVE_NO_ROOT_DIR
; /* According to WINE regression tests */
447 errCode
= NtQueryVolumeInformationFile (hFile
,
450 sizeof(FILE_FS_DEVICE_INFORMATION
),
451 FileFsDeviceInformation
);
452 if (!NT_SUCCESS(errCode
))
455 SetLastErrorByStatus (errCode
);
460 switch (FileFsDevice
.DeviceType
)
462 case FILE_DEVICE_CD_ROM
:
463 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
465 case FILE_DEVICE_VIRTUAL_DISK
:
466 return DRIVE_RAMDISK
;
467 case FILE_DEVICE_NETWORK_FILE_SYSTEM
:
469 case FILE_DEVICE_DISK
:
470 case FILE_DEVICE_DISK_FILE_SYSTEM
:
471 if (FileFsDevice
.Characteristics
& FILE_REMOTE_DEVICE
)
473 if (FileFsDevice
.Characteristics
& FILE_REMOVABLE_MEDIA
)
474 return DRIVE_REMOVABLE
;
478 ERR("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice
.DeviceType
);
480 return DRIVE_UNKNOWN
;
488 GetVolumeInformationA(
489 LPCSTR lpRootPathName
,
490 LPSTR lpVolumeNameBuffer
,
491 DWORD nVolumeNameSize
,
492 LPDWORD lpVolumeSerialNumber
,
493 LPDWORD lpMaximumComponentLength
,
494 LPDWORD lpFileSystemFlags
,
495 LPSTR lpFileSystemNameBuffer
,
496 DWORD nFileSystemNameSize
499 UNICODE_STRING FileSystemNameU
;
500 UNICODE_STRING VolumeNameU
= { 0, 0, NULL
};
501 ANSI_STRING VolumeName
;
502 ANSI_STRING FileSystemName
;
503 PWCHAR RootPathNameW
;
506 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
509 if (lpVolumeNameBuffer
)
511 VolumeNameU
.MaximumLength
= (USHORT
)nVolumeNameSize
* sizeof(WCHAR
);
512 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
514 VolumeNameU
.MaximumLength
);
515 if (VolumeNameU
.Buffer
== NULL
)
521 if (lpFileSystemNameBuffer
)
523 FileSystemNameU
.Length
= 0;
524 FileSystemNameU
.MaximumLength
= (USHORT
)nFileSystemNameSize
* sizeof(WCHAR
);
525 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
527 FileSystemNameU
.MaximumLength
);
528 if (FileSystemNameU
.Buffer
== NULL
)
530 if (VolumeNameU
.Buffer
!= NULL
)
532 RtlFreeHeap(RtlGetProcessHeap(),
538 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
543 Result
= GetVolumeInformationW (RootPathNameW
,
544 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
546 lpVolumeSerialNumber
,
547 lpMaximumComponentLength
,
549 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
550 nFileSystemNameSize
);
554 if (lpVolumeNameBuffer
)
556 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
557 VolumeName
.Length
= 0;
558 VolumeName
.MaximumLength
= (USHORT
)nVolumeNameSize
;
559 VolumeName
.Buffer
= lpVolumeNameBuffer
;
562 if (lpFileSystemNameBuffer
)
564 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
565 FileSystemName
.Length
= 0;
566 FileSystemName
.MaximumLength
= (USHORT
)nFileSystemNameSize
;
567 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
570 /* convert unicode strings to ansi (or oem) */
573 if (lpVolumeNameBuffer
)
575 RtlUnicodeStringToAnsiString (&VolumeName
,
579 if (lpFileSystemNameBuffer
)
581 RtlUnicodeStringToAnsiString (&FileSystemName
,
588 if (lpVolumeNameBuffer
)
590 RtlUnicodeStringToOemString (&VolumeName
,
594 if (lpFileSystemNameBuffer
)
596 RtlUnicodeStringToOemString (&FileSystemName
,
603 if (lpVolumeNameBuffer
)
605 RtlFreeHeap (RtlGetProcessHeap (),
609 if (lpFileSystemNameBuffer
)
611 RtlFreeHeap (RtlGetProcessHeap (),
613 FileSystemNameU
.Buffer
);
619 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
621 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
627 GetVolumeInformationW(
628 LPCWSTR lpRootPathName
,
629 LPWSTR lpVolumeNameBuffer
,
630 DWORD nVolumeNameSize
,
631 LPDWORD lpVolumeSerialNumber
,
632 LPDWORD lpMaximumComponentLength
,
633 LPDWORD lpFileSystemFlags
,
634 LPWSTR lpFileSystemNameBuffer
,
635 DWORD nFileSystemNameSize
638 PFILE_FS_VOLUME_INFORMATION FileFsVolume
;
639 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
640 IO_STATUS_BLOCK IoStatusBlock
;
641 WCHAR RootPathName
[MAX_PATH
];
642 UCHAR Buffer
[max(FS_VOLUME_BUFFER_SIZE
, FS_ATTRIBUTE_BUFFER_SIZE
)];
647 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
648 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
650 TRACE("FileFsVolume %p\n", FileFsVolume
);
651 TRACE("FileFsAttribute %p\n", FileFsAttribute
);
653 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
655 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
659 wcsncpy (RootPathName
, lpRootPathName
, 3);
663 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
664 if (hFile
== INVALID_HANDLE_VALUE
)
669 TRACE("hFile: %x\n", hFile
);
670 errCode
= NtQueryVolumeInformationFile(hFile
,
673 FS_VOLUME_BUFFER_SIZE
,
674 FileFsVolumeInformation
);
675 if ( !NT_SUCCESS(errCode
) )
677 WARN("Status: %x\n", errCode
);
679 SetLastErrorByStatus (errCode
);
683 if (lpVolumeSerialNumber
)
684 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
686 if (lpVolumeNameBuffer
)
688 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
690 memcpy(lpVolumeNameBuffer
,
691 FileFsVolume
->VolumeLabel
,
692 FileFsVolume
->VolumeLabelLength
);
693 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
698 SetLastError(ERROR_MORE_DATA
);
703 errCode
= NtQueryVolumeInformationFile (hFile
,
706 FS_ATTRIBUTE_BUFFER_SIZE
,
707 FileFsAttributeInformation
);
709 if (!NT_SUCCESS(errCode
))
711 WARN("Status: %x\n", errCode
);
712 SetLastErrorByStatus (errCode
);
716 if (lpFileSystemFlags
)
717 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
718 if (lpMaximumComponentLength
)
719 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
720 if (lpFileSystemNameBuffer
)
722 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
724 memcpy(lpFileSystemNameBuffer
,
725 FileFsAttribute
->FileSystemName
,
726 FileFsAttribute
->FileSystemNameLength
);
727 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
731 SetLastError(ERROR_MORE_DATA
);
745 LPCSTR lpRootPathName
,
746 LPCSTR lpVolumeName
/* NULL if deleting label */
749 PWCHAR RootPathNameW
;
750 PWCHAR VolumeNameW
= NULL
;
753 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
758 if (!(VolumeNameW
= FilenameA2W(lpVolumeName
, TRUE
)))
762 Result
= SetVolumeLabelW (RootPathNameW
,
767 RtlFreeHeap (RtlGetProcessHeap (),
781 LPCWSTR lpRootPathName
,
782 LPCWSTR lpVolumeName
/* NULL if deleting label */
785 PFILE_FS_LABEL_INFORMATION LabelInfo
;
786 IO_STATUS_BLOCK IoStatusBlock
;
791 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
792 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
794 sizeof(FILE_FS_LABEL_INFORMATION
) +
796 if (LabelInfo
== NULL
)
798 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
801 LabelInfo
->VolumeLabelLength
= LabelLength
;
802 memcpy(LabelInfo
->VolumeLabel
,
806 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
807 if (INVALID_HANDLE_VALUE
== hFile
)
809 RtlFreeHeap(RtlGetProcessHeap(),
815 Status
= NtSetVolumeInformationFile(hFile
,
818 sizeof(FILE_FS_LABEL_INFORMATION
) +
820 FileFsLabelInformation
);
822 RtlFreeHeap(RtlGetProcessHeap(),
826 if (!NT_SUCCESS(Status
))
828 WARN("Status: %x\n", Status
);
830 SetLastErrorByStatus(Status
);
839 * @name GetVolumeNameForVolumeMountPointW
841 * Return an unique volume name for a drive root or mount point.
843 * @param VolumeMountPoint
844 * Pointer to string that contains either root drive name or
847 * Pointer to buffer that is filled with resulting unique
848 * volume name on success.
849 * @param VolumeNameLength
850 * Size of VolumeName buffer in TCHARs.
853 * TRUE when the function succeeds and the VolumeName buffer is filled,
858 GetVolumeNameForVolumeMountPointW(
859 IN LPCWSTR VolumeMountPoint
,
860 OUT LPWSTR VolumeName
,
861 IN DWORD VolumeNameLength
)
863 UNICODE_STRING NtFileName
;
864 OBJECT_ATTRIBUTES ObjectAttributes
;
866 IO_STATUS_BLOCK Iosb
;
868 PMOUNTDEV_NAME MountDevName
;
869 PMOUNTMGR_MOUNT_POINT MountPoint
;
870 ULONG MountPointSize
;
871 PMOUNTMGR_MOUNT_POINTS MountPoints
;
873 PUCHAR SymbolicLinkName
;
877 if (!VolumeMountPoint
|| !VolumeMountPoint
[0])
879 SetLastError(ERROR_PATH_NOT_FOUND
);
884 * First step is to convert the passed volume mount point name to
885 * an NT acceptable name.
888 if (!RtlDosPathNameToNtPathName_U(VolumeMountPoint
, &NtFileName
, NULL
, NULL
))
890 SetLastError(ERROR_PATH_NOT_FOUND
);
894 if (NtFileName
.Length
> sizeof(WCHAR
) &&
895 NtFileName
.Buffer
[(NtFileName
.Length
/ sizeof(WCHAR
)) - 1] == '\\')
897 NtFileName
.Length
-= sizeof(WCHAR
);
901 * Query mount point device name which we will later use for determining
905 InitializeObjectAttributes(&ObjectAttributes
, &NtFileName
, 0, NULL
, NULL
);
906 Status
= NtOpenFile(&FileHandle
, FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
907 &ObjectAttributes
, &Iosb
,
908 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
909 FILE_SYNCHRONOUS_IO_NONALERT
);
910 RtlFreeUnicodeString(&NtFileName
);
911 if (!NT_SUCCESS(Status
))
913 SetLastErrorByStatus(Status
);
917 BufferLength
= sizeof(MOUNTDEV_NAME
) + 50 * sizeof(WCHAR
);
920 MountDevName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength
);
921 if (MountDevName
== NULL
)
924 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
928 Status
= NtDeviceIoControlFile(FileHandle
, NULL
, NULL
, NULL
, &Iosb
,
929 IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
930 NULL
, 0, MountDevName
, BufferLength
);
931 if (!NT_SUCCESS(Status
))
933 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
934 if (Status
== STATUS_BUFFER_OVERFLOW
)
936 BufferLength
= sizeof(MOUNTDEV_NAME
) + MountDevName
->NameLength
;
942 SetLastErrorByStatus(Status
);
947 while (!NT_SUCCESS(Status
));
952 * Get the mount point information from mount manager.
955 MountPointSize
= MountDevName
->NameLength
+ sizeof(MOUNTMGR_MOUNT_POINT
);
956 MountPoint
= RtlAllocateHeap(GetProcessHeap(), 0, MountPointSize
);
957 if (MountPoint
== NULL
)
959 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
960 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
963 RtlZeroMemory(MountPoint
, sizeof(MOUNTMGR_MOUNT_POINT
));
964 MountPoint
->DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINT
);
965 MountPoint
->DeviceNameLength
= MountDevName
->NameLength
;
966 RtlCopyMemory(MountPoint
+ 1, MountDevName
->Name
, MountDevName
->NameLength
);
967 RtlFreeHeap(RtlGetProcessHeap(), 0, MountDevName
);
969 RtlInitUnicodeString(&NtFileName
, L
"\\??\\MountPointManager");
970 InitializeObjectAttributes(&ObjectAttributes
, &NtFileName
, 0, NULL
, NULL
);
971 Status
= NtOpenFile(&FileHandle
, FILE_GENERIC_READ
, &ObjectAttributes
,
972 &Iosb
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
973 FILE_SYNCHRONOUS_IO_NONALERT
);
974 if (!NT_SUCCESS(Status
))
976 SetLastErrorByStatus(Status
);
977 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint
);
981 BufferLength
= sizeof(MOUNTMGR_MOUNT_POINTS
);
984 MountPoints
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength
);
985 if (MountPoints
== NULL
)
987 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint
);
989 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
993 Status
= NtDeviceIoControlFile(FileHandle
, NULL
, NULL
, NULL
, &Iosb
,
994 IOCTL_MOUNTMGR_QUERY_POINTS
,
995 MountPoint
, MountPointSize
,
996 MountPoints
, BufferLength
);
997 if (!NT_SUCCESS(Status
))
999 if (Status
== STATUS_BUFFER_OVERFLOW
)
1001 BufferLength
= MountPoints
->Size
;
1002 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints
);
1005 else if (!NT_SUCCESS(Status
))
1007 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint
);
1008 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints
);
1009 NtClose(FileHandle
);
1010 SetLastErrorByStatus(Status
);
1015 while (!NT_SUCCESS(Status
));
1017 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint
);
1018 NtClose(FileHandle
);
1021 * Now we've gathered info about all mount points mapped to our device, so
1022 * select the correct one and copy it into the output buffer.
1025 for (Index
= 0; Index
< MountPoints
->NumberOfMountPoints
; Index
++)
1027 MountPoint
= MountPoints
->MountPoints
+ Index
;
1028 SymbolicLinkName
= (PUCHAR
)MountPoints
+ MountPoint
->SymbolicLinkNameOffset
;
1031 * Check for "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
1032 * (with the last slash being optional) style symbolic links.
1035 if (MountPoint
->SymbolicLinkNameLength
== 48 * sizeof(WCHAR
) ||
1036 (MountPoint
->SymbolicLinkNameLength
== 49 * sizeof(WCHAR
) &&
1037 SymbolicLinkName
[48] == L
'\\'))
1039 if (RtlCompareMemory(SymbolicLinkName
, L
"\\??\\Volume{",
1040 11 * sizeof(WCHAR
)) == 11 * sizeof(WCHAR
) &&
1041 SymbolicLinkName
[19] == L
'-' && SymbolicLinkName
[24] == L
'-' &&
1042 SymbolicLinkName
[29] == L
'-' && SymbolicLinkName
[34] == L
'-' &&
1043 SymbolicLinkName
[47] == L
'}')
1045 if (VolumeNameLength
>= MountPoint
->SymbolicLinkNameLength
/ sizeof(WCHAR
))
1047 RtlCopyMemory(VolumeName
,
1048 (PUCHAR
)MountPoints
+ MountPoint
->SymbolicLinkNameOffset
,
1049 MountPoint
->SymbolicLinkNameLength
);
1050 VolumeName
[1] = L
'\\';
1055 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
1059 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints
);
1066 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints
);
1067 SetLastError(ERROR_INVALID_PARAMETER
);
1073 * @implemented (Wine 13 sep 2008)
1077 GetVolumeNameForVolumeMountPointA(
1078 LPCSTR lpszVolumeMountPoint
,
1079 LPSTR lpszVolumeName
,
1080 DWORD cchBufferLength
1084 WCHAR volumeW
[50], *pathW
= NULL
;
1085 DWORD len
= min( sizeof(volumeW
) / sizeof(WCHAR
), cchBufferLength
);
1087 TRACE("(%s, %p, %x)\n", debugstr_a(lpszVolumeMountPoint
), lpszVolumeName
, cchBufferLength
);
1089 if (!lpszVolumeMountPoint
|| !(pathW
= FilenameA2W( lpszVolumeMountPoint
, TRUE
)))
1092 if ((ret
= GetVolumeNameForVolumeMountPointW( pathW
, volumeW
, len
)))
1093 FilenameW2A_N( lpszVolumeName
, len
, volumeW
, -1 );
1095 RtlFreeHeap( RtlGetProcessHeap(), 0, pathW
);
1100 * @implemented (Wine 13 sep 2008)
1110 HANDLE mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
1111 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, INVALID_HANDLE_VALUE
);
1112 if (mgr
== INVALID_HANDLE_VALUE
) return INVALID_HANDLE_VALUE
;
1116 MOUNTMGR_MOUNT_POINT input
;
1117 MOUNTMGR_MOUNT_POINTS
*output
;
1119 if (!(output
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
1121 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1124 memset( &input
, 0, sizeof(input
) );
1126 if (!DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_POINTS
, &input
, sizeof(input
),
1127 output
, size
, NULL
, NULL
))
1129 if (GetLastError() != ERROR_MORE_DATA
) break;
1130 size
= output
->Size
;
1131 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
1135 /* abuse the Size field to store the current index */
1137 if (!FindNextVolumeW( output
, volume
, len
))
1139 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
1140 return INVALID_HANDLE_VALUE
;
1142 return (HANDLE
)output
;
1145 return INVALID_HANDLE_VALUE
;
1149 * @implemented (Wine 13 sep 2008)
1158 WCHAR
*buffer
= NULL
;
1161 buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1165 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1166 return INVALID_HANDLE_VALUE
;
1169 handle
= FindFirstVolumeW( buffer
, len
);
1171 if (handle
!= INVALID_HANDLE_VALUE
)
1173 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
))
1175 FindVolumeClose( handle
);
1176 handle
= INVALID_HANDLE_VALUE
;
1179 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer
);
1184 * @implemented (Wine 13 sep 2008)
1192 return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume
);
1200 GetVolumePathNameA(LPCSTR lpszFileName
,
1201 LPSTR lpszVolumePathName
,
1202 DWORD cchBufferLength
)
1204 PWCHAR FileNameW
= NULL
;
1205 WCHAR VolumePathName
[MAX_PATH
];
1210 if (!(FileNameW
= FilenameA2W(lpszFileName
, FALSE
)))
1214 Result
= GetVolumePathNameW(FileNameW
, VolumePathName
, cchBufferLength
);
1217 FilenameW2A_N(lpszVolumePathName
, MAX_PATH
, VolumePathName
, -1);
1227 GetVolumePathNameW(LPCWSTR lpszFileName
,
1228 LPWSTR lpszVolumePathName
,
1229 DWORD cchBufferLength
)
1232 UNICODE_STRING UnicodeFilePath
;
1234 PWSTR FullFilePath
, FilePathName
;
1236 WCHAR VolumeName
[MAX_PATH
];
1238 BOOL Result
= FALSE
;
1240 if (!(PathLength
= GetFullPathNameW(lpszFileName
, 0, NULL
, NULL
)))
1246 PathLength
= PathLength
+ 10;
1247 PathSize
= PathLength
* sizeof(WCHAR
);
1249 if (!(FullFilePath
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
1251 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1255 if (!GetFullPathNameW(lpszFileName
, PathLength
, FullFilePath
, &FilePart
))
1257 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
1261 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
1263 if (UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] != '\\')
1265 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
1266 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
1267 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
1270 if (!(FilePathName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
1272 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
1273 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1277 while (!GetVolumeNameForVolumeMountPointW(UnicodeFilePath
.Buffer
,
1281 if (((UnicodeFilePath
.Length
== 4) && (UnicodeFilePath
.Buffer
[0] == '\\') &&
1282 (UnicodeFilePath
.Buffer
[1] == '\\')) || ((UnicodeFilePath
.Length
== 6) &&
1283 (UnicodeFilePath
.Buffer
[1] == ':')))
1288 UnicodeFilePath
.Length
-= sizeof(WCHAR
);
1289 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
1291 memcpy(FilePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
1292 FilePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
1294 if (!GetFullPathNameW(FilePathName
, PathLength
, FullFilePath
, &FilePart
))
1301 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
1302 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
1303 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
1304 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
1309 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
1313 if (UnicodeFilePath
.Length
> (cchBufferLength
* sizeof(WCHAR
)) - sizeof(WCHAR
))
1315 ErrorCode
= ERROR_FILENAME_EXCED_RANGE
;
1319 memcpy(lpszVolumePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
1320 lpszVolumePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
1326 SetLastError(ErrorCode
);
1328 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
1329 RtlFreeHeap(RtlGetProcessHeap(), 0, FilePathName
);