mirror of
https://github.com/reactos/reactos.git
synced 2024-10-31 11:56:26 +00:00
ed55d73cfd
svn path=/branches/ntvdm/; revision=59679
740 lines
20 KiB
C
740 lines
20 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: lib/kernel32/file/volume.c
|
|
* PURPOSE: File volume functions
|
|
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
|
|
* Erik Bos, Alexandre Julliard :
|
|
* GetLogicalDriveStringsA,
|
|
* GetLogicalDriveStringsW, GetLogicalDrives
|
|
* UPDATE HISTORY:
|
|
* Created 01/11/98
|
|
*/
|
|
//WINE copyright notice:
|
|
/*
|
|
* DOS drives handling functions
|
|
*
|
|
* Copyright 1993 Erik Bos
|
|
* Copyright 1996 Alexandre Julliard
|
|
*/
|
|
|
|
#include <k32.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
DEBUG_CHANNEL(kernel32file);
|
|
|
|
HANDLE
|
|
WINAPI
|
|
InternalOpenDirW(IN LPCWSTR DirName,
|
|
IN BOOLEAN Write)
|
|
{
|
|
UNICODE_STRING NtPathU;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS errCode;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
HANDLE hFile;
|
|
|
|
if (!RtlDosPathNameToNtPathName_U(DirName, &NtPathU, NULL, NULL))
|
|
{
|
|
WARN("Invalid path\n");
|
|
SetLastError(ERROR_BAD_PATHNAME);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&NtPathU,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
errCode = NtCreateFile(&hFile,
|
|
Write ? FILE_GENERIC_WRITE : FILE_GENERIC_READ,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN,
|
|
0,
|
|
NULL,
|
|
0);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU.Buffer);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
{
|
|
BaseSetLastNTError(errCode);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return hFile;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetVolumeInformationA(IN LPCSTR lpRootPathName,
|
|
IN LPSTR lpVolumeNameBuffer,
|
|
IN DWORD nVolumeNameSize,
|
|
OUT LPDWORD lpVolumeSerialNumber OPTIONAL,
|
|
OUT LPDWORD lpMaximumComponentLength OPTIONAL,
|
|
OUT LPDWORD lpFileSystemFlags OPTIONAL,
|
|
OUT LPSTR lpFileSystemNameBuffer OPTIONAL,
|
|
IN DWORD nFileSystemNameSize)
|
|
{
|
|
UNICODE_STRING FileSystemNameU;
|
|
UNICODE_STRING VolumeNameU = { 0, 0, NULL };
|
|
ANSI_STRING VolumeName;
|
|
ANSI_STRING FileSystemName;
|
|
PWCHAR RootPathNameW;
|
|
BOOL Result;
|
|
|
|
if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
|
|
return FALSE;
|
|
|
|
if (lpVolumeNameBuffer)
|
|
{
|
|
VolumeNameU.MaximumLength = (USHORT)nVolumeNameSize * sizeof(WCHAR);
|
|
VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
|
|
0,
|
|
VolumeNameU.MaximumLength);
|
|
if (VolumeNameU.Buffer == NULL)
|
|
{
|
|
goto FailNoMem;
|
|
}
|
|
}
|
|
|
|
if (lpFileSystemNameBuffer)
|
|
{
|
|
FileSystemNameU.Length = 0;
|
|
FileSystemNameU.MaximumLength = (USHORT)nFileSystemNameSize * sizeof(WCHAR);
|
|
FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
|
|
0,
|
|
FileSystemNameU.MaximumLength);
|
|
if (FileSystemNameU.Buffer == NULL)
|
|
{
|
|
if (VolumeNameU.Buffer != NULL)
|
|
{
|
|
RtlFreeHeap(RtlGetProcessHeap(),
|
|
0,
|
|
VolumeNameU.Buffer);
|
|
}
|
|
|
|
FailNoMem:
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
Result = GetVolumeInformationW (RootPathNameW,
|
|
lpVolumeNameBuffer ? VolumeNameU.Buffer : NULL,
|
|
nVolumeNameSize,
|
|
lpVolumeSerialNumber,
|
|
lpMaximumComponentLength,
|
|
lpFileSystemFlags,
|
|
lpFileSystemNameBuffer ? FileSystemNameU.Buffer : NULL,
|
|
nFileSystemNameSize);
|
|
|
|
if (Result)
|
|
{
|
|
if (lpVolumeNameBuffer)
|
|
{
|
|
VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR);
|
|
VolumeName.Length = 0;
|
|
VolumeName.MaximumLength = (USHORT)nVolumeNameSize;
|
|
VolumeName.Buffer = lpVolumeNameBuffer;
|
|
}
|
|
|
|
if (lpFileSystemNameBuffer)
|
|
{
|
|
FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR);
|
|
FileSystemName.Length = 0;
|
|
FileSystemName.MaximumLength = (USHORT)nFileSystemNameSize;
|
|
FileSystemName.Buffer = lpFileSystemNameBuffer;
|
|
}
|
|
|
|
/* convert unicode strings to ansi (or oem) */
|
|
if (bIsFileApiAnsi)
|
|
{
|
|
if (lpVolumeNameBuffer)
|
|
{
|
|
RtlUnicodeStringToAnsiString (&VolumeName,
|
|
&VolumeNameU,
|
|
FALSE);
|
|
}
|
|
if (lpFileSystemNameBuffer)
|
|
{
|
|
RtlUnicodeStringToAnsiString (&FileSystemName,
|
|
&FileSystemNameU,
|
|
FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (lpVolumeNameBuffer)
|
|
{
|
|
RtlUnicodeStringToOemString (&VolumeName,
|
|
&VolumeNameU,
|
|
FALSE);
|
|
}
|
|
if (lpFileSystemNameBuffer)
|
|
{
|
|
RtlUnicodeStringToOemString (&FileSystemName,
|
|
&FileSystemNameU,
|
|
FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpVolumeNameBuffer)
|
|
{
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
0,
|
|
VolumeNameU.Buffer);
|
|
}
|
|
if (lpFileSystemNameBuffer)
|
|
{
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
0,
|
|
FileSystemNameU.Buffer);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
#define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
|
|
|
|
#define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetVolumeInformationW(IN LPCWSTR lpRootPathName,
|
|
IN LPWSTR lpVolumeNameBuffer,
|
|
IN DWORD nVolumeNameSize,
|
|
OUT LPDWORD lpVolumeSerialNumber OPTIONAL,
|
|
OUT LPDWORD lpMaximumComponentLength OPTIONAL,
|
|
OUT LPDWORD lpFileSystemFlags OPTIONAL,
|
|
OUT LPWSTR lpFileSystemNameBuffer OPTIONAL,
|
|
IN DWORD nFileSystemNameSize)
|
|
{
|
|
PFILE_FS_VOLUME_INFORMATION FileFsVolume;
|
|
PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
WCHAR RootPathName[MAX_PATH];
|
|
UCHAR Buffer[max(FS_VOLUME_BUFFER_SIZE, FS_ATTRIBUTE_BUFFER_SIZE)];
|
|
|
|
HANDLE hFile;
|
|
NTSTATUS errCode;
|
|
|
|
FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
|
|
FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
|
|
|
|
TRACE("FileFsVolume %p\n", FileFsVolume);
|
|
TRACE("FileFsAttribute %p\n", FileFsAttribute);
|
|
|
|
if (!lpRootPathName || !wcscmp(lpRootPathName, L""))
|
|
{
|
|
GetCurrentDirectoryW (MAX_PATH, RootPathName);
|
|
}
|
|
else
|
|
{
|
|
wcsncpy (RootPathName, lpRootPathName, 3);
|
|
}
|
|
RootPathName[3] = 0;
|
|
|
|
hFile = InternalOpenDirW(RootPathName, FALSE);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
TRACE("hFile: %x\n", hFile);
|
|
errCode = NtQueryVolumeInformationFile(hFile,
|
|
&IoStatusBlock,
|
|
FileFsVolume,
|
|
FS_VOLUME_BUFFER_SIZE,
|
|
FileFsVolumeInformation);
|
|
if ( !NT_SUCCESS(errCode) )
|
|
{
|
|
WARN("Status: %x\n", errCode);
|
|
CloseHandle(hFile);
|
|
BaseSetLastNTError (errCode);
|
|
return FALSE;
|
|
}
|
|
|
|
if (lpVolumeSerialNumber)
|
|
*lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
|
|
|
|
if (lpVolumeNameBuffer)
|
|
{
|
|
if (nVolumeNameSize * sizeof(WCHAR) >= FileFsVolume->VolumeLabelLength + sizeof(WCHAR))
|
|
{
|
|
memcpy(lpVolumeNameBuffer,
|
|
FileFsVolume->VolumeLabel,
|
|
FileFsVolume->VolumeLabelLength);
|
|
lpVolumeNameBuffer[FileFsVolume->VolumeLabelLength / sizeof(WCHAR)] = 0;
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(hFile);
|
|
SetLastError(ERROR_MORE_DATA);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
errCode = NtQueryVolumeInformationFile (hFile,
|
|
&IoStatusBlock,
|
|
FileFsAttribute,
|
|
FS_ATTRIBUTE_BUFFER_SIZE,
|
|
FileFsAttributeInformation);
|
|
CloseHandle(hFile);
|
|
if (!NT_SUCCESS(errCode))
|
|
{
|
|
WARN("Status: %x\n", errCode);
|
|
BaseSetLastNTError (errCode);
|
|
return FALSE;
|
|
}
|
|
|
|
if (lpFileSystemFlags)
|
|
*lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
|
|
if (lpMaximumComponentLength)
|
|
*lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
|
|
if (lpFileSystemNameBuffer)
|
|
{
|
|
if (nFileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
|
|
{
|
|
memcpy(lpFileSystemNameBuffer,
|
|
FileFsAttribute->FileSystemName,
|
|
FileFsAttribute->FileSystemNameLength);
|
|
lpFileSystemNameBuffer[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_MORE_DATA);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
SetVolumeLabelA(IN LPCSTR lpRootPathName,
|
|
IN LPCSTR lpVolumeName OPTIONAL) /* NULL if deleting label */
|
|
{
|
|
PWCHAR RootPathNameW;
|
|
PWCHAR VolumeNameW = NULL;
|
|
BOOL Result;
|
|
|
|
if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
|
|
return FALSE;
|
|
|
|
if (lpVolumeName)
|
|
{
|
|
if (!(VolumeNameW = FilenameA2W(lpVolumeName, TRUE)))
|
|
return FALSE;
|
|
}
|
|
|
|
Result = SetVolumeLabelW (RootPathNameW,
|
|
VolumeNameW);
|
|
|
|
if (VolumeNameW)
|
|
{
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
0,
|
|
VolumeNameW );
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
SetVolumeLabelW(IN LPCWSTR lpRootPathName,
|
|
IN LPCWSTR lpVolumeName OPTIONAL) /* NULL if deleting label */
|
|
{
|
|
PFILE_FS_LABEL_INFORMATION LabelInfo;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
ULONG LabelLength;
|
|
HANDLE hFile;
|
|
NTSTATUS Status;
|
|
|
|
LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
|
|
LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
0,
|
|
sizeof(FILE_FS_LABEL_INFORMATION) +
|
|
LabelLength);
|
|
if (LabelInfo == NULL)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
LabelInfo->VolumeLabelLength = LabelLength;
|
|
memcpy(LabelInfo->VolumeLabel,
|
|
lpVolumeName,
|
|
LabelLength);
|
|
|
|
hFile = InternalOpenDirW(lpRootPathName, TRUE);
|
|
if (INVALID_HANDLE_VALUE == hFile)
|
|
{
|
|
RtlFreeHeap(RtlGetProcessHeap(),
|
|
0,
|
|
LabelInfo);
|
|
return FALSE;
|
|
}
|
|
|
|
Status = NtSetVolumeInformationFile(hFile,
|
|
&IoStatusBlock,
|
|
LabelInfo,
|
|
sizeof(FILE_FS_LABEL_INFORMATION) +
|
|
LabelLength,
|
|
FileFsLabelInformation);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(),
|
|
0,
|
|
LabelInfo);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
WARN("Status: %x\n", Status);
|
|
CloseHandle(hFile);
|
|
BaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented (Wine 13 sep 2008)
|
|
*/
|
|
HANDLE
|
|
WINAPI
|
|
FindFirstVolumeW(IN LPWSTR volume,
|
|
IN DWORD len)
|
|
{
|
|
DWORD size = 1024;
|
|
HANDLE mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE );
|
|
if (mgr == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
|
|
|
|
for (;;)
|
|
{
|
|
MOUNTMGR_MOUNT_POINT input;
|
|
MOUNTMGR_MOUNT_POINTS *output;
|
|
|
|
if (!(output = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
|
|
{
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
break;
|
|
}
|
|
memset( &input, 0, sizeof(input) );
|
|
|
|
if (!DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_POINTS, &input, sizeof(input),
|
|
output, size, NULL, NULL ))
|
|
{
|
|
if (GetLastError() != ERROR_MORE_DATA) break;
|
|
size = output->Size;
|
|
RtlFreeHeap( RtlGetProcessHeap(), 0, output );
|
|
continue;
|
|
}
|
|
CloseHandle( mgr );
|
|
/* abuse the Size field to store the current index */
|
|
output->Size = 0;
|
|
if (!FindNextVolumeW( output, volume, len ))
|
|
{
|
|
RtlFreeHeap( RtlGetProcessHeap(), 0, output );
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
return (HANDLE)output;
|
|
}
|
|
CloseHandle( mgr );
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented (Wine 13 sep 2008)
|
|
*/
|
|
HANDLE
|
|
WINAPI
|
|
FindFirstVolumeA(IN LPSTR volume,
|
|
IN DWORD len)
|
|
{
|
|
WCHAR *buffer = NULL;
|
|
HANDLE handle;
|
|
|
|
buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0, len * sizeof(WCHAR) );
|
|
|
|
if (!buffer)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
handle = FindFirstVolumeW( buffer, len );
|
|
|
|
if (handle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, volume, len, NULL, NULL ))
|
|
{
|
|
FindVolumeClose( handle );
|
|
handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
|
|
return handle;
|
|
}
|
|
|
|
/*
|
|
* @implemented (Wine 13 sep 2008)
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
FindVolumeClose(IN HANDLE hFindVolume)
|
|
{
|
|
return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetVolumePathNameA(IN LPCSTR lpszFileName,
|
|
IN LPSTR lpszVolumePathName,
|
|
IN DWORD cchBufferLength)
|
|
{
|
|
PWCHAR FileNameW = NULL;
|
|
WCHAR VolumePathName[MAX_PATH];
|
|
BOOL Result;
|
|
|
|
if (lpszFileName)
|
|
{
|
|
if (!(FileNameW = FilenameA2W(lpszFileName, FALSE)))
|
|
return FALSE;
|
|
}
|
|
|
|
Result = GetVolumePathNameW(FileNameW, VolumePathName, cchBufferLength);
|
|
|
|
if (Result)
|
|
FilenameW2A_N(lpszVolumePathName, MAX_PATH, VolumePathName, -1);
|
|
|
|
return Result;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetVolumePathNameW(IN LPCWSTR lpszFileName,
|
|
IN LPWSTR lpszVolumePathName,
|
|
IN DWORD cchBufferLength)
|
|
{
|
|
DWORD PathLength;
|
|
UNICODE_STRING UnicodeFilePath;
|
|
LPWSTR FilePart;
|
|
PWSTR FullFilePath, FilePathName;
|
|
ULONG PathSize;
|
|
WCHAR VolumeName[MAX_PATH];
|
|
DWORD ErrorCode;
|
|
BOOL Result = FALSE;
|
|
|
|
if (!(PathLength = GetFullPathNameW(lpszFileName, 0, NULL, NULL)))
|
|
{
|
|
return Result;
|
|
}
|
|
else
|
|
{
|
|
PathLength = PathLength + 10;
|
|
PathSize = PathLength * sizeof(WCHAR);
|
|
|
|
if (!(FullFilePath = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize)))
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return Result;
|
|
}
|
|
|
|
if (!GetFullPathNameW(lpszFileName, PathLength, FullFilePath, &FilePart))
|
|
{
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
|
|
return Result;
|
|
}
|
|
|
|
RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
|
|
|
|
if (UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] != '\\')
|
|
{
|
|
UnicodeFilePath.Length += sizeof(WCHAR);
|
|
UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] = '\\';
|
|
UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
|
|
}
|
|
|
|
if (!(FilePathName = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize)))
|
|
{
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return Result;
|
|
}
|
|
|
|
while (!GetVolumeNameForVolumeMountPointW(UnicodeFilePath.Buffer,
|
|
VolumeName,
|
|
MAX_PATH))
|
|
{
|
|
if (((UnicodeFilePath.Length == 4) && (UnicodeFilePath.Buffer[0] == '\\') &&
|
|
(UnicodeFilePath.Buffer[1] == '\\')) || ((UnicodeFilePath.Length == 6) &&
|
|
(UnicodeFilePath.Buffer[1] == ':')))
|
|
{
|
|
break;
|
|
}
|
|
|
|
UnicodeFilePath.Length -= sizeof(WCHAR);
|
|
UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
|
|
|
|
memcpy(FilePathName, UnicodeFilePath.Buffer, UnicodeFilePath.Length);
|
|
FilePathName[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
|
|
|
|
if (!GetFullPathNameW(FilePathName, PathLength, FullFilePath, &FilePart))
|
|
{
|
|
goto Cleanup2;
|
|
}
|
|
|
|
if (!FilePart)
|
|
{
|
|
RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
|
|
UnicodeFilePath.Length += sizeof(WCHAR);
|
|
UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] = '\\';
|
|
UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
|
|
break;
|
|
}
|
|
|
|
FilePart[0] = '\0';
|
|
RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
|
|
}
|
|
}
|
|
|
|
if (UnicodeFilePath.Length > (cchBufferLength * sizeof(WCHAR)) - sizeof(WCHAR))
|
|
{
|
|
ErrorCode = ERROR_FILENAME_EXCED_RANGE;
|
|
goto Cleanup1;
|
|
}
|
|
|
|
memcpy(lpszVolumePathName, UnicodeFilePath.Buffer, UnicodeFilePath.Length);
|
|
lpszVolumePathName[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
|
|
|
|
Result = TRUE;
|
|
goto Cleanup2;
|
|
|
|
Cleanup1:
|
|
SetLastError(ErrorCode);
|
|
Cleanup2:
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, FilePathName);
|
|
return Result;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
FindNextVolumeA(IN HANDLE handle,
|
|
IN LPSTR volume,
|
|
IN DWORD len)
|
|
{
|
|
WCHAR *buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
BOOL ret;
|
|
|
|
if (!buffer)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((ret = FindNextVolumeW( handle, buffer, len )))
|
|
{
|
|
if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, volume, len, NULL, NULL )) ret = FALSE;
|
|
}
|
|
|
|
HeapFree( GetProcessHeap(), 0, buffer );
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
FindNextVolumeW(IN HANDLE handle,
|
|
IN LPWSTR volume,
|
|
IN DWORD len)
|
|
{
|
|
MOUNTMGR_MOUNT_POINTS *data = handle;
|
|
|
|
while (data->Size < data->NumberOfMountPoints)
|
|
{
|
|
static const WCHAR volumeW[] = {'\\','?','?','\\','V','o','l','u','m','e','{',};
|
|
WCHAR *link = (WCHAR *)((char *)data + data->MountPoints[data->Size].SymbolicLinkNameOffset);
|
|
DWORD size = data->MountPoints[data->Size].SymbolicLinkNameLength;
|
|
data->Size++;
|
|
/* skip non-volumes */
|
|
if (size < sizeof(volumeW) || memcmp( link, volumeW, sizeof(volumeW) )) continue;
|
|
if (size + sizeof(WCHAR) >= len * sizeof(WCHAR))
|
|
{
|
|
SetLastError( ERROR_FILENAME_EXCED_RANGE );
|
|
return FALSE;
|
|
}
|
|
memcpy( volume, link, size );
|
|
volume[1] = '\\'; /* map \??\ to \\?\ */
|
|
volume[size / sizeof(WCHAR)] = '\\'; /* Windows appends a backslash */
|
|
volume[size / sizeof(WCHAR) + 1] = 0;
|
|
DPRINT( "returning entry %u %s\n", data->Size - 1, volume );
|
|
return TRUE;
|
|
}
|
|
SetLastError( ERROR_NO_MORE_FILES );
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetVolumePathNamesForVolumeNameA(IN LPCSTR lpszVolumeName,
|
|
IN LPSTR lpszVolumePathNames,
|
|
IN DWORD cchBufferLength,
|
|
OUT PDWORD lpcchReturnLength)
|
|
{
|
|
STUB;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetVolumePathNamesForVolumeNameW(IN LPCWSTR lpszVolumeName,
|
|
IN LPWSTR lpszVolumePathNames,
|
|
IN DWORD cchBufferLength,
|
|
OUT PDWORD lpcchReturnLength)
|
|
{
|
|
STUB;
|
|
return 0;
|
|
}
|
|
|
|
/* EOF */
|