/**************************************************************************** Aaru Data Preservation Suite ----------------------------------------------------------------------------- Author(s) : Natalia Portillo --[ License ] --------------------------------------------------------------- This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ----------------------------------------------------------------------------- Copyright (C) 2011-2021 Natalia Portillo *****************************************************************************/ // ReSharper disable CppJoinDeclarationAndAssignment // ReSharper disable CppDeprecatedEntity #define _CRT_SECURE_NO_WARNINGS 1 #include #include #include #include #include "win32.h" #include "volume.h" #include "../include/defs.h" #include "../log.h" extern DWORD oldVersion; void GetVolumeInfo(const char* path, size_t* clusterSize) { BOOL ret; DWORD error; LPSTR lpVolumeNameBuffer; DWORD dwMaximumComponentLength; DWORD dwFileSystemFlags; LPSTR lpFileSystemNameBuffer; LPSTR lpRootPathName; const size_t pathSize = strlen(path); DWORD dwSectorsPerCluster; DWORD dwBytesPerSector; DWORD dwNumberOfFreeClusters; DWORD dwTotalNumberOfClusters; WIN_OSVERSIONINFO verInfo; ULARGE_INTEGER qwFreeBytesAvailableToCaller; ULARGE_INTEGER qwTotalNumberOfBytes; ULARGE_INTEGER qwTotalNumberOfFreeBytes; void* func; HINSTANCE kernel32; *clusterSize = 0; log_write("Volume information:\n"); log_write("\tPath: %s\n", path); lpVolumeNameBuffer = malloc(dwMaxNameSize); if(lpVolumeNameBuffer == NULL) { log_write("Could not allocate memory.\n"); return; } lpFileSystemNameBuffer = malloc(dwMaxNameSize); if(lpFileSystemNameBuffer == NULL) { log_write("Could not allocate memory.\n"); free(lpVolumeNameBuffer); return; } lpRootPathName = malloc(dwMaxNameSize); if(!lpRootPathName) { log_write("Could not allocate memory.\n"); free(lpVolumeNameBuffer); free(lpFileSystemNameBuffer); return; } memset(lpRootPathName, 0x00, MAX_PATH); strncpy(lpRootPathName, path, MAX_PATH); if(path[pathSize - 1] != '\\') lpRootPathName[pathSize] = '\\'; ret = GetVolumeInformationA(lpRootPathName, lpVolumeNameBuffer, dwMaxNameSize, NULL, &dwMaximumComponentLength, &dwFileSystemFlags, lpFileSystemNameBuffer, dwMaxNameSize); if(!ret) { error = GetLastError(); log_write("Error %lu querying volume information.\n", error); free(lpVolumeNameBuffer); free(lpFileSystemNameBuffer); free(lpRootPathName); return; } log_write("\tFilesystem: %s\n", lpFileSystemNameBuffer); log_write("\tVolume name: %s\n", lpVolumeNameBuffer); log_write("\tMaximum component size: %lu\n", dwMaximumComponentLength); if(dwFileSystemFlags > 0) { log_write("\tFlags:\n"); if(dwFileSystemFlags & (DWORD)FILE_CASE_PRESERVED_NAMES) { log_write("\t\tVolume preserves file name case.\n"); dwFileSystemFlags -= FILE_CASE_PRESERVED_NAMES; } if(dwFileSystemFlags & (DWORD)FILE_CASE_SENSITIVE_SEARCH) { log_write("\t\tVolume supports case sensitiveness.\n"); dwFileSystemFlags -= FILE_CASE_SENSITIVE_SEARCH; } if(dwFileSystemFlags & (DWORD)FILE_DAX_VOLUME) { log_write("\t\tDirect access volume.\n"); dwFileSystemFlags -= FILE_DAX_VOLUME; } if(dwFileSystemFlags & (DWORD)FILE_FILE_COMPRESSION) { log_write("\t\tVolume supports per-file compression.\n"); dwFileSystemFlags -= FILE_FILE_COMPRESSION; } if(dwFileSystemFlags & (DWORD)FILE_NAMED_STREAMS) { log_write("\t\tVolume supports Alternate Data Streams.\n"); dwFileSystemFlags -= FILE_NAMED_STREAMS; } if(dwFileSystemFlags & (DWORD)FILE_PERSISTENT_ACLS) { log_write("\t\tVolume supports persistent Access Control Lists.\n"); dwFileSystemFlags -= FILE_PERSISTENT_ACLS; } if(dwFileSystemFlags & (DWORD)FILE_READ_ONLY_VOLUME) { log_write("\t\tVolume is read-only.\n"); dwFileSystemFlags -= FILE_READ_ONLY_VOLUME; } if(dwFileSystemFlags & (DWORD)FILE_SEQUENTIAL_WRITE_ONCE) { log_write("\t\tVolume supports a single sequential write.\n"); dwFileSystemFlags -= FILE_SEQUENTIAL_WRITE_ONCE; } if(dwFileSystemFlags & (DWORD)FILE_SUPPORTS_ENCRYPTION) { log_write("\t\tVolume supports per-file encryption.\n"); dwFileSystemFlags -= FILE_SUPPORTS_ENCRYPTION; } if(dwFileSystemFlags & (DWORD)FILE_SUPPORTS_EXTENDED_ATTRIBUTES) { log_write("\t\tVolume supports extended attributes.\n"); dwFileSystemFlags -= FILE_SUPPORTS_EXTENDED_ATTRIBUTES; } if(dwFileSystemFlags & (DWORD)FILE_SUPPORTS_HARD_LINKS) { log_write("\t\tVolume supports hard links.\n"); dwFileSystemFlags -= FILE_SUPPORTS_HARD_LINKS; } if(dwFileSystemFlags & (DWORD)FILE_SUPPORTS_OBJECT_IDS) { log_write("\t\tVolume supports object IDs.\n"); dwFileSystemFlags -= FILE_SUPPORTS_OBJECT_IDS; } if(dwFileSystemFlags & (DWORD)FILE_SUPPORTS_OPEN_BY_FILE_ID) { log_write("\t\tVolume can open files by ID.\n"); dwFileSystemFlags -= FILE_SUPPORTS_OPEN_BY_FILE_ID; } if(dwFileSystemFlags & (DWORD)FILE_SUPPORTS_REPARSE_POINTS) { log_write("\t\tVolume supports reparse points.\n"); dwFileSystemFlags -= FILE_SUPPORTS_REPARSE_POINTS; } if(dwFileSystemFlags & (DWORD)FILE_SUPPORTS_SPARSE_FILES) { log_write("\t\tVolume supports sparse files.\n"); dwFileSystemFlags -= FILE_SUPPORTS_SPARSE_FILES; } if(dwFileSystemFlags & (DWORD)FILE_SUPPORTS_TRANSACTIONS) { log_write("\t\tVolume supports transactions.\n"); dwFileSystemFlags -= FILE_SUPPORTS_TRANSACTIONS; } if(dwFileSystemFlags & (DWORD)FILE_SUPPORTS_USN_JOURNAL) { log_write("\t\tVolume has an USN journal.\n"); dwFileSystemFlags -= FILE_SUPPORTS_USN_JOURNAL; } if(dwFileSystemFlags & (DWORD)FILE_UNICODE_ON_DISK) { log_write("\t\tVolume stores filenames as Unicode.\n"); dwFileSystemFlags -= FILE_UNICODE_ON_DISK; } if(dwFileSystemFlags & (DWORD)FILE_VOLUME_IS_COMPRESSED) { log_write("\t\tVolume is compressed.\n"); dwFileSystemFlags -= FILE_VOLUME_IS_COMPRESSED; } if(dwFileSystemFlags & (DWORD)FILE_VOLUME_QUOTAS) { log_write("\t\tVolume supports user quotas.\n"); dwFileSystemFlags -= FILE_VOLUME_QUOTAS; } if(dwFileSystemFlags & (DWORD)FILE_RETURNS_CLEANUP_RESULT_INFO) { log_write("\t\tOn a clean operation, volume returns additional information.\n"); dwFileSystemFlags -= FILE_RETURNS_CLEANUP_RESULT_INFO; } if(dwFileSystemFlags & (DWORD)FILE_SUPPORTS_POSIX_UNLINK_RENAME) { log_write("\t\tVolume supports POSIX-style delete and rename operations.\n"); dwFileSystemFlags -= FILE_SUPPORTS_POSIX_UNLINK_RENAME; } if(dwFileSystemFlags & (DWORD)FS_LFN_APIS) { log_write("\t\tVolume supports LFN API.\n"); dwFileSystemFlags -= FS_LFN_APIS; } if(dwFileSystemFlags > 0) log_write("Unknown flags: 0x%08lx.\n", dwFileSystemFlags); } free(lpVolumeNameBuffer); free(lpFileSystemNameBuffer); ret = GetDiskFreeSpaceA( lpRootPathName, &dwSectorsPerCluster, &dwBytesPerSector, &dwNumberOfFreeClusters, &dwTotalNumberOfClusters); if(!ret) { error = GetLastError(); log_write("Error %lu querying volume space.\n", error); free(lpRootPathName); return; } *clusterSize = dwSectorsPerCluster * dwBytesPerSector; log_write("\tBytes per sector: %lu\n", dwBytesPerSector); log_write("\tSectors per cluster: %lu (" SIZE_T_FORMAT " bytes)\n", dwSectorsPerCluster, *clusterSize); if(WinGetVersionExA) { verInfo.dwOSVersionInfoSize = sizeof(WIN_OSVERSIONINFO); ret = WinGetVersionExA(&verInfo); if(!ret) { error = GetLastError(); log_write("Error %lu querying Windows version.\n", error); free(lpRootPathName); return; } } else if(oldVersion == 0) verInfo.dwPlatformId = VER_PLATFORM_WIN32_NT; if(verInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && verInfo.dwBuildNumber >= 1000 || verInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && kernel32) { kernel32 = LoadLibraryA("kernel32.dll"); if(kernel32) { func = GetProcAddress(kernel32, "GetDiskFreeSpaceExA"); if(func) WinGetDiskFreeSpaceExA = func; } } if(WinGetDiskFreeSpaceExA) { ret = WinGetDiskFreeSpaceExA( lpRootPathName, &qwFreeBytesAvailableToCaller, &qwTotalNumberOfBytes, &qwTotalNumberOfFreeBytes); if(!ret) { error = GetLastError(); log_write("Error %lu querying extended volume space.\n", error); free(lpRootPathName); return; } log_write("\tVolume size: %I64d bytes\n", qwTotalNumberOfBytes.QuadPart); log_write("\tVolume free: %I64d bytes\n", qwTotalNumberOfFreeBytes.QuadPart); } else { qwTotalNumberOfBytes.QuadPart = dwTotalNumberOfClusters; qwTotalNumberOfFreeBytes.QuadPart = dwNumberOfFreeClusters; qwTotalNumberOfBytes.QuadPart *= *clusterSize; qwTotalNumberOfFreeBytes.QuadPart *= *clusterSize; log_write("\tClusters: %lu (%I64d bytes)\n", dwTotalNumberOfClusters, qwTotalNumberOfBytes.QuadPart); log_write("\tFree clusters: %lu (%I64d bytes)\n", dwNumberOfFreeClusters, qwTotalNumberOfFreeBytes.QuadPart); } free(lpRootPathName); if(func) FreeLibrary(kernel32); }