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
32 GetVolumeInformationA(IN LPCSTR lpRootPathName
,
33 IN LPSTR lpVolumeNameBuffer
,
34 IN DWORD nVolumeNameSize
,
35 OUT LPDWORD lpVolumeSerialNumber OPTIONAL
,
36 OUT LPDWORD lpMaximumComponentLength OPTIONAL
,
37 OUT LPDWORD lpFileSystemFlags OPTIONAL
,
38 OUT LPSTR lpFileSystemNameBuffer OPTIONAL
,
39 IN DWORD nFileSystemNameSize
)
43 PUNICODE_STRING RootPathNameU
;
44 ANSI_STRING VolumeName
, FileSystemName
;
45 UNICODE_STRING VolumeNameU
, FileSystemNameU
;
47 /* If no root path provided, default to \ */
48 if (lpRootPathName
== NULL
)
50 lpRootPathName
= "\\";
53 /* Convert root path to unicode */
54 RootPathNameU
= Basep8BitStringToStaticUnicodeString(lpRootPathName
);
55 if (RootPathNameU
== NULL
)
60 /* Init all our STRINGS (U/A) */
61 VolumeNameU
.Buffer
= NULL
;
62 VolumeNameU
.MaximumLength
= 0;
63 FileSystemNameU
.Buffer
= NULL
;
64 FileSystemNameU
.MaximumLength
= 0;
66 VolumeName
.Buffer
= lpVolumeNameBuffer
;
67 VolumeName
.MaximumLength
= nVolumeNameSize
+ 1;
68 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
69 FileSystemName
.MaximumLength
= nFileSystemNameSize
+ 1;
71 /* Assume failure for now */
74 /* If caller wants volume name, allocate a buffer to receive it */
75 if (lpVolumeNameBuffer
!= NULL
)
77 VolumeNameU
.MaximumLength
= sizeof(WCHAR
) * (nVolumeNameSize
+ 1);
78 VolumeNameU
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0,
79 VolumeNameU
.MaximumLength
);
80 if (VolumeNameU
.Buffer
== NULL
)
82 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
87 /* If caller wants file system name, allocate a buffer to receive it */
88 if (lpFileSystemNameBuffer
!= NULL
)
90 FileSystemNameU
.MaximumLength
= sizeof(WCHAR
) * (nVolumeNameSize
+ 1);
91 FileSystemNameU
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0,
92 FileSystemNameU
.MaximumLength
);
93 if (FileSystemNameU
.Buffer
== NULL
)
95 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
101 Ret
= GetVolumeInformationW(RootPathNameU
->Buffer
, VolumeNameU
.Buffer
,
102 nVolumeNameSize
, lpVolumeSerialNumber
,
103 lpMaximumComponentLength
, lpFileSystemFlags
,
104 FileSystemNameU
.Buffer
, nFileSystemNameSize
);
105 /* If it succeed, convert back to ANSI */
108 if (lpVolumeNameBuffer
!= NULL
)
110 RtlInitUnicodeString(&VolumeNameU
, VolumeNameU
.Buffer
);
111 Status
= RtlUnicodeStringToAnsiString(&VolumeName
, &VolumeNameU
, FALSE
);
112 if (!NT_SUCCESS(Status
))
114 BaseSetLastNTError(Status
);
121 if (lpFileSystemNameBuffer
!= NULL
)
123 RtlInitUnicodeString(&FileSystemNameU
, FileSystemNameU
.Buffer
);
124 Status
= RtlUnicodeStringToAnsiString(&FileSystemName
, &FileSystemNameU
, FALSE
);
125 if (!NT_SUCCESS(Status
))
127 BaseSetLastNTError(Status
);
137 if (VolumeNameU
.Buffer
!= NULL
)
139 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameU
.Buffer
);
142 if (FileSystemNameU
.Buffer
!= NULL
)
144 RtlFreeHeap(RtlGetProcessHeap(), 0, FileSystemNameU
.Buffer
);
154 IsThisARootDirectory(IN HANDLE VolumeHandle
,
155 IN PUNICODE_STRING NtPathName
)
158 IO_STATUS_BLOCK IoStatusBlock
;
161 FILE_NAME_INFORMATION
;
162 WCHAR Buffer
[MAX_PATH
];
165 /* If we have a handle, query the name */
168 Status
= NtQueryInformationFile(VolumeHandle
, &IoStatusBlock
, &FileNameInfo
, sizeof(FileNameInfo
), FileNameInformation
);
169 if (!NT_SUCCESS(Status
))
174 /* Check we properly end with a \ */
175 if (FileNameInfo
.FileName
[FileNameInfo
.FileNameLength
/ sizeof(WCHAR
) - 1] != L
'\\')
181 /* If we have a path */
182 if (NtPathName
!= NULL
)
186 ULONG ReturnedLength
;
187 UNICODE_STRING LinkTarget
;
188 OBJECT_ATTRIBUTES ObjectAttributes
;
190 NtPathName
->Length
-= sizeof(WCHAR
);
192 InitializeObjectAttributes(&ObjectAttributes
, NtPathName
,
193 OBJ_CASE_INSENSITIVE
,
196 /* Try to see whether that's a symbolic name */
197 Status
= NtOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
198 NtPathName
->Length
+= sizeof(WCHAR
);
199 if (!NT_SUCCESS(Status
))
204 /* If so, query the target */
205 LinkTarget
.Buffer
= Buffer
;
206 LinkTarget
.Length
= 0;
207 LinkTarget
.MaximumLength
= sizeof(Buffer
);
209 Status
= NtQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, &ReturnedLength
);
211 /* A root directory (NtName) is a symbolic link */
212 if (!NT_SUCCESS(Status
))
226 GetVolumeInformationW(IN LPCWSTR lpRootPathName
,
227 IN LPWSTR lpVolumeNameBuffer
,
228 IN DWORD nVolumeNameSize
,
229 OUT LPDWORD lpVolumeSerialNumber OPTIONAL
,
230 OUT LPDWORD lpMaximumComponentLength OPTIONAL
,
231 OUT LPDWORD lpFileSystemFlags OPTIONAL
,
232 OUT LPWSTR lpFileSystemNameBuffer OPTIONAL
,
233 IN DWORD nFileSystemNameSize
)
238 LPCWSTR RootPathName
;
239 UNICODE_STRING NtPathName
;
240 IO_STATUS_BLOCK IoStatusBlock
;
241 OBJECT_ATTRIBUTES ObjectAttributes
;
242 PFILE_FS_VOLUME_INFORMATION VolumeInfo
;
243 PFILE_FS_ATTRIBUTE_INFORMATION VolumeAttr
;
244 ULONG OldMode
, VolumeInfoSize
, VolumeAttrSize
;
246 /* If no root path provided, default to \ */
247 if (lpRootPathName
== NULL
)
249 RootPathName
= L
"\\";
253 RootPathName
= lpRootPathName
;
256 /* Convert to NT name */
257 if (!RtlDosPathNameToNtPathName_U(RootPathName
, &NtPathName
, NULL
, NULL
))
259 SetLastError(ERROR_PATH_NOT_FOUND
);
263 /* Check we really end with a backslash */
264 if (NtPathName
.Buffer
[(NtPathName
.Length
/ sizeof(WCHAR
)) - 1] != L
'\\')
266 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
267 BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID
);
271 /* Try to open the received path */
272 InitializeObjectAttributes(&ObjectAttributes
, &NtPathName
,
273 OBJ_CASE_INSENSITIVE
,
276 /* No errors to the user */
277 RtlSetThreadErrorMode(RTL_SEM_FAILCRITICALERRORS
, &OldMode
);
278 Status
= NtOpenFile(&VolumeHandle
, SYNCHRONIZE
, &ObjectAttributes
, &IoStatusBlock
, 0, FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
);
279 RtlSetThreadErrorMode(OldMode
, NULL
);
280 if (!NT_SUCCESS(Status
))
282 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
283 BaseSetLastNTError(Status
);
287 /* Check whether that's a root directory */
288 if (!IsThisARootDirectory(VolumeHandle
, &NtPathName
))
290 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
291 NtClose(VolumeHandle
);
292 SetLastError(ERROR_DIR_NOT_ROOT
);
296 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
298 /* Assume we don't need to query FileFsVolumeInformation */
300 /* If user wants volume name, allocate a buffer to query it */
301 if (lpVolumeNameBuffer
!= NULL
)
303 VolumeInfoSize
= nVolumeNameSize
+ sizeof(FILE_FS_VOLUME_INFORMATION
);
305 /* If user just wants the serial number, allocate a dummy buffer */
306 else if (lpVolumeSerialNumber
!= NULL
)
308 VolumeInfoSize
= MAX_PATH
* sizeof(WCHAR
) + sizeof(FILE_FS_VOLUME_INFORMATION
);
310 /* Otherwise, nothing to query */
316 /* If we're to query, allocate a big enough buffer */
317 if (VolumeInfoSize
!= 0)
319 VolumeInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumeInfoSize
);
320 if (VolumeInfo
== NULL
)
322 NtClose(VolumeHandle
);
323 BaseSetLastNTError(STATUS_NO_MEMORY
);
328 /* Assume we don't need to query FileFsAttributeInformation */
330 /* If user wants filesystem name, allocate a buffer to query it */
331 if (lpFileSystemNameBuffer
!= NULL
)
333 VolumeAttrSize
= nFileSystemNameSize
+ sizeof(FILE_FS_ATTRIBUTE_INFORMATION
);
335 /* If user just wants max compo len or flags, allocate a dummy buffer */
336 else if (lpMaximumComponentLength
!= NULL
|| lpFileSystemFlags
!= NULL
)
338 VolumeAttrSize
= MAX_PATH
* sizeof(WCHAR
) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION
);
345 /* If we're to query, allocate a big enough buffer */
346 if (VolumeAttrSize
!= 0)
348 VolumeAttr
= RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumeAttrSize
);
349 if (VolumeAttr
== NULL
)
351 if (VolumeInfo
!= NULL
)
353 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeInfo
);
356 NtClose(VolumeHandle
);
357 BaseSetLastNTError(STATUS_NO_MEMORY
);
362 /* Assume we'll fail */
365 /* If we're to query FileFsVolumeInformation, do it now! */
366 if (VolumeInfo
!= NULL
)
368 Status
= NtQueryVolumeInformationFile(VolumeHandle
, &IoStatusBlock
, VolumeInfo
, VolumeInfoSize
, FileFsVolumeInformation
);
369 if (!NT_SUCCESS(Status
))
371 BaseSetLastNTError(Status
);
376 /* If we're to query FileFsAttributeInformation, do it now! */
377 if (VolumeAttr
!= NULL
)
379 Status
= NtQueryVolumeInformationFile(VolumeHandle
, &IoStatusBlock
, VolumeAttr
, VolumeAttrSize
, FileFsAttributeInformation
);
380 if (!NT_SUCCESS(Status
))
382 BaseSetLastNTError(Status
);
387 /* If user wants volume name */
388 if (lpVolumeNameBuffer
!= NULL
)
390 /* Check its buffer can hold it (+ 0) */
391 if (VolumeInfo
->VolumeLabelLength
>= nVolumeNameSize
)
393 SetLastError(ERROR_BAD_LENGTH
);
398 RtlCopyMemory(lpVolumeNameBuffer
, VolumeInfo
->VolumeLabel
, VolumeInfo
->VolumeLabelLength
);
399 lpVolumeNameBuffer
[VolumeInfo
->VolumeLabelLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
402 /* If user wants wants serial number, return it */
403 if (lpVolumeSerialNumber
!= NULL
)
405 *lpVolumeSerialNumber
= VolumeInfo
->VolumeSerialNumber
;
408 /* If user wants filesystem name */
409 if (lpFileSystemNameBuffer
!= NULL
)
411 /* Check its buffer can hold it (+ 0) */
412 if (VolumeAttr
->FileSystemNameLength
>= nFileSystemNameSize
)
414 SetLastError(ERROR_BAD_LENGTH
);
419 RtlCopyMemory(lpFileSystemNameBuffer
, VolumeAttr
->FileSystemName
, VolumeAttr
->FileSystemNameLength
);
420 lpFileSystemNameBuffer
[VolumeAttr
->FileSystemNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
423 /* If user wants wants max compo len, return it */
424 if (lpMaximumComponentLength
!= NULL
)
426 *lpMaximumComponentLength
= VolumeAttr
->MaximumComponentNameLength
;
429 /* If user wants wants FS flags, return them */
430 if (lpFileSystemFlags
!= NULL
)
432 *lpFileSystemFlags
= VolumeAttr
->FileSystemAttributes
;
439 NtClose(VolumeHandle
);
441 if (VolumeInfo
!= NULL
)
443 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeInfo
);
446 if (VolumeAttr
!= NULL
)
448 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeAttr
);
459 SetVolumeLabelA(IN LPCSTR lpRootPathName
,
460 IN LPCSTR lpVolumeName OPTIONAL
) /* NULL if deleting label */
463 UNICODE_STRING VolumeNameU
;
464 PUNICODE_STRING RootPathNameU
;
466 if (lpRootPathName
== NULL
)
468 lpRootPathName
= "\\";
471 RootPathNameU
= Basep8BitStringToStaticUnicodeString(lpRootPathName
);
472 if (RootPathNameU
== NULL
)
477 if (lpVolumeName
!= NULL
)
479 if (!Basep8BitStringToDynamicUnicodeString(&VolumeNameU
, lpVolumeName
))
486 VolumeNameU
.Buffer
= NULL
;
489 Ret
= SetVolumeLabelW(RootPathNameU
->Buffer
, VolumeNameU
.Buffer
);
490 RtlFreeUnicodeString(&VolumeNameU
);
499 SetVolumeLabelW(IN LPCWSTR lpRootPathName
,
500 IN LPCWSTR lpVolumeName OPTIONAL
) /* NULL if deleting label */
506 WCHAR VolumeGuid
[MAX_PATH
];
507 IO_STATUS_BLOCK IoStatusBlock
;
508 OBJECT_ATTRIBUTES ObjectAttributes
;
509 PFILE_FS_LABEL_INFORMATION FsLabelInfo
;
510 UNICODE_STRING VolumeName
, NtVolumeName
;
512 /* If no root path provided, default to \ */
515 /* If user wants to set a label, make it a string */
516 if (lpVolumeName
!= NULL
)
518 RtlInitUnicodeString(&VolumeName
, lpVolumeName
);
522 VolumeName
.Length
= 0;
523 VolumeName
.MaximumLength
= 0;
524 VolumeName
.Buffer
= NULL
;
527 /* If we received a volume, try to get its GUID name */
528 if (lpRootPathName
!= NULL
)
530 Ret
= GetVolumeNameForVolumeMountPointW(lpRootPathName
, VolumeGuid
, MAX_PATH
);
537 /* If we got the GUID name, use it */
540 VolumeRoot
= VolumeGuid
;
544 /* Otherwise, use the name provided by the caller */
545 if (lpRootPathName
!= NULL
)
547 VolumeRoot
= (PWSTR
)lpRootPathName
;
551 /* Convert to a NT path */
552 if (!RtlDosPathNameToNtPathName_U(VolumeRoot
, &NtVolumeName
, NULL
, NULL
))
554 SetLastError(ERROR_PATH_NOT_FOUND
);
559 /* Check we really end with a backslash */
560 if (NtVolumeName
.Buffer
[(NtVolumeName
.Length
/ sizeof(WCHAR
)) - 1] != L
'\\')
562 RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName
.Buffer
);
563 BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID
);
567 /* Try to open the root directory */
568 InitializeObjectAttributes(&ObjectAttributes
, &NtVolumeName
,
569 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
571 Status
= NtOpenFile(&VolumeHandle
, SYNCHRONIZE
| FILE_WRITE_DATA
,
572 &ObjectAttributes
, &IoStatusBlock
,
573 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
574 FILE_SYNCHRONOUS_IO_NONALERT
);
575 if (!NT_SUCCESS(Status
))
577 RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName
.Buffer
);
578 BaseSetLastNTError(Status
);
582 /* Validate it's really a root path */
583 if (!IsThisARootDirectory(VolumeHandle
, NULL
))
585 RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName
.Buffer
);
586 NtClose(VolumeHandle
);
587 SetLastError(ERROR_DIR_NOT_ROOT
);
592 NtClose(VolumeHandle
);
594 /* Now, open the volume to perform the label change */
595 NtVolumeName
.Length
-= sizeof(WCHAR
);
596 InitializeObjectAttributes(&ObjectAttributes
, &NtVolumeName
,
597 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
599 Status
= NtOpenFile(&VolumeHandle
, SYNCHRONIZE
| FILE_WRITE_DATA
,
600 &ObjectAttributes
, &IoStatusBlock
,
601 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
602 FILE_SYNCHRONOUS_IO_NONALERT
);
604 RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName
.Buffer
);
606 if (!NT_SUCCESS(Status
))
608 BaseSetLastNTError(Status
);
615 /* Allocate a buffer that can hold new label and its size */
616 FsLabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(FILE_FS_LABEL_INFORMATION
) + VolumeName
.Length
);
617 if (FsLabelInfo
!= NULL
)
619 /* Copy name and set its size */
620 RtlCopyMemory(FsLabelInfo
->VolumeLabel
, VolumeName
.Buffer
, VolumeName
.Length
);
621 FsLabelInfo
->VolumeLabelLength
= VolumeName
.Length
;
623 /* And finally, set new label */
624 Status
= NtSetVolumeInformationFile(VolumeHandle
, &IoStatusBlock
, FsLabelInfo
, sizeof(FILE_FS_LABEL_INFORMATION
) + VolumeName
.Length
, FileFsLabelInformation
);
628 /* Allocation failed */
629 Status
= STATUS_NO_MEMORY
;
632 /* In case of failure, set status and mark failure */
633 if (!NT_SUCCESS(Status
))
635 BaseSetLastNTError(Status
);
640 NtClose(VolumeHandle
);
642 /* Free buffer if required */
643 if (FsLabelInfo
!= NULL
)
645 RtlFreeHeap(RtlGetProcessHeap(), 0, FsLabelInfo
);
652 * @implemented (Wine 13 sep 2008)
656 FindFirstVolumeW(IN LPWSTR volume
,
661 HANDLE mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
662 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, INVALID_HANDLE_VALUE
);
663 if (mgr
== INVALID_HANDLE_VALUE
) return INVALID_HANDLE_VALUE
;
667 MOUNTMGR_MOUNT_POINT input
;
668 MOUNTMGR_MOUNT_POINTS
*output
;
670 if (!(output
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
672 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
675 memset( &input
, 0, sizeof(input
) );
677 if (!DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_POINTS
, &input
, sizeof(input
),
678 output
, size
, &br
, NULL
))
680 if (GetLastError() != ERROR_MORE_DATA
) break;
682 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
686 /* abuse the Size field to store the current index */
688 if (!FindNextVolumeW( output
, volume
, len
))
690 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
691 return INVALID_HANDLE_VALUE
;
693 return (HANDLE
)output
;
696 return INVALID_HANDLE_VALUE
;
700 * @implemented (Wine 13 sep 2008)
704 FindFirstVolumeA(IN LPSTR volume
,
707 WCHAR
*buffer
= NULL
;
710 buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0, len
* sizeof(WCHAR
) );
714 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
715 return INVALID_HANDLE_VALUE
;
718 handle
= FindFirstVolumeW( buffer
, len
);
720 if (handle
!= INVALID_HANDLE_VALUE
)
722 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
))
724 FindVolumeClose( handle
);
725 handle
= INVALID_HANDLE_VALUE
;
728 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer
);
733 * @implemented (Wine 13 sep 2008)
737 FindVolumeClose(IN HANDLE hFindVolume
)
739 return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume
);
747 GetVolumePathNameA(IN LPCSTR lpszFileName
,
748 IN LPSTR lpszVolumePathName
,
749 IN DWORD cchBufferLength
)
751 PWCHAR FileNameW
= NULL
;
752 WCHAR VolumePathName
[MAX_PATH
];
757 if (!(FileNameW
= FilenameA2W(lpszFileName
, FALSE
)))
761 Result
= GetVolumePathNameW(FileNameW
, VolumePathName
, cchBufferLength
);
764 FilenameW2A_N(lpszVolumePathName
, MAX_PATH
, VolumePathName
, -1);
774 GetVolumePathNameW(IN LPCWSTR lpszFileName
,
775 IN LPWSTR lpszVolumePathName
,
776 IN DWORD cchBufferLength
)
779 UNICODE_STRING UnicodeFilePath
;
781 PWSTR FullFilePath
, FilePathName
;
783 WCHAR VolumeName
[MAX_PATH
];
787 if (!lpszFileName
|| !lpszVolumePathName
|| !cchBufferLength
)
789 SetLastError(ERROR_INVALID_PARAMETER
);
793 if (!(PathLength
= GetFullPathNameW(lpszFileName
, 0, NULL
, NULL
)))
799 PathLength
= PathLength
+ 10;
800 PathSize
= PathLength
* sizeof(WCHAR
);
802 if (!(FullFilePath
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
804 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
808 if (!GetFullPathNameW(lpszFileName
, PathLength
, FullFilePath
, &FilePart
))
810 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
814 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
816 if (UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] != '\\')
818 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
819 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
820 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
823 if (!(FilePathName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
825 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
826 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
830 while (!GetVolumeNameForVolumeMountPointW(UnicodeFilePath
.Buffer
,
834 if (((UnicodeFilePath
.Length
== 4) && (UnicodeFilePath
.Buffer
[0] == '\\') &&
835 (UnicodeFilePath
.Buffer
[1] == '\\')) || ((UnicodeFilePath
.Length
== 6) &&
836 (UnicodeFilePath
.Buffer
[1] == ':')))
841 UnicodeFilePath
.Length
-= sizeof(WCHAR
);
842 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
844 memcpy(FilePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
845 FilePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
847 if (!GetFullPathNameW(FilePathName
, PathLength
, FullFilePath
, &FilePart
))
854 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
855 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
856 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
857 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
862 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
866 if (UnicodeFilePath
.Length
> (cchBufferLength
* sizeof(WCHAR
)) - sizeof(WCHAR
))
868 ErrorCode
= ERROR_FILENAME_EXCED_RANGE
;
872 memcpy(lpszVolumePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
873 lpszVolumePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
879 SetLastError(ErrorCode
);
881 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
882 RtlFreeHeap(RtlGetProcessHeap(), 0, FilePathName
);
891 FindNextVolumeA(IN HANDLE handle
,
895 WCHAR
*buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, len
* sizeof(WCHAR
));
900 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
904 if ((ret
= FindNextVolumeW( handle
, buffer
, len
)))
906 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
)) ret
= FALSE
;
909 RtlFreeHeap(RtlGetProcessHeap(), 0, buffer
);
918 FindNextVolumeW(IN HANDLE handle
,
922 MOUNTMGR_MOUNT_POINTS
*data
= handle
;
924 while (data
->Size
< data
->NumberOfMountPoints
)
926 static const WCHAR volumeW
[] = {'\\','?','?','\\','V','o','l','u','m','e','{',};
927 WCHAR
*link
= (WCHAR
*)((char *)data
+ data
->MountPoints
[data
->Size
].SymbolicLinkNameOffset
);
928 DWORD size
= data
->MountPoints
[data
->Size
].SymbolicLinkNameLength
;
930 /* skip non-volumes */
931 if (size
< sizeof(volumeW
) || memcmp( link
, volumeW
, sizeof(volumeW
) )) continue;
932 if (size
+ sizeof(WCHAR
) >= len
* sizeof(WCHAR
))
934 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
937 memcpy( volume
, link
, size
);
938 volume
[1] = '\\'; /* map \??\ to \\?\ */
939 volume
[size
/ sizeof(WCHAR
)] = '\\'; /* Windows appends a backslash */
940 volume
[size
/ sizeof(WCHAR
) + 1] = 0;
941 DPRINT( "returning entry %u %s\n", data
->Size
- 1, volume
);
944 SetLastError( ERROR_NO_MORE_FILES
);
953 GetVolumePathNamesForVolumeNameA(IN LPCSTR lpszVolumeName
,
954 IN LPSTR lpszVolumePathNames
,
955 IN DWORD cchBufferLength
,
956 OUT PDWORD lpcchReturnLength
)
960 DWORD cchReturnLength
;
961 ANSI_STRING VolumePathName
;
962 PUNICODE_STRING VolumeNameU
;
963 UNICODE_STRING VolumePathNamesU
;
965 /* Convert volume name to unicode */
966 VolumeNameU
= Basep8BitStringToStaticUnicodeString(lpszVolumeName
);
967 if (VolumeNameU
== NULL
)
972 /* Initialize the strings we'll use later on */
973 VolumePathName
.Length
= 0;
974 VolumePathName
.MaximumLength
= cchBufferLength
;
975 VolumePathName
.Buffer
= lpszVolumePathNames
;
977 VolumePathNamesU
.Length
= 0;
978 VolumePathNamesU
.MaximumLength
= sizeof(WCHAR
) * cchBufferLength
;
979 /* If caller provided a non 0 sized string, allocate a buffer for our unicode string */
980 if (VolumePathNamesU
.MaximumLength
!= 0)
982 VolumePathNamesU
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumePathNamesU
.MaximumLength
);
983 if (VolumePathNamesU
.Buffer
== NULL
)
985 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
991 VolumePathNamesU
.Buffer
= NULL
;
994 /* Call the -W implementation */
995 Ret
= GetVolumePathNamesForVolumeNameW(VolumeNameU
->Buffer
, VolumePathNamesU
.Buffer
,
996 cchBufferLength
, &cchReturnLength
);
997 /* Call succeed, we'll return the total length */
1000 VolumePathNamesU
.Length
= sizeof(WCHAR
) * cchReturnLength
;
1004 /* Else, if we fail for anything else than too small buffer, quit */
1005 if (GetLastError() != ERROR_MORE_DATA
)
1007 if (VolumePathNamesU
.Buffer
!= NULL
)
1009 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNamesU
.Buffer
);
1015 /* Otherwise, we'll just copy as much as we can */
1016 VolumePathNamesU
.Length
= sizeof(WCHAR
) * cchBufferLength
;
1019 /* Convert our output string back to ANSI */
1020 Status
= RtlUnicodeStringToAnsiString(&VolumePathName
, &VolumePathNamesU
, FALSE
);
1021 if (!NT_SUCCESS(Status
))
1023 BaseSetLastNTError(Status
);
1025 if (VolumePathNamesU
.Buffer
!= NULL
)
1027 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNamesU
.Buffer
);
1033 /* If caller wants return length, two cases... */
1034 if (lpcchReturnLength
!= NULL
)
1036 /* We succeed: return the copied length */
1039 *lpcchReturnLength
= VolumePathName
.Length
;
1041 /* We failed, return the size we would have loved having! */
1044 *lpcchReturnLength
= sizeof(WCHAR
) * cchReturnLength
;
1048 /* Release our buffer if allocated */
1049 if (VolumePathNamesU
.Buffer
!= NULL
)
1051 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNamesU
.Buffer
);
1063 GetVolumePathNamesForVolumeNameW(IN LPCWSTR lpszVolumeName
,
1064 IN LPWSTR lpszVolumePathNames
,
1065 IN DWORD cchBufferLength
,
1066 OUT PDWORD lpcchReturnLength
)