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>
10 /* INCLUDES ******************************************************************/
12 #include <ddk/ntddk.h>
13 #include <rosrtl/minmax.h>
19 #define FIN_WORKAROUND_READCLOSE
21 /* FUNCTIONS *****************************************************************/
24 VOID
HexDump(PUCHAR Buffer
, ULONG Length
)
28 const char Hex
[] = "0123456789ABCDEF";
31 DbgPrint("---------------\n");
33 for (i
= 0; i
< ROUND_UP(Length
, 16); i
+= 16)
35 memset(Line
, ' ', 64);
38 for (j
= 0; j
< 16 && j
+ i
< Length
; j
++)
41 Line
[3*j
+ 0] = Hex
[ch
>> 4];
42 Line
[3*j
+ 1] = Hex
[ch
& 0x0f];
43 Line
[48 + j
] = isprint(ch
) ? ch
: '.';
45 DbgPrint("%s\n", Line
);
47 DbgPrint("---------------\n");
53 NpfsRead(PDEVICE_OBJECT DeviceObject
,
56 PIO_STACK_LOCATION IoStack
;
57 PFILE_OBJECT FileObject
;
59 PNPFS_DEVICE_EXTENSION DeviceExt
;
70 DPRINT("NpfsRead(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
72 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
73 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
74 FileObject
= IoStack
->FileObject
;
75 Fcb
= FileObject
->FsContext
;
77 ReadFcb
= Fcb
->OtherSide
;
81 DPRINT("Pipe is NOT connected!\n");
82 if (Fcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
83 Status
= STATUS_PIPE_LISTENING
;
84 else if (Fcb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
85 Status
= STATUS_PIPE_DISCONNECTED
;
87 Status
= STATUS_PIPE_BROKEN
;
89 DPRINT("%x\n", Status
);
93 if (Irp
->MdlAddress
== NULL
)
95 DPRINT("Irp->MdlAddress == NULL\n");
96 Status
= STATUS_UNSUCCESSFUL
;
101 if (ReadFcb
->Data
== NULL
)
103 DPRINT("Pipe is NOT readable!\n");
104 Status
= STATUS_UNSUCCESSFUL
;
109 #ifdef FIN_WORKAROUND_READCLOSE
110 if (ReadFcb
->ReadDataAvailable
== 0 &&
111 ReadFcb
->PipeState
== FILE_PIPE_CLOSING_STATE
)
113 DPRINT("Other end of pipe is closed!\n");
114 Status
= STATUS_PIPE_BROKEN
;
120 Status
= STATUS_SUCCESS
;
121 Length
= IoStack
->Parameters
.Read
.Length
;
124 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
125 KeAcquireSpinLock(&ReadFcb
->DataListLock
, &OldIrql
);
128 /* FIXME: check if in blocking mode */
129 if (ReadFcb
->ReadDataAvailable
== 0)
131 KeResetEvent(&Fcb
->Event
);
132 KeSetEvent(&ReadFcb
->Event
, IO_NO_INCREMENT
, FALSE
);
133 KeReleaseSpinLock(&ReadFcb
->DataListLock
, OldIrql
);
136 Status
= STATUS_SUCCESS
;
140 if (Fcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
142 DPRINT("PipeState: %x\n", Fcb
->PipeState
);
143 Status
= STATUS_PIPE_BROKEN
;
147 /* Wait for ReadEvent to become signaled */
148 DPRINT("Waiting for readable data (%S)\n", Pipe
->PipeName
.Buffer
);
149 Status
= KeWaitForSingleObject(&Fcb
->Event
,
154 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe
->PipeName
.Buffer
, Status
);
156 #ifndef FIN_WORKAROUND_READCLOSE
158 * It's possible that the event was signaled because the
159 * other side of pipe was closed.
161 if (Fcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
163 DPRINT("PipeState: %x\n", Fcb
->PipeState
);
164 Status
= STATUS_PIPE_BROKEN
;
168 KeAcquireSpinLock(&ReadFcb
->DataListLock
, &OldIrql
);
171 if (Pipe
->PipeReadMode
== FILE_PIPE_BYTE_STREAM_MODE
)
173 DPRINT("Byte stream mode\n");
174 /* Byte stream mode */
175 while (Length
> 0 && ReadFcb
->ReadDataAvailable
> 0)
177 CopyLength
= RtlRosMin(ReadFcb
->ReadDataAvailable
, Length
);
178 if (ReadFcb
->ReadPtr
+ CopyLength
<= ReadFcb
->Data
+ ReadFcb
->MaxDataLength
)
180 memcpy(Buffer
, ReadFcb
->ReadPtr
, CopyLength
);
181 ReadFcb
->ReadPtr
+= CopyLength
;
182 if (ReadFcb
->ReadPtr
== ReadFcb
->Data
+ ReadFcb
->MaxDataLength
)
184 ReadFcb
->ReadPtr
= ReadFcb
->Data
;
189 TempLength
= ReadFcb
->Data
+ ReadFcb
->MaxDataLength
- ReadFcb
->ReadPtr
;
190 memcpy(Buffer
, ReadFcb
->ReadPtr
, TempLength
);
191 memcpy(Buffer
+ TempLength
, ReadFcb
->Data
, CopyLength
- TempLength
);
192 ReadFcb
->ReadPtr
= ReadFcb
->Data
+ CopyLength
- TempLength
;
195 Buffer
+= CopyLength
;
196 Length
-= CopyLength
;
197 Information
+= CopyLength
;
199 ReadFcb
->ReadDataAvailable
-= CopyLength
;
200 ReadFcb
->WriteQuotaAvailable
+= CopyLength
;
205 KeSetEvent(&ReadFcb
->Event
, IO_NO_INCREMENT
, FALSE
);
211 DPRINT("Message mode\n");
214 if (ReadFcb
->ReadDataAvailable
)
216 /* Truncate the message if the receive buffer is too small */
217 CopyLength
= RtlRosMin(ReadFcb
->ReadDataAvailable
, Length
);
218 memcpy(Buffer
, ReadFcb
->Data
, CopyLength
);
221 DPRINT("Length %d Buffer %x\n",CopyLength
,Buffer
);
222 HexDump((PUCHAR
)Buffer
, CopyLength
);
225 Information
= CopyLength
;
226 ReadFcb
->ReadDataAvailable
= 0;
227 ReadFcb
->WriteQuotaAvailable
= ReadFcb
->MaxDataLength
;
232 KeSetEvent(&ReadFcb
->Event
, IO_NO_INCREMENT
, FALSE
);
237 #ifdef FIN_WORKAROUND_READCLOSE
238 if (ReadFcb
->ReadDataAvailable
== 0 &&
239 ReadFcb
->PipeState
== FILE_PIPE_CLOSING_STATE
)
241 DPRINT("Other end of pipe is closed!\n");
247 KeReleaseSpinLock(&ReadFcb
->DataListLock
, OldIrql
);
250 Irp
->IoStatus
.Status
= Status
;
251 Irp
->IoStatus
.Information
= Information
;
253 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
255 DPRINT("NpfsRead done (Status %lx)\n", Status
);
262 NpfsWrite(PDEVICE_OBJECT DeviceObject
,
265 PIO_STACK_LOCATION IoStack
;
266 PFILE_OBJECT FileObject
;
267 PNPFS_FCB Fcb
= NULL
;
268 PNPFS_PIPE Pipe
= NULL
;
270 NTSTATUS Status
= STATUS_SUCCESS
;
278 DPRINT("NpfsWrite()\n");
280 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
281 FileObject
= IoStack
->FileObject
;
282 DPRINT("FileObject %p\n", FileObject
);
283 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
285 Fcb
= FileObject
->FsContext
;
288 Length
= IoStack
->Parameters
.Write
.Length
;
289 Offset
= IoStack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
292 if (Irp
->MdlAddress
== NULL
)
294 DPRINT("Irp->MdlAddress == NULL\n");
295 Status
= STATUS_UNSUCCESSFUL
;
300 if (Fcb
->OtherSide
== NULL
)
302 DPRINT("Pipe is NOT connected!\n");
303 if (Fcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
304 Status
= STATUS_PIPE_LISTENING
;
305 else if (Fcb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
306 Status
= STATUS_PIPE_DISCONNECTED
;
308 Status
= STATUS_UNSUCCESSFUL
;
313 if (Fcb
->Data
== NULL
)
315 DPRINT("Pipe is NOT writable!\n");
316 Status
= STATUS_UNSUCCESSFUL
;
321 Status
= STATUS_SUCCESS
;
322 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
324 KeAcquireSpinLock(&Fcb
->DataListLock
, &OldIrql
);
326 DPRINT("Length %d Buffer %x Offset %x\n",Length
,Buffer
,Offset
);
327 HexDump(Buffer
, Length
);
332 if (Fcb
->WriteQuotaAvailable
== 0)
334 KeResetEvent(&Fcb
->Event
);
335 KeSetEvent(&Fcb
->OtherSide
->Event
, IO_NO_INCREMENT
, FALSE
);
336 KeReleaseSpinLock(&Fcb
->DataListLock
, OldIrql
);
337 if (Fcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
339 Status
= STATUS_PIPE_BROKEN
;
343 DPRINT("Waiting for buffer space (%S)\n", Pipe
->PipeName
.Buffer
);
344 Status
= KeWaitForSingleObject(&Fcb
->Event
,
349 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe
->PipeName
.Buffer
, Status
);
351 #ifndef FIN_WORKAROUND_READCLOSE
353 * It's possible that the event was signaled because the
354 * other side of pipe was closed.
356 if (Fcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
358 DPRINT("PipeState: %x\n", Fcb
->PipeState
);
359 Status
= STATUS_PIPE_BROKEN
;
363 KeAcquireSpinLock(&Fcb
->DataListLock
, &OldIrql
);
366 if (Pipe
->PipeWriteMode
== FILE_PIPE_BYTE_STREAM_MODE
)
368 DPRINT("Byte stream mode\n");
369 while (Length
> 0 && Fcb
->WriteQuotaAvailable
> 0)
371 CopyLength
= RtlRosMin(Length
, Fcb
->WriteQuotaAvailable
);
372 if (Fcb
->WritePtr
+ CopyLength
<= Fcb
->Data
+ Fcb
->MaxDataLength
)
374 memcpy(Fcb
->WritePtr
, Buffer
, CopyLength
);
375 Fcb
->WritePtr
+= CopyLength
;
376 if (Fcb
->WritePtr
== Fcb
->Data
+ Fcb
->MaxDataLength
)
378 Fcb
->WritePtr
= Fcb
->Data
;
383 TempLength
= Fcb
->Data
+ Fcb
->MaxDataLength
- Fcb
->WritePtr
;
384 memcpy(Fcb
->WritePtr
, Buffer
, TempLength
);
385 memcpy(Fcb
->Data
, Buffer
+ TempLength
, CopyLength
- TempLength
);
386 Fcb
->WritePtr
= Fcb
->Data
+ CopyLength
- TempLength
;
389 Buffer
+= CopyLength
;
390 Length
-= CopyLength
;
391 Information
+= CopyLength
;
393 Fcb
->ReadDataAvailable
+= CopyLength
;
394 Fcb
->WriteQuotaAvailable
-= CopyLength
;
399 KeSetEvent(&Fcb
->OtherSide
->Event
, IO_NO_INCREMENT
, FALSE
);
405 DPRINT("Message mode\n");
408 CopyLength
= RtlRosMin(Length
, Fcb
->WriteQuotaAvailable
);
409 memcpy(Fcb
->Data
, Buffer
, CopyLength
);
411 Information
= CopyLength
;
412 Fcb
->ReadDataAvailable
= CopyLength
;
413 Fcb
->WriteQuotaAvailable
= 0;
418 KeSetEvent(&Fcb
->OtherSide
->Event
, IO_NO_INCREMENT
, FALSE
);
424 KeReleaseSpinLock(&Fcb
->DataListLock
, OldIrql
);
427 Irp
->IoStatus
.Status
= Status
;
428 Irp
->IoStatus
.Information
= Information
;
430 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
432 DPRINT("NpfsWrite done (Status %lx)\n", Status
);