/// <summary>
        /// Deep copy constructor.
        /// </summary>
        public SmbNtTransactIoctlRequestPacket(SmbNtTransactIoctlRequestPacket packet)
            : base(packet)
        {
            this.InitDefaultValue();

            this.ntTransData.Data = new byte[packet.ntTransData.Data.Length];
            Array.Copy(packet.ntTransData.Data, this.ntTransData.Data, packet.ntTransData.Data.Length);
        }
        /// <summary>
        /// Deep copy constructor.
        /// </summary>
        public SmbNtTransactIoctlRequestPacket(SmbNtTransactIoctlRequestPacket packet)
            : base(packet)
        {
            this.InitDefaultValue();

            this.ntTransData.Data = new byte[packet.ntTransData.Data.Length];
            Array.Copy(packet.ntTransData.Data, this.ntTransData.Data, packet.ntTransData.Data.Length);
        }
        /// <summary>
        /// FSCTL Bad command request.
        /// </summary>
        /// <param name="messageId">This is used to associate a response with a request.</param>
        /// <param name="sessionId">The current session ID for this connection.</param>
        /// <param name="treeId">The tree ID for the corrent share connection.</param>
        /// <param name="isSigned">Indicate whether the message is signed or not for this response.</param>
        /// <param name="fid">The file identifier.</param>
        /// <param name="command">This is used to tell the adapter to send an invalid kind of command.</param>
        public void FsctlBadCommandRequest(
            int messageId,
            int sessionId,
            int treeId,
            bool isSigned,
            int fid,
            FsctlInvalidCommand command)
        {
            #region Create Packet

            NamespaceCifs.SmbNtTransactIoctlRequestPacket smbPacket = new NamespaceCifs.SmbNtTransactIoctlRequestPacket();

            ushort uid = (ushort)this.uId[(uint)sessionId];
            uint functionCode = (uint)command;
            byte[] data = new byte[DataCount];

            smbPacket = this.smbClientStack.CreateNTTransIOCtlRequest(
                (ushort)this.fId[(uint)fid],
                true,
                byte.MinValue,
                functionCode,
                data);

            if (isSigned)
            {
                NamespaceCifs.CifsClientPerConnection connection =
                    this.smbClientStack.Context.GetConnection(ConnectionId);

                NamespaceCifs.CifsClientPerSession session = this.smbClientStack.Context.GetSession(ConnectionId, uid);

                smbPacket.Sign(connection.ClientNextSendSequenceNumber, session.SessionKey);
            }

            #endregion

            #region Send and Receive ExpectPacket

            this.smbClientStack.SendPacket(smbPacket);
            StackPacket response = this.smbClientStack.ExpectPacket(this.timeout);

            NamespaceCifs.SmbPacket smbPacketResponse = (NamespaceCifs.SmbPacket)response;

            this.QueryUidTable(smbPacketResponse);
            this.QueryTidTable(smbPacketResponse);

            VerifyTransport(smbPacketResponse);
            VerifyCommonMessageSyntax(smbPacketResponse);

            SmbErrorResponsePacket smbErrorResponsePacket = response as SmbErrorResponsePacket;
            NamespaceCifs.SmbHeader smbErrorHeader = smbErrorResponsePacket.SmbHeader;
            this.ErrorResponse(smbErrorHeader.Mid + this.addMidMark, (MessageStatus)smbErrorHeader.Status);

            #endregion
        }
        public void FSCCFSCTLNameRequest(int messageId,
            int sessionId,
            int treeId,
            bool isSigned,
            int fid,
            FSCCFSCTLName fsctlName)
        {
            #region Create Packet

            NamespaceCifs.SmbNtTransactIoctlRequestPacket smbPacket = new NamespaceCifs.SmbNtTransactIoctlRequestPacket();

            ushort uid = (ushort)this.uId[(uint)sessionId];
            uint functionCode = (uint)fsctlName;
            byte[] data = new byte[DataCount];
            this.fsccFSCTLName = fsctlName.ToString();

            smbPacket = this.smbClientStack.CreateNTTransIOCtlRequest(
                (ushort)this.fId[(uint)fid],
                true,
                byte.MinValue,
                functionCode,
                data);

            if (isSigned)
            {
                NamespaceCifs.CifsClientPerConnection connection =
                    this.smbClientStack.Context.GetConnection(ConnectionId);

                NamespaceCifs.CifsClientPerSession session = this.smbClientStack.Context.GetSession(ConnectionId, uid);

                smbPacket.Sign(connection.ClientNextSendSequenceNumber, session.SessionKey);
            }

            #endregion

            #region Send and Receive ExpectPacket

            this.smbClientStack.SendPacket(smbPacket);
            StackPacket response = this.smbClientStack.ExpectPacket(this.timeout);

            NamespaceCifs.SmbPacket smbPacketResponse = (NamespaceCifs.SmbPacket)response;

            this.QueryUidTable(smbPacketResponse);
            this.QueryTidTable(smbPacketResponse);

            VerifyTransport(smbPacketResponse);
            VerifyCommonMessageSyntax(smbPacketResponse);

            if (response.GetType() == typeof(SmbErrorResponsePacket))
            {
                SmbErrorResponsePacket smbErrorResponsePacket = response as SmbErrorResponsePacket;
                NamespaceCifs.SmbHeader smbErrorHeader = smbErrorResponsePacket.SmbHeader;
                this.ErrorResponse(
                    smbErrorHeader.Mid + this.addMidMark,
                    (MessageStatus)smbErrorHeader.Status);
            }
            else
            {
                NamespaceCifs.SmbNtTransactIoctlResponsePacket smbNtTransactIoctlResponsePacket
                    = response as SmbNtTransactIoctlResponsePacket;

                NamespaceCifs.SmbHeader ntTransactIoctlResponseHeader = smbNtTransactIoctlResponsePacket.SmbHeader;

                VerifyMessageSyntaxFsctlNameResponse(smbNtTransactIoctlResponsePacket);

                this.FSCCFSCTLNameResponse(
                    ntTransactIoctlResponseHeader.Mid + this.addMidMark,
                    this.QueryUidTable(smbPacketResponse),
                    this.QueryTidTable(smbPacketResponse),
                    (smbPacketResponse).IsSignRequired,
                    (MessageStatus)ntTransactIoctlResponseHeader.Status);
            }

            #endregion
        }
        /// <summary>
        /// Expect a request. If user is not interested in the packet, please call DefaultSendResponse().
        /// </summary>
        /// <param name="timeout">timeout</param>
        /// <param name="connection">the connection between server and client</param>
        /// <param name="session">the session between server and client</param>
        /// <param name="treeConnect">the tree connect between server and client</param>
        /// <param name="open">the file open between server and client</param>
        /// <param name="requestPacket">the request</param>
        public override void ExpectRequest(
            TimeSpan timeout,
            out IFileServiceServerConnection connection,
            out IFileServiceServerSession session,
            out IFileServiceServerTreeConnect treeConnect,
            out IFileServiceServerOpen open,
            out SmbFamilyPacket requestPacket)
        {
            CifsServerPerConnection cifsConnection;
            SmbPacket request = this.cifsServer.ExpectPacket(timeout, out cifsConnection);

            connection    = cifsConnection;
            requestPacket = request;
            session       = null;
            treeConnect   = null;
            open          = null;

            if (request != null)
            {
                session = cifsConnection.GetSession(request.SmbHeader.Uid);
                if (session != null)
                {
                    treeConnect = (session as CifsServerPerSession).GetTreeConnect(request.SmbHeader.Tid);
                    if (treeConnect != null)
                    {
                        ushort fid = 0;
                        SmbTransactionRequestPacket            transactionRequest = request as SmbTransactionRequestPacket;
                        SmbNtTransactIoctlRequestPacket        ioctlRequest       = request as SmbNtTransactIoctlRequestPacket;
                        SmbNtTransactNotifyChangeRequestPacket notifyChange       = request as SmbNtTransactNotifyChangeRequestPacket;

                        if (transactionRequest != null)
                        {
                            //SubCommand(2bytes), FID(2bytes)
                            fid = transactionRequest.SmbParameters.Setup[1];
                        }

                        else if (ioctlRequest != null)
                        {
                            //FunctionCode(4bytes), FID(2bytes), IsFctl(1bytes), IsFlags(1bytes)
                            fid = ioctlRequest.SmbParameters.Setup[2];
                        }
                        else if (notifyChange != null)
                        {
                            //CompletionFilter(4bytes), FID(2bytes), WatchTree(1bytes), Reserved(1bytes)
                            fid = notifyChange.SmbParameters.Setup[2];
                        }
                        else
                        {
                            Type         packetType = request.GetType();
                            PropertyInfo pi         = packetType.GetProperty(
                                "Trans2Parameters", BindingFlags.Instance | BindingFlags.Public);

                            if (pi == null)
                            {
                                pi = packetType.GetProperty(
                                    "NtTransParameters", BindingFlags.Instance | BindingFlags.Public);
                            }
                            if (pi == null)
                            {
                                pi = packetType.GetProperty(
                                    "SmbParameters", BindingFlags.Instance | BindingFlags.Public);
                            }
                            if (pi != null)
                            {
                                object    smbParameters = pi.GetValue(request, null);
                                FieldInfo fi            = smbParameters.GetType().GetField(
                                    "FID",
                                    BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
                                if (fi != null)
                                {
                                    fid = (ushort)fi.GetValue(smbParameters);
                                }
                            }
                        }

                        if (fid > 0)
                        {
                            open = (treeConnect as CifsServerPerTreeConnect).GetOpen(fid);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// find the nt transaction packets
        /// </summary>
        /// <param name="command">the command of nt transaction</param>
        /// <param name="setup">the setup contains the sub command</param>
        /// <returns>the target nt transaction packet</returns>
        private static SmbPacket FindTheNtTransPacket(NtTransSubCommand command, byte[] setup)
        {
            SmbPacket smbPacket = null;
            switch (command)
            {
                case NtTransSubCommand.NT_TRANSACT_CREATE:
                    smbPacket = new SmbNtTransactCreateRequestPacket();
                    break;

                case NtTransSubCommand.NT_TRANSACT_RENAME:
                    smbPacket = new SmbNtTransRenameRequestPacket();
                    break;

                case NtTransSubCommand.NT_TRANSACT_IOCTL:
                    NT_TRANSACT_IOCTL_SETUP subCommand = CifsMessageUtils.ToStuct<NT_TRANSACT_IOCTL_SETUP>(setup);
                    switch ((NtTransFunctionCode)subCommand.FunctionCode)
                    {
                        case NtTransFunctionCode.FSCTL_SRV_ENUMERATE_SNAPSHOTS:
                            smbPacket = new SmbNtTransFsctlSrvEnumerateSnapshotsRequestPacket();
                            break;

                        case NtTransFunctionCode.FSCTL_SRV_REQUEST_RESUME_KEY:
                            smbPacket = new SmbNtTransFsctlSrvRequestResumeKeyRequestPacket();
                            break;

                        case NtTransFunctionCode.FSCTL_SRV_COPYCHUNK:
                            smbPacket = new SmbNtTransFsctlSrvCopyChunkRequestPacket();
                            break;

                        default:
                            smbPacket = new SmbNtTransactIoctlRequestPacket();
                            break;
                    }
                    break;

                default:
                    switch ((SmbNtTransSubCommand)command)
                    {
                        case SmbNtTransSubCommand.NT_TRANSACT_QUERY_QUOTA:
                            smbPacket = new SmbNtTransQueryQuotaRequestPacket();
                            break;

                        case SmbNtTransSubCommand.NT_TRANSACT_SET_QUOTA:
                            smbPacket = new SmbNtTransSetQuotaRequestPacket();
                            break;
                    }
                    break;
            }

            return smbPacket;
        }
        /// <summary>
        /// to create a NtTransactIoctl request packet.
        /// </summary>
        /// <param name="messageId">This field SHOULD be the multiplex ID that is used to associate a response with a
        /// request.</param>
        /// <param name="uid">This field SHOULD identify the authenticated instance of the user.</param>
        /// <param name="treeId">This field identifies the subdirectory (or tree) on the server that the client is
        /// accessing.</param>
        /// <param name="flags">An 8-bit field of 1-bit flags describing various features in effect for the
        /// message</param>
        /// <param name="flags2">A 16-bit field of 1-bit flags that represent various features in effect for the
        /// message. Unspecified bits are reserved and MUST be zero.</param>
        /// <param name="maxParameterCount">The maximum number of parameter bytes that the client will accept in the
        /// transaction reply. The server MUST NOT return more than this number of parameter bytes.</param>
        /// <param name="maxDataCount">The maximum number of data bytes that the client will accept in the transaction
        /// reply. The server MUST NOT return more than this number of data bytes.</param>
        /// <param name="maxSetupCount">Maximum number of setup bytes that the client will accept in the transaction
        /// reply. The server MUST NOT return more than this number of setup bytes</param>
        /// <param name="functionCode">Windows NT device or file system control code</param>
        /// <param name="fid">MUST contain a valid FID obtained from a previously successful SMB open command.</param>
        /// <param name="isFctl">This field is TRUE if the command is a file system control command and the FID is a
        /// file system control device. Otherwise, the command is a device control command and FID is an I/O
        /// device.</param>
        /// <param name="isFlags">If bit 0 is set, the command is to be applied to a share root handle. The share MUST
        /// be a Distributed File System (DFS) type</param>
        /// <param name="data">The raw bytes that are passed to the fsctl or ioctl function as the input
        /// buffer.</param>
        /// <returns>a NtTransactIoctl request packet</returns>
        public SmbNtTransactIoctlRequestPacket CreateNtTransactIoctlRequest(
            ushort messageId,
            ushort uid,
            ushort treeId,
            SmbFlags flags,
            SmbFlags2 flags2,
            byte maxSetupCount,
            uint maxParameterCount,
            uint maxDataCount,
            uint functionCode,
            ushort fid,
            bool isFctl,
            byte isFlags,
            byte[] data)
        {
            if (data == null)
            {
                data = new byte[0];
            }

            SmbNtTransactIoctlRequestPacket packet = new SmbNtTransactIoctlRequestPacket();
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(SmbCommand.SMB_COM_NT_TRANSACT,
                messageId, uid, treeId, flags, flags2);

            // Set Smb_Parameters
            SMB_COM_NT_TRANSACT_Request_SMB_Parameters smbParameters =
                new SMB_COM_NT_TRANSACT_Request_SMB_Parameters();
            smbParameters.MaxSetupCount = maxSetupCount;
            smbParameters.MaxParameterCount = maxParameterCount;
            smbParameters.MaxDataCount = maxDataCount;
            smbParameters.SetupCount = 4; // the cout of Setup is 4.
            smbParameters.Function = NtTransSubCommand.NT_TRANSACT_IOCTL;

            NT_TRANSACT_IOCTL_SETUP setupStruct = new NT_TRANSACT_IOCTL_SETUP();
            setupStruct.FunctionCode = functionCode;
            setupStruct.FID = fid;
            setupStruct.IsFctl = (byte)(isFctl ? 1 : 0);
            setupStruct.IsFlags = isFlags;
            smbParameters.Setup = CifsMessageUtils.ToTypeArray<ushort>(CifsMessageUtils.ToBytes<NT_TRANSACT_IOCTL_SETUP
                >(setupStruct));
            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_NT_TRANSACT_Request_SMB_Parameters>(
                smbParameters) / NumBytesOfWord);

            // Set Smb_Data
            SMB_COM_NT_TRANSACT_Request_SMB_Data smbData = new SMB_COM_NT_TRANSACT_Request_SMB_Data();

            // Set NT_TransData
            NT_TRANSACT_IOCTL_Request_NT_Trans_Data ntTransData = new NT_TRANSACT_IOCTL_Request_NT_Trans_Data();
            ntTransData.Data = data;

            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;
            packet.NtTransData = ntTransData;
            packet.UpdateCountAndOffset();

            return packet;
        }
        public SmbNtTransactIoctlResponsePacket CreateNtTransactIoctlResponse(
            CifsServerPerConnection connection,
            SmbNtTransactIoctlRequestPacket request,
            byte[] data)
        {
            data = data ?? new byte[0];
            SmbNtTransactIoctlResponsePacket response = new SmbNtTransactIoctlResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            NT_TRANSACT_IOCTL_Response_NT_Trans_Data ntTransData = response.NtTransData;
            ntTransData.Data = data;
            response.NtTransData = ntTransData;

            response.UpdateCountAndOffset();

            return response;
        }