summaryrefslogtreecommitdiffstats
path: root/private/ntos/mailslot/writesup.c
blob: 7b94adcd3b789b8959144eee666353ecb5d02a81 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    writesup.c

Abstract:

    This module implements the write support routine.  This is a common
    write function that is called by write and mailslot write.

Author:

    Manny Weiser (mannyw)   16-Jan-1991

Revision History:

--*/

#include "mailslot.h"

//
//  The debug trace level
//

#define Dbg                              (DEBUG_TRACE_WRITESUP)

#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, MsWriteDataQueue )
#endif

BOOLEAN
MsWriteDataQueue (
    IN PDATA_QUEUE WriteQueue,
    IN PUCHAR WriteBuffer,
    IN ULONG WriteLength
    )

/*++

Routine Description:

    This function writes data from the write buffer into read entries in
    the write queue.  It will also dequeue entries in the queue as necessary.

    *** This function must be called from within a try statement.

Arguments:

    WriteQueue - Provides the write queue to process.

    WriteBuffer - Provides the buffer from which to read the data.

    WriteLength  - Provides the length, in bytes, of WriteBuffer.

Return Value:

    BOOLEAN - TRUE if the operation wrote everything and FALSE otherwise.

--*/

{
    BOOLEAN result;

    PDATA_ENTRY dataEntry;
    PLIST_ENTRY listEntry;
    PFCB fcb;

    PUCHAR readBuffer;
    ULONG readLength;
    PIRP readIrp;
    NTSTATUS readStatus = STATUS_UNSUCCESSFUL;

    PWORK_CONTEXT workContext;
    PKTIMER timer;

    PAGED_CODE();
    DebugTrace(+1, Dbg, "MsWriteDataQueue\n", 0);
    DebugTrace( 0, Dbg, "WriteQueue  = %08lx\n", (ULONG)WriteQueue);
    DebugTrace( 0, Dbg, "WriteBuffer = %08lx\n", (ULONG)WriteBuffer);
    DebugTrace( 0, Dbg, "WriteLength = %08lx\n", WriteLength);

    //
    // Now while the write queue has some read entries in it and
    // we have not successfully completed a read then we'll do the
    // following main loop.
    //

    for (listEntry = MsGetNextDataQueueEntry( WriteQueue );

         MsIsDataQueueReaders(WriteQueue) && !NT_SUCCESS(readStatus);

         listEntry = MsGetNextDataQueueEntry( WriteQueue )) {

        dataEntry = CONTAINING_RECORD( listEntry, DATA_ENTRY, ListEntry );
        readBuffer = dataEntry->DataPointer;
        readLength = dataEntry->DataSize;

        DebugTrace(0, Dbg, "Top of write loop...\n", 0);
        DebugTrace(0, Dbg, "ReadBuffer      = %08lx\n", (ULONG)readBuffer);
        DebugTrace(0, Dbg, "ReadLength      = %08lx\n", readLength);

        //
        // We are about to complete a read IRP, so dequeue it.
        //

        readIrp = MsRemoveDataQueueEntry( WriteQueue, dataEntry );
        ASSERT( readIrp != NULL );

        //
        // If the buffer for this read operation is large enough
        // copy the data.
        //

        if ( readLength >= WriteLength ) {

            //
            // Copy the data from the write buffer to the read buffer.
            //

            RtlMoveMemory( readBuffer,
                           WriteBuffer,
                           WriteLength);

            readIrp->IoStatus.Information = WriteLength;
            readStatus = STATUS_SUCCESS;

        } else {

            //
            // This read buffer was overflowed.
            //

            readIrp->IoStatus.Information = 0;
            readStatus = STATUS_BUFFER_TOO_SMALL;

        }

        //
        // Complete the read IRP.
        //

        workContext = dataEntry->TimeoutWorkContext;
        if (workContext != NULL) {

            DebugTrace( 0, Dbg, "Cancelling a timer\n", 0);

            //
            // There was a timer on this read operation.  Attempt
            // to cancel the operation.  If the cancel operation
            // is successful, then we must cleanup after the operation.
            // If it was unsuccessful the timer DPC will run, and
            // will eventually cleanup.
            //

            timer = &workContext->Timer;

            if (KeCancelTimer( timer ) ) {

                //
                // Release the reference to the FCB.
                //

                MsDereferenceFcb( workContext->Fcb );

                //
                // Free the memory from the work context, the timer,
                // and the DPC.
                //

                ExFreePool( workContext );

            }

        }

        //
        // Update the FCB last access time and complete the read request.
        //

        fcb = CONTAINING_RECORD( WriteQueue, FCB, DataQueue );
        if ( NT_SUCCESS( readStatus ) ) {
            KeQuerySystemTime( &fcb->Specific.Fcb.LastAccessTime );
        }

        MsCompleteRequest( readIrp, readStatus );

    }

    DebugTrace(0, Dbg, "Finished loop...\n", 0);

    //
    // At this point we've finished off all of the read entries in the
    // queue and we might not have written the write data.  If that
    // is the case then we'll set our result to FALSE otherwise we're
    // done so we'll return TRUE.
    //

    if ( !NT_SUCCESS( readStatus ) ) {

        ASSERT( !MsIsDataQueueReaders( WriteQueue ));
        result = FALSE;

    } else {

        result = TRUE;
    }

    DebugTrace(-1, Dbg, "MsWriteDataQueue -> %08lx\n", result);
    return result;

}