/*++ Copyright (c) 1989 Microsoft Corporation Module Name: rdwrt.c Abstract: Control routines (etc.) for the _read, _write, and copy tests. Author: Chuck Lenzmeier (chuckl) 24-Jan-1990 Revision History: --*/ #define INCLUDE_SMB_LOCK #define INCLUDE_SMB_RAW #define INCLUDE_SMB_READ_WRITE #include "usrv.h" #include "rdwrt.h" // // Strings indicating what kind of read or write is being performed. // static PSZ RwcModeNames[] = { "normal", "AndX", "AndX (writethrough)", "raw", "raw (writethrough)", "multiplexed", "multiplexed (writethrough)", "bulk" }; NTSTATUS RwcTreeConnect( IN PDESCRIPTOR Redir, IN PSZ DebugString, IN PVOID Unused, IN UCHAR SubCommand, IN PID_SELECTIONS IdSelections, IN OUT PID_VALUES IdValues, OUT PULONG Unused2 ) { ULONG smbSize; UCHAR savedTid; NTSTATUS status; Unused, SubCommand, Unused2; // prevent compiler warnings savedTid = IdSelections->Tid; IdSelections->Tid = STD_TID; if ( Redir->argc > 1 ) { PSZ s = Redir->argv[1]; while ( *s ) { if ( *s++ == 'f' ) { IdSelections->Tid = ALT_TID; break; } } } IF_DEBUG(3) { printf( "Connecting to %s\n", TreeConnectStrings[IdSelections->Tid].Buffer+1 ); } status = MakeTreeConnectSmb( Redir, Redir->Data[0], NULL, 0xFF, IdSelections, IdValues, &smbSize ); if ( !NT_SUCCESS(status) ) { return status; } IdSelections->Tid = savedTid; status = SendAndReceiveSmb( Redir, DebugString, smbSize, 0, 1 ); if ( !NT_SUCCESS(status) ) { return status; } status = VerifyTreeConnect( Redir, NULL, 0xFF, IdSelections, IdValues, &smbSize, Redir->Data[1] ); if ( !NT_SUCCESS(status) ) { return status; } return STATUS_SUCCESS; } // RwcTreeConnect NTSTATUS RwcOpenOutputFile( IN OUT PDESCRIPTOR Redir, IN OUT PVOID Buffer, IN OUT PVOID ForcedParams OPTIONAL, IN UCHAR AndXCommand, IN PID_SELECTIONS IdSelections, IN PID_VALUES IdValues, OUT PULONG SmbSize ) { NTSTATUS status; FileDefs[IdSelections->Fid].DataSize = FileDefs[IdSelections->Fid-1].DataSize; IF_DEBUG(3) { printf( "Creating output file with size %ld bytes\n", FileDefs[IdSelections->Fid].DataSize ); } status = MakeOpenAndXSmb( Redir, Buffer, ForcedParams, AndXCommand, IdSelections, IdValues, SmbSize ); return status; } // RwcOpenOutputFile NTSTATUS RwcController( IN PDESCRIPTOR Redir, IN PSZ DebugString, IN PVOID Unused, IN UCHAR SubCommand, IN PID_SELECTIONS IdSelections, IN PID_VALUES IdValues, OUT PULONG Unused2 ) { ULONG offset; CLONG maxMax; CLONG maxLength, actualLength, bytesLeft; PUCHAR actualData; NTSTATUS status; LARGE_INTEGER startTime, totalStartTime, endTime, elapsedTime, elapsedMs; LARGE_INTEGER magic10000 = { 0xe219652c, 0xd1b71758 }; ULONG iterations; ULONG iteration; BOOLEAN doRead, doWrite, totalsOnly; RWC_MODE mode; READ_FUNCTION reader; WRITE_FUNCTION writer; Unused, SubCommand, Unused2; // prevent compiler warnings if ( _stricmp( Redir->argv[0], "read" ) == 0 ) { doRead = TRUE; doWrite = FALSE; } else if ( _stricmp( Redir->argv[0], "write" ) == 0 ) { doRead = FALSE; doWrite = TRUE; } else if ( _stricmp( Redir->argv[0], "copy" ) == 0 ) { doRead = TRUE; doWrite = TRUE; } else { printf( "RwcController entered with invalid command: %s\n", Redir->argv[0] ); return STATUS_UNSUCCESSFUL; } if ( Redir->argc > 1 ) { iterations = atol( Redir->argv[1] ); } else { iterations = 3; } mode = Normal; reader = DoNormalRead; writer = DoNormalWrite; totalsOnly = FALSE; if ( Redir->argc > 2 ) { PSZ s = Redir->argv[2]; while ( *s ) { switch ( tolower(*s) ) { case 'n': mode = Normal; reader = DoNormalRead; writer = DoNormalWrite; break; case 'x': if ( tolower( *(s+1) ) != 't' ) { mode = AndX; } else { mode = AndXWriteThrough; s++; } reader = DoAndXRead; writer = DoAndXWrite; break; case 'r': if ( tolower( *(s+1) ) != 't' ) { mode = Raw; } else { mode = RawWriteThrough; s++; } reader = DoRawRead; writer = DoRawWrite; break; case 'm': if ( tolower( *(s+1) ) != 't' ) { mode = Multiplexed; } else { mode = MultiplexedWriteThrough; s++; } reader = DoMultiplexedRead; writer = DoMultiplexedWrite; break; case 'b': mode = Bulk; reader = DoBulkRead; writer = DoBulkWrite; break; case 'o': totalsOnly = TRUE; case 'f': // Ignore harddisk/floppy indicator break; default: printf( "RwcController: unknown mode switch '%c' ignored\n", *s ); } s++; } } maxMax = ((mode == Raw) || (mode == RawWriteThrough)) ? 65535 : (mode == Bulk) ? 1048576 : Redir->MaxBufferSize - 100; maxLength = maxMax; if ( Redir->argc > 3 ) { maxLength = atol( Redir->argv[3] ); if ( maxLength > maxMax ) { maxLength = maxMax; } } maxLength = maxLength & ~1023; if ( maxLength == 0 ) { printf( "RwcController: invalid maxLength\n" ); DbgBreakPoint( ); return STATUS_INVALID_PARAMETER; } if ( (mode == Raw) || (mode == RawWriteThrough) || (mode == Bulk) ) { if ( Redir->RawBuffer == NULL ) { Redir->RawBuffer = malloc( 1048576 ); if ( Redir->RawBuffer == NULL ) { printf( "RwcController: unable to allocate raw buffer\n" ); return STATUS_INSUFFICIENT_RESOURCES; } } actualData = Redir->RawBuffer; } else { actualData = NULL; } printf( "Redir %ld: %s %s in %ld byte chunks using %s SMBs " "(%ld iterations)\n", Redir->RedirNumber, doRead ? (doWrite ? "Copying" : "Reading") : "Writing", FileDefs[IdSelections->Fid].Name.Buffer+1, maxLength, RwcModeNames[mode], iterations ); (VOID)NtQuerySystemTime( (PLARGE_INTEGER)&totalStartTime ); for ( iteration = 1; iteration <= iterations; iteration++ ) { // Loop reading and/or writing data. offset = 0; bytesLeft = FileDefs[IdSelections->Fid].DataSize; if ( !totalsOnly ) { (VOID)NtQuerySystemTime( (PLARGE_INTEGER)&startTime ); } do { if ( doRead ) { status = reader( Redir, DebugString, IdSelections, IdValues, mode, maxLength, offset, &actualLength, &actualData ); if ( !NT_SUCCESS(status) ) { return status; } bytesLeft -= actualLength; } else { if ( bytesLeft <= maxLength ) { actualLength = bytesLeft; bytesLeft = 0; } else { actualLength = maxLength; bytesLeft -= maxLength; } } if ( doWrite ) { // // Note that we do the write even if actualLength == 0. // This is so that we close the file even when the file's // length is a multiple of maxLength. If actualLength // is 0, we just do a close. // IdSelections->Fid++; status = writer( Redir, DebugString, IdSelections, IdValues, mode, (BOOLEAN)( (iteration == iterations) && (actualLength < maxLength) ), actualLength, offset, actualData ); IdSelections->Fid--; if ( !NT_SUCCESS(status) ) { return status; } } offset += actualLength; } while ( actualLength == maxLength ); if ( !totalsOnly ) { LARGE_INTEGER kbps; (VOID)NtQuerySystemTime( (PLARGE_INTEGER)&endTime ); elapsedTime.QuadPart = endTime.QuadPart - startTime.QuadPart; elapsedMs = RtlExtendedMagicDivide( elapsedTime, magic10000, 13 ); if ( elapsedMs.LowPart != 0 ) { kbps.QuadPart = Int32x32To64( offset, 1000 ); kbps.QuadPart = kbps.QuadPart / elapsedMs.QuadPart; kbps = RtlExtendedLargeIntegerDivide( kbps, 1024, NULL ); } else { kbps.LowPart = 0; } printf( " Redir %ld, iteration %ld: Bytes %s %ld, ms %ld, " "rate %ld kbps\n", Redir->RedirNumber, iteration, doRead ? (doWrite ? "copied" : "read") : "written", offset, elapsedMs.LowPart, kbps.LowPart ); } //if ( bytesLeft != 0 ) DbgBreakPoint( ); } if ( totalsOnly || iterations > 1 ) { LARGE_INTEGER kbps; (VOID)NtQuerySystemTime( (PLARGE_INTEGER)&endTime ); elapsedTime.QuadPart = endTime.QuadPart - totalStartTime.QuadPart; elapsedMs = RtlExtendedMagicDivide( elapsedTime, magic10000, 13 ); if ( elapsedMs.LowPart != 0 ) { kbps.QuadPart = Int32x32To64( offset, iterations ); kbps = RtlExtendedIntegerMultiply( kbps, 1000 ); kbps.QuadPart = kbps.QuadPart / elapsedMs.QuadPart; kbps = RtlExtendedLargeIntegerDivide( kbps, 1024, NULL ); } else { kbps.LowPart = 0; } printf( "Redir %ld, %ld iterations; bytes %s %ld, ms %ld, " "rate %ld kbps\n", Redir->RedirNumber, iterations, doRead ? (doWrite ? "copied" : "read") : "written", offset * iterations, elapsedMs.LowPart, kbps.LowPart ); } return STATUS_SUCCESS; } // RwcController NTSTATUS WriteController( IN PDESCRIPTOR Redir, IN PSZ DebugString, IN PVOID Unused, IN UCHAR SubCommand, IN PID_SELECTIONS IdSelections, IN PID_VALUES IdValues, OUT PULONG Unused2 ) { ULONG offset; ULONG writeLength; RWC_MODE mode; WRITE_FUNCTION writeFunction; PVOID writeData; NTSTATUS status; Unused, SubCommand, Unused2; // A good compiler is a happy compiler if ( _strnicmp( Redir->argv[0], "funkyclose", strlen( Redir->argv[0] )) == 0) { writeFunction = DoRawWrite; writeLength = 8192; mode = Raw; // Write behind; offset = 0; } else { return STATUS_INVALID_PARAMETER; } writeLength = writeLength & ~1023; if ( writeLength == 0 || writeLength > 65535) { printf( "WriteController: invalid length\n" ); DbgBreakPoint( ); return STATUS_INVALID_PARAMETER; } if ( mode == Raw || mode == RawWriteThrough || mode == Bulk ) { if ( Redir->RawBuffer == NULL ) { Redir->RawBuffer = malloc( 1048576 ); if ( Redir->RawBuffer == NULL ) { printf( "WriteController: unable to allocate raw buffer\n" ); return STATUS_INSUFFICIENT_RESOURCES; } } writeData = Redir->RawBuffer; } else { writeData = NULL; } status = writeFunction( Redir, DebugString, IdSelections, IdValues, mode, FALSE, writeLength, offset, writeData ); return status; } // WriteRawController NTSTATUS UpdateController( IN PDESCRIPTOR Redir, IN PSZ DebugString, IN PVOID Unused, IN UCHAR SubCommand, IN PID_SELECTIONS IdSelections, IN PID_VALUES IdValues, OUT PULONG Unused2 ) { ULONG offset; CLONG maxLength, actualLength; PUCHAR actualData; NTSTATUS status; LARGE_INTEGER startTime, endTime, elapsedTime, elapsedMs; LARGE_INTEGER magic10000 = { 0xe219652c, 0xd1b71758 }; ULONG iteration; Unused, SubCommand, Unused2; // prevent compiler warnings if ( Redir->argc > 1 ) { iteration = atol( Redir->argv[1] ); } else { iteration = 0; } maxLength = Redir->MaxBufferSize - 100; if ( Redir->argc > 3 ) { maxLength = atol( Redir->argv[3] ); } if ( maxLength > (CLONG)(Redir->MaxBufferSize - 100) ) { maxLength = Redir->MaxBufferSize - 100; } maxLength = maxLength & ~1023; if ( maxLength == 0 ) { printf( "UpdateController: invalid maxLength\n" ); DbgBreakPoint( ); return STATUS_INVALID_PARAMETER; } printf( "Updating %s in %ld byte chunks\n", FileDefs[IdSelections->Fid].Name.Buffer+1, maxLength ); for ( ; iteration < 4; iteration++ ) { // // Loop updating the file. Iterations 0 and 1 are simple // read/write; iteration 2 is lock/read/write/unlock; iteration // 3 is lock&read/write&unlock. // offset = 0; (VOID)NtQuerySystemTime( (PLARGE_INTEGER)&startTime ); do { switch ( iteration ) { case 2: status = RwcDoLock( Redir, DebugString, IdSelections, IdValues, offset, maxLength ); if ( !NT_SUCCESS(status) ) { return status; } // fall through to do read case 0: case 1: status = DoNormalRead( Redir, DebugString, IdSelections, IdValues, Normal, maxLength, offset, &actualLength, &actualData ); if ( !NT_SUCCESS(status) ) { return status; } break; case 3: status = RwcDoLockAndRead( Redir, DebugString, IdSelections, IdValues, offset, maxLength, &actualLength, &actualData ); if ( !NT_SUCCESS(status) ) { return status; } } switch ( iteration ) { case 0: case 1: case 2: if ( actualLength != 0 ) { status = DoNormalWrite( Redir, DebugString, IdSelections, IdValues, Normal, FALSE, actualLength, offset, actualData ); if ( !NT_SUCCESS(status) ) { return status; } } if ( iteration == 2 ) { status = RwcDoUnlock( Redir, DebugString, IdSelections, IdValues, offset, maxLength ); if ( !NT_SUCCESS(status) ) { return status; } } break; case 3: if ( actualLength == maxLength ) { status = RwcDoWriteAndUnlock( Redir, DebugString, IdSelections, IdValues, offset, actualLength, actualData ); if ( !NT_SUCCESS(status) ) { return status; } } else { if ( actualLength != 0 ) { status = DoNormalWrite( Redir, DebugString, IdSelections, IdValues, Normal, FALSE, actualLength, offset, actualData ); if ( !NT_SUCCESS(status) ) { return status; } } status = RwcDoUnlock( Redir, DebugString, IdSelections, IdValues, offset, maxLength ); if ( !NT_SUCCESS(status) ) { return status; } } } offset += actualLength; } while ( actualLength == maxLength ); (VOID)NtQuerySystemTime( (PLARGE_INTEGER)&endTime ); elapsedTime.QuadPart = endTime.QuadPart - startTime.QuadPart; elapsedMs = RtlExtendedMagicDivide( elapsedTime, magic10000, 13 ); switch ( iteration ) { case 0: case 1: printf( "Read/Write: " ); break; case 2: printf( "Lock/Read/Write/Unlock: " ); break; case 3: printf( "LockAndRead/WriteAndUnlock: " ); break; } printf( "Bytes updated %ld, ms %ld, rate %ld kbps\n", offset, elapsedMs.LowPart, elapsedMs.LowPart == 0 ? -1 : offset * 1000 / elapsedMs.LowPart / 1024 ); } return STATUS_SUCCESS; } // UpdateController NTSTATUS NewSizeController( IN PDESCRIPTOR Redir, IN PSZ DebugString, IN PVOID Unused, IN UCHAR SubCommand, IN PID_SELECTIONS IdSelections, IN PID_VALUES IdValues, OUT PULONG Unused2 ) { PSMB_HEADER header; PREQ_WRITE request; PRESP_WRITE response; ULONG offset; CLONG smbSize; NTSTATUS status; Unused, SubCommand, Unused2; // prevent compiler warnings if ( Redir->argc > 1 ) { offset = atol( Redir->argv[1] ); } else { offset = 0; } header = (PSMB_HEADER)Redir->Data[0]; request = (PREQ_WRITE)(header + 1); status = MakeSmbHeader( Redir, header, SMB_COM_WRITE, IdSelections, IdValues ); if ( !NT_SUCCESS(status) ) { return status; } request->WordCount = 5; SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] ); SmbPutUshort( &request->Count, 0 ); SmbPutUlong( &request->Offset, offset ); SmbPutUshort( &request->Remaining, 0 ); SmbPutUshort( &request->ByteCount, 0 ); smbSize = GET_ANDX_OFFSET( header, request, REQ_WRITE, 0 ); IF_DEBUG(4) { printf( "Setting new size of %s to %ld bytes\n", FileDefs[IdSelections->Fid].Name.Buffer+1, offset ); } status = SendAndReceiveSmb( Redir, DebugString, smbSize, 0, 1 ); if ( !NT_SUCCESS(status) ) { return status; } header = (PSMB_HEADER)Redir->Data[1]; response = (PRESP_WRITE)(header + 1); status = VerifySmbHeader( Redir, IdSelections, IdValues, header, SMB_COM_WRITE ); if ( !NT_SUCCESS(status) ) { return status; } IF_DEBUG(4) { printf( "Size of %s set to %ld bytes\n", FileDefs[IdSelections->Fid].Name.Buffer+1, offset ); } return STATUS_SUCCESS; } // NewSizeController NTSTATUS SeekController( IN PDESCRIPTOR Redir, IN PSZ DebugString, IN PVOID Unused, IN UCHAR SubCommand, IN PID_SELECTIONS IdSelections, IN PID_VALUES IdValues, OUT PULONG Unused2 ) { LONG offset; LONG dataSize; NTSTATUS status; Unused, SubCommand, Unused2; // prevent compiler warnings // // *** Note that dialect PCLAN1.0 must be negotiated for this test // to work! (Seek to BOF-100 must succeed.) // dataSize = (LONG)FileDefs[IdSelections->Fid].DataSize; IF_DEBUG(4) { printf( "SeekController: size of input file is %ld bytes\n", dataSize ); } if ( dataSize < 100 ) { printf( "SeekController: input file is too small (%ld bytes); " "this test needs 100 bytes or more\n", dataSize ); DbgBreakPoint( ); return STATUS_UNSUCCESSFUL; } status = DoSeek( Redir, DebugString, IdSelections, IdValues, 0, 100, &offset ); if ( !NT_SUCCESS(status) ) { return status; } if ( offset != 100 ) { printf( "SeekController: seek to BOF+100 yielded offset %ld\n", offset ); DbgBreakPoint( ); return STATUS_UNSUCCESSFUL; } status = DoSeek( Redir, DebugString, IdSelections, IdValues, 0, -100, &offset ); if ( !NT_SUCCESS(status) ) { return status; } if ( offset != 0 ) { printf( "SeekController: seek to BOF-100 yielded offset %ld\n", offset ); DbgBreakPoint( ); return STATUS_UNSUCCESSFUL; } status = DoSeek( Redir, DebugString, IdSelections, IdValues, 2, 100, &offset ); if ( !NT_SUCCESS(status) ) { return status; } if ( offset != dataSize+100 ) { printf( "SeekController: seek to EOF+100 (%ld) yielded offset %ld\n", dataSize+100, offset ); DbgBreakPoint( ); return STATUS_UNSUCCESSFUL; } status = DoSeek( Redir, DebugString, IdSelections, IdValues, 2, -100, &offset ); if ( !NT_SUCCESS(status) ) { return status; } if ( offset != dataSize - 100 ) { printf( "SeekController: seek to EOF-100 (%ld) yielded offset %ld\n", dataSize-100, offset ); DbgBreakPoint( ); return STATUS_UNSUCCESSFUL; } status = DoSeek( Redir, DebugString, IdSelections, IdValues, 1, +50, &offset ); if ( !NT_SUCCESS(status) ) { return status; } if ( offset != dataSize - 100 + 50 ) { printf( "SeekController: seek to current+50 (%ld) yielded offset " "%ld\n", dataSize-100+50, offset ); DbgBreakPoint( ); return STATUS_UNSUCCESSFUL; } status = DoSeek( Redir, DebugString, IdSelections, IdValues, 1, -25, &offset ); if ( !NT_SUCCESS(status) ) { return status; } if ( offset != dataSize - 100 + 50 - 25 ) { printf( "SeekController: seek to current-25 (%ld) yielded offset " "%ld\n", dataSize-100+50-25, offset ); DbgBreakPoint( ); return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; } // SeekController NTSTATUS TypeController( IN PDESCRIPTOR Redir, IN PSZ DebugString, IN PVOID Unused, IN UCHAR SubCommand, IN PID_SELECTIONS IdSelections, IN PID_VALUES IdValues, OUT PULONG Unused2 ) { NTSTATUS status; ULONG dataSize; CLONG maxLength; ULONG offset; PUCHAR actualData; CLONG actualLength; Unused, Unused2, SubCommand; // prevent compiler warnings if ( Redir->argc < 2 || (Redir->argc == 3 && *(Redir->argv[2]+1) != 's') ) { printf( "Usage: type X:filename [-sN]\n" ); return STATUS_INVALID_PARAMETER; } maxLength = Redir->MaxBufferSize - 100; if ( Redir->argc == 3 ) { maxLength = atol( Redir->argv[2]+2 ); if ( maxLength > (CLONG)(Redir->MaxBufferSize - 100) ) { maxLength = Redir->MaxBufferSize - 100; } } maxLength = maxLength & ~1023; if ( maxLength == 0 ) { printf( "TypeController: invalid maxLength\n" ); return STATUS_INVALID_PARAMETER; } status = DoRemoteOpen( Redir, DebugString, IdSelections, IdValues, FALSE ); dataSize = FileDefs[IdSelections->Fid].DataSize; IF_DEBUG(3) printf( "Data size is %ld\n", dataSize ); for ( actualLength = 1, offset = 0; offset < dataSize && actualLength != 0; offset += actualLength ) { CLONG i; IF_DEBUG(3) { printf( "\nReading %ld bytes at offset %ld\n", maxLength, offset ); } status = DoNormalRead( Redir, DebugString, IdSelections, IdValues, Normal, maxLength, offset, &actualLength, &actualData ); if ( !NT_SUCCESS(status) ) { printf( "DoNormalRead failed: %X\n", status ); return status; } for ( i = 0; i < actualLength; i++ ) { printf( "%c", actualData[i] ); } } status = DoRemoteClose( Redir, DebugString, IdSelections, IdValues ); printf( "\n" ); return status; } // TypeController NTSTATUS RcpController( IN PDESCRIPTOR Redir, IN PSZ DebugString, IN PVOID Unused, IN UCHAR SubCommand, IN PID_SELECTIONS IdSelections, IN PID_VALUES IdValues, OUT PULONG Unused2 ) { NTSTATUS status; ULONG dataSize; CLONG maxLength; ULONG offset; PUCHAR actualData; CLONG actualLength; HANDLE sourceHandle = NULL; HANDLE destHandle = NULL; USHORT sourceFid = 0; USHORT destFid = 0; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatusBlock; STRING fileName; Unused, Unused2, SubCommand; // prevent compiler warnings if ( Redir->argc != 3 ) { printf( "Usage: rcp source dest\n" ); } maxLength = (Redir->MaxBufferSize - 100) & ~1023; if ( *(Redir->argv[1]+1) == ':' ) { IF_DEBUG(3) { printf( "Opening remote source file %s\n", Redir->argv[1] ); } status = DoRemoteOpen( Redir, DebugString, IdSelections, IdValues, FALSE ); sourceFid = IdValues->Fid[IdSelections->Fid]; dataSize = FileDefs[IdSelections->Fid].DataSize; if ( !NT_SUCCESS(status) ) { printf( "Remote open of source %s failed: %X\n", Redir->argv[1], status ); } } else { FILE_STANDARD_INFORMATION fileStandardInfo; UNICODE_STRING unicodeFileName; fileName.Buffer = Redir->argv[1]; fileName.Length = (SHORT)strlen( fileName.Buffer ); status = RtlAnsiStringToUnicodeString( &unicodeFileName, &fileName, TRUE ); ASSERT( NT_SUCCESS(status) ); InitializeObjectAttributes( &objectAttributes, &unicodeFileName, OBJ_CASE_INSENSITIVE, NULL, NULL ); IF_DEBUG(3) { printf( "Opening local source file %s\n", Redir->argv[1] ); } status = NtOpenFile( &sourceHandle, FILE_READ_DATA | SYNCHRONIZE, &objectAttributes, &ioStatusBlock, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT ); RtlFreeUnicodeString( &unicodeFileName ); if ( !NT_SUCCESS(status) ) { printf( "Local open of source %s failed: %X\n", Redir->argv[1], status ); } status = NtQueryInformationFile( sourceHandle, &ioStatusBlock, &fileStandardInfo, sizeof(fileStandardInfo), FileStandardInformation ); dataSize = fileStandardInfo.EndOfFile.LowPart; } if ( !NT_SUCCESS(status) ) { return status; } Redir->argv++; IF_DEBUG(3) printf( "Source data size is %ld\n", dataSize ); if ( *(Redir->argv[1]+1) == ':' ) { IF_DEBUG(3) { printf( "Opening remote dest file %s\n", Redir->argv[1] ); } status = DoRemoteOpen( Redir, DebugString, IdSelections, IdValues, TRUE ); destFid = IdValues->Fid[IdSelections->Fid]; if ( !NT_SUCCESS(status) ) { printf( "Remote open of dest %s failed: %X\n", Redir->argv[1], status ); Redir->argv--; if ( sourceHandle != NULL ) { NtClose( sourceHandle ); } else { DoRemoteClose( Redir, DebugString, IdSelections, IdValues ); } return status; } else { IF_DEBUG(3) { printf( "%s successfully opened.\n", Redir->argv[1] ); } } } else { LARGE_INTEGER allocationSize; UNICODE_STRING unicodeFileName; allocationSize.LowPart = dataSize; allocationSize.HighPart = 0; fileName.Buffer = Redir->argv[1]; fileName.Length = (SHORT)strlen( fileName.Buffer ); status = RtlAnsiStringToUnicodeString( &unicodeFileName, &fileName, TRUE ); ASSERT( NT_SUCCESS(status) ); InitializeObjectAttributes( &objectAttributes, &unicodeFileName, OBJ_CASE_INSENSITIVE, NULL, NULL ); IF_DEBUG(3) { printf( "Opening local dest file %s\n", Redir->argv[1] ); } status = NtCreateFile( &destHandle, FILE_WRITE_DATA | SYNCHRONIZE, &objectAttributes, &ioStatusBlock, &allocationSize, FILE_ATTRIBUTE_NORMAL, 0L, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); RtlFreeUnicodeString( &unicodeFileName ); if ( !NT_SUCCESS(status) ) { printf( "Local open of dest %s failed: %X\n", Redir->argv[1], status ); Redir->argv--; if ( sourceHandle != NULL ) { NtClose( sourceHandle ); } else { DoRemoteClose( Redir, DebugString, IdSelections, IdValues ); } return status; } else { IF_DEBUG(3) { printf( "%s successfully opened.\n", Redir->argv[1] ); } } } Redir->argv--; for ( actualLength = 1, offset = 0; offset < dataSize && actualLength != 0; offset += actualLength ) { CLONG i; IF_DEBUG(3) { printf( "\nReading %ld bytes at offset %ld\n", maxLength, offset ); } if ( sourceHandle == NULL ) { IdValues->Fid[IdSelections->Fid] = sourceFid; status = DoNormalRead( Redir, DebugString, IdSelections, IdValues, Normal, maxLength, offset, &actualLength, &actualData ); } else { LARGE_INTEGER byteOffset; byteOffset.LowPart = offset; byteOffset.HighPart = 0; status = NtReadFile( sourceHandle, NULL, NULL, NULL, &ioStatusBlock, Redir->Data[0], maxLength, &byteOffset, NULL ); actualData = Redir->Data[0]; actualLength = ioStatusBlock.Information; } if ( !NT_SUCCESS(status) ) { printf( "Read failed: %X\n", status ); return status; } else { IF_DEBUG(3) { printf( "Read %ld bytes successfully\n", actualLength ); } } IF_DEBUG(4) { for ( i = 0; i < actualLength; i++ ) { printf( "%c", actualData[i] ); } } IF_DEBUG(3) { printf( "\nWriting %ld bytes at offset %ld\n", actualLength, offset ); } if ( destHandle == NULL ) { IdValues->Fid[IdSelections->Fid] = destFid; Redir->argv++; status = DoNormalWrite( Redir, DebugString, IdSelections, IdValues, Normal, FALSE, actualLength, offset, actualData ); Redir->argv--; } else { LARGE_INTEGER byteOffset; byteOffset.LowPart = offset; byteOffset.HighPart = 0; status = NtWriteFile( destHandle, NULL, NULL, NULL, &ioStatusBlock, actualData, actualLength, &byteOffset, NULL ); } if ( !NT_SUCCESS(status) ) { printf( "Write failed: %X\n", status ); return status; } else { IF_DEBUG(3) { printf( "Wrote %ld bytes successfully\n", actualLength ); } } } if ( sourceHandle == NULL ) { IdValues->Fid[IdSelections->Fid] = sourceFid; status = DoRemoteClose( Redir, DebugString, IdSelections, IdValues ); } else { NtClose( sourceHandle ); } if ( destHandle == NULL ) { IdValues->Fid[IdSelections->Fid] = destFid; status = DoRemoteClose( Redir, DebugString, IdSelections, IdValues ); } else { NtClose( destHandle ); } return STATUS_SUCCESS; } // RcpController NTSTATUS PipeController( IN PDESCRIPTOR Redir, IN PSZ DebugString, IN PVOID Unused, IN UCHAR SubCommand, IN PID_SELECTIONS IdSelections, IN PID_VALUES IdValues, OUT PULONG Unused2 ) { NTSTATUS status; LARGE_INTEGER startTime, endTime, elapsedTime, elapsedMs; LARGE_INTEGER magic10000 = { 0xe219652c, 0xd1b71758 }; PSZ test; SHORT testNumber; RWC_MODE mode; READ_FUNCTION reader; WRITE_FUNCTION writer; CLONG maxLength; ULONG data; static PUCHAR actualData; static CLONG actualLength; Unused, SubCommand, Unused2; // prevent compiler warnings for (testNumber = 1; testNumber < Redir->argc; testNumber++) { test = Redir->argv[testNumber]; reader = NULL; writer = NULL; mode = -1; (VOID)NtQuerySystemTime( (PLARGE_INTEGER)&startTime ); switch (*test) { case 'c': test++; data = atoi(test); // Get number of bytes to read CallNamedPipe( Redir, DebugString, IdSelections, IdValues, (USHORT)data ); break; case 'p': test++; data = atoi(test); // Get number of bytes to read PeekNamedPipe( Redir, DebugString, IdSelections, IdValues, (USHORT)data ); break; case 'r': test++; if (*test == 'x') { reader = DoAndXRead; mode = AndX; maxLength = atoi(test+1); } else if (*test == 'r') { reader = DoRawRead; mode = Raw; maxLength = atoi(test+1); } else if (*test >= '0' && *test <= '9') { reader = DoNormalRead; mode = Normal; maxLength = atoi(test); } else { printf ("Unknow read command: %s\n", test); } break; case 'w': test++; if (*test == 'x') { writer = DoAndXWrite; mode = AndX; actualLength = atoi(test+1); } else if (*test == 'r') { writer = DoRawWrite; mode = Raw; actualLength = atoi(test+1); } else if (*test == 'z') { RawWriteNamedPipe( Redir, DebugString, IdSelections, IdValues ); } else if (*test >= '0' && *test <= '9') { writer = DoNormalWrite; mode = Normal; actualLength = atoi(test); } else { printf ("Unknown write command: %s\n", test); } break; case 'q': test++; switch (*test) { case 'h': QueryNamedPipeHandle( Redir, DebugString, IdSelections, IdValues ); break; case 'i': test++; data = atoi(test); QueryNamedPipeInfo( Redir, DebugString, IdSelections, IdValues, (USHORT)data // Level ); break; default: printf ("PipeContoller: Unknown command %s ignored\n", test); } break; case 's': // Set named pipe handle state test++; data = (ULONG)atolx(test); SetNamedPipeHandle( Redir, DebugString, IdSelections, IdValues, (USHORT)data ); break; case 't': // Transact named pipe TransactNamedPipe( Redir, DebugString, IdSelections, IdValues, actualData, // Data to send (USHORT)actualLength // Number of bytes to write, and read ); break; case 'z': // Wait named pipe WaitNamedPipe( Redir, DebugString, IdSelections, IdValues ); break; default: printf ("PipeContoller: Unknown command %s ignored\n", test); } if ( mode == Raw ) { if ( Redir->RawBuffer == NULL ) { Redir->RawBuffer = malloc( 1048576 ); if ( Redir->RawBuffer == NULL ) { printf( "RwcController: unable to allocate raw buffer\n" ); return STATUS_INSUFFICIENT_RESOURCES; } } actualData = Redir->RawBuffer; } if ( reader ) { status = reader( Redir, DebugString, IdSelections, IdValues, mode, maxLength, 0L, &actualLength, &actualData ); if ( !NT_SUCCESS(status) ) { return status; } } else if ( writer ) { // // Now write back the same data. // status = writer( Redir, DebugString, IdSelections, IdValues, mode, FALSE, actualLength, 0L, actualData ); if ( !NT_SUCCESS(status) ) { return status; } } (VOID)NtQuerySystemTime( (PLARGE_INTEGER)&endTime ); elapsedTime.QuadPart = endTime.QuadPart - startTime.QuadPart; elapsedMs = RtlExtendedMagicDivide( elapsedTime, magic10000, 13 ); if (reader || writer) { printf( "Bytes %s %ld, ms %ld, rate %ld kbps\n", reader ? "read" : "written", actualLength, elapsedMs.LowPart, elapsedMs.LowPart == 0 ? -1 : actualLength * 1000 / elapsedMs.LowPart / 1024 ); } else { printf( "Transaction processed in %ld ms\n", elapsedMs.LowPart); } } return STATUS_SUCCESS; } // PipeController