2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/file/volume.c
5 * PURPOSE: File volume functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Erik Bos, Alexandre Julliard :
8 * GetLogicalDriveStringsA,
9 * GetLogicalDriveStringsW, GetLogicalDrives
13 //WINE copyright notice:
15 * DOS drives handling functions
17 * Copyright 1993 Erik Bos
18 * Copyright 1996 Alexandre Julliard
24 DEBUG_CHANNEL(kernel32file
);
28 InternalOpenDirW(IN LPCWSTR DirName
,
31 UNICODE_STRING NtPathU
;
32 OBJECT_ATTRIBUTES ObjectAttributes
;
34 IO_STATUS_BLOCK IoStatusBlock
;
37 if (!RtlDosPathNameToNtPathName_U(DirName
, &NtPathU
, NULL
, NULL
))
39 WARN("Invalid path\n");
40 SetLastError(ERROR_BAD_PATHNAME
);
41 return INVALID_HANDLE_VALUE
;
44 InitializeObjectAttributes(&ObjectAttributes
,
50 errCode
= NtCreateFile(&hFile
,
51 Write
? FILE_GENERIC_WRITE
: FILE_GENERIC_READ
,
56 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
62 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU
.Buffer
);
64 if (!NT_SUCCESS(errCode
))
66 BaseSetLastNTError(errCode
);
67 return INVALID_HANDLE_VALUE
;
78 GetVolumeInformationA(IN LPCSTR lpRootPathName
,
79 IN LPSTR lpVolumeNameBuffer
,
80 IN DWORD nVolumeNameSize
,
81 OUT LPDWORD lpVolumeSerialNumber OPTIONAL
,
82 OUT LPDWORD lpMaximumComponentLength OPTIONAL
,
83 OUT LPDWORD lpFileSystemFlags OPTIONAL
,
84 OUT LPSTR lpFileSystemNameBuffer OPTIONAL
,
85 IN DWORD nFileSystemNameSize
)
87 UNICODE_STRING FileSystemNameU
;
88 UNICODE_STRING VolumeNameU
= { 0, 0, NULL
};
89 ANSI_STRING VolumeName
;
90 ANSI_STRING FileSystemName
;
94 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
97 if (lpVolumeNameBuffer
)
99 VolumeNameU
.MaximumLength
= (USHORT
)nVolumeNameSize
* sizeof(WCHAR
);
100 VolumeNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
102 VolumeNameU
.MaximumLength
);
103 if (VolumeNameU
.Buffer
== NULL
)
109 if (lpFileSystemNameBuffer
)
111 FileSystemNameU
.Length
= 0;
112 FileSystemNameU
.MaximumLength
= (USHORT
)nFileSystemNameSize
* sizeof(WCHAR
);
113 FileSystemNameU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
115 FileSystemNameU
.MaximumLength
);
116 if (FileSystemNameU
.Buffer
== NULL
)
118 if (VolumeNameU
.Buffer
!= NULL
)
120 RtlFreeHeap(RtlGetProcessHeap(),
126 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
131 Result
= GetVolumeInformationW (RootPathNameW
,
132 lpVolumeNameBuffer
? VolumeNameU
.Buffer
: NULL
,
134 lpVolumeSerialNumber
,
135 lpMaximumComponentLength
,
137 lpFileSystemNameBuffer
? FileSystemNameU
.Buffer
: NULL
,
138 nFileSystemNameSize
);
142 if (lpVolumeNameBuffer
)
144 VolumeNameU
.Length
= wcslen(VolumeNameU
.Buffer
) * sizeof(WCHAR
);
145 VolumeName
.Length
= 0;
146 VolumeName
.MaximumLength
= (USHORT
)nVolumeNameSize
;
147 VolumeName
.Buffer
= lpVolumeNameBuffer
;
150 if (lpFileSystemNameBuffer
)
152 FileSystemNameU
.Length
= wcslen(FileSystemNameU
.Buffer
) * sizeof(WCHAR
);
153 FileSystemName
.Length
= 0;
154 FileSystemName
.MaximumLength
= (USHORT
)nFileSystemNameSize
;
155 FileSystemName
.Buffer
= lpFileSystemNameBuffer
;
158 /* convert unicode strings to ansi (or oem) */
161 if (lpVolumeNameBuffer
)
163 RtlUnicodeStringToAnsiString (&VolumeName
,
167 if (lpFileSystemNameBuffer
)
169 RtlUnicodeStringToAnsiString (&FileSystemName
,
176 if (lpVolumeNameBuffer
)
178 RtlUnicodeStringToOemString (&VolumeName
,
182 if (lpFileSystemNameBuffer
)
184 RtlUnicodeStringToOemString (&FileSystemName
,
191 if (lpVolumeNameBuffer
)
193 RtlFreeHeap (RtlGetProcessHeap (),
197 if (lpFileSystemNameBuffer
)
199 RtlFreeHeap (RtlGetProcessHeap (),
201 FileSystemNameU
.Buffer
);
207 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
209 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
216 GetVolumeInformationW(IN LPCWSTR lpRootPathName
,
217 IN LPWSTR lpVolumeNameBuffer
,
218 IN DWORD nVolumeNameSize
,
219 OUT LPDWORD lpVolumeSerialNumber OPTIONAL
,
220 OUT LPDWORD lpMaximumComponentLength OPTIONAL
,
221 OUT LPDWORD lpFileSystemFlags OPTIONAL
,
222 OUT LPWSTR lpFileSystemNameBuffer OPTIONAL
,
223 IN DWORD nFileSystemNameSize
)
225 PFILE_FS_VOLUME_INFORMATION FileFsVolume
;
226 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
227 IO_STATUS_BLOCK IoStatusBlock
;
228 WCHAR RootPathName
[MAX_PATH
];
229 UCHAR Buffer
[max(FS_VOLUME_BUFFER_SIZE
, FS_ATTRIBUTE_BUFFER_SIZE
)];
234 FileFsVolume
= (PFILE_FS_VOLUME_INFORMATION
)Buffer
;
235 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
237 TRACE("FileFsVolume %p\n", FileFsVolume
);
238 TRACE("FileFsAttribute %p\n", FileFsAttribute
);
240 if (!lpRootPathName
|| !wcscmp(lpRootPathName
, L
""))
242 GetCurrentDirectoryW (MAX_PATH
, RootPathName
);
246 wcsncpy (RootPathName
, lpRootPathName
, 3);
250 hFile
= InternalOpenDirW(RootPathName
, FALSE
);
251 if (hFile
== INVALID_HANDLE_VALUE
)
256 TRACE("hFile: %p\n", hFile
);
257 errCode
= NtQueryVolumeInformationFile(hFile
,
260 FS_VOLUME_BUFFER_SIZE
,
261 FileFsVolumeInformation
);
262 if ( !NT_SUCCESS(errCode
) )
264 WARN("Status: %x\n", errCode
);
266 BaseSetLastNTError (errCode
);
270 if (lpVolumeSerialNumber
)
271 *lpVolumeSerialNumber
= FileFsVolume
->VolumeSerialNumber
;
273 if (lpVolumeNameBuffer
)
275 if (nVolumeNameSize
* sizeof(WCHAR
) >= FileFsVolume
->VolumeLabelLength
+ sizeof(WCHAR
))
277 memcpy(lpVolumeNameBuffer
,
278 FileFsVolume
->VolumeLabel
,
279 FileFsVolume
->VolumeLabelLength
);
280 lpVolumeNameBuffer
[FileFsVolume
->VolumeLabelLength
/ sizeof(WCHAR
)] = 0;
285 SetLastError(ERROR_MORE_DATA
);
290 errCode
= NtQueryVolumeInformationFile (hFile
,
293 FS_ATTRIBUTE_BUFFER_SIZE
,
294 FileFsAttributeInformation
);
296 if (!NT_SUCCESS(errCode
))
298 WARN("Status: %x\n", errCode
);
299 BaseSetLastNTError (errCode
);
303 if (lpFileSystemFlags
)
304 *lpFileSystemFlags
= FileFsAttribute
->FileSystemAttributes
;
305 if (lpMaximumComponentLength
)
306 *lpMaximumComponentLength
= FileFsAttribute
->MaximumComponentNameLength
;
307 if (lpFileSystemNameBuffer
)
309 if (nFileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
311 memcpy(lpFileSystemNameBuffer
,
312 FileFsAttribute
->FileSystemName
,
313 FileFsAttribute
->FileSystemNameLength
);
314 lpFileSystemNameBuffer
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
318 SetLastError(ERROR_MORE_DATA
);
330 SetVolumeLabelA(IN LPCSTR lpRootPathName
,
331 IN LPCSTR lpVolumeName OPTIONAL
) /* NULL if deleting label */
333 PWCHAR RootPathNameW
;
334 PWCHAR VolumeNameW
= NULL
;
337 if (!(RootPathNameW
= FilenameA2W(lpRootPathName
, FALSE
)))
342 if (!(VolumeNameW
= FilenameA2W(lpVolumeName
, TRUE
)))
346 Result
= SetVolumeLabelW (RootPathNameW
,
351 RtlFreeHeap (RtlGetProcessHeap (),
364 SetVolumeLabelW(IN LPCWSTR lpRootPathName
,
365 IN LPCWSTR lpVolumeName OPTIONAL
) /* NULL if deleting label */
367 PFILE_FS_LABEL_INFORMATION LabelInfo
;
368 IO_STATUS_BLOCK IoStatusBlock
;
373 LabelLength
= wcslen(lpVolumeName
) * sizeof(WCHAR
);
374 LabelInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
376 sizeof(FILE_FS_LABEL_INFORMATION
) +
378 if (LabelInfo
== NULL
)
380 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
383 LabelInfo
->VolumeLabelLength
= LabelLength
;
384 memcpy(LabelInfo
->VolumeLabel
,
388 hFile
= InternalOpenDirW(lpRootPathName
, TRUE
);
389 if (INVALID_HANDLE_VALUE
== hFile
)
391 RtlFreeHeap(RtlGetProcessHeap(),
397 Status
= NtSetVolumeInformationFile(hFile
,
400 sizeof(FILE_FS_LABEL_INFORMATION
) +
402 FileFsLabelInformation
);
404 RtlFreeHeap(RtlGetProcessHeap(),
408 if (!NT_SUCCESS(Status
))
410 WARN("Status: %x\n", Status
);
412 BaseSetLastNTError(Status
);
421 * @implemented (Wine 13 sep 2008)
425 FindFirstVolumeW(IN LPWSTR volume
,
429 HANDLE mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
430 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, INVALID_HANDLE_VALUE
);
431 if (mgr
== INVALID_HANDLE_VALUE
) return INVALID_HANDLE_VALUE
;
435 MOUNTMGR_MOUNT_POINT input
;
436 MOUNTMGR_MOUNT_POINTS
*output
;
438 if (!(output
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
440 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
443 memset( &input
, 0, sizeof(input
) );
445 if (!DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_POINTS
, &input
, sizeof(input
),
446 output
, size
, NULL
, NULL
))
448 if (GetLastError() != ERROR_MORE_DATA
) break;
450 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
454 /* abuse the Size field to store the current index */
456 if (!FindNextVolumeW( output
, volume
, len
))
458 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
459 return INVALID_HANDLE_VALUE
;
461 return (HANDLE
)output
;
464 return INVALID_HANDLE_VALUE
;
468 * @implemented (Wine 13 sep 2008)
472 FindFirstVolumeA(IN LPSTR volume
,
475 WCHAR
*buffer
= NULL
;
478 buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0, len
* sizeof(WCHAR
) );
482 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
483 return INVALID_HANDLE_VALUE
;
486 handle
= FindFirstVolumeW( buffer
, len
);
488 if (handle
!= INVALID_HANDLE_VALUE
)
490 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
))
492 FindVolumeClose( handle
);
493 handle
= INVALID_HANDLE_VALUE
;
496 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer
);
501 * @implemented (Wine 13 sep 2008)
505 FindVolumeClose(IN HANDLE hFindVolume
)
507 return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume
);
515 GetVolumePathNameA(IN LPCSTR lpszFileName
,
516 IN LPSTR lpszVolumePathName
,
517 IN DWORD cchBufferLength
)
519 PWCHAR FileNameW
= NULL
;
520 WCHAR VolumePathName
[MAX_PATH
];
525 if (!(FileNameW
= FilenameA2W(lpszFileName
, FALSE
)))
529 Result
= GetVolumePathNameW(FileNameW
, VolumePathName
, cchBufferLength
);
532 FilenameW2A_N(lpszVolumePathName
, MAX_PATH
, VolumePathName
, -1);
542 GetVolumePathNameW(IN LPCWSTR lpszFileName
,
543 IN LPWSTR lpszVolumePathName
,
544 IN DWORD cchBufferLength
)
547 UNICODE_STRING UnicodeFilePath
;
549 PWSTR FullFilePath
, FilePathName
;
551 WCHAR VolumeName
[MAX_PATH
];
555 if (!lpszFileName
|| !lpszVolumePathName
|| !cchBufferLength
)
557 SetLastError(ERROR_INVALID_PARAMETER
);
561 if (!(PathLength
= GetFullPathNameW(lpszFileName
, 0, NULL
, NULL
)))
567 PathLength
= PathLength
+ 10;
568 PathSize
= PathLength
* sizeof(WCHAR
);
570 if (!(FullFilePath
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
572 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
576 if (!GetFullPathNameW(lpszFileName
, PathLength
, FullFilePath
, &FilePart
))
578 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
582 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
584 if (UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] != '\\')
586 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
587 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
588 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
591 if (!(FilePathName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
593 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
594 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
598 while (!GetVolumeNameForVolumeMountPointW(UnicodeFilePath
.Buffer
,
602 if (((UnicodeFilePath
.Length
== 4) && (UnicodeFilePath
.Buffer
[0] == '\\') &&
603 (UnicodeFilePath
.Buffer
[1] == '\\')) || ((UnicodeFilePath
.Length
== 6) &&
604 (UnicodeFilePath
.Buffer
[1] == ':')))
609 UnicodeFilePath
.Length
-= sizeof(WCHAR
);
610 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
612 memcpy(FilePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
613 FilePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
615 if (!GetFullPathNameW(FilePathName
, PathLength
, FullFilePath
, &FilePart
))
622 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
623 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
624 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
625 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
630 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
634 if (UnicodeFilePath
.Length
> (cchBufferLength
* sizeof(WCHAR
)) - sizeof(WCHAR
))
636 ErrorCode
= ERROR_FILENAME_EXCED_RANGE
;
640 memcpy(lpszVolumePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
641 lpszVolumePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
647 SetLastError(ErrorCode
);
649 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
650 RtlFreeHeap(RtlGetProcessHeap(), 0, FilePathName
);
659 FindNextVolumeA(IN HANDLE handle
,
663 WCHAR
*buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, len
* sizeof(WCHAR
));
668 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
672 if ((ret
= FindNextVolumeW( handle
, buffer
, len
)))
674 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
)) ret
= FALSE
;
677 RtlFreeHeap(RtlGetProcessHeap(), 0, buffer
);
686 FindNextVolumeW(IN HANDLE handle
,
690 MOUNTMGR_MOUNT_POINTS
*data
= handle
;
692 while (data
->Size
< data
->NumberOfMountPoints
)
694 static const WCHAR volumeW
[] = {'\\','?','?','\\','V','o','l','u','m','e','{',};
695 WCHAR
*link
= (WCHAR
*)((char *)data
+ data
->MountPoints
[data
->Size
].SymbolicLinkNameOffset
);
696 DWORD size
= data
->MountPoints
[data
->Size
].SymbolicLinkNameLength
;
698 /* skip non-volumes */
699 if (size
< sizeof(volumeW
) || memcmp( link
, volumeW
, sizeof(volumeW
) )) continue;
700 if (size
+ sizeof(WCHAR
) >= len
* sizeof(WCHAR
))
702 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
705 memcpy( volume
, link
, size
);
706 volume
[1] = '\\'; /* map \??\ to \\?\ */
707 volume
[size
/ sizeof(WCHAR
)] = '\\'; /* Windows appends a backslash */
708 volume
[size
/ sizeof(WCHAR
) + 1] = 0;
709 DPRINT( "returning entry %u %s\n", data
->Size
- 1, volume
);
712 SetLastError( ERROR_NO_MORE_FILES
);
721 GetVolumePathNamesForVolumeNameA(IN LPCSTR lpszVolumeName
,
722 IN LPSTR lpszVolumePathNames
,
723 IN DWORD cchBufferLength
,
724 OUT PDWORD lpcchReturnLength
)
736 GetVolumePathNamesForVolumeNameW(IN LPCWSTR lpszVolumeName
,
737 IN LPWSTR lpszVolumePathNames
,
738 IN DWORD cchBufferLength
,
739 OUT PDWORD lpcchReturnLength
)