1 /* $Id: rw.c,v 1.15 2004/05/10 19:58:10 navaraf Exp $
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 /* FUNCTIONS *****************************************************************/
22 VOID
HexDump(PUCHAR Buffer
, ULONG Length
)
26 const char Hex
[] = "0123456789ABCDEF";
29 DbgPrint("---------------\n");
31 for (i
= 0; i
< ROUND_UP(Length
, 16); i
+= 16)
33 memset(Line
, ' ', 64);
36 for (j
= 0; j
< 16 && j
+ i
< Length
; j
++)
39 Line
[3*j
+ 0] = Hex
[ch
>> 4];
40 Line
[3*j
+ 1] = Hex
[ch
& 0x0f];
41 Line
[48 + j
] = isprint(ch
) ? ch
: '.';
43 DbgPrint("%s\n", Line
);
45 DbgPrint("---------------\n");
50 NpfsRead(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
52 PIO_STACK_LOCATION IoStack
;
53 PFILE_OBJECT FileObject
;
55 PNPFS_DEVICE_EXTENSION DeviceExt
;
66 DPRINT("NpfsRead(DeviceObject %p Irp %p)\n", DeviceObject
, Irp
);
68 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
69 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
70 FileObject
= IoStack
->FileObject
;
71 Fcb
= FileObject
->FsContext
;
73 ReadFcb
= Fcb
->OtherSide
;
77 DPRINT("Pipe is NOT connected!\n");
78 if (Fcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
79 Status
= STATUS_PIPE_LISTENING
;
80 else if (Fcb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
81 Status
= STATUS_PIPE_DISCONNECTED
;
83 Status
= STATUS_PIPE_BROKEN
;
85 DPRINT("%x\n", Status
);
89 if (Irp
->MdlAddress
== NULL
)
91 DPRINT("Irp->MdlAddress == NULL\n");
92 Status
= STATUS_UNSUCCESSFUL
;
97 if (ReadFcb
->Data
== NULL
)
99 DPRINT("Pipe is NOT readable!\n");
100 Status
= STATUS_UNSUCCESSFUL
;
105 #ifdef FIN_WORKAROUND_READCLOSE
106 if (ReadFcb
->ReadDataAvailable
== 0 &&
107 ReadFcb
->PipeState
== FILE_PIPE_CLOSING_STATE
)
109 DPRINT("Other end of pipe is closed!\n");
110 Status
= STATUS_PIPE_BROKEN
;
116 Status
= STATUS_SUCCESS
;
117 Length
= IoStack
->Parameters
.Read
.Length
;
120 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
121 KeAcquireSpinLock(&ReadFcb
->DataListLock
, &OldIrql
);
124 /* FIXME: check if in blocking mode */
125 if (ReadFcb
->ReadDataAvailable
== 0)
127 KeResetEvent(&Fcb
->Event
);
128 KeSetEvent(&ReadFcb
->Event
, IO_NO_INCREMENT
, FALSE
);
129 KeReleaseSpinLock(&ReadFcb
->DataListLock
, OldIrql
);
132 Status
= STATUS_SUCCESS
;
135 if (Fcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
137 DPRINT("PipeState: %x\n", Fcb
->PipeState
);
138 Status
= STATUS_PIPE_BROKEN
;
141 /* Wait for ReadEvent to become signaled */
142 DPRINT("Waiting for readable data (%S)\n", Pipe
->PipeName
.Buffer
);
143 Status
= KeWaitForSingleObject(&Fcb
->Event
,
148 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe
->PipeName
.Buffer
, Status
);
149 #ifndef FIN_WORKAROUND_READCLOSE
151 * It's possible that the event was signaled because the
152 * other side of pipe was closed.
154 if (Fcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
156 DPRINT("PipeState: %x\n", Fcb
->PipeState
);
157 Status
= STATUS_PIPE_BROKEN
;
161 KeAcquireSpinLock(&ReadFcb
->DataListLock
, &OldIrql
);
164 if (Pipe
->PipeReadMode
== FILE_PIPE_BYTE_STREAM_MODE
)
166 DPRINT("Byte stream mode\n");
167 /* Byte stream mode */
168 while (Length
> 0 && ReadFcb
->ReadDataAvailable
> 0)
170 CopyLength
= RtlRosMin(ReadFcb
->ReadDataAvailable
, Length
);
171 if (ReadFcb
->ReadPtr
+ CopyLength
<= ReadFcb
->Data
+ ReadFcb
->MaxDataLength
)
173 memcpy(Buffer
, ReadFcb
->ReadPtr
, CopyLength
);
174 ReadFcb
->ReadPtr
+= CopyLength
;
175 if (ReadFcb
->ReadPtr
== ReadFcb
->Data
+ ReadFcb
->MaxDataLength
)
177 ReadFcb
->ReadPtr
= ReadFcb
->Data
;
182 TempLength
= ReadFcb
->Data
+ ReadFcb
->MaxDataLength
- ReadFcb
->ReadPtr
;
183 memcpy(Buffer
, ReadFcb
->ReadPtr
, TempLength
);
184 memcpy(Buffer
+ TempLength
, ReadFcb
->Data
, CopyLength
- TempLength
);
185 ReadFcb
->ReadPtr
= ReadFcb
->Data
+ CopyLength
- TempLength
;
188 Buffer
+= CopyLength
;
189 Length
-= CopyLength
;
190 Information
+= CopyLength
;
192 ReadFcb
->ReadDataAvailable
-= CopyLength
;
193 ReadFcb
->WriteQuotaAvailable
+= CopyLength
;
198 KeSetEvent(&ReadFcb
->Event
, IO_NO_INCREMENT
, FALSE
);
204 DPRINT("Message mode\n");
207 if (ReadFcb
->ReadDataAvailable
)
209 /* Truncate the message if the receive buffer is too small */
210 CopyLength
= RtlRosMin(ReadFcb
->ReadDataAvailable
, Length
);
211 memcpy(Buffer
, ReadFcb
->Data
, CopyLength
);
214 DPRINT("Length %d Buffer %x\n",CopyLength
,Buffer
);
215 HexDump((PUCHAR
)Buffer
, CopyLength
);
218 Information
= CopyLength
;
219 ReadFcb
->ReadDataAvailable
= 0;
220 ReadFcb
->WriteQuotaAvailable
= ReadFcb
->MaxDataLength
;
224 KeSetEvent(&ReadFcb
->Event
, IO_NO_INCREMENT
, FALSE
);
229 #ifdef FIN_WORKAROUND_READCLOSE
230 if (ReadFcb
->ReadDataAvailable
== 0 &&
231 ReadFcb
->PipeState
== FILE_PIPE_CLOSING_STATE
)
233 DPRINT("Other end of pipe is closed!\n");
238 KeReleaseSpinLock(&ReadFcb
->DataListLock
, OldIrql
);
241 Irp
->IoStatus
.Status
= Status
;
242 Irp
->IoStatus
.Information
= Information
;
244 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
251 NpfsWrite(PDEVICE_OBJECT DeviceObject
,
254 PIO_STACK_LOCATION IoStack
;
255 PFILE_OBJECT FileObject
;
256 PNPFS_FCB Fcb
= NULL
;
257 PNPFS_PIPE Pipe
= NULL
;
259 NTSTATUS Status
= STATUS_SUCCESS
;
267 DPRINT("NpfsWrite()\n");
269 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
270 FileObject
= IoStack
->FileObject
;
271 DPRINT("FileObject %p\n", FileObject
);
272 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
274 Fcb
= FileObject
->FsContext
;
277 Length
= IoStack
->Parameters
.Write
.Length
;
278 Offset
= IoStack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
281 if (Irp
->MdlAddress
== NULL
)
283 DPRINT("Irp->MdlAddress == NULL\n");
284 Status
= STATUS_UNSUCCESSFUL
;
289 if (Fcb
->OtherSide
== NULL
)
291 DPRINT("Pipe is NOT connected!\n");
292 if (Fcb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
293 Status
= STATUS_PIPE_LISTENING
;
294 else if (Fcb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
295 Status
= STATUS_PIPE_DISCONNECTED
;
297 Status
= STATUS_UNSUCCESSFUL
;
302 if (Fcb
->Data
== NULL
)
304 DPRINT("Pipe is NOT writable!\n");
305 Status
= STATUS_UNSUCCESSFUL
;
310 Status
= STATUS_SUCCESS
;
311 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
313 KeAcquireSpinLock(&Fcb
->DataListLock
, &OldIrql
);
315 DPRINT("Length %d Buffer %x Offset %x\n",Length
,Buffer
,Offset
);
316 HexDump(Buffer
, Length
);
321 if (Fcb
->WriteQuotaAvailable
== 0)
323 KeResetEvent(&Fcb
->Event
);
324 KeSetEvent(&Fcb
->OtherSide
->Event
, IO_NO_INCREMENT
, FALSE
);
325 KeReleaseSpinLock(&Fcb
->DataListLock
, OldIrql
);
326 if (Fcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
328 Status
= STATUS_PIPE_BROKEN
;
331 DPRINT("Waiting for buffer space (%S)\n", Pipe
->PipeName
.Buffer
);
332 Status
= KeWaitForSingleObject(&Fcb
->Event
,
337 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe
->PipeName
.Buffer
, Status
);
338 #ifndef FIN_WORKAROUND_READCLOSE
340 * It's possible that the event was signaled because the
341 * other side of pipe was closed.
343 if (Fcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
345 DPRINT("PipeState: %x\n", Fcb
->PipeState
);
346 Status
= STATUS_PIPE_BROKEN
;
350 KeAcquireSpinLock(&Fcb
->DataListLock
, &OldIrql
);
352 if (Pipe
->PipeWriteMode
== FILE_PIPE_BYTE_STREAM_MODE
)
354 DPRINT("Byte stream mode\n");
355 while (Length
> 0 && Fcb
->WriteQuotaAvailable
> 0)
357 CopyLength
= RtlRosMin(Length
, Fcb
->WriteQuotaAvailable
);
358 if (Fcb
->WritePtr
+ CopyLength
<= Fcb
->Data
+ Fcb
->MaxDataLength
)
360 memcpy(Fcb
->WritePtr
, Buffer
, CopyLength
);
361 Fcb
->WritePtr
+= CopyLength
;
362 if (Fcb
->WritePtr
== Fcb
->Data
+ Fcb
->MaxDataLength
)
364 Fcb
->WritePtr
= Fcb
->Data
;
369 TempLength
= Fcb
->Data
+ Fcb
->MaxDataLength
- Fcb
->WritePtr
;
370 memcpy(Fcb
->WritePtr
, Buffer
, TempLength
);
371 memcpy(Fcb
->Data
, Buffer
+ TempLength
, CopyLength
- TempLength
);
372 Fcb
->WritePtr
= Fcb
->Data
+ CopyLength
- TempLength
;
375 Buffer
+= CopyLength
;
376 Length
-= CopyLength
;
377 Information
+= CopyLength
;
379 Fcb
->ReadDataAvailable
+= CopyLength
;
380 Fcb
->WriteQuotaAvailable
-= CopyLength
;
385 KeSetEvent(&Fcb
->OtherSide
->Event
, IO_NO_INCREMENT
, FALSE
);
393 CopyLength
= RtlRosMin(Length
, Fcb
->WriteQuotaAvailable
);
394 memcpy(Fcb
->Data
, Buffer
, CopyLength
);
396 Information
= CopyLength
;
397 Fcb
->ReadDataAvailable
= CopyLength
;
398 Fcb
->WriteQuotaAvailable
= 0;
402 KeSetEvent(&Fcb
->OtherSide
->Event
, IO_NO_INCREMENT
, FALSE
);
407 KeReleaseSpinLock(&Fcb
->DataListLock
, OldIrql
);
410 Irp
->IoStatus
.Status
= Status
;
411 Irp
->IoStatus
.Information
= Information
;
413 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);