/*++ Copyright (c) 1993 Microsoft Corporation Module Name: tex.c Abstract: User mode test program for the Microsoft Netware redir file system. This test program can be built from the command line using the command 'nmake UMTEST=tex'. Author: Manny Weiser (mannyw) 7-Jun-1993 Revision History: --*/ #include #include #include #include #include #include #include #include // // Local definitions // VOID DisplayUsage( PSZ ProgramName ); SendMessage( IN char* Format, ... ); VOID SetLock( PCHAR FileHandle, BOOLEAN Exclusive, ULONG ByteOffset, ULONG Length, ULONG Timeout ); NTSTATUS FormatRequest( PCHAR SendBuffer, PULONG SendBufferLength, char* Format, va_list a ); BOOLEAN OpenServer( PHANDLE Handle, PWCH ServerName ); NTSTATUS _cdecl ParseResponse( char* FormatString, ... // format specific parameters ); #define BUFFER_SIZE 200 WCHAR *ServerName = L"NETWARE311"; UCHAR Pid = 255; HANDLE ServerHandle; _cdecl main( int argc, char *argv[], ) { BOOLEAN success; UCHAR DirectoryHandle; UCHAR FileHandle1[6]; UCHAR FileHandle2[6]; success = OpenServer( &ServerHandle, ServerName ); if ( !success) { return 1; } printf("Opened server, %S\n", ServerName ); // Get directory handle for SYS: SendMessage( "Sbbp", 0x16, 0x12, 0, 0, "SYS:" ); ParseResponse( "b", &DirectoryHandle ); // Open FILE1 Pid = 100; SendMessage( "Fbbbp", 0x4C, DirectoryHandle, 0x07, 01, "File1" ); ParseResponse( "r", FileHandle1, 6 ); // Open FILE1 Pid = 101; SendMessage( "Fbbbp", 0x4C, DirectoryHandle, 0x07, 01, "File1" ); ParseResponse( "r", FileHandle2, 6 ); // Lock test Pid = 100; SetLock( FileHandle1, TRUE, 0, 10, 0xFFFF ); SetLock( FileHandle1, TRUE, 10, 10, 0xFFFF ); SetLock( FileHandle1, TRUE, 5, 10, 0xFFFF ); SetLock( FileHandle1, TRUE, 10, 10, 0xFFFF ); Pid = 101; SetLock( FileHandle2, TRUE, 6, 10, 0xFFFF ); SetLock( FileHandle2, TRUE, 7, 10, 0xFFFF ); SetLock( FileHandle2, TRUE, 0, 10, 0xFFFF ); Sleep( 10 * 1000 ); // Close FILE1 SendMessage( "F-r", 0x42, FileHandle1, 6 ); ParseResponse( "" ); // Close FILE1 SendMessage( "F-r", 0x42, FileHandle2, 6 ); ParseResponse( "" ); // End Job Pid = 100; SendMessage( "F-", 0x18 ); Pid = 101; SendMessage( "F-", 0x18 ); // Close the directory SendMessage( "Sb", 0x16, 0x14, DirectoryHandle ); ParseResponse( "" ); printf( "%s exiting\n", argv[0]); return 0; } VOID SetLock( PCHAR FileHandle, BOOLEAN Exclusive, ULONG ByteOffset, ULONG Length, ULONG Timeout ) { USHORT Flags; if ( Exclusive ) { Flags = 1; } else { Flags = 3; } SendMessage( "Fbrddw", 0x1A, Flags, FileHandle, 6, ByteOffset, Length, Timeout ); ParseResponse( "" ); } BOOLEAN OpenServer( PHANDLE Handle, PWCH ServerName ) { NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatusBlock; WCHAR FileNameBuffer[100]; UNICODE_STRING FileName; FileName.Buffer = FileNameBuffer; FileName.Length = 0; FileName.MaximumLength = 100; status = RtlAppendUnicodeToString( &FileName, DD_NWFS_DEVICE_NAME_U ); ASSERT( status == STATUS_SUCCESS ); status = RtlAppendUnicodeToString( &FileName, L"\\" ); ASSERT( status == STATUS_SUCCESS ); status = RtlAppendUnicodeToString( &FileName, ServerName ); ASSERT( status == STATUS_SUCCESS ); // // Open the file // InitializeObjectAttributes( &objectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtOpenFile ( Handle, FILE_GENERIC_READ | SYNCHRONIZE, &objectAttributes, &ioStatusBlock, FILE_SHARE_WRITE | FILE_SHARE_READ, 0L ); if (!NT_SUCCESS(status) ) { printf( "Open status = %x for file %Z\n", status, &FileName ); } return ( (BOOLEAN) NT_SUCCESS( status ) ); } CHAR Buffer1[100]; CHAR Buffer2[100]; SendMessage( IN char* Format, ... ) { NTSTATUS status; IO_STATUS_BLOCK IoStatusBlock; va_list Arguments; NTSTATUS Status; ULONG ReceiveBufferSize = 100; ULONG SendBufferSize = 100; va_start( Arguments, Format ); Buffer1[0] = Pid; Status = FormatRequest( &Buffer1[1], &SendBufferSize, Format, Arguments ); if ( !NT_SUCCESS( Status ) ) { return( Status ); } printf("Sending message\n" ); status = NtFsControlFile( ServerHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_NWR_ANY_NCP, Buffer1, SendBufferSize + 1, Buffer2, ReceiveBufferSize ); if ( NT_SUCCESS( status ) ) { status = NtWaitForSingleObject( ServerHandle, FALSE, NULL ); if ( NT_SUCCESS( status )) { status = IoStatusBlock.Status; } } if ( !NT_SUCCESS( status ) ) { printf("NtFsControlFile returns %08lx\n", status ); return( status ); } else { printf("Message received\n" ); } return( status ); } NTSTATUS FormatRequest( PCHAR SendBuffer, PULONG SendBufferLength, char* Format, va_list a ) /*++ Routine Description: Send the packet described by Format and the additional parameters. Arguments: Format - the information needed to create the request to the server. The first byte indicates the packet type and the following bytes contain field types. Packet types: 'A' SAP broadcast ( void ) 'C' NCP connect ( void ) 'F' NCP function ( byte ) 'S' NCP subfunction ( byte, byte ) 'D' NCP disconnect ( void ) Field types, request/response: 'b' byte ( byte / byte* ) 'w' hi-lo word ( word / word* ) 'd' hi-lo dword ( dword / dword* ) '-' zero/skip byte ( void ) '=' zero/skip word ( void ) ._. zero/skip string ( word ) 'p' pstring ( char* ) 'u' p unicode string ( UNICODE_STRING * ) 'c' cstring ( char* ) 'r' raw bytes ( byte*, word ) 'u' p unicode string ( UNICODE_STRING * ) 'U' p uppercase string( UNICODE_STRING * ) 'f' separate fragment ( PMDL ) An 'f' field must be last, and in a response it cannot be preceeded by 'p' or 'c' fields. Return Value: Normally returns STATUS_PENDING. --*/ { NTSTATUS status; char* pFormatCharacter; USHORT t = 1; ULONG data_size; ULONG length; data_size = 1; SendBuffer[ 0 ] = va_arg( a, UCHAR ); if ( *Format == 'S' ) { data_size += 2; SendBuffer[data_size++] = va_arg( a, UCHAR ); } pFormatCharacter = Format; while ( *++pFormatCharacter && *pFormatCharacter != 'f' ) { switch ( *pFormatCharacter ) { case '=': SendBuffer[data_size++] = 0; case '-': SendBuffer[data_size++] = 0; break; case '_': length = va_arg ( a, USHORT ); if ( data_size + length > *SendBufferLength ) { printf("***exch:!0!\n"); return( FALSE ); } while ( length-- ) { SendBuffer[data_size++] = 0; } break; case 'b': SendBuffer[data_size++] = va_arg ( a, UCHAR ); break; case 'w': { USHORT w = va_arg ( a, USHORT ); SendBuffer[data_size++] = (UCHAR) (w >> 8); SendBuffer[data_size++] = (UCHAR) (w >> 0); break; } case 'd': { ULONG d = va_arg ( a, ULONG ); SendBuffer[data_size++] = (UCHAR) (d >> 24); SendBuffer[data_size++] = (UCHAR) (d >> 16); SendBuffer[data_size++] = (UCHAR) (d >> 8); SendBuffer[data_size++] = (UCHAR) (d >> 0); break; } case 'c': { char* c = va_arg ( a, char* ); length = strlen( c ); if ( data_size + length > *SendBufferLength ) { printf("***exch:!1!\n"); return( FALSE ); } RtlCopyMemory( &SendBuffer[data_size], c, length + 1 ); data_size += length + 1; break; } case 'p': { char* c = va_arg ( a, char* ); length = strlen( c ); if ( data_size + length > *SendBufferLength ) { printf("***exch:!2!\n"); return FALSE; } SendBuffer[data_size++] = (UCHAR)length; RtlCopyMemory( &SendBuffer[data_size], c, length ); data_size += length; break; } case 'u': { PUNICODE_STRING pUString = va_arg ( a, PUNICODE_STRING ); OEM_STRING OemString; // // Calculate required string length, excluding trailing NUL. // length = (USHORT)RtlUnicodeStringToOemSize( pUString ) - 1; ASSERT( length < 0x100 ); if ( data_size + length > *SendBufferLength ) { printf("***exch:!4!\n"); return( FALSE ); } SendBuffer[data_size++] = (UCHAR)length; OemString.Buffer = &SendBuffer[data_size]; OemString.MaximumLength = (USHORT)length + 1; status = RtlUnicodeStringToCountedOemString( &OemString, pUString, FALSE ); ASSERT( NT_SUCCESS( status )); data_size += (USHORT)length; break; } case 'U': { USHORT i; // // UPPERCASE the string, copy it from unicode to the packet // PUNICODE_STRING pUString = va_arg ( a, PUNICODE_STRING ); UNICODE_STRING UUppercaseString; OEM_STRING OemString; if ( pUString->Length > 0 ) { RtlUpcaseUnicodeString( &UUppercaseString, pUString, TRUE ); // // Change all '\' to '/' // for ( i = 0 ; i < UUppercaseString.Length ; i++ ) { if ( UUppercaseString.Buffer[i] == L'\\' ) { UUppercaseString.Buffer[i] = L'/'; } } // // Calculate required string length, excluding trailing NUL. // length = (USHORT)RtlUnicodeStringToOemSize( &UUppercaseString ) - 1; ASSERT( length < 0x100 ); } else { UUppercaseString = *pUString; length = 0; } if ( data_size + length > *SendBufferLength ) { printf("***exch:!5!\n"); return( FALSE ); } SendBuffer[data_size++] = (UCHAR)length; OemString.Buffer = &SendBuffer[data_size]; OemString.MaximumLength = (USHORT)length + 1; status = RtlUnicodeStringToCountedOemString( &OemString, &UUppercaseString, FALSE ); ASSERT( NT_SUCCESS( status )); if ( pUString->Length > 0 ) { RtlFreeUnicodeString( &UUppercaseString ); } data_size += (USHORT)length; break; } case 'r': { UCHAR* b = va_arg ( a, UCHAR* ); length = va_arg ( a, USHORT ); if ( data_size + length > *SendBufferLength ) { printf("***exch:!6!\n"); return( FALSE ); } RtlCopyMemory( &SendBuffer[data_size], b, length ); data_size += length; break; } default: printf ( "*****exchange: invalid request field, %x\n", *pFormatCharacter); return( FALSE ); } if ( data_size > *SendBufferLength ) { printf( "*****exchange: CORRUPT, too much request data\n" ); va_end( a ); return FALSE; } } if ( *Format == 'S' ) { SendBuffer[1] = (UCHAR)((data_size-3) >> 8); SendBuffer[2] = (UCHAR)(data_size-3); } va_end( a ); *SendBufferLength = data_size; return TRUE; } NTSTATUS _cdecl ParseResponse( char* FormatString, ... // format specific parameters ) /*++ Routine Description: This routine parse an NCP response. Arguments: FormatString - supplies the information needed to create the request to the server. The first byte indicates the packet type and the following bytes contain field types. Field types, request/response: 'b' byte ( byte* ) 'w' hi-lo word ( word* ) 'd' hi-lo dword ( dword* ) '-' zero/skip byte ( void ) '=' zero/skip word ( void ) ._. zero/skip string ( word ) 'p' pstring ( char* ) 'c' cstring ( char* ) 'r' raw bytes ( byte*, word ) 'R' ASCIIZ to Unicode ( UNICODE_STRING *, word ) Return Value: STATUS - The converted error code from the NCP response. --*/ { PCHAR FormatByte; va_list Arguments; int Length = 0; va_start( Arguments, FormatString ); FormatByte = FormatString; while ( *FormatByte ) { switch ( *FormatByte ) { case '-': Length += 1; break; case '=': Length += 2; break; case '_': { USHORT l = va_arg ( Arguments, USHORT ); Length += l; break; } case 'b': { UCHAR* b = va_arg ( Arguments, UCHAR* ); *b = Buffer2[Length++]; break; } case 'w': { UCHAR* b = va_arg ( Arguments, UCHAR* ); b[1] = Buffer2[Length++]; b[0] = Buffer2[Length++]; break; } case 'd': { UCHAR* b = va_arg ( Arguments, UCHAR* ); b[3] = Buffer2[Length++]; b[2] = Buffer2[Length++]; b[1] = Buffer2[Length++]; b[0] = Buffer2[Length++]; break; } case 'c': { char* c = va_arg ( Arguments, char* ); USHORT l = strlen( &Buffer2[Length] ); memcpy ( c, &Buffer2[Length], l+1 ); Length += l+1; break; } case 'p': { char* c = va_arg ( Arguments, char* ); UCHAR l = Buffer2[Length++]; memcpy ( c, &Buffer2[Length], l ); c[l+1] = 0; break; } #if 0 case 'P': { PUNICODE_STRING pUString = va_arg ( Arguments, PUNICODE_STRING ); OEM_STRING OemString; OemString.Length = Buffer2[Length++]; OemString.Buffer = &Buffer2[Length]; Status = RtlOemStringToCountedUnicodeString( pUString, &OemString, FALSE ); ASSERT( NT_SUCCESS( Status )); break; } #endif case 'r': { UCHAR* b = va_arg ( Arguments, UCHAR* ); USHORT l = va_arg ( Arguments, USHORT ); RtlCopyMemory( b, &Buffer2[Length], l ); Length += l; break; } #if 0 case 'R': { // // Interpret the buffer as an ASCIIZ string. Convert // it to unicode in the preallocated buffer. // PUNICODE_STRING pUString = va_arg ( Arguments, PUNICODE_STRING ); OEM_STRING OemString; USHORT len = va_arg ( Arguments, USHORT ); OemString.Buffer = &Buffer2[Length]; OemString.Length = strlen( OemString.Buffer ); OemString.MaximumLength = OemString.Length; Status = RtlOemStringToCountedUnicodeString( pUString, &OemString, FALSE ); ASSERT( NT_SUCCESS( Status )); Length += len; break; } #endif default: printf ( "*****exchange: invalid response field, %x\n", *FormatByte ); return( FALSE ); } #if 0 if ( Length > PacketLength ) { printf ( "*****exchange: not enough response data, %d\n", i ); } #endif FormatByte++; } va_end( Arguments ); }