3.2.4.7 Application Requests Writing to a File or Named Pipe
The application provides:
A handle to the Open identifying a file or named pipe.
The offset, in bytes, from where data is written.
The number of bytes to write.
A buffer containing the bytes to be written.
WriteThrough, a Boolean flag indicating whether the data has to be written to persistent store on the server before a response is sent (optional).
UnbufferedWrite, a Boolean flag indicating whether the write data is not to be buffered on the server (optional).
CompressWrite, a Boolean flag indicating that the request is eligible for compression (optional).
If the handle is invalid, or if no Open referenced by the handle is found, the client MUST return an implementation-specific error code. If the handle is valid and Open is found, the client MUST proceed as follows.
For the specified Open, the client MUST select a connection as specified in section 3.2.4.1.7. If no connection is available, the client MUST fail the write operation.
Otherwise, the client initializes an SMB2 WRITE Request, following the syntax specified in section 2.2.21. The SMB2 header MUST be initialized as follows:
The Command field is set to SMB2 WRITE.
The SessionId field is set to Open.TreeConnect.Session.SessionId.
The TreeId field is set to Open.TreeConnect.TreeConnectId.
The SMB2 WRITE Request MUST be initialized as follows:
The Length field is set to the number of bytes the application requested to write.
The Offset field is set to the offset within the file, in bytes, at which the application requested the write to start.
The FileId field is set to Open.FileId.
The DataOffset field MUST be set to an implementation-specific<157> value.
If Connection.Dialect is not "2.0.2", and application-supplied WriteThrough is TRUE, the SMB2_WRITEFLAG_WRITE_THROUGH bit in the Flags field MUST be set.
If Connection.Dialect is "3.0.2" or "3.1.1", and the application-supplied UnbufferedWrite is TRUE, the SMB2_WRITEFLAG_WRITE_UNBUFFERED bit in the Flags field MUST be set.
If the number of bytes to write exceeds the Connection.MaxWriteSize, the client MUST split the write into separate write operations no larger than the Connection.MaxWriteSize. The client MAY<158> send these separate writes in any order.
If the connection is not established in RDMA mode or if the size of the operation is less than or equal to an implementation-specific threshold <159>or if either Open.TreeConnect.Session.SigningRequired or Open.TreeConnect.Session.EncryptData is TRUE, the following fields of the request MUST be initialized as follows:
If Connection.Dialect belongs to the SMB 3.x dialect family,
The Channel field MUST be set to SMB2_CHANNEL_NONE.
The WriteChannelInfoOffset field MUST be set to 0.
The WriteChannelInfoLength field MUST be set to 0.
The RemainingBytes field MUST be set to 0.
The data being written MUST be copied into the Buffer field at DataOffset bytes from the beginning of the SMB2 header.
The client MUST fill the bytes, if any, between the beginning of the Buffer field and the beginning of the data (at DataOffset) with zeros.
Otherwise, the interface in [MS-SMBD] section 3.1.4.3 Register Buffer MUST be used to register the buffer on the Connection with read permissions, which will supply the data to be written. The returned list of SMB_DIRECT_BUFFER_DESCRIPTOR_V1 structures MUST be stored in Request.BufferDescriptorList. The following fields of the request MUST be initialized as follows:
If Connection.Dialect is “3.1.1”, Connection.RDMATransformIds is not empty,
Channel field of the request MUST be set to SMB2_CHANNEL_RDMA_TRANSFORM.
Construct SMB2_RDMA_TRANSFORM structure with the following values:
Set RdmaDescriptorLength to the size of Request.BufferDescriptorList.
Set TransformCount to 1.
If processing of received remote invalidation is supported as specified in [MS-SMBD] section 3.1.5.8, the Channel SHOULD be set to SMB2_CHANNEL_RDMA_V1_INVALIDATE. Otherwise, Channel MUST be set to SMB2_CHANNEL_RDMA_V1.
Construct SMB2_RDMA_CRYPTO_TRANSFORM structure with the following values:
If Connection.RDMATransformIds includes SMB2_RDMA_TRANSFORM_ENCRYPTION and the request is encrypted as specified in section 3.2.4.1.8, TransformType MUST be set to SMB2_RDMA_TRANSFORM_TYPE_ENCRYPTION. Otherwise, TransformType MUST be set to SMB2_RDMA_TRANSFORM_TYPE_SIGNING.
If TransformType is SMB2_RDMA_TRANSFORM_TYPE_ENCRYPTION
If Connection.CipherID is AES-128-CCM or AES-256-CCM, Nonce MUST be set to 11-byte implementation specific value. If Connection.CipherID is AES-128-GCM or AES-256-GCM, Nonce MUST be set to 12-byte implementation specific value.
Set Signature to a value generated using the algorithm specified in Connection.CipherID with the following inputs:
Nonce.
Write data to be signed.
Session.EncryptionKey, as the key for signing.
If TransformType is SMB2_RDMA_TRANSFORM_TYPE_SIGNING
Set Signature to a value generated using the algorithm specified in Connection.SigningAlgorithmId, as specified in section 3.1.4.1. If Connection.SigningAlgorithmId is AES-GMAC, Nonce set to 12-byte implementation specific value MUST be used for Signature generation. Otherwise, Nonce MUST be set to empty.
Set SignatureLength to the size of Signature field.
Set NonceLength to the size of Nonce field.
If TransformType is SMB2_RDMA_TRANSFORM_TYPE_ENCRYPTION, data contained in the buffer registered with [MS-SMBD] MUST be encrypted using Session.EncryptionKey with the algorithm specified in Connection.CipherID.
Buffer field of the request MUST be set to the constructed SMB2_RDMA_TRANSFORM structure, followed by the constructed SMB2_RDMA_CRYPTO_TRANSFORM structure, followed by the list of structures in Request.BufferDescriptorList.
RdmaDescriptorOffset in SMB2_RDMA_TRANSFORM structure MUST be set to the sum of the sizes of SMB2_RDMA_TRANSFORM and SMB2_RDMA_CRYPTO_TRANSFORM.
WriteChannelInfoLength MUST be set to RdmaDescriptorOffset plus RdmaDescriptorLength.
WriteChannelInfoOffset MUST be set to the offset of the Buffer field of the request from the beginning of the SMB2 header.
Otherwise if Connection.Dialect belongs to the SMB 3.x dialect family,
If Connection.Dialect is "3.0.2" or "3.1.1" and processing of received remote invalidation is supported as specified in [MS-SMBD] section 3.1.5.8, the Channel field of the request SHOULD be set to SMB2_CHANNEL_RDMA_V1_INVALIDATE. Otherwise, the Channel field of the request MUST be set to SMB2_CHANNEL_RDMA_V1.
The returned list of SMB_DIRECT_BUFFER_DESCRIPTOR_V1 structures MUST be added to the Buffer field of the request.
The WriteChannelInfoOffset MUST be set to the offset of the added list from the beginning of the SMB2 header.
The WriteChannelInfoLength MUST be set to the length of the added list.
The Length and DataOffset fields MUST be set to 0.
The RemainingBytes field MUST be set to the number of bytes of data being written.
If a client requests writing to a file, Connection.Dialect is not "2.0.2", and if Connection.SupportsMultiCredit is TRUE, the CreditCharge field in the SMB2 header MUST be set to ( 1 + (Length – 1) / 65536 ).
The MessageId field in the SMB2 header is set as specified in section 3.2.4.1.3.
If Connection.Dialect is "3.1.1", IsCompressionSupported is TRUE, Connection.CompressionIds is not empty, and the application-supplied CompressWrite or TreeConnect.CompressData is TRUE, the client MUST process the request as specified in section 3.1.4.4.
The request MUST be sent to the server.