/*++ Copyright (c) 1989-1999 Microsoft Corporation Module Name: ioTestUserSup.c Abstract: // @@BEGIN_DDKSPLIT Author: George Jenkins (GeorgeJe) // @@END_DDKSPLIT Environment: User mode // @@BEGIN_DDKSPLIT Revision History: Molly Brown (MollyBro) 21-Apr-1999 Broke out the logging code and added command mode functionality. // @@END_DDKSPLIT --*/ #include #include #include #include #include #include #include "ioTest.h" #include "ioTestLog.h" #include "ioTestLib.h" #define NT_SUCCESS(Status) ((LONG)(Status) >= 0) #define TEST_DIRECTORY_NAME L"\\ioTest" #define READ_TEST_FILE_NAME TEST_DIRECTORY_NAME L"\\read.txt" #define READ_TEST_DATA L"Hello world!" EXPECTED_OPERATION gExpectedReadOperationsTop[] = { { TOP_FILTER, IRP_MJ_CREATE }, { BOTTOM_FILTER, IRP_MJ_CREATE }, { TOP_FILTER, IRP_MJ_READ }, { BOTTOM_FILTER, IRP_MJ_READ }, { TOP_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_MAXIMUM_FUNCTION + 1 } }; EXPECTED_OPERATION gExpectedReadOperationsDirected[] = { { BOTTOM_FILTER, IRP_MJ_CREATE }, { BOTTOM_FILTER, IRP_MJ_READ }, { BOTTOM_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_MAXIMUM_FUNCTION + 1 } }; #define WRITE_TEST_FILE_NAME TEST_DIRECTORY_NAME L"\\write.txt" #define WRITE_TEST_DATA L"Good morning!" EXPECTED_OPERATION gExpectedWriteOperationsTop[] = { { TOP_FILTER, IRP_MJ_CREATE }, { BOTTOM_FILTER, IRP_MJ_CREATE }, { TOP_FILTER, IRP_MJ_WRITE }, { BOTTOM_FILTER, IRP_MJ_WRITE }, { TOP_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_MAXIMUM_FUNCTION + 1 } }; EXPECTED_OPERATION gExpectedWriteOperationsDirected[] = { { BOTTOM_FILTER, IRP_MJ_CREATE }, { BOTTOM_FILTER, IRP_MJ_WRITE }, { BOTTOM_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_MAXIMUM_FUNCTION + 1 } }; #define RENAME_SOURCE_FILE_NAME TEST_DIRECTORY_NAME L"\\renameSource.txt" #define RENAME_TARGET_FILE_NAME TEST_DIRECTORY_NAME L"\\renameTarget.txt" EXPECTED_OPERATION gExpectedRenameOperationsTop[] = { { TOP_FILTER, IRP_MJ_CREATE }, { BOTTOM_FILTER, IRP_MJ_CREATE }, { TOP_FILTER, IRP_MJ_SET_INFORMATION }, { BOTTOM_FILTER, IRP_MJ_SET_INFORMATION }, { TOP_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_MAXIMUM_FUNCTION + 1 } }; EXPECTED_OPERATION gExpectedRenameOperationsDirected[] = { { BOTTOM_FILTER, IRP_MJ_CREATE }, { BOTTOM_FILTER, IRP_MJ_SET_INFORMATION }, { BOTTOM_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_MAXIMUM_FUNCTION + 1 } }; #define SHARE_FILE_NAME TEST_DIRECTORY_NAME L"\\share.txt" EXPECTED_OPERATION gExpectedShareOperationsTop[] = { { TOP_FILTER, IRP_MJ_CREATE }, { BOTTOM_FILTER, IRP_MJ_CREATE }, { TOP_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_MAXIMUM_FUNCTION + 1 } }; EXPECTED_OPERATION gExpectedShareOperationsDirected[] = { { BOTTOM_FILTER, IRP_MJ_CREATE }, { BOTTOM_FILTER, IRP_MJ_CLEANUP }, { BOTTOM_FILTER, IRP_MJ_MAXIMUM_FUNCTION + 1 } }; BOOL CreateTestDirectory ( PWCHAR DriveName, ULONG DriveNameLength ) { WCHAR testDirName[MAX_PATH]; DWORD result; BOOL bResult; if (sizeof( TEST_DIRECTORY_NAME ) + DriveNameLength > MAX_PATH) { printf ("Can't create test directory -- name buffer too small\n"); return FALSE; } wcscpy( testDirName, DriveName ); wcscat( testDirName, TEST_DIRECTORY_NAME ); bResult = CreateDirectory( testDirName, NULL ); if (!bResult) { result = GetLastError(); if (result != ERROR_ALREADY_EXISTS) { DisplayError( result ); return FALSE; } } return TRUE; } VOID DumpTestResultBanner ( PWCHAR TestName, BOOL Begin ) { if (Begin) { printf( "***BEGIN %S TEST RESULTS***\n", TestName ); } else { printf( "***END %S TEST RESULTS***\n", TestName ); } } VOID DumpKernelResults ( PIOTEST_STATUS TestStatus ) { printf( "Kernel verification: " ); if (NT_SUCCESS( TestStatus->TestResult )) { printf( "\tTest PASSED\n" ); } else { switch( TestStatus->Phase ) { case IoTestSetup: printf( "\tTest failed in SETUP phase with status 0x%08x\n", TestStatus->TestResult ); break; case IoTestAction: printf( "\tTest failed in ACTION phase with status 0x%08x\n", TestStatus->TestResult ); break; case IoTestValidation: printf( "\tTest failed in VALIDATION phase with status 0x%08x\n", TestStatus->TestResult ); break; case IoTestCleanup: printf( "\tTest failed in CLEANUP phase with status 0x%08x\n", TestStatus->TestResult ); break; case IoTestCompleted: printf( "\tTest failed in COMPLETED phase with status 0x%08x\n", TestStatus->TestResult ); break; default: printf( "\tTest failed in UNKNOWN phase with status 0x%08x\n", TestStatus->TestResult ); break; } } } VOID ReadTest ( PLOG_CONTEXT Context, PWCHAR DriveName, ULONG DriveNameLength, BOOLEAN TopOfStack ) { HANDLE testFile = INVALID_HANDLE_VALUE; PIOTEST_READ_WRITE_PARAMETERS parms = NULL; DWORD parmsLength; IOTEST_STATUS testStatus; BOOL bResult; DWORD bytesReturned; DWORD result; bResult = CreateTestDirectory( DriveName, DriveNameLength ); if (!bResult) { goto ReadTest_Cleanup; } // // Setup parms // parmsLength = sizeof( IOTEST_READ_WRITE_PARAMETERS ) + sizeof( READ_TEST_DATA ); parms = malloc (parmsLength); if (parms == NULL) { printf( "Insufficient resources to run READ test\n" ); goto ReadTest_Cleanup; } CopyMemory( parms->DriveNameBuffer, DriveName, DriveNameLength ); parms->DriveNameLength = DriveNameLength; if ((sizeof( READ_TEST_FILE_NAME ) + DriveNameLength) > MAX_PATH ) { // // The READ test file name is longer than our FileNameBuffer, // so return an error and quit. // printf( "READ Test file name is too long.\n" ); goto ReadTest_Cleanup; } // // We've got enough room, so build up the file name. // wcscpy( parms->FileNameBuffer, parms->DriveNameBuffer ); wcscat( parms->FileNameBuffer, READ_TEST_FILE_NAME ); parms->FileNameLength = wcslen( parms->FileNameBuffer ) * sizeof( WCHAR ); parms->FileDataLength = sizeof( READ_TEST_DATA ); CopyMemory( parms->FileData, READ_TEST_DATA, parms->FileDataLength ); parms->Flags = 0; if (TopOfStack) { parms->Flags |= IO_TEST_TOP_OF_STACK; } // // Create test file // testFile = CreateFile( parms->FileNameBuffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (testFile == INVALID_HANDLE_VALUE) { result = GetLastError(); printf ("Error opening READ test file.\n"); DisplayError( result ); goto ReadTest_Cleanup; } // // Write data to test file // bResult = WriteFile( testFile, READ_TEST_DATA, sizeof( READ_TEST_DATA ), &bytesReturned, NULL ); if (!bResult) { result = GetLastError(); printf("ERROR writing data READ test file...\n"); DisplayError( result ); goto ReadTest_Cleanup; } CloseHandle( testFile ); testFile = INVALID_HANDLE_VALUE; // // Send message down to filter // bResult = DeviceIoControl( Context->Device, IOTEST_ReadTest, parms, parmsLength, &testStatus, sizeof( testStatus ), &bytesReturned, NULL); if (!bResult) { result = GetLastError(); printf("ERROR running READ test...\n"); DisplayError( result ); goto ReadTest_Cleanup; } // // Print out the result of the kernel verification tests. // DumpTestResultBanner( L"READ", TRUE ); DumpKernelResults( &testStatus ); // // Read and verify log // if (TopOfStack) { VerifyCurrentLogRecords( Context, gExpectedReadOperationsTop ); } else { VerifyCurrentLogRecords( Context, gExpectedReadOperationsDirected ); } DumpTestResultBanner( L"READ", FALSE ); ReadTest_Cleanup: if (testFile != INVALID_HANDLE_VALUE) { CloseHandle( testFile ); } if (parms != NULL) { free( parms ); } return; } VOID RenameTest ( PLOG_CONTEXT Context, PWCHAR DriveName, ULONG DriveNameLength, BOOLEAN TopOfStack ) { BOOL bResult; IOTEST_RENAME_PARAMETERS parms; IOTEST_STATUS testStatus; HANDLE sourceFile; HANDLE targetFile; DWORD bytesReturned; DWORD result; bResult = CreateTestDirectory( DriveName, DriveNameLength ); if (!bResult) { goto RenameTest_Cleanup; } // // Setup parameters // CopyMemory( &(parms.DriveNameBuffer), DriveName, DriveNameLength ); parms.DriveNameLength = DriveNameLength; if ((sizeof( RENAME_SOURCE_FILE_NAME ) + DriveNameLength) > MAX_PATH ) { // // The RENAME test source file name is longer than our // SourceFileNameBuffer, so return an error and quit. // printf( "RENAME Test source file name is too long.\n" ); goto RenameTest_Cleanup; } // // We've got enough room, so build up the source file name. // wcscpy( parms.SourceFileNameBuffer, parms.DriveNameBuffer ); wcscat( parms.SourceFileNameBuffer, RENAME_SOURCE_FILE_NAME ); parms.SourceFileNameLength = wcslen( parms.SourceFileNameBuffer ) * sizeof( WCHAR ); if ((sizeof( RENAME_TARGET_FILE_NAME ) + DriveNameLength) > MAX_PATH ) { // // The RENAME test target file name is longer than our // TargetFileNameBuffer, so return an error and quit. // printf( "RENAME Test target file name is too long.\n" ); goto RenameTest_Cleanup; } // // We've got enough room, so build up the source file name. // wcscpy( parms.TargetFileNameBuffer, parms.DriveNameBuffer ); wcscat( parms.TargetFileNameBuffer, RENAME_TARGET_FILE_NAME ); parms.TargetFileNameLength = wcslen( parms.TargetFileNameBuffer ) * sizeof( WCHAR ); parms.Flags = 0; if (TopOfStack) { parms.Flags |= IO_TEST_TOP_OF_STACK; } // // Setup source file // sourceFile = CreateFile( RENAME_SOURCE_FILE_NAME, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (sourceFile == INVALID_HANDLE_VALUE) { result = GetLastError(); printf ("Error opening RENAME test source file.\n"); DisplayError( result ); goto RenameTest_Cleanup; } CloseHandle( sourceFile ); sourceFile = INVALID_HANDLE_VALUE; // // Make sure that the target file does NOT exist. // targetFile = CreateFile( RENAME_TARGET_FILE_NAME, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL ); if (targetFile == INVALID_HANDLE_VALUE) { result = GetLastError(); if (result != ERROR_ALREADY_EXISTS && result != ERROR_FILE_NOT_FOUND) { printf ("Error opening RENAME test target file.\n"); DisplayError( result ); goto RenameTest_Cleanup; } } else { // // The file does exist, so lets delete by closing the handle. // CloseHandle( targetFile ); targetFile = INVALID_HANDLE_VALUE; } // // Send message down to filter // bResult = DeviceIoControl( Context->Device, IOTEST_RenameTest, &parms, sizeof( parms ), &testStatus, sizeof( testStatus ), &bytesReturned, NULL); if (!bResult) { result = GetLastError(); printf("ERROR running RENAME test...\n"); DisplayError( result ); goto RenameTest_Cleanup; } // // Display test results. // DumpTestResultBanner( L"RENAME", TRUE ); DumpKernelResults( &testStatus ); // // Read and verify logs // if (TopOfStack) { VerifyCurrentLogRecords( Context, gExpectedRenameOperationsTop ); } else { VerifyCurrentLogRecords( Context, gExpectedRenameOperationsDirected ); } // // Verify that the sourceFile is no longer present. // sourceFile = CreateFile( RENAME_SOURCE_FILE_NAME, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL ); if (sourceFile == INVALID_HANDLE_VALUE) { printf( "User test verification:\tPASSED - Source file no longer present.\n" ); } else { printf( "User test verification:\tFAILED - Source test file still exists.\n" ); CloseHandle( sourceFile ); } // // Verify that the targetFile is present // targetFile = CreateFile( RENAME_TARGET_FILE_NAME, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL ); if (targetFile == INVALID_HANDLE_VALUE) { result = GetLastError(); printf( "User test verification:\tFAILED - Unexpected error trying to open target file %d.\n", result ); } else { printf( "User test verification:\tPASSED - Target test file exists.\n" ); CloseHandle( targetFile ); targetFile = INVALID_HANDLE_VALUE; } DumpTestResultBanner( L"RENAME", FALSE ); RenameTest_Cleanup: if (sourceFile != INVALID_HANDLE_VALUE) { CloseHandle( sourceFile ); } if (targetFile != INVALID_HANDLE_VALUE) { CloseHandle( targetFile ); } return; } VOID ShareTest ( PLOG_CONTEXT Context, PWCHAR DriveName, ULONG DriveNameLength, BOOLEAN TopOfStack ) { BOOL bResult; IOTEST_SHARE_PARAMETERS parms; IOTEST_STATUS testStatus; HANDLE file; DWORD bytesReturned; DWORD result; bResult = CreateTestDirectory( DriveName, DriveNameLength ); if (!bResult) { goto ShareTest_Cleanup; } // // Setup parameters // CopyMemory( &(parms.DriveNameBuffer), DriveName, DriveNameLength ); parms.DriveNameLength = DriveNameLength; if ((sizeof( SHARE_FILE_NAME ) + DriveNameLength) > MAX_PATH ) { // // The RENAME test source file name is longer than our // SourceFileNameBuffer, so return an error and quit. // printf( "SHARE Test file name is too long.\n" ); goto ShareTest_Cleanup; } // // We've got enough room, so build up the source file name. // wcscpy( parms.FileNameBuffer, parms.DriveNameBuffer ); wcscat( parms.FileNameBuffer, SHARE_FILE_NAME ); parms.FileNameLength = wcslen( parms.FileNameBuffer ) * sizeof( WCHAR ); parms.Flags = 0; if (TopOfStack) { parms.Flags |= IO_TEST_TOP_OF_STACK; } // // Setup source file // file = CreateFile( SHARE_FILE_NAME, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (file == INVALID_HANDLE_VALUE) { result = GetLastError(); printf ("Error opening SHARE test file.\n"); DisplayError( result ); goto ShareTest_Cleanup; } // // Send message down to filter // bResult = DeviceIoControl( Context->Device, IOTEST_ShareTest, &parms, sizeof( parms ), &testStatus, sizeof( testStatus ), &bytesReturned, NULL); if (!bResult) { result = GetLastError(); printf("ERROR running SHARE test...\n"); DisplayError( result ); goto ShareTest_Cleanup; } // // Display test results. // DumpTestResultBanner( L"SHARE", TRUE ); DumpKernelResults( &testStatus ); // // Read and verify logs // if (TopOfStack) { VerifyCurrentLogRecords( Context, gExpectedShareOperationsTop ); } else { VerifyCurrentLogRecords( Context, gExpectedShareOperationsDirected ); } DumpTestResultBanner( L"SHARE", FALSE ); ShareTest_Cleanup: if (file != INVALID_HANDLE_VALUE) { CloseHandle( file ); } return; }