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
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
,
430 HANDLE mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
431 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, INVALID_HANDLE_VALUE
);
432 if (mgr
== INVALID_HANDLE_VALUE
) return INVALID_HANDLE_VALUE
;
436 MOUNTMGR_MOUNT_POINT input
;
437 MOUNTMGR_MOUNT_POINTS
*output
;
439 if (!(output
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
441 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
444 memset( &input
, 0, sizeof(input
) );
446 if (!DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_POINTS
, &input
, sizeof(input
),
447 output
, size
, &br
, NULL
))
449 if (GetLastError() != ERROR_MORE_DATA
) break;
451 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
455 /* abuse the Size field to store the current index */
457 if (!FindNextVolumeW( output
, volume
, len
))
459 RtlFreeHeap( RtlGetProcessHeap(), 0, output
);
460 return INVALID_HANDLE_VALUE
;
462 return (HANDLE
)output
;
465 return INVALID_HANDLE_VALUE
;
469 * @implemented (Wine 13 sep 2008)
473 FindFirstVolumeA(IN LPSTR volume
,
476 WCHAR
*buffer
= NULL
;
479 buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0, len
* sizeof(WCHAR
) );
483 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
484 return INVALID_HANDLE_VALUE
;
487 handle
= FindFirstVolumeW( buffer
, len
);
489 if (handle
!= INVALID_HANDLE_VALUE
)
491 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
))
493 FindVolumeClose( handle
);
494 handle
= INVALID_HANDLE_VALUE
;
497 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer
);
502 * @implemented (Wine 13 sep 2008)
506 FindVolumeClose(IN HANDLE hFindVolume
)
508 return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume
);
516 GetVolumePathNameA(IN LPCSTR lpszFileName
,
517 IN LPSTR lpszVolumePathName
,
518 IN DWORD cchBufferLength
)
520 PWCHAR FileNameW
= NULL
;
521 WCHAR VolumePathName
[MAX_PATH
];
526 if (!(FileNameW
= FilenameA2W(lpszFileName
, FALSE
)))
530 Result
= GetVolumePathNameW(FileNameW
, VolumePathName
, cchBufferLength
);
533 FilenameW2A_N(lpszVolumePathName
, MAX_PATH
, VolumePathName
, -1);
543 GetVolumePathNameW(IN LPCWSTR lpszFileName
,
544 IN LPWSTR lpszVolumePathName
,
545 IN DWORD cchBufferLength
)
548 UNICODE_STRING UnicodeFilePath
;
550 PWSTR FullFilePath
, FilePathName
;
552 WCHAR VolumeName
[MAX_PATH
];
556 if (!lpszFileName
|| !lpszVolumePathName
|| !cchBufferLength
)
558 SetLastError(ERROR_INVALID_PARAMETER
);
562 if (!(PathLength
= GetFullPathNameW(lpszFileName
, 0, NULL
, NULL
)))
568 PathLength
= PathLength
+ 10;
569 PathSize
= PathLength
* sizeof(WCHAR
);
571 if (!(FullFilePath
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
573 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
577 if (!GetFullPathNameW(lpszFileName
, PathLength
, FullFilePath
, &FilePart
))
579 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
583 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
585 if (UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] != '\\')
587 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
588 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
589 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
592 if (!(FilePathName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize
)))
594 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
595 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
599 while (!GetVolumeNameForVolumeMountPointW(UnicodeFilePath
.Buffer
,
603 if (((UnicodeFilePath
.Length
== 4) && (UnicodeFilePath
.Buffer
[0] == '\\') &&
604 (UnicodeFilePath
.Buffer
[1] == '\\')) || ((UnicodeFilePath
.Length
== 6) &&
605 (UnicodeFilePath
.Buffer
[1] == ':')))
610 UnicodeFilePath
.Length
-= sizeof(WCHAR
);
611 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
613 memcpy(FilePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
614 FilePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
616 if (!GetFullPathNameW(FilePathName
, PathLength
, FullFilePath
, &FilePart
))
623 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
624 UnicodeFilePath
.Length
+= sizeof(WCHAR
);
625 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
) - 1] = '\\';
626 UnicodeFilePath
.Buffer
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
631 RtlInitUnicodeString(&UnicodeFilePath
, FullFilePath
);
635 if (UnicodeFilePath
.Length
> (cchBufferLength
* sizeof(WCHAR
)) - sizeof(WCHAR
))
637 ErrorCode
= ERROR_FILENAME_EXCED_RANGE
;
641 memcpy(lpszVolumePathName
, UnicodeFilePath
.Buffer
, UnicodeFilePath
.Length
);
642 lpszVolumePathName
[UnicodeFilePath
.Length
/ sizeof(WCHAR
)] = '\0';
648 SetLastError(ErrorCode
);
650 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath
);
651 RtlFreeHeap(RtlGetProcessHeap(), 0, FilePathName
);
660 FindNextVolumeA(IN HANDLE handle
,
664 WCHAR
*buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, len
* sizeof(WCHAR
));
669 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
673 if ((ret
= FindNextVolumeW( handle
, buffer
, len
)))
675 if (!WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, volume
, len
, NULL
, NULL
)) ret
= FALSE
;
678 RtlFreeHeap(RtlGetProcessHeap(), 0, buffer
);
687 FindNextVolumeW(IN HANDLE handle
,
691 MOUNTMGR_MOUNT_POINTS
*data
= handle
;
693 while (data
->Size
< data
->NumberOfMountPoints
)
695 static const WCHAR volumeW
[] = {'\\','?','?','\\','V','o','l','u','m','e','{',};
696 WCHAR
*link
= (WCHAR
*)((char *)data
+ data
->MountPoints
[data
->Size
].SymbolicLinkNameOffset
);
697 DWORD size
= data
->MountPoints
[data
->Size
].SymbolicLinkNameLength
;
699 /* skip non-volumes */
700 if (size
< sizeof(volumeW
) || memcmp( link
, volumeW
, sizeof(volumeW
) )) continue;
701 if (size
+ sizeof(WCHAR
) >= len
* sizeof(WCHAR
))
703 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
706 memcpy( volume
, link
, size
);
707 volume
[1] = '\\'; /* map \??\ to \\?\ */
708 volume
[size
/ sizeof(WCHAR
)] = '\\'; /* Windows appends a backslash */
709 volume
[size
/ sizeof(WCHAR
) + 1] = 0;
710 DPRINT( "returning entry %u %s\n", data
->Size
- 1, volume
);
713 SetLastError( ERROR_NO_MORE_FILES
);
722 GetVolumePathNamesForVolumeNameA(IN LPCSTR lpszVolumeName
,
723 IN LPSTR lpszVolumePathNames
,
724 IN DWORD cchBufferLength
,
725 OUT PDWORD lpcchReturnLength
)
737 GetVolumePathNamesForVolumeNameW(IN LPCWSTR lpszVolumeName
,
738 IN LPWSTR lpszVolumePathNames
,
739 IN DWORD cchBufferLength
,
740 OUT PDWORD lpcchReturnLength
)