- Fixed various problems (hangs/crashes) with connecting, disconnecting and closing...
[reactos.git] / reactos / drivers / fs / np / rw.c
1 /* $Id: rw.c,v 1.13 2004/05/05 18:30:16 navaraf Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/fs/np/rw.c
6 * PURPOSE: Named pipe filesystem
7 * PROGRAMMER: David Welch <welch@cwcom.net>
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ddk/ntddk.h>
13 #include <rosrtl/minmax.h>
14 #include "npfs.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* FUNCTIONS *****************************************************************/
20
21 NTSTATUS STDCALL
22 NpfsRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
23 {
24 PIO_STACK_LOCATION IoStack;
25 PFILE_OBJECT FileObject;
26 NTSTATUS Status;
27 PNPFS_DEVICE_EXTENSION DeviceExt;
28 KIRQL OldIrql;
29 ULONG Information;
30 PNPFS_FCB Fcb;
31 PNPFS_FCB ReadFcb;
32 PNPFS_PIPE Pipe;
33 ULONG Length;
34 PVOID Buffer;
35 ULONG CopyLength;
36 ULONG TempLength;
37
38 DPRINT("NpfsRead(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
39
40 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
41 IoStack = IoGetCurrentIrpStackLocation(Irp);
42 FileObject = IoStack->FileObject;
43 Fcb = FileObject->FsContext;
44 Pipe = Fcb->Pipe;
45 ReadFcb = Fcb->OtherSide;
46
47 if (ReadFcb == NULL)
48 {
49 DPRINT("Pipe is NOT connected!\n");
50 if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
51 Status = STATUS_PIPE_LISTENING;
52 else if (Fcb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
53 Status = STATUS_PIPE_DISCONNECTED;
54 else
55 Status = STATUS_UNSUCCESSFUL;
56 Information = 0;
57 goto done;
58 }
59
60 if (Irp->MdlAddress == NULL)
61 {
62 DPRINT("Irp->MdlAddress == NULL\n");
63 Status = STATUS_UNSUCCESSFUL;
64 Information = 0;
65 goto done;
66 }
67
68 if (ReadFcb->Data == NULL)
69 {
70 DPRINT("Pipe is NOT readable!\n");
71 Status = STATUS_UNSUCCESSFUL;
72 Information = 0;
73 goto done;
74 }
75
76
77 Status = STATUS_SUCCESS;
78 Length = IoStack->Parameters.Read.Length;
79 Information = 0;
80
81 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
82 KeAcquireSpinLock(&ReadFcb->DataListLock, &OldIrql);
83 while (1)
84 {
85 /* FIXME: check if in blocking mode */
86 if (ReadFcb->ReadDataAvailable == 0)
87 {
88 KeResetEvent(&Fcb->Event);
89 KeSetEvent(&ReadFcb->Event, IO_NO_INCREMENT, FALSE);
90 KeReleaseSpinLock(&ReadFcb->DataListLock, OldIrql);
91 if (Information > 0)
92 {
93 Status = STATUS_SUCCESS;
94 goto done;
95 }
96 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
97 {
98 DPRINT("PipeState: %x\n", Fcb->PipeState);
99 Status = STATUS_PIPE_BROKEN;
100 goto done;
101 }
102 /* Wait for ReadEvent to become signaled */
103 DPRINT("Waiting for readable data (%S)\n", Pipe->PipeName.Buffer);
104 Status = KeWaitForSingleObject(&Fcb->Event,
105 UserRequest,
106 KernelMode,
107 FALSE,
108 NULL);
109 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe->PipeName.Buffer, Status);
110 KeAcquireSpinLock(&ReadFcb->DataListLock, &OldIrql);
111 }
112
113 if (Pipe->PipeReadMode == FILE_PIPE_BYTE_STREAM_MODE)
114 {
115 DPRINT("Byte stream mode\n");
116 /* Byte stream mode */
117 while (Length > 0 && ReadFcb->ReadDataAvailable > 0)
118 {
119 CopyLength = RtlRosMin(ReadFcb->ReadDataAvailable, Length);
120 if (ReadFcb->ReadPtr + CopyLength <= ReadFcb->Data + ReadFcb->MaxDataLength)
121 {
122 memcpy(Buffer, ReadFcb->ReadPtr, CopyLength);
123 ReadFcb->ReadPtr += CopyLength;
124 if (ReadFcb->ReadPtr == ReadFcb->Data + ReadFcb->MaxDataLength)
125 {
126 ReadFcb->ReadPtr = ReadFcb->Data;
127 }
128 }
129 else
130 {
131 TempLength = ReadFcb->Data + ReadFcb->MaxDataLength - ReadFcb->ReadPtr;
132 memcpy(Buffer, ReadFcb->ReadPtr, TempLength);
133 memcpy(Buffer + TempLength, ReadFcb->Data, CopyLength - TempLength);
134 ReadFcb->ReadPtr = ReadFcb->Data + CopyLength - TempLength;
135 }
136
137 Buffer += CopyLength;
138 Length -= CopyLength;
139 Information += CopyLength;
140
141 ReadFcb->ReadDataAvailable -= CopyLength;
142 ReadFcb->WriteQuotaAvailable += CopyLength;
143 }
144
145 if (Length == 0)
146 {
147 KeSetEvent(&ReadFcb->Event, IO_NO_INCREMENT, FALSE);
148 break;
149 }
150 }
151 else
152 {
153 DPRINT("Message mode\n");
154
155 /* Message mode */
156 if (ReadFcb->ReadDataAvailable)
157 {
158 /* Truncate the message if the receive buffer is too small */
159 CopyLength = RtlRosMin(ReadFcb->ReadDataAvailable, Length);
160 memcpy(Buffer, ReadFcb->Data, CopyLength);
161
162 #ifndef NDEBUG
163 DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
164 {
165 DbgPrint("------\n");
166 ULONG X;
167 for (X = 0; X < CopyLength; X++)
168 DbgPrint("%02x ", ((PUCHAR)Buffer)[X]);
169 DbgPrint("\n");
170 DbgPrint("------\n");
171 }
172 #endif
173
174 Information = CopyLength;
175 ReadFcb->ReadDataAvailable = 0;
176 ReadFcb->WriteQuotaAvailable = ReadFcb->MaxDataLength;
177 }
178 if (Information > 0)
179 {
180 KeSetEvent(&ReadFcb->Event, IO_NO_INCREMENT, FALSE);
181 break;
182 }
183 }
184 }
185 KeReleaseSpinLock(&ReadFcb->DataListLock, OldIrql);
186
187 done:
188 Irp->IoStatus.Status = Status;
189 Irp->IoStatus.Information = Information;
190
191 IoCompleteRequest(Irp, IO_NO_INCREMENT);
192
193 return(Status);
194 }
195
196
197 NTSTATUS STDCALL
198 NpfsWrite(PDEVICE_OBJECT DeviceObject,
199 PIRP Irp)
200 {
201 PIO_STACK_LOCATION IoStack;
202 PFILE_OBJECT FileObject;
203 PNPFS_FCB Fcb = NULL;
204 PNPFS_PIPE Pipe = NULL;
205 PUCHAR Buffer;
206 NTSTATUS Status = STATUS_SUCCESS;
207 ULONG Length;
208 ULONG Offset;
209 KIRQL OldIrql;
210 ULONG Information;
211 ULONG CopyLength;
212 ULONG TempLength;
213
214 DPRINT("NpfsWrite()\n");
215
216 IoStack = IoGetCurrentIrpStackLocation(Irp);
217 FileObject = IoStack->FileObject;
218 DPRINT("FileObject %p\n", FileObject);
219 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
220
221 Fcb = FileObject->FsContext;
222 Pipe = Fcb->Pipe;
223
224 Length = IoStack->Parameters.Write.Length;
225 Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
226 Information = 0;
227
228 if (Irp->MdlAddress == NULL)
229 {
230 DPRINT("Irp->MdlAddress == NULL\n");
231 Status = STATUS_UNSUCCESSFUL;
232 Length = 0;
233 goto done;
234 }
235
236 if (Fcb->OtherSide == NULL)
237 {
238 DPRINT("Pipe is NOT connected!\n");
239 if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
240 Status = STATUS_PIPE_LISTENING;
241 else if (Fcb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
242 Status = STATUS_PIPE_DISCONNECTED;
243 else
244 Status = STATUS_UNSUCCESSFUL;
245 Length = 0;
246 goto done;
247 }
248
249 if (Fcb->Data == NULL)
250 {
251 DPRINT("Pipe is NOT writable!\n");
252 Status = STATUS_UNSUCCESSFUL;
253 Length = 0;
254 goto done;
255 }
256
257 Status = STATUS_SUCCESS;
258 Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
259 #ifndef NDEBUG
260 DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
261 {
262 DbgPrint("------\n");
263 ULONG X;
264 for (X = 0; X < Length; X++)
265 DbgPrint("%02x ", Buffer[X]);
266 DbgPrint("\n");
267 DbgPrint("------\n");
268 }
269 #endif
270
271 KeAcquireSpinLock(&Fcb->DataListLock, &OldIrql);
272 while(1)
273 {
274 if (Fcb->WriteQuotaAvailable == 0)
275 {
276 KeResetEvent(&Fcb->Event);
277 KeSetEvent(&Fcb->OtherSide->Event, IO_NO_INCREMENT, FALSE);
278 KeReleaseSpinLock(&Fcb->DataListLock, OldIrql);
279 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
280 {
281 Status = STATUS_PIPE_BROKEN;
282 goto done;
283 }
284 DPRINT("Waiting for buffer space (%S)\n", Pipe->PipeName.Buffer);
285 Status = KeWaitForSingleObject(&Fcb->Event,
286 UserRequest,
287 KernelMode,
288 FALSE,
289 NULL);
290 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe->PipeName.Buffer, Status);
291 KeAcquireSpinLock(&Fcb->DataListLock, &OldIrql);
292 }
293 if (Pipe->PipeWriteMode == FILE_PIPE_BYTE_STREAM_MODE)
294 {
295 DPRINT("Byte stream mode\n");
296 while (Length > 0 && Fcb->WriteQuotaAvailable > 0)
297 {
298 CopyLength = RtlRosMin(Length, Fcb->WriteQuotaAvailable);
299 if (Fcb->WritePtr + CopyLength <= Fcb->Data + Fcb->MaxDataLength)
300 {
301 memcpy(Fcb->WritePtr, Buffer, CopyLength);
302 Fcb->WritePtr += CopyLength;
303 if (Fcb->WritePtr == Fcb->Data + Fcb->MaxDataLength)
304 {
305 Fcb->WritePtr = Fcb->Data;
306 }
307 }
308 else
309 {
310 TempLength = Fcb->Data + Fcb->MaxDataLength - Fcb->WritePtr;
311 memcpy(Fcb->WritePtr, Buffer, TempLength);
312 memcpy(Fcb->Data, Buffer + TempLength, CopyLength - TempLength);
313 Fcb->WritePtr = Fcb->Data + CopyLength - TempLength;
314 }
315
316 Buffer += CopyLength;
317 Length -= CopyLength;
318 Information += CopyLength;
319
320 Fcb->ReadDataAvailable += CopyLength;
321 Fcb->WriteQuotaAvailable -= CopyLength;
322 }
323
324 if (Length == 0)
325 {
326 KeSetEvent(&Fcb->OtherSide->Event, IO_NO_INCREMENT, FALSE);
327 break;
328 }
329 }
330 else
331 {
332 if (Length > 0)
333 {
334 CopyLength = RtlRosMin(Length, Fcb->WriteQuotaAvailable);
335 memcpy(Fcb->Data, Buffer, CopyLength);
336
337 Information = CopyLength;
338 Fcb->ReadDataAvailable = CopyLength;
339 Fcb->WriteQuotaAvailable = 0;
340 }
341 if (Information > 0)
342 {
343 KeSetEvent(&Fcb->OtherSide->Event, IO_NO_INCREMENT, FALSE);
344 break;
345 }
346 }
347 }
348 KeReleaseSpinLock(&Fcb->DataListLock, OldIrql);
349
350 done:
351 Irp->IoStatus.Status = Status;
352 Irp->IoStatus.Information = Information;
353
354 IoCompleteRequest(Irp, IO_NO_INCREMENT);
355
356 return(Status);
357 }
358
359 /* EOF */