/*++ Copyright (c) 2000 Microsoft Corporation Module Name: spwin.c Abstract: Win32 portability layer to support windows\winstate\...\cablib.c file i/o Get/SpSetLastWin32Error see also .\spcab.c .\spbasefile.c .\spbasefile.h windows\winstate\...\cablib.c windows\winstate\cobra\utils\main\basefile.c windows\winstate\cobra\utils\inc\basefile.h Author: Jay Krell (a-JayK) November 2000 Revision History: --*/ #include "spprecmp.h" #include "spcab.h" #include "nt.h" #include "ntrtl.h" #include "zwapi.h" #include "spwin.h" #include "spwinp.h" #include #include "fci.h" // // fold with rtl.. // extern const UNICODE_STRING SpWin32NtRoot = RTL_CONSTANT_STRING( L"\\\\?" ); extern const UNICODE_STRING SpWin32NtRootSlash = RTL_CONSTANT_STRING( L"\\\\?\\" ); extern const UNICODE_STRING SpWin32NtUncRoot = RTL_CONSTANT_STRING( L"\\\\?\\UNC" ); extern const UNICODE_STRING SpWin32NtUncRootSlash = RTL_CONSTANT_STRING( L"\\\\?\\UNC\\" ); NTSTATUS SpConvertWin32FileOpenOrCreateToNtFileOpenOrCreate( ULONG Win32OpenOrCreate, ULONG* NtOpenOrCreate ) { // // there's no pattern here and the values all overlap // yuck; this is copied from kernel32 source // *NtOpenOrCreate = ~0; switch (Win32OpenOrCreate) { default: return STATUS_INVALID_PARAMETER; case CREATE_NEW: *NtOpenOrCreate = FILE_CREATE; break; case CREATE_ALWAYS: *NtOpenOrCreate = FILE_OVERWRITE_IF; break; case OPEN_EXISTING: *NtOpenOrCreate = FILE_OPEN; break; case OPEN_ALWAYS: *NtOpenOrCreate = FILE_OPEN_IF; break; case TRUNCATE_EXISTING : *NtOpenOrCreate = FILE_OPEN; } return STATUS_SUCCESS; } NTSTATUS SpConvertWin32FileAccessToNtFileAccess( ULONG Win32FileAccess, ULONG* NtFileAccess ) { // // ZwCreateFile oddities require us to do this conversion, or at least // to add in SYNCHRONIZE. // *NtFileAccess = (Win32FileAccess & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)) | ((Win32FileAccess & GENERIC_READ) ? FILE_GENERIC_READ : 0) | ((Win32FileAccess & GENERIC_WRITE) ? FILE_GENERIC_WRITE : 0) | ((Win32FileAccess & GENERIC_EXECUTE) ? FILE_GENERIC_EXECUTE : 0) | ((Win32FileAccess & GENERIC_ALL) ? FILE_ALL_ACCESS : 0) | SYNCHRONIZE ; return STATUS_SUCCESS; } NTSTATUS SpConvertWin32FileShareToNtFileShare( ULONG Win32FileShare, ULONG* NtFileShare ) { *NtFileShare = Win32FileShare; return STATUS_SUCCESS; } NTSTATUS SpGetLastNtStatus( VOID ) { return NtCurrentTeb()->LastStatusValue; } ULONG WINAPI SpGetLastWin32Error( VOID ) { return NtCurrentTeb()->LastErrorValue; } VOID WINAPI SpSetLastWin32Error( ULONG Error ) { #if DBG if (NtCurrentTeb()->LastErrorValue != Error) #endif NtCurrentTeb()->LastErrorValue = Error; } VOID SpSetLastWin32ErrorAndNtStatusFromNtStatus( NTSTATUS Status ) { SpSetLastWin32Error(RtlNtStatusToDosError(Status)); } HANDLE SpNtCreateFileW( PCUNICODE_STRING ConstantPath, IN ULONG FileAccess, IN ULONG FileShare, IN LPSECURITY_ATTRIBUTES SecurityAttributes, IN ULONG Win32FileOpenOrCreate, IN ULONG FlagsAndAttributes, IN HANDLE TemplateFile ) /*++ Subset: no security no directories no async no console no ea (extended attributes) --*/ { NTSTATUS Status = STATUS_SUCCESS; IO_STATUS_BLOCK IoStatusBlock = { 0 }; HANDLE FileHandle = INVALID_HANDLE_VALUE; ULONG NtFileOpenOrCreate = 0; FILE_ALLOCATION_INFORMATION AllocationInfo = { 0 }; PUNICODE_STRING Path = RTL_CONST_CAST(PUNICODE_STRING)(ConstantPath); /*const*/OBJECT_ATTRIBUTES ObjectAttributes = { sizeof(ObjectAttributes), NULL, Path, OBJ_CASE_INSENSITIVE }; ASSERT(TemplateFile == NULL); ASSERT(SecurityAttributes == NULL); ASSERT((FlagsAndAttributes & ~(FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE)) == 0); if (!NT_SUCCESS(Status = SpConvertWin32FileAccessToNtFileAccess(FileAccess, &FileAccess))) goto NtExit; if (!NT_SUCCESS(Status = SpConvertWin32FileOpenOrCreateToNtFileOpenOrCreate(Win32FileOpenOrCreate, &NtFileOpenOrCreate))) goto NtExit; if (!NT_SUCCESS(Status = SpConvertWin32FileShareToNtFileShare(FileShare, &FileShare))) goto NtExit; Status = ZwCreateFile( &FileHandle, FileAccess | SYNCHRONIZE // like kernel32 | FILE_READ_ATTRIBUTES, // like kernel32 &ObjectAttributes, &IoStatusBlock, NULL, // AllocationSize FlagsAndAttributes, FileShare, NtFileOpenOrCreate, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, NULL, // EaBuffer, 0 // EaLength ); // based closely on kernel32 if ( !NT_SUCCESS(Status) ) { SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); if ( Status == STATUS_OBJECT_NAME_COLLISION ) { SpSetLastWin32Error(ERROR_FILE_EXISTS); } else if ( Status == STATUS_FILE_IS_A_DIRECTORY ) { if (Path->Length != 0 && Path->Buffer[Path->Length / sizeof(Path->Buffer[0])] == '\\') { SpSetLastWin32Error(ERROR_PATH_NOT_FOUND); } else { SpSetLastWin32Error(ERROR_ACCESS_DENIED); } } FileHandle = INVALID_HANDLE_VALUE; goto Exit; } // // if NT returns supersede/overwritten, it means that a create_always, openalways // found an existing copy of the file. In this case ERROR_ALREADY_EXISTS is returned // if ( (Win32FileOpenOrCreate == CREATE_ALWAYS && IoStatusBlock.Information == FILE_OVERWRITTEN) || (Win32FileOpenOrCreate == OPEN_ALWAYS && IoStatusBlock.Information == FILE_OPENED) ) { SpSetLastWin32Error(ERROR_ALREADY_EXISTS); } else { SpSetLastWin32Error(0); } // // Truncate the file if required // if ( Win32FileOpenOrCreate == TRUNCATE_EXISTING) { AllocationInfo.AllocationSize.QuadPart = 0; Status = ZwSetInformationFile( FileHandle, &IoStatusBlock, &AllocationInfo, sizeof(AllocationInfo), FileAllocationInformation ); if ( !NT_SUCCESS(Status) ) { ZwClose(FileHandle); FileHandle = INVALID_HANDLE_VALUE; SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); } } Exit: return FileHandle; NtExit: SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); goto Exit; } HANDLE WINAPI SpWin32CreateFileW( IN PCWSTR FileName, IN ULONG FileAccess, IN ULONG FileShare, IN LPSECURITY_ATTRIBUTES SecurityAttributes, IN ULONG FileOpenOrCreate, IN ULONG FlagsAndAttributes, IN HANDLE TemplateFile ) { HANDLE FileHandle = INVALID_HANDLE_VALUE; UNICODE_STRING UnicodeString = { 0 }; NTSTATUS Status = STATUS_SUCCESS; RtlInitUnicodeString(&UnicodeString, FileName); FileHandle = SpNtCreateFileW(&UnicodeString, FileAccess, FileShare, SecurityAttributes, FileOpenOrCreate, FlagsAndAttributes, TemplateFile); ASSERT (FileHandle); // never NULL if (FileHandle == INVALID_HANDLE_VALUE) goto Exit; Exit: return FileHandle; } HANDLE WINAPI SpWin32CreateFileA( IN PCSTR FileName, IN ULONG FileAccess, IN ULONG FileShare, IN LPSECURITY_ATTRIBUTES SecurityAttributes, IN ULONG FileOpenOrCreate, IN ULONG dwFlagsAndAttributes, IN HANDLE TemplateFile ) { ANSI_STRING AnsiString = { 0 }; NTSTATUS Status = STATUS_SUCCESS; HANDLE Handle = INVALID_HANDLE_VALUE; UNICODE_STRING UnicodeString = { 0 }; RtlInitAnsiString(&AnsiString, FileName); AnsiString.Length = AnsiString.MaximumLength; // include terminal nul if (!NT_SUCCESS(Status = SpAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE))) goto NtExit; UnicodeString.Length -= sizeof(UnicodeString.Buffer[0]); // remove terminal nul Handle = SpNtCreateFileW(&UnicodeString, FileAccess, FileShare, SecurityAttributes, FileOpenOrCreate, dwFlagsAndAttributes, TemplateFile); Exit: SpFreeStringW(&UnicodeString); KdPrintEx(( DPFLTR_SETUP_ID, SpHandleToDbgPrintLevel(Handle), "SETUP:"__FUNCTION__"(%s) exiting with FileHandle: %p Status:0x%08lx Error:%d\n", FileName, Handle, SpGetLastNtStatus(), SpGetLastWin32Error() )); return Handle; NtExit: SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); goto Exit; } BOOL WINAPI SpWin32ReadFile( HANDLE hFile, PVOID lpBuffer, ULONG nNumberOfBytesToRead, ULONG* lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped ) { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; ASSERT(!ARGUMENT_PRESENT(lpOverlapped)); if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) ) { *lpNumberOfBytesRead = 0; } Status = ZwReadFile( hFile, NULL, NULL, NULL, &IoStatusBlock, lpBuffer, nNumberOfBytesToRead, NULL, NULL ); if ( Status == STATUS_PENDING) { // Operation must complete before return & IoStatusBlock destroyed Status = ZwWaitForSingleObject( hFile, FALSE, NULL ); if ( NT_SUCCESS(Status)) { Status = IoStatusBlock.Status; } } if ( NT_SUCCESS(Status) ) { *lpNumberOfBytesRead = (ULONG)IoStatusBlock.Information; return TRUE; } else if (Status == STATUS_END_OF_FILE) { *lpNumberOfBytesRead = 0; return TRUE; } else { if ( NT_WARNING(Status) ) { *lpNumberOfBytesRead = (ULONG)IoStatusBlock.Information; } SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); return FALSE; } } BOOL WINAPI SpWin32WriteFile( HANDLE hFile, CONST VOID* lpBuffer, ULONG nNumberOfBytesToWrite, ULONG* lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped ) { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; PPEB Peb; ASSERT(!ARGUMENT_PRESENT( lpOverlapped ) ); if ( ARGUMENT_PRESENT(lpNumberOfBytesWritten) ) { *lpNumberOfBytesWritten = 0; } Status = ZwWriteFile( hFile, NULL, NULL, NULL, &IoStatusBlock, RTL_CONST_CAST(PVOID)(lpBuffer), nNumberOfBytesToWrite, NULL, NULL ); if ( Status == STATUS_PENDING) { // Operation must complete before return & IoStatusBlock destroyed Status = ZwWaitForSingleObject( hFile, FALSE, NULL ); if ( NT_SUCCESS(Status)) { Status = IoStatusBlock.Status; } } if ( NT_SUCCESS(Status)) { *lpNumberOfBytesWritten = (ULONG)IoStatusBlock.Information; return TRUE; } else { if ( NT_WARNING(Status) ) { *lpNumberOfBytesWritten = (ULONG)IoStatusBlock.Information; } SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); return FALSE; } } ULONG WINAPI SpSetFilePointer( HANDLE hFile, LONG lDistanceToMove, LONG* lpDistanceToMoveHigh, ULONG dwMoveMethod ) { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; FILE_POSITION_INFORMATION CurrentPosition; FILE_STANDARD_INFORMATION StandardInfo; LARGE_INTEGER Large; if (ARGUMENT_PRESENT(lpDistanceToMoveHigh)) { Large.HighPart = *lpDistanceToMoveHigh; Large.LowPart = lDistanceToMove; } else { Large.QuadPart = lDistanceToMove; } switch (dwMoveMethod) { case FILE_BEGIN : CurrentPosition.CurrentByteOffset = Large; break; case FILE_CURRENT : // // Get the current position of the file pointer // Status = ZwQueryInformationFile( hFile, &IoStatusBlock, &CurrentPosition, sizeof(CurrentPosition), FilePositionInformation ); if ( !NT_SUCCESS(Status) ) { SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); return (ULONG)(LONG)-1; } CurrentPosition.CurrentByteOffset.QuadPart += Large.QuadPart; break; case FILE_END : Status = ZwQueryInformationFile( hFile, &IoStatusBlock, &StandardInfo, sizeof(StandardInfo), FileStandardInformation ); if ( !NT_SUCCESS(Status) ) { SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); return (ULONG)(LONG)-1; } CurrentPosition.CurrentByteOffset.QuadPart = StandardInfo.EndOfFile.QuadPart + Large.QuadPart; break; default: SpSetLastWin32Error(ERROR_INVALID_PARAMETER); return (ULONG)(LONG)-1; break; } // // If the resulting file position is negative, or if the app is not // prepared for greater than // than 32 bits than fail // if ( CurrentPosition.CurrentByteOffset.QuadPart < 0 ) { SpSetLastWin32Error(ERROR_NEGATIVE_SEEK); return (ULONG)(LONG)-1; } if ( !ARGUMENT_PRESENT(lpDistanceToMoveHigh) && (CurrentPosition.CurrentByteOffset.HighPart & MAXLONG) ) { SpSetLastWin32Error(ERROR_INVALID_PARAMETER); return (ULONG)(LONG)-1; } // // Set the current file position // Status = ZwSetInformationFile( hFile, &IoStatusBlock, &CurrentPosition, sizeof(CurrentPosition), FilePositionInformation ); if ( NT_SUCCESS(Status) ) { if (ARGUMENT_PRESENT(lpDistanceToMoveHigh)){ *lpDistanceToMoveHigh = CurrentPosition.CurrentByteOffset.HighPart; } if ( CurrentPosition.CurrentByteOffset.LowPart == -1 ) { SpSetLastWin32Error(0); } return CurrentPosition.CurrentByteOffset.LowPart; } else { SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); if (ARGUMENT_PRESENT(lpDistanceToMoveHigh)){ *lpDistanceToMoveHigh = -1; } return (ULONG)(LONG)-1; } } BOOL WINAPI SpWin32DeleteFileA( PCSTR FileName ) { BOOL Success = FALSE; NTSTATUS Status = STATUS_SUCCESS; ANSI_STRING AnsiString = { 0 }; UNICODE_STRING UnicodeString = { 0 }; if (FileName == NULL || FileName[0] == 0) { KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_TRACE_LEVEL, "SETUP:"__FUNCTION__"(NULL or empty), claiming success\n" )); Success = TRUE; goto Exit; } RtlInitAnsiString(&AnsiString, FileName); AnsiString.Length = AnsiString.MaximumLength; // include terminal nul Status = SpAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE); if (!NT_SUCCESS(Status)) goto NtExit; Status = SpDeleteFile(UnicodeString.Buffer, NULL, NULL); if (!NT_SUCCESS(Status)) goto NtExit; Success = TRUE; Exit: SpFreeStringW(&UnicodeString); KdPrintEx(( DPFLTR_SETUP_ID, SpBoolToDbgPrintLevel(Success), "SETUP:"__FUNCTION__"(%s) exiting with Success: %s Status:0x%08lx Error:%d\n", FileName, SpBooleanToStringA(Success), SpGetLastNtStatus(), SpGetLastWin32Error() )); return Success; NtExit: SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); goto Exit; } // // move this to ntrtl // #define AlmostTwoSeconds (2*1000*1000*10 - 1) BOOL APIENTRY SpFileTimeToDosDateTime( CONST FILETIME *lpFileTime, LPWORD lpFatDate, LPWORD lpFatTime ) { TIME_FIELDS TimeFields; LARGE_INTEGER FileTime; FileTime.LowPart = lpFileTime->dwLowDateTime; FileTime.HighPart = lpFileTime->dwHighDateTime; FileTime.QuadPart = FileTime.QuadPart + (LONGLONG)AlmostTwoSeconds; if ( FileTime.QuadPart < 0 ) { SpSetLastWin32Error(ERROR_INVALID_PARAMETER); return FALSE; } RtlTimeToTimeFields(&FileTime, &TimeFields); if (TimeFields.Year < 1980 || TimeFields.Year > 2107) { SpSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER); return FALSE; } *lpFatDate = (WORD)( ((USHORT)(TimeFields.Year-(CSHORT)1980) << 9) | ((USHORT)TimeFields.Month << 5) | (USHORT)TimeFields.Day ); *lpFatTime = (WORD)( ((USHORT)TimeFields.Hour << 11) | ((USHORT)TimeFields.Minute << 5) | ((USHORT)TimeFields.Second >> 1) ); return TRUE; } BOOL APIENTRY SpDosDateTimeToFileTime( WORD wFatDate, WORD wFatTime, LPFILETIME lpFileTime ) { TIME_FIELDS TimeFields; LARGE_INTEGER FileTime; TimeFields.Year = (CSHORT)((wFatDate & 0xFE00) >> 9)+(CSHORT)1980; TimeFields.Month = (CSHORT)((wFatDate & 0x01E0) >> 5); TimeFields.Day = (CSHORT)((wFatDate & 0x001F) >> 0); TimeFields.Hour = (CSHORT)((wFatTime & 0xF800) >> 11); TimeFields.Minute = (CSHORT)((wFatTime & 0x07E0) >> 5); TimeFields.Second = (CSHORT)((wFatTime & 0x001F) << 1); TimeFields.Milliseconds = 0; if (RtlTimeFieldsToTime(&TimeFields,&FileTime)) { lpFileTime->dwLowDateTime = FileTime.LowPart; lpFileTime->dwHighDateTime = FileTime.HighPart; return TRUE; } else { SpSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER); return FALSE; } } BOOL WINAPI SpFileTimeToLocalFileTime( CONST FILETIME *lpFileTime, LPFILETIME lpLocalFileTime ) { // // just return it unchanged // UTC is good // *lpLocalFileTime = *lpFileTime; return TRUE; } BOOL WINAPI SpLocalFileTimeToFileTime( CONST FILETIME *lpLocalFileTime, LPFILETIME lpFileTime ) { // // just return it unchanged // UTC is good // *lpFileTime = *lpLocalFileTime; return TRUE; } BOOL WINAPI SpSetFileTime( HANDLE hFile, CONST FILETIME *lpCreationTime, CONST FILETIME *lpLastAccessTime, CONST FILETIME *lpLastWriteTime ) { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION BasicInfo = { 0 }; // // For each time value that is specified, copy it to the I/O system // record. // if (ARGUMENT_PRESENT( lpCreationTime )) { BasicInfo.CreationTime.LowPart = lpCreationTime->dwLowDateTime; BasicInfo.CreationTime.HighPart = lpCreationTime->dwHighDateTime; } if (ARGUMENT_PRESENT( lpLastAccessTime )) { BasicInfo.LastAccessTime.LowPart = lpLastAccessTime->dwLowDateTime; BasicInfo.LastAccessTime.HighPart = lpLastAccessTime->dwHighDateTime; } if (ARGUMENT_PRESENT( lpLastWriteTime )) { BasicInfo.LastWriteTime.LowPart = lpLastWriteTime->dwLowDateTime; BasicInfo.LastWriteTime.HighPart = lpLastWriteTime->dwHighDateTime; } // // Set the requested times. // Status = ZwSetInformationFile( hFile, &IoStatusBlock, &BasicInfo, sizeof(BasicInfo), FileBasicInformation ); if ( NT_SUCCESS(Status) ) { return TRUE; } else { SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); return FALSE; } } BOOL APIENTRY SpSetFileAttributesA( PCSTR lpFileName, DWORD dwFileAttributes ) { UNICODE_STRING UnicodeString = { 0 }; ANSI_STRING AnsiString = { 0 }; BOOL Success = FALSE; NTSTATUS Status = STATUS_SUCCESS; RtlInitAnsiString(&AnsiString, lpFileName); AnsiString.Length = AnsiString.MaximumLength; // include terminal nul if (!NT_SUCCESS(Status = SpAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE))) goto NtExit; Success = ( SpSetFileAttributesW( UnicodeString.Buffer, dwFileAttributes ) ); if (!Success) goto Exit; Success = TRUE; Exit: SpFreeStringW(&UnicodeString); return Success; NtExit: SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); goto Exit; } BOOL APIENTRY SpSetFileAttributesW( PCWSTR lpFileName, DWORD dwFileAttributes ) { BOOL Success = FALSE; NTSTATUS Status = STATUS_SUCCESS; HANDLE Handle; UNICODE_STRING FileName; OBJECT_ATTRIBUTES ObjectAttributes = { sizeof(ObjectAttributes), NULL, &FileName, OBJ_CASE_INSENSITIVE }; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION BasicInfo = { 0 }; RtlInitUnicodeString(&FileName, lpFileName); // // Open the file inhibiting the reparse behavior. // Status = ZwOpenFile( &Handle, (ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT ); if ( !NT_SUCCESS(Status) ) { SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); goto Exit; } // // Set the attributes // BasicInfo.FileAttributes = (dwFileAttributes & FILE_ATTRIBUTE_VALID_SET_FLAGS) | FILE_ATTRIBUTE_NORMAL; Status = ZwSetInformationFile( Handle, &IoStatusBlock, &BasicInfo, sizeof(BasicInfo), FileBasicInformation ); ZwClose(Handle); if ( !NT_SUCCESS(Status) ) { SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); goto Exit; } Success = TRUE; Exit: return Success; } NTSTATUS SpAllocateLocallyUniqueId( PLUID Luid ) /* hack until ZwAllocateLocallyUniqueId is exported */ { static LUID Counter = { 0, 0 }; // // This does not actually correctly deal with wrapperaround in a multithreaded environment. // That's ok with us, and we can switch to ZwAllocateLocallyUniqueId. // Luid->LowPart = InterlockedIncrement(&Counter.LowPart); if (Luid->LowPart == 0) Luid->HighPart = 0; /*InterlockedIncrement(&Counter.HighPart);*/ else Luid->HighPart = 0; /*Counter.HighPart;*/ return STATUS_SUCCESS; } #if 0 UINT WINAPI SpWin32GetTempFileNameW( PCWSTR TempDirectory, PCWSTR Prefix, // oops, I forgot to handle this.. UINT IgnoredNumber, PWSTR File ) { NTSTATUS Status = STATUS_SUCCESS; LUID Luid = { 0 }; UNICODE_STRING UnicodeString = { 0 }; WCHAR LuidStringBuffer[sizeof(LUID) * CHAR_BIT]; UNICODE_STRING LuidString = { 0, sizeof(LuidStringBuffer), LuidStringBuffer }; /*const*/ static UNICODE_STRING BackSlashString = RTL_CONSTANT_STRING(L"\\"); LARGE_INTEGER LargeInteger = { 0 }; UINT Length = 0; ASSERT(TempDirectory != NULL && TempDirectory[0] != 0); Status = SpAllocateLocallyUniqueId(&Luid); if (!NT_SUCCESS(Status)) { KdPrintEx(( DPFLTR_SETUP_ID, SpNtStatusToDbgPrintLevel(Status), "SETUP:"__FUNCTION__":AllocateLocallyUniqueId:0x%08lx\n", Status )); goto NtExit; } LargeInteger.LowPart = Luid.LowPart; LargeInteger.HighPart = Luid.HighPart; UnicodeString.Buffer = File; UnicodeString.Length = 0; UnicodeString.MaximumLength = (CB_MAX_CAB_PATH - 1) * sizeof(UnicodeString.Buffer[0]); Status = RtlAppendUnicodeToString(&UnicodeString, TempDirectory); if (!NT_SUCCESS(Status)) { KdPrintEx(( DPFLTR_SETUP_ID, SpNtStatusToDbgPrintLevel(Status), "SETUP:"__FUNCTION__":RtlAppendUnicodeToString:0x%08lx\n", Status )); goto NtExit; } if (UnicodeString.Buffer[UnicodeString.Length / sizeof(UnicodeString.Buffer[0]) - 1] != BackSlashString.Buffer[0]) { Status = RtlAppendUnicodeStringToString(&UnicodeString, &BackSlashString); if (!NT_SUCCESS(Status)) { KdPrintEx(( DPFLTR_SETUP_ID, SpNtStatusToDbgPrintLevel(Status), "SETUP:"__FUNCTION__":RtlAppendUnicodeStringToString:0x%08lx\n", Status )); goto NtExit; } } Status = RtlInt64ToUnicodeString(LargeInteger.QuadPart, 10, &LuidString); if (!NT_SUCCESS(Status)) { KdPrintEx(( DPFLTR_SETUP_ID, SpNtStatusToDbgPrintLevel(Status), "SETUP:"__FUNCTION__":RtlInt64ToUnicodeString:0x%08lx\n", Status )); goto NtExit; } Status = RtlAppendUnicodeStringToString(&UnicodeString, &LuidString); if (!NT_SUCCESS(Status)) { KdPrintEx(( DPFLTR_SETUP_ID, SpNtStatusToDbgPrintLevel(Status), "SETUP:"__FUNCTION__":RtlAppendUnicodeStringToString:0x%08lx\n", Status )); goto NtExit; } Length = UnicodeString.Length / sizeof(UnicodeString.Buffer[0]); UnicodeString.Buffer[Length] = 0; Exit: KdPrintEx(( DPFLTR_SETUP_ID, SpBoolToDbgPrintLevel(Length != 0), "SETUP:"__FUNCTION__":Length:0x%08lx\n", Length )); return Length; NtExit: SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); goto Exit; } #endif BOOL APIENTRY SpGetFileAttributesExA( PCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, PVOID lpFileInformation ) { UNICODE_STRING UnicodeString = { 0 }; ANSI_STRING AnsiString = { 0 }; BOOL Success = FALSE; NTSTATUS Status = STATUS_SUCCESS; RtlInitAnsiString(&AnsiString, lpFileName); AnsiString.Length = AnsiString.MaximumLength; // include terminal nul if (!NT_SUCCESS(Status = SpAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE))) { KdPrintEx(( DPFLTR_SETUP_ID, SpNtStatusToDbgPrintLevel(Status), "SETUP:"__FUNCTION__":SpAnsiStringToUnicodeString:0x%08lx\n", Status )); goto NtExit; } Success = SpGetFileAttributesExW( UnicodeString.Buffer, fInfoLevelId, lpFileInformation ); Exit: SpFreeStringW(&UnicodeString); return Success; NtExit: SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); goto Exit; } #if 0 NTSTATUS SpQueryFullAttributesFile( IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation ) /* cut dependency for now on NtQueryFullAttributesFile, since it isn't yet exported and I'm having problems with the kernel I built, use Jim's instead.. */ { HANDLE FileHandle = INVALID_HANDLE_VALUE; NTSTATUS Status = STATUS_SUCCESS; IO_STATUS_BLOCK IoStatusBlock; Status = ZwCreateFile( &FileHandle, FILE_READ_ATTRIBUTES, ObjectAttributes, &IoStatusBlock, NULL, // AllocationSize 0, // FileAttributes FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, // CreateDisposition FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT, // CreateOptions NULL, // ea 0 // ea ); if (!NT_SUCCESS(Status)) { KdPrintEx(( DPFLTR_SETUP_ID, SpNtStatusToDbgPrintLevel(Status), "SETUP:"__FUNCTION__":ZwCreateFile:0x%08lx\n", Status )); goto Exit; } Status = ZwQueryInformationFile( FileHandle, &IoStatusBlock, FileInformation, sizeof(*FileInformation), FileNetworkOpenInformation ); if (!NT_SUCCESS(Status)) { KdPrintEx(( DPFLTR_SETUP_ID, SpNtStatusToDbgPrintLevel(Status), "SETUP:"__FUNCTION__":ZwQueryInformationFile:0x%08lx\n", Status )); goto Exit; } Status = STATUS_SUCCESS; Exit: if (FileHandle != INVALID_HANDLE_VALUE) { ZwClose(FileHandle); } return Status; } #else #define SpQueryFullAttributesFile ZwQueryFullAttributesFile #endif BOOL APIENTRY SpGetFileAttributesExW( LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation ) // from base\win32\client\filemisc.c { NTSTATUS Status; UNICODE_STRING FileName; /*const*/ OBJECT_ATTRIBUTES ObjectAttributes = { sizeof(ObjectAttributes), NULL, &FileName, OBJ_CASE_INSENSITIVE }; FILE_NETWORK_OPEN_INFORMATION NetworkInfo; RtlInitUnicodeString(&FileName, lpFileName); if ( !RTL_SOFT_VERIFY(fInfoLevelId == GetFileExInfoStandard )) { SpSetLastWin32Error(ERROR_INVALID_PARAMETER); return FALSE; } Status = SpQueryFullAttributesFile( &ObjectAttributes, &NetworkInfo ); if ( NT_SUCCESS(Status) ) { const LPWIN32_FILE_ATTRIBUTE_DATA AttributeData = (LPWIN32_FILE_ATTRIBUTE_DATA)lpFileInformation; AttributeData->dwFileAttributes = NetworkInfo.FileAttributes; AttributeData->ftCreationTime = *(PFILETIME)&NetworkInfo.CreationTime; AttributeData->ftLastAccessTime = *(PFILETIME)&NetworkInfo.LastAccessTime; AttributeData->ftLastWriteTime = *(PFILETIME)&NetworkInfo.LastWriteTime; AttributeData->nFileSizeHigh = NetworkInfo.EndOfFile.HighPart; AttributeData->nFileSizeLow = (DWORD)NetworkInfo.EndOfFile.LowPart; return TRUE; } else { if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { KdPrintEx(( DPFLTR_SETUP_ID, SpNtStatusToDbgPrintLevel(Status), "SETUP:"__FUNCTION__":SpQueryFullAttributesFile:0x%08lx\n", Status )); } SpSetLastWin32ErrorAndNtStatusFromNtStatus(Status); return FALSE; } }