/*++ Copyright (c) 1989-1997 Microsoft Corporation Module Name: rentest.c Abstract: This module contains tests for stream rename support --*/ extern "C" { #include #include #include #include } #include #include #define DEFAULT_DATA_STREAM "::$DATA" // // Simple wrapper for NtCreateFile // NTSTATUS OpenObject ( WCHAR const *pwszFile, HANDLE RelatedObject, ULONG CreateOptions, ULONG DesiredAccess, ULONG ShareAccess, ULONG CreateDisposition, HANDLE *ph) { NTSTATUS Status; OBJECT_ATTRIBUTES oa; UNICODE_STRING str; IO_STATUS_BLOCK isb; if (RelatedObject == NULL) { RtlDosPathNameToNtPathName_U(pwszFile, &str, NULL, NULL); } else { RtlInitUnicodeString(&str, pwszFile); } InitializeObjectAttributes( &oa, &str, OBJ_CASE_INSENSITIVE, RelatedObject, NULL); Status = NtCreateFile( ph, DesiredAccess | SYNCHRONIZE, &oa, &isb, NULL, // pallocationsize (none!) FILE_ATTRIBUTE_NORMAL, ShareAccess, CreateDisposition, CreateOptions, NULL, // EA buffer (none!) 0); RtlFreeHeap(RtlProcessHeap(), 0, str.Buffer); return(Status); } void SzToWsz ( OUT WCHAR *Unicode, IN char *Ansi ) { while (*Unicode++ = *Ansi++) ; } typedef enum { NoTarget, EmptyTarget, NonZeroTarget } TARGET_STATUS; typedef enum { EmptySource, SmallSource, BigSource } SOURCE_STATUS; void StickDataIn ( HANDLE Handle, char *SomeData, SOURCE_STATUS SourceStatus ) { if (SourceStatus == EmptySource) { } else if (SourceStatus == SmallSource) { IO_STATUS_BLOCK Iosb; NTSTATUS Status = NtWriteFile( Handle, NULL, NULL, NULL, &Iosb, SomeData, strlen( SomeData ), NULL, NULL ); if (!NT_SUCCESS( Status )) { printf( "Unable to stick data in - %x\n", Status ); } NtFlushBuffersFile( Handle, &Iosb ); } else if (SourceStatus == BigSource) { IO_STATUS_BLOCK Iosb; LARGE_INTEGER Offset; Offset.QuadPart = 1024 * 1024; NTSTATUS Status = NtWriteFile( Handle, NULL, NULL, NULL, &Iosb, SomeData, strlen( SomeData ), &Offset, NULL ); if (!NT_SUCCESS( Status )) { printf( "Unable to stick data in - %x\n", Status ); } NtFlushBuffersFile( Handle, &Iosb ); } } void CheckData ( HANDLE Handle, char *Data, SOURCE_STATUS SourceStatus, int Line ) { if (SourceStatus == EmptySource) { // // Verify that the source is zero bytes long // } else if (SourceStatus == SmallSource) { IO_STATUS_BLOCK Iosb; char *FileData = new char[ strlen( Data )]; NTSTATUS Status = NtReadFile( Handle, NULL, NULL, NULL, &Iosb, FileData, strlen( Data ), NULL, NULL ); if (!NT_SUCCESS( Status )) { printf( "line %d Unable to read data - %x\n", Line, Status ); } if (memcmp( Data, FileData, strlen( Data ))) { printf( "line %d small data is different\n", Line ); printf( "File: '%.*s' Test: '%s'\n", strlen( Data ), FileData, Data ); } delete [] FileData; } else if (SourceStatus == BigSource) { IO_STATUS_BLOCK Iosb; char *FileData = new char[ strlen( Data )]; LARGE_INTEGER Offset; Offset.QuadPart = 1024 * 1024; NTSTATUS Status = NtReadFile( Handle, NULL, NULL, NULL, &Iosb, FileData, strlen( Data ), &Offset, NULL ); if (!NT_SUCCESS( Status )) { printf( "line %d Unable to read data in - %x\n", Line, Status ); } if (memcmp( Data, FileData, strlen( Data ))) { printf( "line %d large data is different\n", Line ); printf( "File: '%.*s' Test: '%s'\n", strlen( Data ), FileData, Data ); } delete [] FileData; } } #define TESTONE \ printf( "TestOne( %s, %s, %x, %x, %x, Line %d ): ", \ SourceStream, TargetStream, \ TargetStatus, ReplaceIfExists, ExpectedStatus, \ Line ) #define CLOSE(h) { \ NTSTATUS TmpStatus = NtClose(h); \ h = INVALID_HANDLE_VALUE; \ if (!NT_SUCCESS( TmpStatus )) { \ TESTONE; printf( "Couldn't close handle @ %d\n", __LINE__ ); \ } \ } // // Open a handle relative to the parent of the Source stream. // void TestOne ( char *FileName, char *SourceStream, SOURCE_STATUS SourceStatus, char *TargetStream, TARGET_STATUS TargetStatus, BOOLEAN ReplaceIfExists, NTSTATUS ExpectedStatus, int Line ) { NTSTATUS Status; WCHAR UnicodeFullSourceStreamName[MAX_PATH]; WCHAR UnicodeFullTargetStreamName[MAX_PATH]; WCHAR UnicodeTargetStreamName[MAX_PATH]; HANDLE SourceHandle; HANDLE TargetHandle; // // Convert names to unicode and form complete source name // SzToWsz( UnicodeFullSourceStreamName, FileName ); SzToWsz( UnicodeFullSourceStreamName + wcslen( UnicodeFullSourceStreamName ), SourceStream ); SzToWsz( UnicodeTargetStreamName, TargetStream ); SzToWsz( UnicodeFullTargetStreamName, FileName ); SzToWsz( UnicodeFullTargetStreamName + wcslen( UnicodeFullTargetStreamName ), TargetStream ); // // Create/open source stream // Status = OpenObject( UnicodeFullSourceStreamName, NULL, FILE_SYNCHRONOUS_IO_NONALERT, FILE_READ_DATA | FILE_WRITE_DATA | DELETE, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, &SourceHandle ); if (!NT_SUCCESS( Status )) { TESTONE; printf( "unable to open source stream - %x\n", Status ); } // // Stick data into source // StickDataIn( SourceHandle, SourceStream, SourceStatus ); // // If target is not supposed to exist // if (TargetStatus == NoTarget) { // // Create/Open target stream with delete-on-close // Status = OpenObject( UnicodeFullTargetStreamName, NULL, FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE, FILE_READ_DATA | FILE_WRITE_DATA | DELETE, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, &TargetHandle ); // // Close target stream (do the delete) // if (NT_SUCCESS( Status )) { CLOSE( TargetHandle ); } else { TESTONE; printf( "Unable to set NoTarget on %s - %x\n", TargetStream, Status ); } } else { // // Create/open target stream // Status = OpenObject( UnicodeFullTargetStreamName, NULL, FILE_SYNCHRONOUS_IO_NONALERT, FILE_READ_DATA | FILE_WRITE_DATA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, &TargetHandle ); if (!NT_SUCCESS( Status )) { TESTONE; printf( "unable to open target for sizing %x\n", Status ); } FILE_END_OF_FILE_INFORMATION EndOfFile; EndOfFile.EndOfFile.QuadPart = 0i64; IO_STATUS_BLOCK Iosb; Status = NtSetInformationFile( TargetHandle, &Iosb, &EndOfFile, sizeof( EndOfFile ), FileEndOfFileInformation ); // // If target has data in it // if (TargetStatus == NonZeroTarget) { // // Stick data into target // StickDataIn( TargetHandle, TargetStream, SmallSource ); } // // Close target // CLOSE( TargetHandle ); } // // Set up FileRenameInformation // char buffer[sizeof( FILE_RENAME_INFORMATION ) + MAX_PATH * sizeof( WCHAR )]; PFILE_RENAME_INFORMATION FileRenameInformationBlock = (PFILE_RENAME_INFORMATION) buffer; FileRenameInformationBlock->ReplaceIfExists = ReplaceIfExists; FileRenameInformationBlock->RootDirectory = NULL; FileRenameInformationBlock->FileNameLength = strlen( TargetStream ) * sizeof( WCHAR ); SzToWsz( FileRenameInformationBlock->FileName, TargetStream ); // // Attempt to rename // IO_STATUS_BLOCK Iosb; Status = NtSetInformationFile( SourceHandle, &Iosb, FileRenameInformationBlock, sizeof( buffer ), FileRenameInformation ); // // Check output status codes // if (Status != ExpectedStatus) { TESTONE; printf( "status was %x\n", Status ); } // // Close Source stream // CLOSE( SourceHandle ); // // If we succeeded in tehe rename // if (NT_SUCCESS( Status )) { // // Verify that the source stream no longer exists // Status = OpenObject( UnicodeFullSourceStreamName, NULL, FILE_SYNCHRONOUS_IO_NONALERT, FILE_READ_DATA | FILE_WRITE_DATA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, &SourceHandle ); // // Verify that the source does/doesn't exist as appropriate // if (NT_SUCCESS( Status )) { if (!strcmp( SourceStream, DEFAULT_DATA_STREAM )) { // Default data stream still exists. No problem } else { TESTONE; printf( "source stream still exists\n" ); } CLOSE( SourceHandle ); } else if (!strcmp( SourceStream, DEFAULT_DATA_STREAM )) { TESTONE; printf( "failed to open default data stream - %x\n", Status ); } else { // failed to open previous source stream. No problem } // // Reopen the target stream (formerly source stream) // Status = OpenObject( UnicodeFullTargetStreamName, NULL, FILE_SYNCHRONOUS_IO_NONALERT, FILE_READ_DATA | FILE_WRITE_DATA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, &TargetHandle ); if (!NT_SUCCESS( Status )) { TESTONE; printf( "unable to open target for verification %x\n", Status ); } // // Verify the contents // CheckData( TargetHandle, SourceStream, SourceStatus, Line ); CLOSE( TargetHandle ); } } void RenameTest ( char *FileName ) { // Test: // ::$Data to :New Succeed // ::$Data to :NonZero Fail always // ::$Data to :Empty Succeed if ReplaceIfExists // :Test to ::$Data Succeed if ReplaceIfExists // :Test to ::$Data Fail always // // XXX:Test to YYY:Test Fail always // // ::$Data to :New Succeed TestOne( FileName, DEFAULT_DATA_STREAM, EmptySource, ":New", NoTarget, FALSE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, EmptySource, ":New", NoTarget, TRUE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, SmallSource, ":New", NoTarget, FALSE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, SmallSource, ":New", NoTarget, TRUE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, BigSource, ":New", NoTarget, FALSE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, BigSource, ":New", NoTarget, TRUE, STATUS_SUCCESS, __LINE__ ); // ::$Data to :NonZero Fail always TestOne( FileName, DEFAULT_DATA_STREAM, EmptySource, ":NonZero", NonZeroTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, EmptySource, ":NonZero", NonZeroTarget, TRUE, STATUS_INVALID_PARAMETER, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, SmallSource, ":NonZero", NonZeroTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, SmallSource, ":NonZero", NonZeroTarget, TRUE, STATUS_INVALID_PARAMETER, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, BigSource, ":NonZero", NonZeroTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, BigSource, ":NonZero", NonZeroTarget, TRUE, STATUS_INVALID_PARAMETER, __LINE__ ); // ::$Data to :Empty Succeed if ReplaceIfExists TestOne( FileName, DEFAULT_DATA_STREAM, EmptySource, ":Empty", EmptyTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, EmptySource, ":Empty", EmptyTarget, TRUE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, SmallSource, ":Empty", EmptyTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, SmallSource, ":Empty", EmptyTarget, TRUE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, BigSource, ":Empty", EmptyTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, DEFAULT_DATA_STREAM, BigSource, ":Empty", EmptyTarget, TRUE, STATUS_SUCCESS, __LINE__ ); // :Test to ::$Data Succeed if ReplaceIfExists TestOne( FileName, ":Test", EmptySource, DEFAULT_DATA_STREAM, EmptyTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", EmptySource, DEFAULT_DATA_STREAM, EmptyTarget, TRUE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, ":Test", SmallSource, DEFAULT_DATA_STREAM, EmptyTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", SmallSource, DEFAULT_DATA_STREAM, EmptyTarget, TRUE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, ":Test", BigSource, DEFAULT_DATA_STREAM, EmptyTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", BigSource, DEFAULT_DATA_STREAM, EmptyTarget, TRUE, STATUS_SUCCESS, __LINE__ ); // :Test to ::$Data Fail always TestOne( FileName, ":Test", EmptySource, DEFAULT_DATA_STREAM, NonZeroTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", EmptySource, DEFAULT_DATA_STREAM, NonZeroTarget, TRUE, STATUS_INVALID_PARAMETER, __LINE__ ); TestOne( FileName, ":Test", SmallSource, DEFAULT_DATA_STREAM, NonZeroTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", SmallSource, DEFAULT_DATA_STREAM, NonZeroTarget, TRUE, STATUS_INVALID_PARAMETER, __LINE__ ); TestOne( FileName, ":Test", BigSource, DEFAULT_DATA_STREAM, NonZeroTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", BigSource, DEFAULT_DATA_STREAM, NonZeroTarget, TRUE, STATUS_INVALID_PARAMETER, __LINE__ ); // :Test to :New Succeed TestOne( FileName, ":Test", EmptySource, ":New", NoTarget, FALSE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, ":Test", EmptySource, ":New", NoTarget, TRUE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, ":Test", SmallSource, ":New", NoTarget, FALSE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, ":Test", SmallSource, ":New", NoTarget, TRUE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, ":Test", BigSource, ":New", NoTarget, FALSE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, ":Test", BigSource, ":New", NoTarget, TRUE, STATUS_SUCCESS, __LINE__ ); // :Test to :NonZero Fail always TestOne( FileName, ":Test", EmptySource, ":New", NonZeroTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", EmptySource, ":New", NonZeroTarget, TRUE, STATUS_INVALID_PARAMETER, __LINE__ ); TestOne( FileName, ":Test", SmallSource, ":New", NonZeroTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", SmallSource, ":New", NonZeroTarget, TRUE, STATUS_INVALID_PARAMETER, __LINE__ ); TestOne( FileName, ":Test", BigSource, ":New", NonZeroTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", BigSource, ":New", NonZeroTarget, TRUE, STATUS_INVALID_PARAMETER, __LINE__ ); // :Test to :Empty Succeed if ReplaceIfExists TestOne( FileName, ":Test", EmptySource, ":New", EmptyTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", EmptySource, ":New", EmptyTarget, TRUE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, ":Test", SmallSource, ":New", EmptyTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", SmallSource, ":New", EmptyTarget, TRUE, STATUS_SUCCESS, __LINE__ ); TestOne( FileName, ":Test", BigSource, ":New", EmptyTarget, FALSE, STATUS_OBJECT_NAME_COLLISION, __LINE__ ); TestOne( FileName, ":Test", BigSource, ":New", EmptyTarget, TRUE, STATUS_SUCCESS, __LINE__ ); } int __cdecl main ( int argc, char **argv) { DbgPrint( "--------------------------------------------\n" ); while (--argc != 0) { RenameTest( *++argv ); } DbgPrint( "--------------------------------------------\n" ); return 0; }