2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/client/file/volume.c
5 * PURPOSE: File volume functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Erik Bos, Alexandre Julliard :
8 * GetLogicalDriveStringsA,
9 * GetLogicalDriveStringsW, GetLogicalDrives
10 * Pierre Schweitzer (pierre@reactos.org)
14 //WINE copyright notice:
16 * DOS drives handling functions
18 * Copyright 1993 Erik Bos
19 * Copyright 1996 Alexandre Julliard
25 DEBUG_CHANNEL(kernel32file
);
29 InternalOpenDirW(IN LPCWSTR DirName
,
32 UNICODE_STRING NtPathU
;
33 OBJECT_ATTRIBUTES ObjectAttributes
;
35 IO_STATUS_BLOCK IoStatusBlock
;
38 if (!RtlDosPathNameToNtPathName_U(DirName
, &NtPathU
, NULL
, NULL
))
40 WARN("Invalid path\n");
41 SetLastError(ERROR_BAD_PATHNAME
);
42 return INVALID_HANDLE_VALUE
;
45 InitializeObjectAttributes(&ObjectAttributes
,
51 errCode
= NtCreateFile(&hFile
,
52 Write
? FILE_GENERIC_WRITE
: FILE_GENERIC_READ
,
57 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
63 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU
.Buffer
);
65 if (!NT_SUCCESS(errCode
))
67 BaseSetLastNTError(errCode
);
68 return INVALID_HANDLE_VALUE
;
79 GetVolumeInformationA(IN LPCSTR lpRootPathName
,
80 IN LPSTR lpVolumeNameBuffer
,
81 IN DWORD nVolumeNameSize
,
82 OUT LPDWORD lpVolumeSerialNumber OPTIONAL
,
83 OUT LPDWORD lpMaximumComponentLength OPTIONAL
,
84 OUT LPDWORD lpFileSystemFlags OPTIONAL
,
85 OUT LPSTR lpFileSystemNameBuffer OPTIONAL
,
86 IN DWORD nFileSystemNameSize
)
88 UNICODE_STRING FileSystemNameU
;
89 UNICODE_STRING VolumeNameU
= { 0, 0, NULL
};
90 ANSI_STRING VolumeName
;
91 ANSI_STRING FileSystemName
;
95 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
98 if (lpVolumeNameBuffer
)
100 VolumeNameU
.MaximumLength
= (USHORT
)nVolumeNameSize
* sizeof(WCHAR
);
101 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
103 VolumeNameU
.MaximumLength
);
104 if (VolumeNameU
.Buffer
== NULL
)
110 if (lpFileSystemNameBuffer
)
112 FileSystemNameU
.Length
= 0;
113 FileSystemNameU
.MaximumLength
= (USHORT
)nFileSystemNameSize
* sizeof(WCHAR
);
114 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
116 FileSystemNameU
.MaximumLength
);
117 if (FileSystemNameU
.Buffer
== NULL
)
119 if (VolumeNameU
.Buffer
!= NULL
)
121 RtlFreeHeap(RtlGetProcessHeap(),
127 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
132 Result
= GetVolumeInformationW (RootPathNameW
,
133 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
135 lpVolumeSerialNumber
,
136 lpMaximumComponentLength
,
138 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
139 nFileSystemNameSize
);
143 if (lpVolumeNameBuffer
)
145 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
146 VolumeName
.Length
= 0;
147 VolumeName
.MaximumLength
= (USHORT
)nVolumeNameSize
;
148 VolumeName
.Buffer
= lpVolumeNameBuffer
;
151 if (lpFileSystemNameBuffer
)
153 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
154 FileSystemName
.Length
= 0;
155 FileSystemName
.MaximumLength
= (USHORT
)nFileSystemNameSize
;
156 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
159 /* convert unicode strings to ansi (or oem) */
162 if (lpVolumeNameBuffer
)
164 RtlUnicodeStringToAnsiString (&VolumeName
,
168 if (lpFileSystemNameBuffer
)
170 RtlUnicodeStringToAnsiString (&FileSystemName
,
177 if (lpVolumeNameBuffer
)
179 RtlUnicodeStringToOemString (&VolumeName
,
183 if (lpFileSystemNameBuffer
)
185 RtlUnicodeStringToOemString (&FileSystemName
,
192 if (lpVolumeNameBuffer
)
194 RtlFreeHeap (RtlGetProcessHeap (),
198 if (lpFileSystemNameBuffer
)
200 RtlFreeHeap (RtlGetProcessHeap (),
202 FileSystemNameU
.Buffer
);
212 IsThisARootDirectory(IN HANDLE VolumeHandle
,
213 IN PUNICODE_STRING NtPathName
)
216 IO_STATUS_BLOCK IoStatusBlock
;
219 FILE_NAME_INFORMATION
;
220 WCHAR Buffer
[MAX_PATH
];
223 /* If we have a handle, query the name */
226 Status
= NtQueryInformationFile(VolumeHandle
, &IoStatusBlock
, &FileNameInfo
, sizeof(FileNameInfo
), FileNameInformation
);
227 if (!NT_SUCCESS(Status
))
232 /* Check we properly end with a \ */
233 if (FileNameInfo
.FileName
[FileNameInfo
.FileNameLength
/ sizeof(WCHAR
) - 1] != L
'\\')
239 /* If we have a path */
240 if (NtPathName
!= NULL
)
244 ULONG ReturnedLength
;
245 UNICODE_STRING LinkTarget
;
246 OBJECT_ATTRIBUTES ObjectAttributes
;
248 NtPathName
->Length
-= sizeof(WCHAR
);
250 InitializeObjectAttributes(&ObjectAttributes
, NtPathName
,
251 OBJ_CASE_INSENSITIVE
,
254 /* Try to see whether that's a symbolic name */
255 Status
= NtOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
256 NtPathName
->Length
+= sizeof(WCHAR
);
257 if (!NT_SUCCESS(Status
))
262 /* If so, query the target */
263 LinkTarget
.Buffer
= Buffer
;
264 LinkTarget
.Length
= 0;
265 LinkTarget
.MaximumLength
= sizeof(Buffer
);
267 Status
= NtQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, &ReturnedLength
);
269 /* A root directory (NtName) is a symbolic link */
270 if (!NT_SUCCESS(Status
))
284 GetVolumeInformationW(IN LPCWSTR lpRootPathName
,
285 IN LPWSTR lpVolumeNameBuffer
,
286 IN DWORD nVolumeNameSize
,
287 OUT LPDWORD lpVolumeSerialNumber OPTIONAL
,
288 OUT LPDWORD lpMaximumComponentLength OPTIONAL
,
289 OUT LPDWORD lpFileSystemFlags OPTIONAL
,
290 OUT LPWSTR lpFileSystemNameBuffer OPTIONAL
,
291 IN DWORD nFileSystemNameSize
)
296 LPCWSTR RootPathName
;
297 UNICODE_STRING NtPathName
;
298 IO_STATUS_BLOCK IoStatusBlock
;
299 OBJECT_ATTRIBUTES ObjectAttributes
;
300 PFILE_FS_VOLUME_INFORMATION VolumeInfo
;
301 PFILE_FS_ATTRIBUTE_INFORMATION VolumeAttr
;
302 ULONG OldMode
, VolumeInfoSize
, VolumeAttrSize
;
304 /* If no root path provided, default to \ */
305 if (lpRootPathName
== NULL
)
307 RootPathName
= L
"\\";
311 RootPathName
= lpRootPathName
;
314 /* Convert to NT name */
315 if (!RtlDosPathNameToNtPathName_U(RootPathName
, &NtPathName
, NULL
, NULL
))
317 SetLastError(ERROR_PATH_NOT_FOUND
);
321 /* Check we really end with a backslash */
322 if (NtPathName
.Buffer
[(NtPathName
.Length
/ sizeof(WCHAR
)) - 1] != L
'\\')
324 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
325 BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID
);
329 /* Try to open the received path */
330 InitializeObjectAttributes(&ObjectAttributes
, &NtPathName
,
331 OBJ_CASE_INSENSITIVE
,
334 /* No errors to the user */
335 RtlSetThreadErrorMode(RTL_SEM_FAILCRITICALERRORS
, &OldMode
);
336 Status
= NtOpenFile(&VolumeHandle
, SYNCHRONIZE
, &ObjectAttributes
, &IoStatusBlock
, 0, FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
);
337 RtlSetThreadErrorMode(OldMode
, NULL
);
338 if (!NT_SUCCESS(Status
))
340 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
341 BaseSetLastNTError(Status
);
345 /* Check whether that's a root directory */
346 if (!IsThisARootDirectory(VolumeHandle
, &NtPathName
))
348 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
349 NtClose(VolumeHandle
);
350 SetLastError(ERROR_DIR_NOT_ROOT
);
354 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
356 /* Assume we don't need to query FileFsVolumeInformation */
358 /* If user wants volume name, allocate a buffer to query it */
359 if (lpVolumeNameBuffer
!= NULL
)
361 VolumeInfoSize
= nVolumeNameSize
+ sizeof(FILE_FS_VOLUME_INFORMATION
);
363 /* If user just wants the serial number, allocate a dummy buffer */
364 else if (lpVolumeSerialNumber
!= NULL
)
366 VolumeInfoSize
= MAX_PATH
* sizeof(WCHAR
) + sizeof(FILE_FS_VOLUME_INFORMATION
);
368 /* Otherwise, nothing to query */
374 /* If we're to query, allocate a big enough buffer */
375 if (VolumeInfoSize
!= 0)
377 VolumeInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumeInfoSize
);
378 if (VolumeInfo
== NULL
)
380 NtClose(VolumeHandle
);
381 BaseSetLastNTError(STATUS_NO_MEMORY
);
386 /* Assume we don't need to query FileFsAttributeInformation */
388 /* If user wants filesystem name, allocate a buffer to query it */
389 if (lpFileSystemNameBuffer
!= NULL
)
391 VolumeAttrSize
= nFileSystemNameSize
+ sizeof(FILE_FS_ATTRIBUTE_INFORMATION
);
393 /* If user just wants max compo len or flags, allocate a dummy buffer */
394 else if (lpMaximumComponentLength
!= NULL
|| lpFileSystemFlags
!= NULL
)
396 VolumeAttrSize
= MAX_PATH
* sizeof(WCHAR
) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION
);
403 /* If we're to query, allocate a big enough buffer */
404 if (VolumeAttrSize
!= 0)
406 VolumeAttr
= RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumeAttrSize
);
407 if (VolumeAttr
== NULL
)
409 if (VolumeInfo
!= NULL
)
411 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeInfo
);
414 NtClose(VolumeHandle
);
415 BaseSetLastNTError(STATUS_NO_MEMORY
);
420 /* Assume we'll fail */
423 /* If we're to query FileFsVolumeInformation, do it now! */
424 if (VolumeInfo
!= NULL
)
426 Status
= NtQueryVolumeInformationFile(VolumeHandle
, &IoStatusBlock
, VolumeInfo
, VolumeInfoSize
, FileFsVolumeInformation
);
427 if (!NT_SUCCESS(Status
))
429 BaseSetLastNTError(Status
);
434 /* If we're to query FileFsAttributeInformation, do it now! */
435 if (VolumeAttr
!= NULL
)
437 Status
= NtQueryVolumeInformationFile(VolumeHandle
, &IoStatusBlock
, VolumeAttr
, VolumeAttrSize
, FileFsAttributeInformation
);
438 if (!NT_SUCCESS(Status
))
440 BaseSetLastNTError(Status
);
445 /* If user wants volume name */
446 if (lpVolumeNameBuffer
!= NULL
)
448 /* Check its buffer can hold it (+ 0) */
449 if (VolumeInfo
->VolumeLabelLength
>= nVolumeNameSize
)
451 SetLastError(ERROR_BAD_LENGTH
);
456 RtlCopyMemory(lpVolumeNameBuffer
, VolumeInfo
->VolumeLabel
, VolumeInfo
->VolumeLabelLength
);
457 lpVolumeNameBuffer
[VolumeInfo
->VolumeLabelLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
460 /* If user wants wants serial number, return it */
461 if (lpVolumeSerialNumber
!= NULL
)
463 *lpVolumeSerialNumber
= VolumeInfo
->VolumeSerialNumber
;
466 /* If user wants filesystem name */
467 if (lpFileSystemNameBuffer
!= NULL
)
469 /* Check its buffer can hold it (+ 0) */
470 if (VolumeAttr
->FileSystemNameLength
>= nFileSystemNameSize
)
472 SetLastError(ERROR_BAD_LENGTH
);
477 RtlCopyMemory(lpFileSystemNameBuffer
, VolumeAttr
->FileSystemName
, VolumeAttr
->FileSystemNameLength
);
478 lpFileSystemNameBuffer
[VolumeAttr
->FileSystemNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
481 /* If user wants wants max compo len, return it */
482 if (lpMaximumComponentLength
!= NULL
)
484 *lpMaximumComponentLength
= VolumeAttr
->MaximumComponentNameLength
;
487 /* If user wants wants FS flags, return them */
488 if (lpFileSystemFlags
!= NULL
)
490 *lpFileSystemFlags
= VolumeAttr
->FileSystemAttributes
;
497 NtClose(VolumeHandle
);
499 if (VolumeInfo
!= NULL
)
501 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeInfo
);
504 if (VolumeAttr
!= NULL
)
506 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeAttr
);
517 SetVolumeLabelA(IN LPCSTR lpRootPathName
,
518 IN LPCSTR lpVolumeName OPTIONAL
) /* NULL if deleting label */
520 PWCHAR RootPathNameW
;
521 PWCHAR VolumeNameW
= NULL
;
524 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
529 if (!(VolumeNameW
= FilenameA2W(lpVolumeName
, TRUE
)))
533 Result
= SetVolumeLabelW (RootPathNameW
,
538 RtlFreeHeap (RtlGetProcessHeap (),
551 SetVolumeLabelW(IN LPCWSTR lpRootPathName
,
552 IN LPCWSTR lpVolumeName OPTIONAL
) /* NULL if deleting label */
554 PFILE_FS_LABEL_INFORMATION LabelInfo
;
555 IO_STATUS_BLOCK IoStatusBlock
;
560 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
561 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
563 sizeof(FILE_FS_LABEL_INFORMATION
) +
565 if (LabelInfo
== NULL
)
567 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
570 LabelInfo
->VolumeLabelLength
= LabelLength
;
571 memcpy(LabelInfo
->VolumeLabel
,
575 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
576 if (INVALID_HANDLE_VALUE
== hFile
)
578 RtlFreeHeap(RtlGetProcessHeap(),
584 Status
= NtSetVolumeInformationFile(hFile
,
587 sizeof(FILE_FS_LABEL_INFORMATION
) +
589 FileFsLabelInformation
);
591 RtlFreeHeap(RtlGetProcessHeap(),
595 if (!NT_SUCCESS(Status
))
597 WARN("Status: %x\n", Status
);
599 BaseSetLastNTError(Status
);
608 * @implemented (Wine 13 sep 2008)
612 FindFirstVolumeW(IN LPWSTR volume
,
617 HANDLE mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
618 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, INVALID_HANDLE_VALUE
);
619 if (mgr
== INVALID_HANDLE_VALUE
) return INVALID_HANDLE_VALUE
;
623 MOUNTMGR_MOUNT_POINT input
;
624 MOUNTMGR_MOUNT_POINTS
*output
;
626 if (!(output
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
628 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
631 memset( &input
, 0, sizeof(input
) );
633 if (!DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_POINTS
, &input
, sizeof(input
),
634 output
, size
, &br
, NULL
))
636 if (GetLastError() != ERROR_MORE_DATA
) break;
638 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
642 /* abuse the Size field to store the current index */
644 if (!FindNextVolumeW( output
, volume
, len
))
646 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
647 return INVALID_HANDLE_VALUE
;
649 return (HANDLE
)output
;
652 return INVALID_HANDLE_VALUE
;
656 * @implemented (Wine 13 sep 2008)
660 FindFirstVolumeA(IN LPSTR volume
,
663 WCHAR
*buffer
= NULL
;
666 buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0, len
* sizeof(WCHAR
) );
670 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
671 return INVALID_HANDLE_VALUE
;
674 handle
= FindFirstVolumeW( buffer
, len
);
676 if (handle
!= INVALID_HANDLE_VALUE
)
678 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
))
680 FindVolumeClose( handle
);
681 handle
= INVALID_HANDLE_VALUE
;
684 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer
);
689 * @implemented (Wine 13 sep 2008)
693 FindVolumeClose(IN HANDLE hFindVolume
)
695 return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume
);
703 GetVolumePathNameA(IN LPCSTR lpszFileName
,
704 IN LPSTR lpszVolumePathName
,
705 IN DWORD cchBufferLength
)
707 PWCHAR FileNameW
= NULL
;
708 WCHAR VolumePathName
[MAX_PATH
];
713 if (!(FileNameW
= FilenameA2W(lpszFileName
, FALSE
)))
717 Result
= GetVolumePathNameW(FileNameW
, VolumePathName
, cchBufferLength
);
720 FilenameW2A_N(lpszVolumePathName
, MAX_PATH
, VolumePathName
, -1);
730 GetVolumePathNameW(IN LPCWSTR lpszFileName
,
731 IN LPWSTR lpszVolumePathName
,
732 IN DWORD cchBufferLength
)
735 UNICODE_STRING UnicodeFilePath
;
737 PWSTR FullFilePath
, FilePathName
;
739 WCHAR VolumeName
[MAX_PATH
];
743 if (!lpszFileName
|| !lpszVolumePathName
|| !cchBufferLength
)
745 SetLastError(ERROR_INVALID_PARAMETER
);
749 if (!(PathLength
= GetFullPathNameW(lpszFileName
, 0, NULL
, NULL
)))
755 PathLength
= PathLength
+ 10;
756 PathSize
= PathLength
* sizeof(WCHAR
);
758 if (!(FullFilePath
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
760 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
764 if (!GetFullPathNameW(lpszFileName
, PathLength
, FullFilePath
, &FilePart
))
766 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
770 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
772 if (UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] != '\\')
774 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
775 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
776 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
779 if (!(FilePathName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
781 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
782 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
786 while (!GetVolumeNameForVolumeMountPointW(UnicodeFilePath
.Buffer
,
790 if (((UnicodeFilePath
.Length
== 4) && (UnicodeFilePath
.Buffer
[0] == '\\') &&
791 (UnicodeFilePath
.Buffer
[1] == '\\')) || ((UnicodeFilePath
.Length
== 6) &&
792 (UnicodeFilePath
.Buffer
[1] == ':')))
797 UnicodeFilePath
.Length
-= sizeof(WCHAR
);
798 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
800 memcpy(FilePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
801 FilePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
803 if (!GetFullPathNameW(FilePathName
, PathLength
, FullFilePath
, &FilePart
))
810 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
811 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
812 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
813 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
818 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
822 if (UnicodeFilePath
.Length
> (cchBufferLength
* sizeof(WCHAR
)) - sizeof(WCHAR
))
824 ErrorCode
= ERROR_FILENAME_EXCED_RANGE
;
828 memcpy(lpszVolumePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
829 lpszVolumePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
835 SetLastError(ErrorCode
);
837 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
838 RtlFreeHeap(RtlGetProcessHeap(), 0, FilePathName
);
847 FindNextVolumeA(IN HANDLE handle
,
851 WCHAR
*buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, len
* sizeof(WCHAR
));
856 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
860 if ((ret
= FindNextVolumeW( handle
, buffer
, len
)))
862 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
)) ret
= FALSE
;
865 RtlFreeHeap(RtlGetProcessHeap(), 0, buffer
);
874 FindNextVolumeW(IN HANDLE handle
,
878 MOUNTMGR_MOUNT_POINTS
*data
= handle
;
880 while (data
->Size
< data
->NumberOfMountPoints
)
882 static const WCHAR volumeW
[] = {'\\','?','?','\\','V','o','l','u','m','e','{',};
883 WCHAR
*link
= (WCHAR
*)((char *)data
+ data
->MountPoints
[data
->Size
].SymbolicLinkNameOffset
);
884 DWORD size
= data
->MountPoints
[data
->Size
].SymbolicLinkNameLength
;
886 /* skip non-volumes */
887 if (size
< sizeof(volumeW
) || memcmp( link
, volumeW
, sizeof(volumeW
) )) continue;
888 if (size
+ sizeof(WCHAR
) >= len
* sizeof(WCHAR
))
890 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
893 memcpy( volume
, link
, size
);
894 volume
[1] = '\\'; /* map \??\ to \\?\ */
895 volume
[size
/ sizeof(WCHAR
)] = '\\'; /* Windows appends a backslash */
896 volume
[size
/ sizeof(WCHAR
) + 1] = 0;
897 DPRINT( "returning entry %u %s\n", data
->Size
- 1, volume
);
900 SetLastError( ERROR_NO_MORE_FILES
);
909 GetVolumePathNamesForVolumeNameA(IN LPCSTR lpszVolumeName
,
910 IN LPSTR lpszVolumePathNames
,
911 IN DWORD cchBufferLength
,
912 OUT PDWORD lpcchReturnLength
)
924 GetVolumePathNamesForVolumeNameW(IN LPCWSTR lpszVolumeName
,
925 IN LPWSTR lpszVolumePathNames
,
926 IN DWORD cchBufferLength
,
927 OUT PDWORD lpcchReturnLength
)