Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1925 lines
49 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
rdwrtsub.c
Abstract:
Subroutines (etc.) for the _read, _write, and copy tests. (See
rdwrt.c for "main" routines for these 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"
NTSTATUS
DoNormalRead(
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN RWC_MODE Mode,
IN CLONG MaxLength,
IN ULONG Offset,
OUT CLONG *ActualLength,
OUT PUCHAR *ActualData
)
{
PSMB_HEADER header;
PREQ_READ request;
PRESP_READ response;
NTSTATUS status;
CLONG smbSize;
Mode;
header = (PSMB_HEADER)Redir->Data[0];
request = (PREQ_READ)(header + 1);
status = MakeSmbHeader(
Redir,
header,
SMB_COM_READ,
IdSelections,
IdValues
);
if ( !NT_SUCCESS(status) ) {
return status;
}
request->WordCount = 5;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUshort( &request->Count, (USHORT)MaxLength );
SmbPutUlong( &request->Offset, Offset );
SmbPutUshort( &request->Remaining, 0 );
SmbPutUshort( &request->ByteCount, 0 );
smbSize = GET_ANDX_OFFSET( header, request, REQ_READ, 0 );
IF_DEBUG(4) printf( "reading %ld bytes at offset %ld\n",
MaxLength, Offset );
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
0,
1
);
if ( !NT_SUCCESS(status) ) {
return status;
}
header = (PSMB_HEADER)Redir->Data[1];
response = (PRESP_READ)(header + 1);
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_READ
);
if ( !NT_SUCCESS(status) ) {
return status;
}
*ActualLength = (CLONG)SmbGetUshort( &response->Count );
*ActualData = (PUCHAR)response->Buffer;
if ( *ActualLength > MaxLength ) {
printf( "Too much read data returned. Expected %ld, received %ld\n",
MaxLength, *ActualLength );
SMB_ERROR_BREAK;
return STATUS_UNSUCCESSFUL;
}
IF_DEBUG(4) printf( "%ld bytes read\n", *ActualLength );
return STATUS_SUCCESS;
} // DoNormalRead
NTSTATUS
DoAndXRead(
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN RWC_MODE Mode,
IN CLONG MaxLength,
IN ULONG Offset,
OUT CLONG *ActualLength,
OUT PUCHAR *ActualData
)
{
PSMB_HEADER header;
PREQ_READ_ANDX request;
PRESP_READ_ANDX response;
NTSTATUS status;
CLONG smbSize;
Mode;
header = (PSMB_HEADER)Redir->Data[0];
request = (PREQ_READ_ANDX)(header + 1);
status = MakeSmbHeader(
Redir,
header,
SMB_COM_READ_ANDX,
IdSelections,
IdValues
);
if ( !NT_SUCCESS(status) ) {
return status;
}
request->WordCount = 10;
request->AndXCommand = SMB_COM_NO_ANDX_COMMAND;
request->AndXReserved = 0;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUlong( &request->Offset, Offset );
SmbPutUshort( &request->MaxCount, (USHORT)MaxLength );
SmbPutUshort( &request->MinCount, (USHORT)MaxLength );
SmbPutUlong( &request->Timeout, 0 );
SmbPutUshort( &request->Remaining, 0 );
SmbPutUshort( &request->ByteCount, 0 );
smbSize = GET_ANDX_OFFSET( header, request, REQ_READ_ANDX, 0 );
IF_DEBUG(4) printf( "reading %ld bytes at offset %ld\n",
MaxLength, Offset );
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
0,
1
);
if ( !NT_SUCCESS(status) ) {
return status;
}
header = (PSMB_HEADER)Redir->Data[1];
response = (PRESP_READ_ANDX)(header + 1);
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_READ_ANDX
);
if ( !NT_SUCCESS(status) ) {
return status;
}
*ActualLength = (CLONG)SmbGetUshort( &response->DataLength );
*ActualData = (PUCHAR)header + SmbGetUshort( &response->DataOffset );
if ( *ActualLength > MaxLength ) {
printf( "Too much read data returned. Expected %ld, received %ld\n",
MaxLength, *ActualLength );
SMB_ERROR_BREAK;
return STATUS_UNSUCCESSFUL;
}
IF_DEBUG(4) printf( "%ld bytes read\n", *ActualLength );
return STATUS_SUCCESS;
} // DoAndXRead
NTSTATUS
DoRawRead(
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN RWC_MODE Mode,
IN CLONG MaxLength,
IN ULONG Offset,
OUT CLONG *ActualLength,
OUT PUCHAR *ActualData
)
{
PSMB_HEADER header;
PREQ_READ_RAW request;
NTSTATUS status;
CLONG smbSize;
PUCHAR destination;
CLONG lengthRead;
CLONG readLength;
Mode;
header = (PSMB_HEADER)Redir->Data[0];
request = (PREQ_READ_RAW)(header + 1);
lengthRead = 0;
destination = Redir->RawBuffer;
while ( MaxLength != 0 ) {
status = MakeSmbHeader(
Redir,
header,
SMB_COM_READ_RAW,
IdSelections,
IdValues
);
if ( !NT_SUCCESS(status) ) {
return status;
}
request->WordCount = 8;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUlong( &request->Offset, Offset );
SmbPutUshort( &request->MaxCount, (USHORT)MaxLength );
SmbPutUshort( &request->MinCount, 0 );
SmbPutUlong( &request->Timeout, 0 );
SmbPutUshort( &request->Reserved, 0 );
SmbPutUshort( &request->ByteCount, 0 );
smbSize = GET_ANDX_OFFSET( header, request, REQ_READ_RAW, 0 );
IF_DEBUG(4) {
printf( "requesting raw read of %ld bytes at offset %ld\n",
MaxLength, Offset );
}
//
// Start a receive for the raw read data before sending the
// request.
//
status = StartReceive(
DebugString,
Redir->FileHandle,
Redir->EventHandle[1],
&Redir->Iosb[1],
destination,
MaxLength
);
if ( !NT_SUCCESS(status) ) {
return status;
}
//
// Send the request for raw data.
//
// *** If there is an error, the receive remains posted!
status = SendSmb( Redir, DebugString, smbSize, 0 );
if ( !NT_SUCCESS(status) ) {
return status;
}
//
// Wait for the raw data to arrive.
//
status = WaitForSendOrReceive( DebugString, Redir, 1, "receive" );
if ( !NT_SUCCESS(status) ) {
return status;
}
//
// If any data was received, then the raw read succeeded.
//
if ( Redir->Iosb[1].Information != 0 ) {
IF_DEBUG(4) {
printf( "Raw read succeeded; %ld bytes received\n",
Redir->Iosb[1].Information );
}
*ActualLength = lengthRead + Redir->Iosb[1].Information;
*ActualData = Redir->RawBuffer;
return STATUS_SUCCESS;
}
//
// A zero-length message was received. Either 1) the server
// didn't have resources to process the request; 2) the read
// failed; or 3) we tried to read at or beyond EOF. Retry with
// a normal Read.
//
IF_DEBUG(4) {
printf( "Raw read returned 0 bytes; trying normal read\n" );
}
readLength = MIN(
MaxLength,
(CLONG)((Redir->MaxBufferSize - 100) & ~1023)
);
status = DoNormalRead(
Redir,
DebugString,
IdSelections,
IdValues,
Normal,
readLength,
Offset,
ActualLength,
ActualData
);
if ( !NT_SUCCESS(status) ) {
//
// The normal read failed, so things are really screwed up.
//
IF_DEBUG(4) printf( "Normal read failed: %X\n", status );
return status;
}
if ( *ActualLength == 0 ) {
//
// The normal read succeeded, but we didn't get any data, so
// we must be at EOF.
//
IF_DEBUG(4) printf( "Normal read returned 0 bytes; at EOF\n" );
*ActualLength = lengthRead;
*ActualData = Redir->RawBuffer;
return STATUS_SUCCESS;
}
//
// The normal read succeeded, and we got some data back. Copy
// the data into the output buffer and update counters.
//
RtlMoveMemory( destination, *ActualData, *ActualLength );
lengthRead += *ActualLength;
MaxLength -= *ActualLength;
destination += *ActualLength;
Offset += *ActualLength;
if ( *ActualLength != readLength ) {
//
// We didn't read as much as we asked for, so we must have
// hit EOF.
//
IF_DEBUG(4) {
printf( "Normal read didn't return full-length; at EOF\n" );
}
*ActualLength = lengthRead;
*ActualData = Redir->RawBuffer;
return STATUS_SUCCESS;
}
//
// The normal read returned as much as we asked for. Keep going.
//
IF_DEBUG(4) {
printf( "Normal read returned full-length; continuing\n" );
}
} // while ( MaxLength != 0 )
*ActualLength = lengthRead;
*ActualData = Redir->RawBuffer;
return STATUS_SUCCESS;
} // DoRawRead
NTSTATUS
DoMultiplexedRead(
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN RWC_MODE Mode,
IN CLONG MaxLength,
IN ULONG Offset,
OUT CLONG *ActualLength,
OUT PUCHAR *ActualData
)
{
Redir, DebugString, IdSelections, IdValues, Mode, MaxLength, Offset;
ActualLength, ActualData;
printf( "DoMultiplexedRead: not implemented\n" );
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
DoBulkRead(
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN RWC_MODE Mode,
IN CLONG MaxLength,
IN ULONG Offset,
OUT CLONG *ActualLength,
OUT PUCHAR *ActualData
)
{
#if 1
Redir, DebugString, IdSelections, IdValues, Mode, MaxLength, Offset;
ActualLength, ActualData;
printf( "DoBulkRead: not implemented\n" );
return STATUS_NOT_IMPLEMENTED;
#else
PSMB_HEADER header;
PREQ_READ2 request;
PRESP_READ2 response;
PCHAR tempBuffer;
ULONG bytesReceivedSoFar;
ULONG totalBytesToReceive;
NTSTATUS status;
CLONG smbSize;
Mode;
//
// Allocate a buffer to hold responses.
//
tempBuffer = malloc( 65536 );
if ( tempBuffer == NULL ) {
return STATUS_NO_MEMORY;
}
header = (PSMB_HEADER)Redir->Data[0];
request = (PREQ_READ2)(header + 1);
status = MakeSmbHeader(
Redir,
header,
SMB_COM_READ2,
IdSelections,
IdValues
);
if ( !NT_SUCCESS(status) ) {
free( tempBuffer );
return status;
}
request->WordCount = 5;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUlong( &request->Count, (ULONG)MaxLength );
SmbPutUlong( &request->Offset, Offset );
SmbPutUlong( &request->Remaining, 0 );
SmbPutUshort( &request->ByteCount, 0 );
smbSize = GET_ANDX_OFFSET( header, request, REQ_READ2, 0 );
IF_DEBUG(4) printf( "reading %ld bytes at offset %ld\n",
MaxLength, Offset );
//
// Start a receive for the first response data before sending the
// request.
//
status = StartReceive(
DebugString,
Redir->FileHandle,
Redir->EventHandle[1],
&Redir->Iosb[1],
tempBuffer,
65536
);
if ( !NT_SUCCESS(status) ) {
free( tempBuffer );
return status;
}
//
// Send the request for bulk data.
//
// *** If there is an error, the receive remains posted!
status = SendSmb( Redir, DebugString, smbSize, 0 );
if ( !NT_SUCCESS(status) ) {
free( tempBuffer );
return status;
}
//
// Wait for the first response to arrive.
//
status = WaitForSendOrReceive( DebugString, Redir, 1, "receive" );
if ( !NT_SUCCESS(status) ) {
free( tempBuffer );
return status;
}
IF_DEBUG(4) {
printf( "Bulk read succeeded; %ld bytes received\n",
Redir->Iosb[1].Information );
}
*ActualLength = totalBytesToReceive;
*ActualData = Redir->RawBuffer;
header = (PSMB_HEADER)tempBuffer;
response = (PRESP_READ2)(header + 1);
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_READ2
);
if ( !NT_SUCCESS(status) ) {
free( tempBuffer );
return status;
}
totalBytesToReceive = SmbGetUlong( &response->Count );
bytesReceivedSoFar = SmbGetUshort( &response->ByteCount );
IF_DEBUG(4) {
printf( "%ld bytes total, %ld in first message\n",
totalBytesToReceive, bytesReceivedSoFar );
}
//
// Copy the read data into the real buffer.
//
RtlMoveMemory(
Redir->RawBuffer,
response->Buffer,
bytesReceivedSoFar
);
//
// Loop receiving the rest of the data.
//
while ( bytesReceivedSoFar < totalBytesToReceive ) {
PBULK_DATA_MESSAGE bulkResponse = (PBULK_DATA_MESSAGE)response;
ULONG bulkOffset;
ULONG bulkLength;
status = StartReceive(
DebugString,
Redir->FileHandle,
Redir->EventHandle[1],
&Redir->Iosb[1],
tempBuffer,
65536
);
if ( !NT_SUCCESS(status) ) {
free( tempBuffer );
return status;
}
status = WaitForSendOrReceive( DebugString, Redir, 1, "receive" );
if ( !NT_SUCCESS(status) ) {
free( tempBuffer );
return status;
}
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_READ2
);
if ( !NT_SUCCESS(status) ) {
free( tempBuffer );
return status;
}
bulkOffset = SmbGetUlong( &bulkResponse->Data1MessageOffset );
bulkLength = SmbGetUlong( &bulkResponse->Data1Length );
bytesReceivedSoFar += bulkLength;
IF_DEBUG(4) {
printf( "received %ld data bytes, %ld so far, offset %ld\n",
bulkLength, bytesReceivedSoFar, bulkOffset );
}
RtlMoveMemory(
(PCHAR)Redir->RawBuffer +
SmbGetUlong( &bulkResponse->Data1BlockOffset ),
(PCHAR)bulkResponse + bulkOffset,
bulkLength
);
}
ASSERT( bytesReceivedSoFar == totalBytesToReceive );
*ActualLength = (CLONG)totalBytesToReceive;
*ActualData = Redir->RawBuffer;
if ( *ActualLength > MaxLength ) {
printf( "Too much read data returned. Expected %ld, received %ld\n",
MaxLength, *ActualLength );
SMB_ERROR_BREAK;
free( tempBuffer );
return STATUS_UNSUCCESSFUL;
}
IF_DEBUG(4) printf( "%ld bytes read\n", *ActualLength );
free( tempBuffer );
return STATUS_SUCCESS;
#endif
} // DoBulkRead
NTSTATUS
DoNormalWrite(
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN RWC_MODE Mode,
IN BOOLEAN UseClose,
IN CLONG WriteLength,
IN ULONG Offset,
IN PUCHAR WriteData
)
{
PSMB_HEADER header;
NTSTATUS status;
CLONG smbSize;
Mode;
header = (PSMB_HEADER)Redir->Data[1];
if ( WriteLength == 0 ) {
if ( !UseClose ) {
IF_DEBUG(4) printf( "skipping zero-length write\n" );
return STATUS_SUCCESS;
}
status = MakeCloseSmb(
Redir,
header,
NULL,
SMB_COM_NO_ANDX_COMMAND,
IdSelections,
IdValues,
&smbSize
);
} else {
status = MakeSmbHeader(
Redir,
header,
(UCHAR)(UseClose ?
SMB_COM_WRITE_AND_CLOSE : SMB_COM_WRITE),
IdSelections,
IdValues
);
if ( !NT_SUCCESS(status) ) {
return status;
}
if ( !UseClose ) {
PREQ_WRITE request = (PREQ_WRITE)(header + 1);
request->WordCount = 5;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUshort( &request->Count, (USHORT)WriteLength );
SmbPutUlong( &request->Offset, Offset );
SmbPutUshort( &request->Remaining, 0 );
SmbPutUshort(
&request->ByteCount,
(USHORT)(WriteLength + FIELD_OFFSET(REQ_WRITE,Buffer[0]) -
FIELD_OFFSET(REQ_WRITE,BufferFormat))
);
request->BufferFormat = SMB_FORMAT_DATA;
SmbPutUshort( &request->DataLength, (USHORT)WriteLength );
if ( (WriteData != NULL) &&
(WriteData != (PUCHAR)request->Buffer) ) {
printf( "DoNormalWrite copying data from 0x%lx to 0x%lx\n",
WriteData, request->Buffer );
RtlMoveMemory( request->Buffer, WriteData, WriteLength );
}
smbSize = GET_ANDX_OFFSET(
header,
request,
REQ_WRITE,
SmbGetUshort( &request->ByteCount )
);
} else {
PREQ_WRITE_AND_CLOSE request = (PREQ_WRITE_AND_CLOSE)(header + 1);
request->WordCount = 6;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUshort( &request->Count, (USHORT)WriteLength );
SmbPutUlong( &request->Offset, Offset );
SmbPutUlong( &request->LastWriteTimeInSeconds, 0 );
SmbPutUshort(
&request->ByteCount,
(USHORT)(WriteLength +
FIELD_OFFSET(REQ_WRITE_AND_CLOSE,Buffer[0]) -
FIELD_OFFSET(REQ_WRITE_AND_CLOSE,Pad))
);
request->Pad = 0;
if ( (WriteData != NULL) &&
(WriteData != (PUCHAR)request->Buffer) ) {
printf( "DoNormalWrite copying data from 0x%lx to 0x%lx\n",
WriteData, request->Buffer );
RtlMoveMemory( request->Buffer, WriteData, WriteLength );
}
smbSize = GET_ANDX_OFFSET(
header,
request,
REQ_WRITE_AND_CLOSE,
SmbGetUshort( &request->ByteCount )
);
}
}
IF_DEBUG(4) {
if ( WriteLength == 0 ) {
printf( "skipping zero-length write; sending close\n" );
} else {
printf( "writing %ld bytes at offset %ld\n",
WriteLength, Offset );
}
}
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
1,
0
);
if ( !NT_SUCCESS(status) ) {
return status;
}
header = (PSMB_HEADER)Redir->Data[0];
if ( WriteLength == 0 ) {
status = VerifyClose(
Redir,
NULL,
SMB_COM_NO_ANDX_COMMAND,
IdSelections,
IdValues,
&smbSize,
header
);
} else {
PRESP_WRITE response = (PRESP_WRITE)(header + 1);
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
(UCHAR)(UseClose ? SMB_COM_WRITE_AND_CLOSE : SMB_COM_WRITE)
);
if ( !NT_SUCCESS(status) ) {
return status;
}
if ( (CLONG)SmbGetUshort( &response->Count ) != WriteLength ) {
printf( "Length written incorrect. Sent %ld, wrote %ld\n",
WriteLength, SmbGetUshort( &response->Count ) );
SMB_ERROR_BREAK;
return STATUS_UNSUCCESSFUL;
}
}
IF_DEBUG(4) {
if ( WriteLength == 0 ) {
printf( "output file closed\n" );
} else {
printf( "%ld bytes written\n", WriteLength );
}
}
return STATUS_SUCCESS;
} // DoNormalWrite
NTSTATUS
DoAndXWrite(
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN RWC_MODE Mode,
IN BOOLEAN UseClose,
IN CLONG WriteLength,
IN ULONG Offset,
IN PUCHAR WriteData
)
{
PSMB_HEADER header;
NTSTATUS status;
CLONG smbSize;
Mode;
header = (PSMB_HEADER)Redir->Data[1];
if ( WriteLength == 0 ) {
if ( !UseClose ) {
IF_DEBUG(4) printf( "skipping zero-length write\n" );
return STATUS_SUCCESS;
}
status = MakeCloseSmb(
Redir,
header,
NULL,
SMB_COM_NO_ANDX_COMMAND,
IdSelections,
IdValues,
&smbSize
);
} else {
status = MakeSmbHeader(
Redir,
header,
(UCHAR)(UseClose ?
SMB_COM_WRITE_AND_CLOSE : SMB_COM_WRITE_ANDX),
IdSelections,
IdValues
);
if ( !NT_SUCCESS(status) ) {
return status;
}
if ( !UseClose ) {
PREQ_WRITE_ANDX request = (PREQ_WRITE_ANDX)(header + 1);
CLONG dataOffset, pad;
request->WordCount = 12;
request->AndXCommand = SMB_COM_NO_ANDX_COMMAND;
request->AndXReserved = 0;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUlong( &request->Offset, Offset );
SmbPutUlong( &request->Timeout, 0 );
SmbPutUshort( &request->WriteMode, 0 );
SmbPutUshort( &request->Remaining, 0 );
SmbPutUshort( &request->Reserved, 0 );
SmbPutUshort( &request->DataLength, (USHORT)WriteLength );
dataOffset = request->Buffer - (PUCHAR)header;
pad = (4 - (dataOffset & 3)) & 3;
dataOffset += pad;
SmbPutUshort( &request->DataOffset, (USHORT)dataOffset );
SmbPutUshort( &request->ByteCount, (USHORT)(pad + WriteLength) );
if ( (WriteData != NULL) && (WriteData != request->Buffer+pad) ) {
printf( "DoAndXWrite copying data from 0x%lx to 0x%lx\n",
WriteData, request->Buffer+pad );
RtlMoveMemory( request->Buffer + pad, WriteData, WriteLength );
}
smbSize = GET_ANDX_OFFSET(
header,
request,
REQ_WRITE_ANDX,
WriteLength + pad
);
SmbPutUshort( &request->AndXOffset, (USHORT)smbSize );
} else {
PREQ_WRITE_AND_CLOSE_LONG request =
(PREQ_WRITE_AND_CLOSE_LONG)(header + 1);
request->WordCount = 12;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUshort( &request->Count, (USHORT)WriteLength );
SmbPutUlong( &request->Offset, Offset );
SmbPutUlong( &request->LastWriteTimeInSeconds, 0 );
RtlZeroMemory( &request->Reserved[0], sizeof(request->Reserved) );
SmbPutUshort(
&request->ByteCount,
(USHORT)(WriteLength +
FIELD_OFFSET(REQ_WRITE_AND_CLOSE_LONG,Buffer[0]) -
FIELD_OFFSET(REQ_WRITE_AND_CLOSE_LONG,Pad))
);
request->Pad = 0;
if ( (WriteData != NULL) &&
(WriteData != (PUCHAR)request->Buffer) ) {
printf( "DoAndXWrite copying data from 0x%lx to 0x%lx\n",
WriteData, request->Buffer );
RtlMoveMemory( request->Buffer, WriteData, WriteLength );
}
smbSize = GET_ANDX_OFFSET(
header,
request,
REQ_WRITE_AND_CLOSE_LONG,
SmbGetUshort( &request->ByteCount )
);
}
}
IF_DEBUG(4) {
if ( WriteLength == 0 ) {
printf( "skipping zero-length write; sending close\n" );
} else {
printf( "writing %ld bytes at offset %ld\n",
WriteLength, Offset );
}
}
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
1,
0
);
if ( !NT_SUCCESS(status) ) {
return status;
}
header = (PSMB_HEADER)Redir->Data[0];
if ( WriteLength == 0 ) {
status = VerifyClose(
Redir,
NULL,
SMB_COM_NO_ANDX_COMMAND,
IdSelections,
IdValues,
&smbSize,
header
);
} else {
CLONG lengthWritten;
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
(UCHAR)(UseClose ?
SMB_COM_WRITE_AND_CLOSE : SMB_COM_WRITE_ANDX )
);
if( !NT_SUCCESS(status) ) {
return status;
}
if ( !UseClose ) {
PRESP_WRITE_ANDX response = (PRESP_WRITE_ANDX)(header + 1);
lengthWritten = (CLONG)SmbGetUshort( &response->Count );
} else {
PRESP_WRITE_AND_CLOSE response =
(PRESP_WRITE_AND_CLOSE)(header + 1);
lengthWritten = (CLONG)SmbGetUshort( &response->Count );
}
if ( lengthWritten != WriteLength ) {
printf( "Length written incorrect. Sent %ld, wrote %ld\n",
WriteLength, lengthWritten );
SMB_ERROR_BREAK;
return STATUS_UNSUCCESSFUL;
}
}
IF_DEBUG(4) {
if ( WriteLength == 0 ) {
printf( "output file closed\n" );
} else {
printf( "%ld bytes written\n", WriteLength );
}
}
return STATUS_SUCCESS;
} // DoAndXWrite
NTSTATUS
DoRawWrite(
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN RWC_MODE Mode,
IN BOOLEAN UseClose,
IN CLONG WriteLength,
IN ULONG Offset,
IN PUCHAR WriteData
)
{
PSMB_HEADER header;
PREQ_WRITE_RAW request;
PRESP_WRITE_COMPLETE finalResponse;
NTSTATUS status;
CLONG smbSize;
PVOID savedDataPointer;
PUCHAR source;
CLONG lengthWritten;
CLONG immediateLength;
USHORT smbStatus;
source = WriteData;
lengthWritten = 0;
immediateLength = 0;
while ( TRUE ) {
header = (PSMB_HEADER)Redir->Data[0];
request = (PREQ_WRITE_RAW)(header + 1);
status = MakeSmbHeader(
Redir,
header,
SMB_COM_WRITE_RAW,
IdSelections,
IdValues
);
if ( !NT_SUCCESS(status) ) {
return status;
}
request->WordCount = 12;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUshort( &request->Count, (USHORT)WriteLength );
SmbPutUshort( &request->Reserved, 0 );
SmbPutUlong( &request->Offset, Offset );
SmbPutUlong( &request->Timeout, 0 );
SmbPutUshort(
&request->WriteMode,
(USHORT)(Mode == Raw ? 0 : SMB_WMODE_WRITE_THROUGH)
);
SmbPutUlong( &request->Reserved2, 0 );
if ( immediateLength == 0 ) {
SmbPutUshort( &request->DataLength, 0 );
SmbPutUshort( &request->DataOffset, 0 );
SmbPutUshort( &request->ByteCount, 0 );
smbSize = GET_ANDX_OFFSET( header, request, REQ_WRITE_RAW, 0 );
} else {
CLONG pad;
CLONG dataOffset;
dataOffset = request->Buffer - (PUCHAR)header;
pad = (4 - (dataOffset & 3)) & 3;
dataOffset += pad;
SmbPutUshort( &request->DataLength, (USHORT)immediateLength );
SmbPutUshort( &request->DataOffset, (USHORT)dataOffset );
SmbPutUshort(
&request->ByteCount,
(USHORT)(pad + immediateLength)
);
RtlMoveMemory( request->Buffer + pad, source, immediateLength );
smbSize = GET_ANDX_OFFSET(
header,
request,
REQ_WRITE_RAW,
pad + immediateLength
);
}
IF_DEBUG(4) {
printf( "requesting raw write of %ld bytes (%ld immediate) "
"at offset %ld\n",
WriteLength, immediateLength, Offset );
}
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
0,
1
);
if ( !NT_SUCCESS(status) ) {
return status;
}
header = (PSMB_HEADER)Redir->Data[1];
smbStatus = SmbGetUshort( &header->Error );
if ( smbStatus == SMB_ERR_SUCCESS ) {
//
// The request to send raw write data was accepted. Go do it.
//
break;
} else if ( (smbStatus == SMB_ERR_USE_STANDARD) ||
(smbStatus == SMB_ERR_USE_MPX) ) {
//
// The server isn't accepting raw writes just now. Try it
// again, this time sending immediate data. The immediate
// data will be written, even if the server can't do the
// raw part at the moment.
//
source += immediateLength;
lengthWritten += immediateLength;
Offset += immediateLength;
WriteLength -= immediateLength;
if ( WriteLength == 0 ) {
IF_DEBUG(4) {
printf( "Raw write rejected, but immediate write "
"sent all remaining data\n" );
}
return STATUS_SUCCESS;
}
immediateLength = MIN(
WriteLength,
(CLONG)((Redir->MaxBufferSize - 100) & ~1023)
);
IF_DEBUG(4) {
printf( "Server rejected raw write. Retrying "
"with immediate data.\n" );
}
continue;
} else {
//
// Fatal error.
//
(VOID)VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_NO_ANDX_COMMAND
);
return STATUS_UNSUCCESSFUL;
}
} // while ( TRUE )
//
// The request to send raw write data was accepted. Send the rest
// of data, minus immediate data sent in the request. (Note that
// we may have sent _all_ of the remaining data as immediate data.)
//
if ( WriteLength - immediateLength != 0 ) {
IF_DEBUG(4) printf( "sending raw write data\n" );
savedDataPointer = Redir->Data[0];
Redir->Data[0] = source + immediateLength;
if ( Mode == Raw ) {
status = SendSmb(
Redir,
DebugString,
WriteLength - immediateLength,
0
);
Redir->Data[0] = savedDataPointer;
if ( !NT_SUCCESS(status) ) {
return status;
}
} else {
status = SendAndReceiveSmb(
Redir,
DebugString,
WriteLength - immediateLength,
0,
1
);
Redir->Data[0] = savedDataPointer;
if ( !NT_SUCCESS(status) ) {
return status;
}
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_WRITE_COMPLETE
);
if ( !NT_SUCCESS(status) ) {
return status;
}
finalResponse = (PRESP_WRITE_COMPLETE)(header + 1);
if ( (CLONG)SmbGetUshort( &finalResponse->Count ) != WriteLength ) {
printf( "Write length incorrect. Sent %ld, wrote %ld\n",
WriteLength, SmbGetUshort( &finalResponse->Count ) );
SMB_ERROR_BREAK;
return STATUS_UNSUCCESSFUL;
}
}
}
if ( UseClose ) {
return DoRemoteClose(
Redir,
DebugString,
IdSelections,
IdValues
);
}
return STATUS_SUCCESS;
} // DoRawWrite
NTSTATUS
DoMultiplexedWrite(
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN RWC_MODE Mode,
IN BOOLEAN UseClose,
IN CLONG WriteLength,
IN ULONG Offset,
IN PUCHAR WriteData
)
{
Redir, DebugString, IdSelections, IdValues, Mode, UseClose;
WriteLength, Offset, WriteData;
printf( "DoMultiplexedWrite: not implemented\n" );
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
DoBulkWrite (
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN RWC_MODE Mode,
IN BOOLEAN UseClose,
IN CLONG WriteLength,
IN ULONG Offset,
IN PUCHAR WriteData
)
{
Redir, DebugString, IdSelections, IdValues, Mode, UseClose;
WriteLength, Offset, WriteData;
printf( "DoBulkWrite: not implemented\n" );
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
RwcDoLock(
IN PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN PID_VALUES IdValues,
IN ULONG Offset,
IN CLONG Length
)
{
NTSTATUS status;
CLONG smbSize;
PSMB_HEADER header;
PREQ_LOCK_BYTE_RANGE request;
header = (PSMB_HEADER)Redir->Data[0];
request = (PREQ_LOCK_BYTE_RANGE)(header + 1);
(VOID)MakeSmbHeader(
Redir,
header,
SMB_COM_LOCK_BYTE_RANGE,
IdSelections,
IdValues
);
request->WordCount = 5;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUlong( &request->Offset, Offset );
SmbPutUlong( &request->Count, Length );
SmbPutUshort( &request->ByteCount, 0 );
smbSize = GET_ANDX_OFFSET( header, request, REQ_LOCK_BYTE_RANGE, 0 );
IF_DEBUG(4) printf( "locking %ld bytes at offset %ld\n",
Length, Offset );
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
0,
1
);
if ( !NT_SUCCESS(status) ) {
return status;
}
header = (PSMB_HEADER)Redir->Data[1];
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_LOCK_BYTE_RANGE
);
if ( !NT_SUCCESS(status) ) {
return status;
}
return STATUS_SUCCESS;
} // RwcDoLock
NTSTATUS
RwcDoUnlock(
IN PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN ULONG Offset,
IN CLONG Length
)
{
NTSTATUS status;
CLONG smbSize;
PSMB_HEADER header;
PREQ_UNLOCK_BYTE_RANGE request;
header = (PSMB_HEADER)Redir->Data[0];
request = (PREQ_UNLOCK_BYTE_RANGE)(header + 1);
(VOID)MakeSmbHeader(
Redir,
header,
SMB_COM_UNLOCK_BYTE_RANGE,
IdSelections,
IdValues
);
request->WordCount = 5;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUlong( &request->Offset, Offset );
SmbPutUlong( &request->Count, Length );
SmbPutUshort( &request->ByteCount, 0 );
smbSize = GET_ANDX_OFFSET( header, request, REQ_UNLOCK_BYTE_RANGE, 0 );
IF_DEBUG(4) printf( "unlocking %ld bytes at offset %ld\n",
Length, Offset );
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
0,
1
);
if ( !NT_SUCCESS(status) ) {
return status;
}
header = (PSMB_HEADER)Redir->Data[1];
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_UNLOCK_BYTE_RANGE
);
if ( !NT_SUCCESS(status) ) {
return status;
}
return STATUS_SUCCESS;
} // RwcDoUnlock
NTSTATUS
RwcDoLockAndRead(
IN PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN ULONG Offset,
IN CLONG MaxLength,
IN OUT PCLONG ActualLength,
IN PUCHAR *ActualData
)
{
NTSTATUS status;
CLONG smbSize;
PSMB_HEADER header;
PREQ_READ request;
PRESP_READ response;
header = (PSMB_HEADER)Redir->Data[0];
request = (PREQ_READ)(header + 1);
status = MakeSmbHeader(
Redir,
header,
SMB_COM_LOCK_AND_READ,
IdSelections,
IdValues
);
if ( !NT_SUCCESS(status) ) {
return status;
}
request->WordCount = 5;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUshort( &request->Count, (USHORT)MaxLength );
SmbPutUlong( &request->Offset, Offset );
SmbPutUshort( &request->Remaining, 0 );
SmbPutUshort( &request->ByteCount, 0 );
smbSize = GET_ANDX_OFFSET(
header,
request,
REQ_READ,
0
);
IF_DEBUG(4) printf( "locking and reading %ld bytes at offset %ld\n",
MaxLength, Offset );
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
0,
1
);
if ( !NT_SUCCESS(status) ) {
return status;
}
header = (PSMB_HEADER)Redir->Data[1];
response = (PRESP_READ)(header + 1);
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_LOCK_AND_READ
);
if ( !NT_SUCCESS(status) ) {
return status;
}
if ( (CLONG)SmbGetUshort( &response->Count ) > MaxLength ) {
printf( "Read size too large. Expected %ld, received %ld\n",
MaxLength, SmbGetUshort( &response->Count ) );
SMB_ERROR_BREAK;
return STATUS_UNSUCCESSFUL;
}
*ActualLength = SmbGetUshort( &response->Count );
*ActualData = (PUCHAR)response->Buffer;
IF_DEBUG(4) printf( "%ld bytes locked and read\n", *ActualLength );
return STATUS_SUCCESS;
} // DoLockAndRead
NTSTATUS
RwcDoWriteAndUnlock(
IN PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN ULONG Offset,
IN CLONG WriteLength,
IN PUCHAR WriteData OPTIONAL
)
{
NTSTATUS status;
CLONG smbSize;
PSMB_HEADER header;
PREQ_WRITE request;
PRESP_WRITE response;
header = (PSMB_HEADER)Redir->Data[1];
request = (PREQ_WRITE)(header + 1);
status = MakeSmbHeader(
Redir,
header,
SMB_COM_WRITE_AND_UNLOCK,
IdSelections,
IdValues
);
if ( !NT_SUCCESS(status) ) {
return status;
}
request->WordCount = 5;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUshort( &request->Count, (USHORT)WriteLength );
SmbPutUlong( &request->Offset, Offset );
SmbPutUshort( &request->Remaining, 0 );
SmbPutUshort(
&request->ByteCount,
(USHORT)(WriteLength + FIELD_OFFSET(REQ_WRITE,Buffer[0]) -
FIELD_OFFSET(REQ_WRITE,BufferFormat))
);
request->BufferFormat = SMB_FORMAT_DATA;
SmbPutUshort( &request->DataLength, (USHORT)WriteLength );
if ( (WriteData != NULL) &&
(WriteData != (PUCHAR)request->Buffer) ) {
printf( "RwcDoWriteAndUnlock copying data from 0x%lx to 0x%lx\n",
WriteData, request->Buffer );
RtlMoveMemory( request->Buffer, WriteData, WriteLength );
}
smbSize = GET_ANDX_OFFSET(
header,
request,
REQ_WRITE,
SmbGetUshort( &request->ByteCount )
);
IF_DEBUG(4) printf( "writing and unlocking %ld bytes at offset %ld\n",
WriteLength, Offset );
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
1,
0
);
if ( !NT_SUCCESS(status) ) {
return status;
}
header = (PSMB_HEADER)Redir->Data[0];
response = (PRESP_WRITE)(header + 1);
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_WRITE_AND_UNLOCK
);
if ( !NT_SUCCESS(status) ) {
return status;
}
if ( (CLONG)SmbGetUshort( &response->Count ) != WriteLength ) {
printf( "Write size incorrect. Sent %ld, wrote %ld\n",
WriteLength, SmbGetUshort( &response->Count ) );
SMB_ERROR_BREAK;
return STATUS_UNSUCCESSFUL;
}
IF_DEBUG(4) printf( "%ld bytes written and unlocked\n", WriteLength );
return STATUS_SUCCESS;
} // RwcDoWriteAndUnlock
NTSTATUS
DoSeek (
IN OUT PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN OUT PID_VALUES IdValues,
IN USHORT Mode,
IN LONG Offset,
IN PLONG ResultingOffset
)
{
PSMB_HEADER header;
PREQ_SEEK request;
PRESP_SEEK response;
CLONG smbSize;
NTSTATUS status;
header = (PSMB_HEADER)Redir->Data[0];
request = (PREQ_SEEK)(header + 1);
status = MakeSmbHeader(
Redir,
header,
SMB_COM_SEEK,
IdSelections,
IdValues
);
if ( !NT_SUCCESS(status) ) {
return status;
}
request->WordCount = 4;
SmbPutUshort( &request->Fid, IdValues->Fid[IdSelections->Fid] );
SmbPutUshort( &request->Mode, Mode );
SmbPutUlong( &request->Offset, (ULONG)Offset );
SmbPutUshort( &request->ByteCount, 0 );
smbSize = GET_ANDX_OFFSET( header, request, REQ_SEEK, 0 );
IF_DEBUG(4) {
printf( "Setting offset to %s%s%ld\n",
(Mode == 0) ? "BOF" : (Mode == 1) ? "current" : "EOF",
(Offset < 0) ? "" : "+", Offset );
}
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
0,
1
);
if ( !NT_SUCCESS(status) ) {
return status;
}
header = (PSMB_HEADER)Redir->Data[1];
response = (PRESP_SEEK)(header + 1);
status = VerifySmbHeader(
Redir,
IdSelections,
IdValues,
header,
SMB_COM_SEEK
);
if ( !NT_SUCCESS(status) ) {
return status;
}
*ResultingOffset = (LONG)SmbGetUlong( &response->Offset );
IF_DEBUG(4) printf( "Resulting offset is %ld\n", *ResultingOffset );
return STATUS_SUCCESS;
} // DoSeek
NTSTATUS
DoRemoteOpen(
IN PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN PID_VALUES IdValues,
IN BOOLEAN UseAndX
)
{
NTSTATUS status;
ULONG smbSize = 0;
if ( UseAndX ) {
status = MakeOpenAndXSmb(
Redir,
Redir->Data[0],
NULL,
0xFF,
IdSelections,
IdValues,
&smbSize
);
} else {
status = MakeOpenSmb(
Redir,
Redir->Data[0],
NULL,
0xFF,
IdSelections,
IdValues,
&smbSize
);
}
if ( !NT_SUCCESS(status) ) {
return status;
}
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
0,
1
);
if ( !NT_SUCCESS(status) ) {
return status;
}
if ( UseAndX ) {
status = VerifyOpenAndX(
Redir,
NULL,
0,
IdSelections,
IdValues,
&smbSize,
Redir->Data[1]
);
} else {
status = VerifyOpen(
Redir,
NULL,
0,
IdSelections,
IdValues,
&smbSize,
Redir->Data[1]
);
}
if ( !NT_SUCCESS(status) ) {
printf( "Open failed: %X\n", status );
}
return status;
} // DoRemoteOpen
NTSTATUS
DoRemoteClose(
IN PDESCRIPTOR Redir,
IN PSZ DebugString,
IN PID_SELECTIONS IdSelections,
IN PID_VALUES IdValues
)
{
NTSTATUS status;
ULONG smbSize;
status = MakeCloseSmb(
Redir,
Redir->Data[0],
NULL,
0,
IdSelections,
IdValues,
&smbSize
);
if ( !NT_SUCCESS(status) ) {
return status;
}
status = SendAndReceiveSmb(
Redir,
DebugString,
smbSize,
0,
1
);
if ( !NT_SUCCESS(status) ) {
return status;
}
status = VerifyClose(
Redir,
NULL,
0,
IdSelections,
IdValues,
&smbSize,
Redir->Data[1]
);
if ( !NT_SUCCESS(status) ) {
printf( "Close failed: %X\n", status );
}
return status;
} // DoRemoteClose