progwrp/file.c
2025-12-13 23:37:26 +01:00

395 lines
13 KiB
C

#include "progwrp.h"
#include "export.h"
#include "implementations.h"
#include <strsafe.h>
typedef enum {
FileDirectoryInfo = 1,
FileFullDirectoryInformation, // 2
FileBothDirectoryInformation, // 3
FileBasicInformation, // 4
FileStandardInformation, // 5
FileInternalInformation, // 6
FileEaInformation, // 7
FileAccessInformation, // 8
FileNameInformation, // 9
FileRenameInformation, // 10
FileLinkInformation, // 11
FileNamesInformation, // 12
FileDispositionInformation, // 13
FilePositionInformation, // 14
FileFullEaInformation, // 15
FileModeInformation, // 16
FileAlignmentInformation, // 17
FileAllInformation, // 18
FileAllocationInformation, // 19
FileEndOfFileInformation, // 20
FileAlternateNameInformation, // 21
FileStreamInformation, // 22
FilePipeInformation, // 23
FilePipeLocalInformation, // 24
FilePipeRemoteInformation, // 25
FileMailslotQueryInformation, // 26
FileMailslotSetInformation, // 27
FileCompressionInformation, // 28
FileObjectIdInformation, // 29
FileCompletionInformation, // 30
FileMoveClusterInformation, // 31
FileQuotaInformation, // 32
FileReparsePointInformation, // 33
FileNetworkOpenInformation, // 34
FileAttributeTagInformation, // 35
FileTrackingInformation, // 36
FileIdBothDirectoryInformation, // 37
FileIdFullDirectoryInformation, // 38
FileValidDataLengthInformation, // 39
FileShortNameInformation, // 40
FileIoCompletionNotificationInformation, // 41
FileIoStatusBlockRangeInformation, // 42
FileIoPriorityHintInformation, // 43
FileSfioReserveInformation, // 44
FileSfioVolumeInformation, // 45
FileHardLinkInformation, // 46
FileProcessIdsUsingFileInformation, // 47
FileNormalizedNameInformation, // 48
FileNetworkPhysicalNameInformation, // 49
FileIdGlobalTxDirectoryInformation, // 50
FileIsRemoteDeviceInformation, // 51
FileUnusedInformation, // 52
FileNumaNodeInformation, // 53
FileStandardLinkInformation, // 54
FileRemoteProtocolInformation, // 55
//
// These are special versions of these operations (defined earlier)
// which can be used by kernel mode drivers only to bypass security
// access checks for Rename and HardLink operations. These operations
// are only recognized by the IOManager, a file system should never
// receive these.
//
FileRenameInformationBypassAccessCheck, // 56
FileLinkInformationBypassAccessCheck, // 57
//
// End of special information classes reserved for IOManager.
//
FileVolumeNameInformation, // 58
FileIdInformation, // 59
FileIdExtdDirectoryInformation, // 60
FileReplaceCompletionInformation, // 61
FileHardLinkFullIdInformation, // 62
FileIdExtdBothDirectoryInformation, // 63
FileDispositionInformationEx, // 64
FileRenameInformationEx, // 65
FileRenameInformationExBypassAccessCheck, // 66
FileDesiredStorageClassInformation, // 67
FileStatInformation, // 68
FileMemoryPartitionInformation, // 69
FileStatLxInformation, // 70
FileCaseSensitiveInformation, // 71
FileLinkInformationEx, // 72
FileLinkInformationExBypassAccessCheck, // 73
FileStorageReserveIdInformation, // 74
FileCaseSensitiveInformationForceAccessCheck, // 75
FileKnownFolderInformation, // 76
FileMaximumInformation
} FILEINFOCLASS, *PFILEINFOCLASS;
#define ObjectNameInformation 1
typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING Name;
WCHAR NameBuffer[1];
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
typedef struct _FILE_NAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
NTSTATUS
NTAPI
NtQueryInformationFile (
_In_ HANDLE FileHandle,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID FileInformation,
_In_ ULONG Length,
_In_ FILEINFOCLASS FileInformationClass
);
typedef enum _FSINFOCLASS {
FileFsVolumeInformation,
FileFsLabelInformation,
FileFsSizeInformation,
FileFsDeviceInformation,
FileFsAttributeInformation,
FileFsControlInformation,
FileFsFullSizeInformation,
FileFsObjectIdInformation,
FileFsDriverPathInformation,
FileFsVolumeFlagsInformation,
FileFsSectorSizeInformation,
FileFsDataCopyInformation,
FileFsMetadataSizeInformation,
FileFsFullSizeInformationEx,
FileFsGuidInformation,
FileFsMaximumInformation
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
NTSTATUS NTAPI NtQueryVolumeInformationFile(
_In_ HANDLE FileHandle,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_ PVOID FsInformation,
_In_ ULONG Length,
_In_ FS_INFORMATION_CLASS FsInformationClass
);
HANDLE WINAPI Implementation_FindFirstFileExW(LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData,
FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
{
if(dwAdditionalFlags & FIND_FIRST_EX_LARGE_FETCH)
dwAdditionalFlags &= ~FIND_FIRST_EX_LARGE_FETCH;
typedef HANDLE (WINAPI* pfnFindFirstFileExW)(LPCWSTR, FINDEX_INFO_LEVELS, LPVOID, FINDEX_SEARCH_OPS, LPVOID, DWORD);
pfnFindFirstFileExW pFFFEXW = (pfnFindFirstFileExW)Implementation_GetProcAddress(GetModuleHandleA("kernel32.dll"), "FindFirstFileExW");
return pFFFEXW(lpFileName, FindExInfoStandard, lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags);
}
BOOL WINAPI Implementation_GetFileInformationByHandleEx(
HANDLE hFile,
FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
LPVOID lpFileInformation,
DWORD dwBufferSize
)
/*
Seems like a wrapper around NtQueryInformationFile, but with the
file information classes shifted around a little bit.
A switch statement will take care of that.
*/
{
IO_STATUS_BLOCK isb;
NTSTATUS Status;
switch(FileInformationClass)
{
case FileBasicInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileBasicInformation);
break;
case FileStandardInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileStandardInformation);
break;
case FileNameInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileNameInformation);
break;
case FileRenameInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileRenameInformation);
break;
case FileDispositionInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileDispositionInformation);
break;
case FileAllocationInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileAllocationInformation);
break;
case FileEndOfFileInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileEndOfFileInformation);
break;
case FileStreamInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileStreamInformation);
break;
case FileCompressionInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileCompressionInformation);
break;
case FileAttributeTagInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileAttributeTagInformation);
break;
case FileIdBothDirectoryInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileIdBothDirectoryInformation);
break;
case FileIdBothDirectoryRestartInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileIdFullDirectoryInformation); // ??
break;
case FileIoPriorityHintInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileIoPriorityHintInformation);
break;
case FileRemoteProtocolInfo:
Status = NtQueryInformationFile(hFile, &isb, lpFileInformation, dwBufferSize, FileRemoteProtocolInformation);
break;
default: // All other classes are not known to work on XP or below
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if(Status == 0x0)
return TRUE;
else
{
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL WINAPI Implementation_CancelIoEx(HANDLE hFile, LPOVERLAPPED lpOverlapped)
{
return CancelIo(hFile);
}
DWORD WINAPI Implementation_GetFinalPathNameByHandleW(
HANDLE hFile,
LPWSTR lpszFilePath,
DWORD cchFilePath,
DWORD dwFlags
)
/*
NtQueryInformationFile returns the path without the volume name.
NtQueryObject returns the path with the NT volume name.
The DOS volume name can be retrieved using QueryDosDeviceW to compare with the NtQueryObject value.
*/
{
IO_STATUS_BLOCK isb;
PFILE_NAME_INFORMATION fni;
NTSTATUS Status;
ULONG BufferSize, NtNameLen, VolumeNameLen, NoVolNameLen;
WCHAR DosDriveLetter [3] = L"A:";
WCHAR Path [MAX_PATH];
PWSTR VolumeName;
HANDLE hMap;
PVOID Mem;
if(dwFlags & ~(VOLUME_NAME_NONE | VOLUME_NAME_NT | FILE_NAME_OPENED)) // todo: add VOLUME_NAME_GUID support
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
BufferSize = sizeof(FILE_NAME_INFORMATION);
fni = (PFILE_NAME_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
while(1)
{
Status = NtQueryInformationFile(hFile, &isb, (PVOID)fni, BufferSize, FileNameInformation);
if(Status == 0)
break;
else if(Status == 0x80000005)
BufferSize += 8;
else
{
HeapFree(GetProcessHeap(), 0, fni);
BaseSetLastNTError(Status);
return 0;
}
HeapFree(GetProcessHeap(), 0, fni);
fni = (PFILE_NAME_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
}
NoVolNameLen = fni->FileNameLength;
if(dwFlags & VOLUME_NAME_NONE)
{
if(cchFilePath >= fni->FileNameLength)
StringCchCopyW(lpszFilePath, cchFilePath, fni->FileName);
HeapFree(GetProcessHeap(), 0, fni);
return NoVolNameLen;
}
hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 1, NULL);
if(hMap)
{
Mem = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 1);
if(Mem)
{
NtNameLen = GetMappedFileNameW(GetCurrentProcess(), Mem, Path, MAX_PATH);
}
else
{
CloseHandle(hMap);
return 0;
}
CloseHandle(hMap);
}
else
{
return 0;
}
/*
BufferSize = sizeof(OBJECT_NAME_INFORMATION);
oni = (POBJECT_NAME_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
while(1)
{
Status = NtQueryObject(hFile, ObjectNameInformation, oni, BufferSize, NULL);
if(Status == 0)
break;
else if(Status == 0x80000005)
BufferSize += 8;
else
{
HeapFree(GetProcessHeap(), 0, oni);
BaseSetLastNTError(Status);
return 0;
}
HeapFree(GetProcessHeap(), 0, oni);
oni = (POBJECT_NAME_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
}
*/
if(dwFlags & VOLUME_NAME_NT)
{
if(cchFilePath >= NtNameLen)
StringCchCopyW(lpszFilePath, cchFilePath, Path);
return NtNameLen;
}
VolumeName = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
while(DosDriveLetter[0] <= L"Z")
{
VolumeNameLen = QueryDosDeviceW(DosDriveLetter, VolumeName, BufferSize / sizeof(WCHAR));
if(LimitedStrCmp(0, VolumeNameLen, Path, VolumeName))
break;
if(DosDriveLetter[0] == L"Z")
{
SetLastError(ERROR_PATH_NOT_FOUND);
return 0;
}
++DosDriveLetter[0];
}
StringCchCopyW(lpszFilePath, cchFilePath, L"\?\\");
StringCchCatW(lpszFilePath, cchFilePath, DosDriveLetter);
StringCchCatW(lpszFilePath, cchFilePath, L"\\");
StringCchCatW(lpszFilePath, cchFilePath, fni->FileName);
HeapFree(GetProcessHeap(), 0, VolumeName);
HeapFree(GetProcessHeap(), 0, fni);
return NoVolNameLen + 8;
}
BOOL WINAPI Implementation_SetFileInformationByHandle(
HANDLE hFile,
FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
LPVOID lpFileInformation,
DWORD dwBufferSize
)
{
return FALSE;
}
BOOL Implementation_GetVolumePathNamesForVolumeNameW(
LPCWSTR lpszVolumeName,
LPWCH lpszVolumePathNames,
DWORD cchBufferLength,
PDWORD lpcchReturnLength
)
{
return FALSE;
}