mirror of
https://github.com/reactos/reactos.git
synced 2024-06-11 06:55:21 +00:00
126768af64
svn path=/trunk/; revision=527
523 lines
13 KiB
C
523 lines
13 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 :
|
|
* DRIVE_IsValid, 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 <windows.h>
|
|
#include <ddk/ntddk.h>
|
|
#include <wchar.h>
|
|
#include <string.h>
|
|
|
|
#define NDEBUG
|
|
#include <kernel32/kernel32.h>
|
|
|
|
|
|
#define MAX_DOS_DRIVES 26
|
|
|
|
|
|
int DRIVE_IsValid( int drive )
|
|
{
|
|
char Drives[4];
|
|
Drives[0] = 'A';
|
|
Drives[1] = ':';
|
|
Drives[2] = '\\';
|
|
Drives[3] = 0;
|
|
|
|
Drives[0] = 'A' + drive -1;
|
|
if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
|
|
if ( CreateFileA(Drives,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS|FILE_ATTRIBUTE_DIRECTORY,NULL) == INVALID_HANDLE_VALUE ) {
|
|
return 0;
|
|
}
|
|
return drive;
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
STDCALL
|
|
GetLogicalDriveStringsA(
|
|
DWORD nBufferLength,
|
|
LPSTR lpBuffer
|
|
)
|
|
{
|
|
int drive, count;
|
|
|
|
for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
|
|
if (DRIVE_IsValid(drive)) count++;
|
|
if (count * 4 * sizeof(char) <= nBufferLength)
|
|
{
|
|
LPSTR p = lpBuffer;
|
|
for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
|
|
if (DRIVE_IsValid(drive))
|
|
{
|
|
*p++ = 'A' + drive;
|
|
*p++ = ':';
|
|
*p++ = '\\';
|
|
*p++ = '\0';
|
|
}
|
|
*p = '\0';
|
|
}
|
|
return count * 4 * sizeof(char);
|
|
}
|
|
|
|
|
|
DWORD
|
|
STDCALL
|
|
GetLogicalDriveStringsW(
|
|
DWORD nBufferLength,
|
|
LPWSTR lpBuffer
|
|
)
|
|
{
|
|
int drive, count;
|
|
|
|
for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
|
|
if (DRIVE_IsValid(drive)) count++;
|
|
if (count * 4 * sizeof(WCHAR) <= nBufferLength)
|
|
{
|
|
LPWSTR p = lpBuffer;
|
|
for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
|
|
if (DRIVE_IsValid(drive))
|
|
{
|
|
*p++ = (WCHAR)('A' + drive);
|
|
*p++ = (WCHAR)':';
|
|
*p++ = (WCHAR)'\\';
|
|
*p++ = (WCHAR)'\0';
|
|
}
|
|
*p = (WCHAR)'\0';
|
|
}
|
|
return count * 4 * sizeof(WCHAR);
|
|
}
|
|
|
|
|
|
DWORD
|
|
STDCALL
|
|
GetLogicalDrives(VOID)
|
|
{
|
|
DWORD ret = 0;
|
|
int drive;
|
|
|
|
for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
|
|
if (DRIVE_IsValid(drive)) ret |= (1 << drive);
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
WINBOOL
|
|
STDCALL
|
|
GetDiskFreeSpaceA(
|
|
LPCSTR lpRootPathName,
|
|
LPDWORD lpSectorsPerCluster,
|
|
LPDWORD lpBytesPerSector,
|
|
LPDWORD lpNumberOfFreeClusters,
|
|
LPDWORD lpTotalNumberOfClusters
|
|
)
|
|
{
|
|
WCHAR RootPathNameW[MAX_PATH];
|
|
|
|
if (lpRootPathName)
|
|
{
|
|
ULONG i = 0;
|
|
while ((*lpRootPathName)!=0 && i < MAX_PATH)
|
|
{
|
|
RootPathNameW[i] = *lpRootPathName;
|
|
lpRootPathName++;
|
|
i++;
|
|
}
|
|
RootPathNameW[i] = 0;
|
|
}
|
|
|
|
return GetDiskFreeSpaceW(lpRootPathName?RootPathNameW:NULL,
|
|
lpSectorsPerCluster,
|
|
lpBytesPerSector,
|
|
lpNumberOfFreeClusters,
|
|
lpTotalNumberOfClusters);
|
|
}
|
|
|
|
WINBOOL
|
|
STDCALL
|
|
GetDiskFreeSpaceW(
|
|
LPCWSTR lpRootPathName,
|
|
LPDWORD lpSectorsPerCluster,
|
|
LPDWORD lpBytesPerSector,
|
|
LPDWORD lpNumberOfFreeClusters,
|
|
LPDWORD lpTotalNumberOfClusters
|
|
)
|
|
{
|
|
FILE_FS_SIZE_INFORMATION FileFsSize;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
WCHAR RootPathName[MAX_PATH];
|
|
HANDLE hFile;
|
|
NTSTATUS errCode;
|
|
|
|
if (lpRootPathName)
|
|
{
|
|
wcsncpy (RootPathName, lpRootPathName, 3);
|
|
}
|
|
else
|
|
{
|
|
GetCurrentDirectoryW (MAX_PATH, RootPathName);
|
|
RootPathName[3] = 0;
|
|
}
|
|
|
|
hFile = CreateFileW(RootPathName,
|
|
FILE_READ_ATTRIBUTES,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
errCode = NtQueryVolumeInformationFile(hFile,
|
|
&IoStatusBlock,
|
|
&FileFsSize,
|
|
sizeof(FILE_FS_SIZE_INFORMATION),
|
|
FileFsSizeInformation);
|
|
if (!NT_SUCCESS(errCode))
|
|
{
|
|
CloseHandle(hFile);
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
return FALSE;
|
|
}
|
|
|
|
*lpBytesPerSector = FileFsSize.BytesPerSector;
|
|
*lpSectorsPerCluster = FileFsSize.SectorsPerAllocationUnit;
|
|
*lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.u.LowPart;
|
|
*lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.u.LowPart;
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
|
|
WINBOOL
|
|
STDCALL
|
|
GetDiskFreeSpaceExA(
|
|
LPCSTR lpDirectoryName,
|
|
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
|
|
PULARGE_INTEGER lpTotalNumberOfBytes,
|
|
PULARGE_INTEGER lpTotalNumberOfFreeBytes
|
|
)
|
|
{
|
|
WCHAR DirectoryNameW[MAX_PATH];
|
|
|
|
if (lpDirectoryName)
|
|
{
|
|
ULONG i = 0;
|
|
while ((*lpDirectoryName)!=0 && i < MAX_PATH)
|
|
{
|
|
DirectoryNameW[i] = *lpDirectoryName;
|
|
lpDirectoryName++;
|
|
i++;
|
|
}
|
|
DirectoryNameW[i] = 0;
|
|
}
|
|
|
|
return GetDiskFreeSpaceExW(lpDirectoryName?DirectoryNameW:NULL,
|
|
lpFreeBytesAvailableToCaller,
|
|
lpTotalNumberOfBytes,
|
|
lpTotalNumberOfFreeBytes);
|
|
}
|
|
|
|
|
|
WINBOOL
|
|
STDCALL
|
|
GetDiskFreeSpaceExW(
|
|
LPCWSTR lpDirectoryName,
|
|
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
|
|
PULARGE_INTEGER lpTotalNumberOfBytes,
|
|
PULARGE_INTEGER lpTotalNumberOfFreeBytes
|
|
)
|
|
{
|
|
FILE_FS_SIZE_INFORMATION FileFsSize;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
ULARGE_INTEGER BytesPerCluster;
|
|
WCHAR RootPathName[MAX_PATH];
|
|
HANDLE hFile;
|
|
NTSTATUS errCode;
|
|
|
|
if (lpDirectoryName)
|
|
{
|
|
wcsncpy (RootPathName, lpDirectoryName, 3);
|
|
}
|
|
else
|
|
{
|
|
GetCurrentDirectoryW (MAX_PATH, RootPathName);
|
|
RootPathName[3] = 0;
|
|
}
|
|
|
|
hFile = CreateFileW(RootPathName,
|
|
FILE_READ_ATTRIBUTES,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
errCode = NtQueryVolumeInformationFile(hFile,
|
|
&IoStatusBlock,
|
|
&FileFsSize,
|
|
sizeof(FILE_FS_SIZE_INFORMATION),
|
|
FileFsSizeInformation);
|
|
if (!NT_SUCCESS(errCode))
|
|
{
|
|
CloseHandle(hFile);
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
return FALSE;
|
|
}
|
|
|
|
BytesPerCluster.QuadPart =
|
|
FileFsSize.BytesPerSector * FileFsSize.SectorsPerAllocationUnit;
|
|
|
|
// FIXME: Use quota information
|
|
lpFreeBytesAvailableToCaller->QuadPart =
|
|
BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
|
|
|
|
lpTotalNumberOfBytes->QuadPart =
|
|
BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.QuadPart;
|
|
lpTotalNumberOfFreeBytes->QuadPart =
|
|
BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
|
|
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
UINT
|
|
STDCALL
|
|
GetDriveTypeA(
|
|
LPCSTR lpRootPathName
|
|
)
|
|
{
|
|
ULONG i;
|
|
WCHAR RootPathNameW[MAX_PATH];
|
|
i = 0;
|
|
while ((*lpRootPathName)!=0 && i < MAX_PATH)
|
|
{
|
|
RootPathNameW[i] = *lpRootPathName;
|
|
lpRootPathName++;
|
|
i++;
|
|
}
|
|
RootPathNameW[i] = 0;
|
|
return GetDriveTypeW(RootPathNameW);
|
|
}
|
|
|
|
UINT
|
|
STDCALL
|
|
GetDriveTypeW(
|
|
LPCWSTR lpRootPathName
|
|
)
|
|
{
|
|
FILE_FS_DEVICE_INFORMATION FileFsDevice;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
HANDLE hFile;
|
|
NTSTATUS errCode;
|
|
|
|
hFile = CreateFileW(
|
|
lpRootPathName,
|
|
GENERIC_ALL,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
errCode = NtQueryVolumeInformationFile(hFile,&IoStatusBlock,&FileFsDevice, sizeof(FILE_FS_DEVICE_INFORMATION),FileFsDeviceInformation);
|
|
if ( !NT_SUCCESS(errCode) ) {
|
|
CloseHandle(hFile);
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
return 0;
|
|
}
|
|
CloseHandle(hFile);
|
|
return (UINT)FileFsDevice.DeviceType;
|
|
|
|
|
|
|
|
}
|
|
|
|
WINBOOL
|
|
STDCALL
|
|
GetVolumeInformationA(
|
|
LPCSTR lpRootPathName,
|
|
LPSTR lpVolumeNameBuffer,
|
|
DWORD nVolumeNameSize,
|
|
LPDWORD lpVolumeSerialNumber,
|
|
LPDWORD lpMaximumComponentLength,
|
|
LPDWORD lpFileSystemFlags,
|
|
LPSTR lpFileSystemNameBuffer,
|
|
DWORD nFileSystemNameSize
|
|
)
|
|
{
|
|
ULONG i;
|
|
WCHAR RootPathNameW[MAX_PATH];
|
|
WCHAR VolumeNameBufferW[MAX_PATH];
|
|
WCHAR FileSystemNameBufferW[MAX_PATH];
|
|
|
|
|
|
i = 0;
|
|
while ((*lpRootPathName)!=0 && i < MAX_PATH)
|
|
{
|
|
RootPathNameW[i] = *lpRootPathName;
|
|
lpRootPathName++;
|
|
i++;
|
|
}
|
|
RootPathNameW[i] = 0;
|
|
|
|
if ( GetVolumeInformationW(RootPathNameW,
|
|
VolumeNameBufferW,
|
|
nVolumeNameSize,
|
|
lpVolumeSerialNumber,
|
|
lpMaximumComponentLength,
|
|
lpFileSystemFlags,
|
|
FileSystemNameBufferW,
|
|
nFileSystemNameSize ) ) {
|
|
for(i=0;i<nVolumeNameSize;i++)
|
|
lpVolumeNameBuffer[i] = (CHAR)VolumeNameBufferW[i];
|
|
|
|
for(i=0;i<nFileSystemNameSize;i++)
|
|
lpFileSystemNameBuffer[i] = (CHAR)FileSystemNameBufferW[i];
|
|
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define FS_VOLUME_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_VOLUME_INFORMATION))
|
|
|
|
#define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
|
|
|
|
|
|
WINBOOL
|
|
STDCALL
|
|
GetVolumeInformationW(
|
|
LPCWSTR lpRootPathName,
|
|
LPWSTR lpVolumeNameBuffer,
|
|
DWORD nVolumeNameSize,
|
|
LPDWORD lpVolumeSerialNumber,
|
|
LPDWORD lpMaximumComponentLength,
|
|
LPDWORD lpFileSystemFlags,
|
|
LPWSTR lpFileSystemNameBuffer,
|
|
DWORD nFileSystemNameSize
|
|
)
|
|
{
|
|
PFILE_FS_VOLUME_INFORMATION FileFsVolume;
|
|
PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
USHORT Buffer[FS_VOLUME_BUFFER_SIZE];
|
|
USHORT Buffer2[FS_ATTRIBUTE_BUFFER_SIZE];
|
|
|
|
HANDLE hFile;
|
|
NTSTATUS errCode;
|
|
|
|
FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
|
|
FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer2;
|
|
|
|
DPRINT("FileFsVolume %p\n", FileFsVolume);
|
|
DPRINT("FileFsAttribute %p\n", FileFsAttribute);
|
|
|
|
hFile = CreateFileW(lpRootPathName,
|
|
FILE_READ_ATTRIBUTES,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
DPRINT("hFile: %x\n", hFile);
|
|
errCode = NtQueryVolumeInformationFile(hFile,
|
|
&IoStatusBlock,
|
|
FileFsVolume,
|
|
FS_VOLUME_BUFFER_SIZE,
|
|
FileFsVolumeInformation);
|
|
if ( !NT_SUCCESS(errCode) ) {
|
|
DPRINT("Status: %x\n", errCode);
|
|
CloseHandle(hFile);
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
return FALSE;
|
|
}
|
|
|
|
if (lpVolumeSerialNumber)
|
|
*lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
|
|
|
|
if (lpVolumeNameBuffer)
|
|
wcsncpy(lpVolumeNameBuffer, FileFsVolume->VolumeLabel,min(nVolumeNameSize,MAX_PATH));
|
|
|
|
errCode = NtQueryVolumeInformationFile(hFile,&IoStatusBlock,FileFsAttribute, FS_ATTRIBUTE_BUFFER_SIZE,FileFsAttributeInformation);
|
|
if ( !NT_SUCCESS(errCode) ) {
|
|
DPRINT("Status: %x\n", errCode);
|
|
CloseHandle(hFile);
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
return FALSE;
|
|
}
|
|
|
|
if (lpFileSystemFlags)
|
|
*lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
|
|
if (lpMaximumComponentLength)
|
|
*lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
|
|
if (lpFileSystemNameBuffer)
|
|
wcsncpy(lpFileSystemNameBuffer, FileFsAttribute->FileSystemName,min(nFileSystemNameSize,MAX_PATH));
|
|
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
|
|
WINBOOL
|
|
STDCALL
|
|
SetVolumeLabelA(
|
|
LPCSTR lpRootPathName,
|
|
LPCSTR lpVolumeName
|
|
)
|
|
{
|
|
WCHAR RootPathNameW[MAX_PATH];
|
|
WCHAR VolumeNameW[MAX_PATH];
|
|
UINT i;
|
|
|
|
i = 0;
|
|
while ((*lpRootPathName)!=0 && i < MAX_PATH)
|
|
{
|
|
RootPathNameW[i] = *lpRootPathName;
|
|
lpRootPathName++;
|
|
i++;
|
|
}
|
|
RootPathNameW[i] = 0;
|
|
|
|
i = 0;
|
|
while ((*lpVolumeName)!=0 && i < MAX_PATH)
|
|
{
|
|
VolumeNameW[i] = *lpVolumeName;
|
|
lpVolumeName++;
|
|
i++;
|
|
}
|
|
VolumeNameW[i] = 0;
|
|
return SetVolumeLabelW(RootPathNameW,VolumeNameW);
|
|
}
|
|
|
|
WINBOOL
|
|
STDCALL
|
|
SetVolumeLabelW(
|
|
LPCWSTR lpRootPathName,
|
|
LPCWSTR lpVolumeName
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|