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.
1925 lines
49 KiB
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
|