The Write Block Raw protocol is used to maximize the performance of writing a large block of data from the client to the server. The Write Block Raw command's scope includes files, Named Pipes, and spooled output (can be used in place COM_WRITE_PRINT_FILE ).
Client Request ========================== |
Description ========================================= |
UCHAR WordCount; | Count of parameter words = 12 |
USHORT Fid; | File handle |
USHORT Count; | Total bytes, including this buffer |
USHORT Reserved; | |
ULONG Offset; | Offset in file to begin write |
ULONG Timeout; | |
USHORT WriteMode; | Write mode: |
bit 0 - complete write to disk and send final result response | |
bit 1 - return Remaining (pipe/dev) | |
(see WriteAndX for #defines) | |
ULONG Reserved2; | |
USHORT DataLength; | Number of data bytes this buffer |
USHORT DataOffset; | Offset (from header start) to data |
USHORT ByteCount; | Count of data bytes |
UCHAR Pad[]; | Pad to SHORT or LONG |
UCHAR Data[]; | Data (# = DataLength) |
First Server Response ============================== |
Description ===================================== |
UCHAR WordCount; | Count of parameter words = 1 |
USHORT Remaining; | Bytes remaining to be read if pipe |
USHORT ByteCount; | Count of data bytes = 0 |
Final Server Response ================================== |
Description ================================= |
UCHAR Command (in SMB header) | SMB_COM_WRITE_COMPLETE |
UCHAR WordCount; | Count of parameter words = 1 |
USHORT Count; | Total number of bytes written |
USHORT ByteCount; | Count of data bytes = 0 |
The first response format will be that of the final server response in the case where the server gets an error while writing the data sent along with the request. Thus count is the number of bytes which did get written any time an error is returned. If an error occurs after the first response has been sent allowing the client to send the remaining data, the final response should not be sent unless write through is set. Rather the server should return this "write behind" error on the next access to the fid.
The client must guarantee that there is (and will be) no other request on the connection for the duration of this request. The server will reserve enough resources to receive the data and respond with a response SMB as defined above. The client then sends the raw data in one send. Thus the server is able to receive up to 65,535 bytes of data directly into the server buffer. The amount of data transferred is expected to be larger than the negotiated buffer size for this protocol.
The reason that no other requests can be active on the connection for the duration of the request is that if other receives are present on the connection, there is normally no way to guarantee that the data will be received into the correct server buffer, rather the data may fill one (or more) of the other buffers. Also if the client is sending other requests on the connection, a request may land in the buffer that the server has allocated for the this SMB's data.
Whether or not SMB_COM_WRITE_RAW is supported is returned in the response to SMB_COM_NEGOTIATE. SMB_COM_WRITE_RAW is not supported for connectionless clients.
When write through is not specified ((writemode & 01) == 0) this SMB is assumed to be a form of write behind. The transport layer guarantees delivery of all secondary requests from the client. Thus no "got the data you sent" SMB is needed. If an error should occur at the server end, all bytes must be received and thrown away. If an error occurs while writing data to disk such as disk full, the next access of the file handle (another write, close, read, etc.) will return the fact that the error occurred.
If write through is specified ((writemode & 01) != 0), the server will receive the data, write it to disk and then send a final response indicating the result of the write. The total number of bytes written is also returned in this response in the count field.
The flow for the SMB_COM_WRITE_RAW SMB is:
client -----> SMB_COM_WRITE_RAW request (optional data) >-------> server
client <------------------< OK send (more) data <---------------- server
client ----------------------> raw data >----------------------> server
client <---< data on disk or error (write through only) <------- server
This protocol is set up such that the SMB_COM_WRITE_RAW request may also carry data. This is an optimization in that up to the server's buffer size (maxcount from SMB_COM_NEGOTIATE response), minus the size of the SMB_COM_WRITE_RAW SMB request, may be sent along with the request. Thus if the server is busy and unable to support the raw write of the remaining data, the data sent along with the request has been delivered and need not be sent again. The server will write any data sent in the request (and wait for it to be on the disk or device if write through is set), prior to sending the response.
The specific responses error class ERRSRV, error codes ERRusempx and ERRusestd, indicate that the server is temporarily out of the resources needed to support the raw write of the remaining data, but that any data sent along with the request has been successfully written. The client should then write the remaining data using a different type of SMB write request, or delay and retry using SMB_COM_WRITE_RAW. If a write error occurs writing the initial data, it will be returned and the write raw request is implicitly denied.
The return field remaining is returned for named pipes only. It is used to return the number of bytes currently available in the pipe. This information can then be used by the client to know when a subsequent (non blocking) read of the pipe may return some data. Of course when the read request is actually received by the server there may be more or less actual data in the pipe (more data has been written to the pipe / device or another reader drained it). If the information is currently not available or the request is NOT for a pipe or the server does not support this feature, a -1 value should be returned.
If the negotiated dialect is NT LM 0.12
or later, and the response to the SMB_COM_NEGOTIATE SMB has CAP_LARGE_FILES set in the capabilities field, an additional request format is allowed which accommodates very large files having 64 bit offsets:
Client Request ================================== |
Description ================================= |
UCHAR WordCount; | Count of parameter words = 14 |
USHORT Fid; | File handle |
USHORT Count; | Total bytes, including this buffer |
USHORT Reserved; | |
ULONG Offset; | Offset in file to begin write |
ULONG Timeout; | |
USHORT WriteMode; | Write mode: |
bit 0 - complete write to disk and send final result response | |
bit 1 - return Remaining (pipe/dev) | |
ULONG Reserved2; | |
USHORT DataLength; | Number of data bytes this buffer |
USHORT DataOffset; | Offset (from header start) to data |
ULONG OffsetHigh; | Upper 32 bits of offset |
USHORT ByteCount; | Count of data bytes |
UCHAR Pad[]; | Pad to SHORT or LONG |
UCHAR Data[]; | Data (# = DataLength) |
In this case the final offset in the file is formed by combining offsethigh and offset, the resulting offset must not be negative.