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 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
;
439 UNICODE_STRING NtPath
;
440 OBJECT_ATTRIBUTES ObjectAttributes
;
441 WCHAR Buffer
[MAX_PATH
+1];
447 /* Get current directory */
448 cBytes
= RtlGetCurrentDirectory_U(sizeof(Buffer
), Buffer
);
449 if(cBytes
< sizeof(Buffer
))
451 ASSERT(cBytes
< MAX_PATH
*sizeof(WCHAR
));
452 Buffer
[cBytes
/sizeof(WCHAR
)] = L
'\\';
453 Buffer
[cBytes
/sizeof(WCHAR
)+1] = L
'\0';
454 lpRootPathName
= Buffer
;
455 } /* else fail... should we allow longer current dirs? */
458 if (!RtlDosPathNameToNtPathName_U(lpRootPathName
, &NtPath
, NULL
, NULL
))
460 WARN("Invalid path: %ls\n", lpRootPathName
);
461 return DRIVE_NO_ROOT_DIR
;
464 /* Path from RtlDosPathNameToNtPathName_U does not contain '/' and multiple '\\' in a row */
465 if(!NtPath
.Length
|| NtPath
.Buffer
[NtPath
.Length
/sizeof(WCHAR
)-1] != L
'\\')
467 /* Path must be ended by slash */
468 WARN("Invalid path: %ls\n", NtPath
.Buffer
);
469 return DRIVE_NO_ROOT_DIR
;
472 /* Remove ending slash */
473 NtPath
.Length
-= sizeof(WCHAR
);
475 InitializeObjectAttributes(&ObjectAttributes
,
477 OBJ_CASE_INSENSITIVE
,
481 Status
= NtCreateFile(&hFile
,
487 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
493 RtlFreeUnicodeString(&NtPath
);
495 if (!NT_SUCCESS(Status
))
497 WARN("Invalid path: %ls\n", lpRootPathName
);
498 return DRIVE_NO_ROOT_DIR
; /* According to WINE regression tests */
501 Status
= NtQueryVolumeInformationFile (hFile
,
504 sizeof(FILE_FS_DEVICE_INFORMATION
),
505 FileFsDeviceInformation
);
507 if (!NT_SUCCESS(Status
))
509 ERR("NtQueryVolumeInformationFile failed for %ls\n", lpRootPathName
);
510 return DRIVE_UNKNOWN
;
513 switch (FileFsDevice
.DeviceType
)
515 case FILE_DEVICE_CD_ROM
:
516 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
518 case FILE_DEVICE_VIRTUAL_DISK
:
519 return DRIVE_RAMDISK
;
520 case FILE_DEVICE_NETWORK_FILE_SYSTEM
:
522 case FILE_DEVICE_DISK
:
523 case FILE_DEVICE_DISK_FILE_SYSTEM
:
524 if (FileFsDevice
.Characteristics
& FILE_REMOTE_DEVICE
)
526 if (FileFsDevice
.Characteristics
& FILE_REMOVABLE_MEDIA
)
527 return DRIVE_REMOVABLE
;
531 ERR("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice
.DeviceType
);
533 return DRIVE_UNKNOWN
;
541 GetVolumeInformationA(
542 LPCSTR lpRootPathName
,
543 LPSTR lpVolumeNameBuffer
,
544 DWORD nVolumeNameSize
,
545 LPDWORD lpVolumeSerialNumber
,
546 LPDWORD lpMaximumComponentLength
,
547 LPDWORD lpFileSystemFlags
,
548 LPSTR lpFileSystemNameBuffer
,
549 DWORD nFileSystemNameSize
552 UNICODE_STRING FileSystemNameU
;
553 UNICODE_STRING VolumeNameU
= { 0, 0, NULL
};
554 ANSI_STRING VolumeName
;
555 ANSI_STRING FileSystemName
;
556 PWCHAR RootPathNameW
;
559 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
562 if (lpVolumeNameBuffer
)
564 VolumeNameU
.MaximumLength
= (USHORT
)nVolumeNameSize
* sizeof(WCHAR
);
565 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
567 VolumeNameU
.MaximumLength
);
568 if (VolumeNameU
.Buffer
== NULL
)
574 if (lpFileSystemNameBuffer
)
576 FileSystemNameU
.Length
= 0;
577 FileSystemNameU
.MaximumLength
= (USHORT
)nFileSystemNameSize
* sizeof(WCHAR
);
578 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
580 FileSystemNameU
.MaximumLength
);
581 if (FileSystemNameU
.Buffer
== NULL
)
583 if (VolumeNameU
.Buffer
!= NULL
)
585 RtlFreeHeap(RtlGetProcessHeap(),
591 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
596 Result
= GetVolumeInformationW (RootPathNameW
,
597 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
599 lpVolumeSerialNumber
,
600 lpMaximumComponentLength
,
602 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
603 nFileSystemNameSize
);
607 if (lpVolumeNameBuffer
)
609 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
610 VolumeName
.Length
= 0;
611 VolumeName
.MaximumLength
= (USHORT
)nVolumeNameSize
;
612 VolumeName
.Buffer
= lpVolumeNameBuffer
;
615 if (lpFileSystemNameBuffer
)
617 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
618 FileSystemName
.Length
= 0;
619 FileSystemName
.MaximumLength
= (USHORT
)nFileSystemNameSize
;
620 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
623 /* convert unicode strings to ansi (or oem) */
626 if (lpVolumeNameBuffer
)
628 RtlUnicodeStringToAnsiString (&VolumeName
,
632 if (lpFileSystemNameBuffer
)
634 RtlUnicodeStringToAnsiString (&FileSystemName
,
641 if (lpVolumeNameBuffer
)
643 RtlUnicodeStringToOemString (&VolumeName
,
647 if (lpFileSystemNameBuffer
)
649 RtlUnicodeStringToOemString (&FileSystemName
,
656 if (lpVolumeNameBuffer
)
658 RtlFreeHeap (RtlGetProcessHeap (),
662 if (lpFileSystemNameBuffer
)
664 RtlFreeHeap (RtlGetProcessHeap (),
666 FileSystemNameU
.Buffer
);
672 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
674 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
680 GetVolumeInformationW(
681 LPCWSTR lpRootPathName
,
682 LPWSTR lpVolumeNameBuffer
,
683 DWORD nVolumeNameSize
,
684 LPDWORD lpVolumeSerialNumber
,
685 LPDWORD lpMaximumComponentLength
,
686 LPDWORD lpFileSystemFlags
,
687 LPWSTR lpFileSystemNameBuffer
,
688 DWORD nFileSystemNameSize
691 PFILE_FS_VOLUME_INFORMATION FileFsVolume
;
692 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
693 IO_STATUS_BLOCK IoStatusBlock
;
694 WCHAR RootPathName
[MAX_PATH
];
695 UCHAR Buffer
[max(FS_VOLUME_BUFFER_SIZE
, FS_ATTRIBUTE_BUFFER_SIZE
)];
700 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
701 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
703 TRACE("FileFsVolume %p\n", FileFsVolume
);
704 TRACE("FileFsAttribute %p\n", FileFsAttribute
);
706 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
708 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
712 wcsncpy (RootPathName
, lpRootPathName
, 3);
716 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
717 if (hFile
== INVALID_HANDLE_VALUE
)
722 TRACE("hFile: %x\n", hFile
);
723 errCode
= NtQueryVolumeInformationFile(hFile
,
726 FS_VOLUME_BUFFER_SIZE
,
727 FileFsVolumeInformation
);
728 if ( !NT_SUCCESS(errCode
) )
730 WARN("Status: %x\n", errCode
);
732 SetLastErrorByStatus (errCode
);
736 if (lpVolumeSerialNumber
)
737 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
739 if (lpVolumeNameBuffer
)
741 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
743 memcpy(lpVolumeNameBuffer
,
744 FileFsVolume
->VolumeLabel
,
745 FileFsVolume
->VolumeLabelLength
);
746 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
751 SetLastError(ERROR_MORE_DATA
);
756 errCode
= NtQueryVolumeInformationFile (hFile
,
759 FS_ATTRIBUTE_BUFFER_SIZE
,
760 FileFsAttributeInformation
);
762 if (!NT_SUCCESS(errCode
))
764 WARN("Status: %x\n", errCode
);
765 SetLastErrorByStatus (errCode
);
769 if (lpFileSystemFlags
)
770 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
771 if (lpMaximumComponentLength
)
772 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
773 if (lpFileSystemNameBuffer
)
775 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
777 memcpy(lpFileSystemNameBuffer
,
778 FileFsAttribute
->FileSystemName
,
779 FileFsAttribute
->FileSystemNameLength
);
780 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
784 SetLastError(ERROR_MORE_DATA
);
798 LPCSTR lpRootPathName
,
799 LPCSTR lpVolumeName
/* NULL if deleting label */
802 PWCHAR RootPathNameW
;
803 PWCHAR VolumeNameW
= NULL
;
806 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
811 if (!(VolumeNameW
= FilenameA2W(lpVolumeName
, TRUE
)))
815 Result
= SetVolumeLabelW (RootPathNameW
,
820 RtlFreeHeap (RtlGetProcessHeap (),
834 LPCWSTR lpRootPathName
,
835 LPCWSTR lpVolumeName
/* NULL if deleting label */
838 PFILE_FS_LABEL_INFORMATION LabelInfo
;
839 IO_STATUS_BLOCK IoStatusBlock
;
844 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
845 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
847 sizeof(FILE_FS_LABEL_INFORMATION
) +
849 if (LabelInfo
== NULL
)
851 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
854 LabelInfo
->VolumeLabelLength
= LabelLength
;
855 memcpy(LabelInfo
->VolumeLabel
,
859 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
860 if (INVALID_HANDLE_VALUE
== hFile
)
862 RtlFreeHeap(RtlGetProcessHeap(),
868 Status
= NtSetVolumeInformationFile(hFile
,
871 sizeof(FILE_FS_LABEL_INFORMATION
) +
873 FileFsLabelInformation
);
875 RtlFreeHeap(RtlGetProcessHeap(),
879 if (!NT_SUCCESS(Status
))
881 WARN("Status: %x\n", Status
);
883 SetLastErrorByStatus(Status
);
892 * @name GetVolumeNameForVolumeMountPointW
894 * Return an unique volume name for a drive root or mount point.
896 * @param VolumeMountPoint
897 * Pointer to string that contains either root drive name or
900 * Pointer to buffer that is filled with resulting unique
901 * volume name on success.
902 * @param VolumeNameLength
903 * Size of VolumeName buffer in TCHARs.
906 * TRUE when the function succeeds and the VolumeName buffer is filled,
911 GetVolumeNameForVolumeMountPointW(
912 IN LPCWSTR VolumeMountPoint
,
913 OUT LPWSTR VolumeName
,
914 IN DWORD VolumeNameLength
)
916 UNICODE_STRING NtFileName
;
917 OBJECT_ATTRIBUTES ObjectAttributes
;
919 IO_STATUS_BLOCK Iosb
;
921 PMOUNTDEV_NAME MountDevName
;
922 PMOUNTMGR_MOUNT_POINT MountPoint
;
923 ULONG MountPointSize
;
924 PMOUNTMGR_MOUNT_POINTS MountPoints
;
926 PUCHAR SymbolicLinkName
;
930 if (!VolumeMountPoint
|| !VolumeMountPoint
[0])
932 SetLastError(ERROR_PATH_NOT_FOUND
);
937 * First step is to convert the passed volume mount point name to
938 * an NT acceptable name.
941 if (!RtlDosPathNameToNtPathName_U(VolumeMountPoint
, &NtFileName
, NULL
, NULL
))
943 SetLastError(ERROR_PATH_NOT_FOUND
);
947 if (NtFileName
.Length
> sizeof(WCHAR
) &&
948 NtFileName
.Buffer
[(NtFileName
.Length
/ sizeof(WCHAR
)) - 1] == '\\')
950 NtFileName
.Length
-= sizeof(WCHAR
);
954 * Query mount point device name which we will later use for determining
958 InitializeObjectAttributes(&ObjectAttributes
, &NtFileName
, 0, NULL
, NULL
);
959 Status
= NtOpenFile(&FileHandle
, FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
960 &ObjectAttributes
, &Iosb
,
961 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
962 FILE_SYNCHRONOUS_IO_NONALERT
);
963 RtlFreeUnicodeString(&NtFileName
);
964 if (!NT_SUCCESS(Status
))
966 SetLastErrorByStatus(Status
);
970 BufferLength
= sizeof(MOUNTDEV_NAME
) + 50 * sizeof(WCHAR
);
973 MountDevName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength
);
974 if (MountDevName
== NULL
)
977 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
981 Status
= NtDeviceIoControlFile(FileHandle
, NULL
, NULL
, NULL
, &Iosb
,
982 IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
983 NULL
, 0, MountDevName
, BufferLength
);
984 if (!NT_SUCCESS(Status
))
986 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
987 if (Status
== STATUS_BUFFER_OVERFLOW
)
989 BufferLength
= sizeof(MOUNTDEV_NAME
) + MountDevName
->NameLength
;
995 SetLastErrorByStatus(Status
);
1000 while (!NT_SUCCESS(Status
));
1002 NtClose(FileHandle
);
1005 * Get the mount point information from mount manager.
1008 MountPointSize
= MountDevName
->NameLength
+ sizeof(MOUNTMGR_MOUNT_POINT
);
1009 MountPoint
= RtlAllocateHeap(GetProcessHeap(), 0, MountPointSize
);
1010 if (MountPoint
== NULL
)
1012 RtlFreeHeap(GetProcessHeap(), 0, MountDevName
);
1013 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1016 RtlZeroMemory(MountPoint
, sizeof(MOUNTMGR_MOUNT_POINT
));
1017 MountPoint
->DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINT
);
1018 MountPoint
->DeviceNameLength
= MountDevName
->NameLength
;
1019 RtlCopyMemory(MountPoint
+ 1, MountDevName
->Name
, MountDevName
->NameLength
);
1020 RtlFreeHeap(RtlGetProcessHeap(), 0, MountDevName
);
1022 RtlInitUnicodeString(&NtFileName
, L
"\\??\\MountPointManager");
1023 InitializeObjectAttributes(&ObjectAttributes
, &NtFileName
, 0, NULL
, NULL
);
1024 Status
= NtOpenFile(&FileHandle
, FILE_GENERIC_READ
| SYNCHRONIZE
, &ObjectAttributes
,
1025 &Iosb
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1026 FILE_SYNCHRONOUS_IO_NONALERT
);
1027 if (!NT_SUCCESS(Status
))
1029 SetLastErrorByStatus(Status
);
1030 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint
);
1034 BufferLength
= sizeof(MOUNTMGR_MOUNT_POINTS
);
1037 MountPoints
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength
);
1038 if (MountPoints
== NULL
)
1040 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint
);
1041 NtClose(FileHandle
);
1042 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1046 Status
= NtDeviceIoControlFile(FileHandle
, NULL
, NULL
, NULL
, &Iosb
,
1047 IOCTL_MOUNTMGR_QUERY_POINTS
,
1048 MountPoint
, MountPointSize
,
1049 MountPoints
, BufferLength
);
1050 if (!NT_SUCCESS(Status
))
1052 if (Status
== STATUS_BUFFER_OVERFLOW
)
1054 BufferLength
= MountPoints
->Size
;
1055 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints
);
1058 else if (!NT_SUCCESS(Status
))
1060 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint
);
1061 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints
);
1062 NtClose(FileHandle
);
1063 SetLastErrorByStatus(Status
);
1068 while (!NT_SUCCESS(Status
));
1070 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoint
);
1071 NtClose(FileHandle
);
1074 * Now we've gathered info about all mount points mapped to our device, so
1075 * select the correct one and copy it into the output buffer.
1078 for (Index
= 0; Index
< MountPoints
->NumberOfMountPoints
; Index
++)
1080 MountPoint
= MountPoints
->MountPoints
+ Index
;
1081 SymbolicLinkName
= (PUCHAR
)MountPoints
+ MountPoint
->SymbolicLinkNameOffset
;
1084 * Check for "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
1085 * (with the last slash being optional) style symbolic links.
1088 if (MountPoint
->SymbolicLinkNameLength
== 48 * sizeof(WCHAR
) ||
1089 (MountPoint
->SymbolicLinkNameLength
== 49 * sizeof(WCHAR
) &&
1090 SymbolicLinkName
[48] == L
'\\'))
1092 if (RtlCompareMemory(SymbolicLinkName
, L
"\\??\\Volume{",
1093 11 * sizeof(WCHAR
)) == 11 * sizeof(WCHAR
) &&
1094 SymbolicLinkName
[19] == L
'-' && SymbolicLinkName
[24] == L
'-' &&
1095 SymbolicLinkName
[29] == L
'-' && SymbolicLinkName
[34] == L
'-' &&
1096 SymbolicLinkName
[47] == L
'}')
1098 if (VolumeNameLength
>= MountPoint
->SymbolicLinkNameLength
/ sizeof(WCHAR
))
1100 RtlCopyMemory(VolumeName
,
1101 (PUCHAR
)MountPoints
+ MountPoint
->SymbolicLinkNameOffset
,
1102 MountPoint
->SymbolicLinkNameLength
);
1103 VolumeName
[1] = L
'\\';
1108 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
1112 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints
);
1119 RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints
);
1120 SetLastError(ERROR_INVALID_PARAMETER
);
1126 * @implemented (Wine 13 sep 2008)
1130 GetVolumeNameForVolumeMountPointA(
1131 LPCSTR lpszVolumeMountPoint
,
1132 LPSTR lpszVolumeName
,
1133 DWORD cchBufferLength
1137 WCHAR volumeW
[50], *pathW
= NULL
;
1138 DWORD len
= min( sizeof(volumeW
) / sizeof(WCHAR
), cchBufferLength
);
1140 TRACE("(%s, %p, %x)\n", debugstr_a(lpszVolumeMountPoint
), lpszVolumeName
, cchBufferLength
);
1142 if (!lpszVolumeMountPoint
|| !(pathW
= FilenameA2W( lpszVolumeMountPoint
, TRUE
)))
1145 if ((ret
= GetVolumeNameForVolumeMountPointW( pathW
, volumeW
, len
)))
1146 FilenameW2A_N( lpszVolumeName
, len
, volumeW
, -1 );
1148 RtlFreeHeap( RtlGetProcessHeap(), 0, pathW
);
1153 * @implemented (Wine 13 sep 2008)
1163 HANDLE mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
1164 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, INVALID_HANDLE_VALUE
);
1165 if (mgr
== INVALID_HANDLE_VALUE
) return INVALID_HANDLE_VALUE
;
1169 MOUNTMGR_MOUNT_POINT input
;
1170 MOUNTMGR_MOUNT_POINTS
*output
;
1172 if (!(output
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
1174 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1177 memset( &input
, 0, sizeof(input
) );
1179 if (!DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_POINTS
, &input
, sizeof(input
),
1180 output
, size
, NULL
, NULL
))
1182 if (GetLastError() != ERROR_MORE_DATA
) break;
1183 size
= output
->Size
;
1184 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
1188 /* abuse the Size field to store the current index */
1190 if (!FindNextVolumeW( output
, volume
, len
))
1192 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
1193 return INVALID_HANDLE_VALUE
;
1195 return (HANDLE
)output
;
1198 return INVALID_HANDLE_VALUE
;
1202 * @implemented (Wine 13 sep 2008)
1211 WCHAR
*buffer
= NULL
;
1214 buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1218 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1219 return INVALID_HANDLE_VALUE
;
1222 handle
= FindFirstVolumeW( buffer
, len
);
1224 if (handle
!= INVALID_HANDLE_VALUE
)
1226 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
))
1228 FindVolumeClose( handle
);
1229 handle
= INVALID_HANDLE_VALUE
;
1232 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer
);
1237 * @implemented (Wine 13 sep 2008)
1245 return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume
);
1253 GetVolumePathNameA(LPCSTR lpszFileName
,
1254 LPSTR lpszVolumePathName
,
1255 DWORD cchBufferLength
)
1257 PWCHAR FileNameW
= NULL
;
1258 WCHAR VolumePathName
[MAX_PATH
];
1263 if (!(FileNameW
= FilenameA2W(lpszFileName
, FALSE
)))
1267 Result
= GetVolumePathNameW(FileNameW
, VolumePathName
, cchBufferLength
);
1270 FilenameW2A_N(lpszVolumePathName
, MAX_PATH
, VolumePathName
, -1);
1280 GetVolumePathNameW(LPCWSTR lpszFileName
,
1281 LPWSTR lpszVolumePathName
,
1282 DWORD cchBufferLength
)
1285 UNICODE_STRING UnicodeFilePath
;
1287 PWSTR FullFilePath
, FilePathName
;
1289 WCHAR VolumeName
[MAX_PATH
];
1291 BOOL Result
= FALSE
;
1293 if (!(PathLength
= GetFullPathNameW(lpszFileName
, 0, NULL
, NULL
)))
1299 PathLength
= PathLength
+ 10;
1300 PathSize
= PathLength
* sizeof(WCHAR
);
1302 if (!(FullFilePath
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
1304 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1308 if (!GetFullPathNameW(lpszFileName
, PathLength
, FullFilePath
, &FilePart
))
1310 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
1314 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
1316 if (UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] != '\\')
1318 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
1319 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
1320 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
1323 if (!(FilePathName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
1325 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
1326 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1330 while (!GetVolumeNameForVolumeMountPointW(UnicodeFilePath
.Buffer
,
1334 if (((UnicodeFilePath
.Length
== 4) && (UnicodeFilePath
.Buffer
[0] == '\\') &&
1335 (UnicodeFilePath
.Buffer
[1] == '\\')) || ((UnicodeFilePath
.Length
== 6) &&
1336 (UnicodeFilePath
.Buffer
[1] == ':')))
1341 UnicodeFilePath
.Length
-= sizeof(WCHAR
);
1342 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
1344 memcpy(FilePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
1345 FilePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
1347 if (!GetFullPathNameW(FilePathName
, PathLength
, FullFilePath
, &FilePart
))
1354 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
1355 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
1356 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
1357 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
1362 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
1366 if (UnicodeFilePath
.Length
> (cchBufferLength
* sizeof(WCHAR
)) - sizeof(WCHAR
))
1368 ErrorCode
= ERROR_FILENAME_EXCED_RANGE
;
1372 memcpy(lpszVolumePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
1373 lpszVolumePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
1379 SetLastError(ErrorCode
);
1381 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
1382 RtlFreeHeap(RtlGetProcessHeap(), 0, FilePathName
);