/* $Id$ * * 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 #include #include #define NDEBUG #include #include #define MAX_DOS_DRIVES 26 HANDLE InternalOpenDirW(PWCHAR DirName, BOOLEAN Write) { UNICODE_STRING NtPathU; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS errCode; IO_STATUS_BLOCK IoStatusBlock; HANDLE hFile; if (!RtlDosPathNameToNtPathName_U ((LPWSTR)DirName, &NtPathU, NULL, NULL)) { DPRINT("Invalid path\n"); SetLastError(ERROR_BAD_PATHNAME); return INVALID_HANDLE_VALUE; } InitializeObjectAttributes(&ObjectAttributes, &NtPathU, Write ? FILE_WRITE_ATTRIBUTES : FILE_READ_ATTRIBUTES, 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); RtlFreeUnicodeString(&NtPathU); if (!NT_SUCCESS(errCode)) { SetLastErrorByStatus (errCode); return INVALID_HANDLE_VALUE; } return hFile; } DWORD STDCALL GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer) { DWORD drive, count; DWORD dwDriveMap; dwDriveMap = SharedUserData->DosDeviceMap; for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++) { if (dwDriveMap & (1<DosDeviceMap; for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++) { if (dwDriveMap & (1<DosDeviceMap); } WINBOOL STDCALL GetDiskFreeSpaceA ( LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters ) { UNICODE_STRING RootPathNameU; ANSI_STRING RootPathName; WINBOOL Result; RtlInitAnsiString (&RootPathName, (LPSTR)lpRootPathName); RtlInitUnicodeString (&RootPathNameU, NULL); if (lpRootPathName) { /* convert ansi (or oem) string to unicode */ if (bIsFileApiAnsi) RtlAnsiStringToUnicodeString (&RootPathNameU, &RootPathName, TRUE); else RtlOemStringToUnicodeString (&RootPathNameU, &RootPathName, TRUE); } Result = GetDiskFreeSpaceW (RootPathNameU.Buffer, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters); if (lpRootPathName) { RtlFreeHeap (RtlGetProcessHeap (), 0, RootPathNameU.Buffer); } return Result; } 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; } if (INVALID_HANDLE_VALUE == (hFile = InternalOpenDirW((PWCHAR)lpRootPathName, FALSE))) { return FALSE; } errCode = NtQueryVolumeInformationFile(hFile, &IoStatusBlock, &FileFsSize, sizeof(FILE_FS_SIZE_INFORMATION), FileFsSizeInformation); if (!NT_SUCCESS(errCode)) { CloseHandle(hFile); SetLastErrorByStatus (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 ) { UNICODE_STRING DirectoryNameU; ANSI_STRING DirectoryName; WINBOOL Result; RtlInitAnsiString (&DirectoryName, (LPSTR)lpDirectoryName); RtlInitUnicodeString (&DirectoryNameU, NULL); if (lpDirectoryName) { /* convert ansi (or oem) string to unicode */ if (bIsFileApiAnsi) RtlAnsiStringToUnicodeString (&DirectoryNameU, &DirectoryName, TRUE); else RtlOemStringToUnicodeString (&DirectoryNameU, &DirectoryName, TRUE); } Result = GetDiskFreeSpaceExW (DirectoryNameU.Buffer, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes); if (lpDirectoryName) { RtlFreeHeap (RtlGetProcessHeap (), 0, DirectoryNameU.Buffer); } return Result; } 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; } if (INVALID_HANDLE_VALUE == (hFile = InternalOpenDirW(lpDirectoryName, FALSE))) { return FALSE; } errCode = NtQueryVolumeInformationFile(hFile, &IoStatusBlock, &FileFsSize, sizeof(FILE_FS_SIZE_INFORMATION), FileFsSizeInformation); if (!NT_SUCCESS(errCode)) { CloseHandle(hFile); SetLastErrorByStatus (errCode); return FALSE; } BytesPerCluster.QuadPart = FileFsSize.BytesPerSector * FileFsSize.SectorsPerAllocationUnit; // FIXME: Use quota information if (lpFreeBytesAvailableToCaller) lpFreeBytesAvailableToCaller->QuadPart = BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart; if (lpTotalNumberOfBytes) lpTotalNumberOfBytes->QuadPart = BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.QuadPart; if (lpTotalNumberOfFreeBytes) lpTotalNumberOfFreeBytes->QuadPart = BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart; CloseHandle(hFile); return TRUE; } UINT STDCALL GetDriveTypeA(LPCSTR lpRootPathName) { UNICODE_STRING RootPathNameU; ANSI_STRING RootPathName; UINT Result; RtlInitAnsiString (&RootPathName, (LPSTR)lpRootPathName); /* convert ansi (or oem) string to unicode */ if (bIsFileApiAnsi) RtlAnsiStringToUnicodeString (&RootPathNameU, &RootPathName, TRUE); else RtlOemStringToUnicodeString (&RootPathNameU, &RootPathName, TRUE); Result = GetDriveTypeW (RootPathNameU.Buffer); RtlFreeHeap (RtlGetProcessHeap (), 0, RootPathNameU.Buffer); return Result; } UINT STDCALL GetDriveTypeW(LPCWSTR lpRootPathName) { FILE_FS_DEVICE_INFORMATION FileFsDevice; IO_STATUS_BLOCK IoStatusBlock; HANDLE hFile; NTSTATUS errCode; hFile = InternalOpenDirW(lpRootPathName, FALSE); if (hFile == INVALID_HANDLE_VALUE) { return 0; } errCode = NtQueryVolumeInformationFile (hFile, &IoStatusBlock, &FileFsDevice, sizeof(FILE_FS_DEVICE_INFORMATION), FileFsDeviceInformation); if (!NT_SUCCESS(errCode)) { CloseHandle(hFile); SetLastErrorByStatus (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 ) { UNICODE_STRING RootPathNameU; UNICODE_STRING FileSystemNameU; UNICODE_STRING VolumeNameU; ANSI_STRING RootPathName; ANSI_STRING VolumeName; ANSI_STRING FileSystemName; WINBOOL Result; RtlInitAnsiString (&RootPathName, (LPSTR)lpRootPathName); /* convert ansi (or oem) string to unicode */ if (bIsFileApiAnsi) RtlAnsiStringToUnicodeString (&RootPathNameU, &RootPathName, TRUE); else RtlOemStringToUnicodeString (&RootPathNameU, &RootPathName, TRUE); VolumeNameU.Length = 0; VolumeNameU.MaximumLength = nVolumeNameSize * sizeof(WCHAR); VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (), 0, VolumeNameU.MaximumLength); FileSystemNameU.Length = 0; FileSystemNameU.MaximumLength = nFileSystemNameSize * sizeof(WCHAR); FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (), 0, FileSystemNameU.MaximumLength); Result = GetVolumeInformationW (RootPathNameU.Buffer, VolumeNameU.Buffer, nVolumeNameSize, lpVolumeSerialNumber, lpMaximumComponentLength, lpFileSystemFlags, FileSystemNameU.Buffer, nFileSystemNameSize); if (Result) { VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR); VolumeName.Length = 0; VolumeName.MaximumLength = nVolumeNameSize; VolumeName.Buffer = lpVolumeNameBuffer; FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR); FileSystemName.Length = 0; FileSystemName.MaximumLength = nFileSystemNameSize; FileSystemName.Buffer = lpFileSystemNameBuffer; /* convert unicode strings to ansi (or oem) */ if (bIsFileApiAnsi) { RtlUnicodeStringToAnsiString (&VolumeName, &VolumeNameU, FALSE); RtlUnicodeStringToAnsiString (&FileSystemName, &FileSystemNameU, FALSE); } else { RtlUnicodeStringToOemString (&VolumeName, &VolumeNameU, FALSE); RtlUnicodeStringToOemString (&FileSystemName, &FileSystemNameU, FALSE); } } RtlFreeHeap (RtlGetProcessHeap (), 0, RootPathNameU.Buffer); RtlFreeHeap (RtlGetProcessHeap (), 0, VolumeNameU.Buffer); RtlFreeHeap (RtlGetProcessHeap (), 0, FileSystemNameU.Buffer); return Result; } #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; OBJECT_ATTRIBUTES ObjectAttributes; 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 = InternalOpenDirW(lpRootPathName, FALSE); if (hFile == INVALID_HANDLE_VALUE) { return FALSE; } 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); SetLastErrorByStatus (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); SetLastErrorByStatus (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 ) { UNICODE_STRING RootPathNameU; ANSI_STRING RootPathName; UNICODE_STRING VolumeNameU; ANSI_STRING VolumeName; WINBOOL Result; RtlInitAnsiString (&RootPathName, (LPSTR)lpRootPathName); RtlInitAnsiString (&VolumeName, (LPSTR)lpVolumeName); /* convert ansi (or oem) strings to unicode */ if (bIsFileApiAnsi) { RtlAnsiStringToUnicodeString (&RootPathNameU, &RootPathName, TRUE); RtlAnsiStringToUnicodeString (&VolumeNameU, &VolumeName, TRUE); } else { RtlOemStringToUnicodeString (&RootPathNameU, &RootPathName, TRUE); RtlOemStringToUnicodeString (&VolumeNameU, &VolumeName, TRUE); } Result = SetVolumeLabelW (RootPathNameU.Buffer, VolumeNameU.Buffer); RtlFreeHeap (RtlGetProcessHeap (), 0, RootPathNameU.Buffer); RtlFreeHeap (RtlGetProcessHeap (), 0, VolumeNameU.Buffer); return Result; } WINBOOL STDCALL SetVolumeLabelW(LPCWSTR lpRootPathName, LPCWSTR lpVolumeName) { 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); LabelInfo->VolumeLabelLength = LabelLength; wcscpy(LabelInfo->VolumeLabel, lpVolumeName); if (INVALID_HANDLE_VALUE == (hFile = InternalOpenDirW(lpRootPathName, TRUE))) { return FALSE; } Status = NtSetVolumeInformationFile(hFile, &IoStatusBlock, LabelInfo, sizeof(FILE_FS_LABEL_INFORMATION) + LabelLength, FileFsLabelInformation); RtlFreeHeap(RtlGetProcessHeap(), 0, LabelInfo); if (!NT_SUCCESS(Status)) { DPRINT("Status: %x\n", Status); CloseHandle(hFile); SetLastErrorByStatus(Status); return FALSE; } CloseHandle(hFile); return TRUE; } /* EOF */