mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1667 lines
44 KiB
1667 lines
44 KiB
/*++
|
|
|
|
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
|