- Fixed various problems (hangs/crashes) with connecting, disconnecting and closing...
[reactos.git] / reactos / drivers / fs / np / create.c
1 /* $Id: create.c,v 1.19 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/create.c
6 * PURPOSE: Named pipe filesystem
7 * PROGRAMMER: David Welch <welch@cwcom.net>
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ddk/ntddk.h>
13
14 #include "npfs.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* FUNCTIONS *****************************************************************/
20
21 NTSTATUS STDCALL
22 NpfsCreate(
23 PDEVICE_OBJECT DeviceObject,
24 PIRP Irp)
25 {
26 PLIST_ENTRY CurrentEntry;
27 PNPFS_PIPE Current;
28 PIO_STACK_LOCATION IoStack;
29 PFILE_OBJECT FileObject;
30 PNPFS_PIPE Pipe;
31 PNPFS_FCB ClientFcb;
32 PNPFS_FCB ServerFcb;
33 PNPFS_DEVICE_EXTENSION DeviceExt;
34 ULONG Disposition;
35
36 DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
37
38 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
39 IoStack = IoGetCurrentIrpStackLocation(Irp);
40 FileObject = IoStack->FileObject;
41 Disposition = ((IoStack->Parameters.Create.Options >> 24) & 0xff);
42 DPRINT("FileObject %p\n", FileObject);
43 DPRINT("FileName %wZ\n", &FileObject->FileName);
44
45 Irp->IoStatus.Information = 0;
46
47 /*
48 * Step 1. Find the pipe we're trying to open.
49 */
50
51 KeLockMutex(&DeviceExt->PipeListLock);
52 CurrentEntry = DeviceExt->PipeListHead.Flink;
53 while (CurrentEntry != &DeviceExt->PipeListHead)
54 {
55 Current = CONTAINING_RECORD(CurrentEntry, NPFS_PIPE, PipeListEntry);
56 if (RtlCompareUnicodeString(
57 &FileObject->FileName,
58 &Current->PipeName,
59 TRUE) == 0)
60 {
61 break;
62 }
63 CurrentEntry = CurrentEntry->Flink;
64 }
65
66 /* Not found, bail out with error. */
67 if (CurrentEntry == &DeviceExt->PipeListHead)
68 {
69 DPRINT("No pipe found!\n");
70 KeUnlockMutex(&DeviceExt->PipeListLock);
71 Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND;
72 IoCompleteRequest(Irp, IO_NO_INCREMENT);
73 return STATUS_OBJECT_NAME_NOT_FOUND;
74 }
75
76 KeUnlockMutex(&DeviceExt->PipeListLock);
77
78 /* Save the pipe we found for later use. */
79 Pipe = Current;
80
81 /*
82 * Step 2. Search for listening server FCB.
83 */
84
85 /*
86 * Acquire the lock for FCB lists. From now on no modifications to the
87 * FCB lists are allowed, because it can cause various misconsistencies.
88 */
89 KeLockMutex(&Pipe->FcbListLock);
90
91 CurrentEntry = Pipe->ServerFcbListHead.Flink;
92 while (CurrentEntry != &Pipe->ServerFcbListHead)
93 {
94 ServerFcb = CONTAINING_RECORD(CurrentEntry, NPFS_FCB, FcbListEntry);
95 if (ServerFcb->PipeState == FILE_PIPE_LISTENING_STATE)
96 {
97 DPRINT("Server found! Fcb %p\n", ServerFcb);
98 break;
99 }
100 CurrentEntry = CurrentEntry->Flink;
101 }
102
103 /* Not found, bail out with error for FILE_OPEN requests. */
104 if (CurrentEntry == &Pipe->ServerFcbListHead)
105 {
106 DPRINT("No server fcb found!\n");
107 if (Disposition == FILE_OPEN)
108 {
109 KeUnlockMutex(&Pipe->FcbListLock);
110 Irp->IoStatus.Status = STATUS_PIPE_BUSY;
111 IoCompleteRequest(Irp, IO_NO_INCREMENT);
112 return STATUS_PIPE_BUSY;
113 }
114 ServerFcb = NULL;
115 }
116
117 /*
118 * Step 3. Create the client FCB.
119 */
120
121 ClientFcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
122 if (ClientFcb == NULL)
123 {
124 DPRINT("No memory!\n");
125 KeUnlockMutex(&Pipe->FcbListLock);
126 Irp->IoStatus.Status = STATUS_NO_MEMORY;
127 IoCompleteRequest(Irp, IO_NO_INCREMENT);
128 return STATUS_NO_MEMORY;
129 }
130
131 ClientFcb->Pipe = Pipe;
132 ClientFcb->PipeEnd = FILE_PIPE_CLIENT_END;
133 ClientFcb->OtherSide = NULL;
134 ClientFcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
135
136 /* Initialize data list. */
137 if (Pipe->InboundQuota)
138 {
139 ClientFcb->Data = ExAllocatePool(NonPagedPool, Pipe->InboundQuota);
140 if (ClientFcb->Data == NULL)
141 {
142 DPRINT("No memory!\n");
143 ExFreePool(ClientFcb);
144 KeUnlockMutex(&Pipe->FcbListLock);
145 Irp->IoStatus.Status = STATUS_NO_MEMORY;
146 IoCompleteRequest(Irp, IO_NO_INCREMENT);
147 return STATUS_NO_MEMORY;
148 }
149 }
150 else
151 {
152 ClientFcb->Data = NULL;
153 }
154
155 ClientFcb->ReadPtr = ClientFcb->Data;
156 ClientFcb->WritePtr = ClientFcb->Data;
157 ClientFcb->ReadDataAvailable = 0;
158 ClientFcb->WriteQuotaAvailable = Pipe->InboundQuota;
159 ClientFcb->MaxDataLength = Pipe->InboundQuota;
160 KeInitializeSpinLock(&ClientFcb->DataListLock);
161 KeInitializeEvent(&ClientFcb->ConnectEvent, SynchronizationEvent, FALSE);
162 KeInitializeEvent(&ClientFcb->Event, SynchronizationEvent, FALSE);
163
164 /*
165 * Step 4. Add the client FCB to a list and connect it if necessary.
166 */
167
168 /* Add the client FCB to the pipe FCB list. */
169 InsertTailList(&Pipe->ClientFcbListHead, &ClientFcb->FcbListEntry);
170
171 if (ServerFcb)
172 {
173 ClientFcb->OtherSide = ServerFcb;
174 ServerFcb->OtherSide = ClientFcb;
175 ClientFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
176 ServerFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
177
178 /* Wake server thread */
179 DPRINT("Setting the ConnectEvent for %x\n", ServerFcb);
180 KeSetEvent(&ServerFcb->ConnectEvent, 0, FALSE);
181 }
182
183 KeUnlockMutex(&Pipe->FcbListLock);
184
185 FileObject->FsContext = ClientFcb;
186
187 Irp->IoStatus.Status = STATUS_SUCCESS;
188 IoCompleteRequest(Irp, IO_NO_INCREMENT);
189
190 DPRINT("Success!\n");
191
192 return STATUS_SUCCESS;
193 }
194
195
196 NTSTATUS STDCALL
197 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
198 PIRP Irp)
199 {
200 PIO_STACK_LOCATION IoStack;
201 PFILE_OBJECT FileObject;
202 PNPFS_DEVICE_EXTENSION DeviceExt;
203 PNPFS_PIPE Pipe;
204 PNPFS_FCB Fcb;
205 PLIST_ENTRY current_entry;
206 PNPFS_PIPE current;
207 PIO_PIPE_CREATE_BUFFER Buffer;
208
209 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
210
211 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
212 IoStack = IoGetCurrentIrpStackLocation(Irp);
213 FileObject = IoStack->FileObject;
214 DPRINT("FileObject %p\n", FileObject);
215 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
216
217 Buffer = (PIO_PIPE_CREATE_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
218
219 Irp->IoStatus.Information = 0;
220
221 Fcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
222 if (Fcb == NULL)
223 {
224 Irp->IoStatus.Status = STATUS_NO_MEMORY;
225 IoCompleteRequest(Irp, IO_NO_INCREMENT);
226 return STATUS_NO_MEMORY;
227 }
228
229 KeLockMutex(&DeviceExt->PipeListLock);
230
231 /*
232 * First search for existing Pipe with the same name.
233 */
234
235 current_entry = DeviceExt->PipeListHead.Flink;
236 while (current_entry != &DeviceExt->PipeListHead)
237 {
238 current = CONTAINING_RECORD(current_entry,
239 NPFS_PIPE,
240 PipeListEntry);
241
242 if (RtlCompareUnicodeString(&FileObject->FileName, &current->PipeName, TRUE) == 0)
243 {
244 break;
245 }
246
247 current_entry = current_entry->Flink;
248 }
249
250 if (current_entry != &DeviceExt->PipeListHead)
251 {
252 /*
253 * Found Pipe with the same name. Check if we are
254 * allowed to use it.
255 */
256
257 Pipe = current;
258 KeUnlockMutex(&DeviceExt->PipeListLock);
259
260 if (Pipe->CurrentInstances >= Pipe->MaximumInstances)
261 {
262 DPRINT("Out of instances.\n");
263 ExFreePool(Fcb);
264 Irp->IoStatus.Status = STATUS_PIPE_BUSY;
265 IoCompleteRequest(Irp, IO_NO_INCREMENT);
266 return STATUS_PIPE_BUSY;
267 }
268
269 /* FIXME: Check pipe modes also! */
270 if (Pipe->MaximumInstances != Buffer->MaxInstances ||
271 Pipe->TimeOut.QuadPart != Buffer->TimeOut.QuadPart)
272 {
273 DPRINT("Asked for invalid pipe mode.\n");
274 ExFreePool(Fcb);
275 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
276 IoCompleteRequest(Irp, IO_NO_INCREMENT);
277 return STATUS_ACCESS_DENIED;
278 }
279 }
280 else
281 {
282 Pipe = ExAllocatePool(NonPagedPool, sizeof(NPFS_PIPE));
283 if (Pipe == NULL)
284 {
285 KeUnlockMutex(&DeviceExt->PipeListLock);
286 Irp->IoStatus.Status = STATUS_NO_MEMORY;
287 Irp->IoStatus.Information = 0;
288 IoCompleteRequest(Irp, IO_NO_INCREMENT);
289 return STATUS_NO_MEMORY;
290 }
291
292 if (RtlCreateUnicodeString(&Pipe->PipeName, FileObject->FileName.Buffer) == 0)
293 {
294 KeUnlockMutex(&DeviceExt->PipeListLock);
295 ExFreePool(Pipe);
296 ExFreePool(Fcb);
297 Irp->IoStatus.Status = STATUS_NO_MEMORY;
298 Irp->IoStatus.Information = 0;
299 IoCompleteRequest(Irp, IO_NO_INCREMENT);
300 return(STATUS_NO_MEMORY);
301 }
302
303 InitializeListHead(&Pipe->ServerFcbListHead);
304 InitializeListHead(&Pipe->ClientFcbListHead);
305 KeInitializeMutex(&Pipe->FcbListLock, 0);
306
307 Pipe->PipeType = Buffer->WriteModeMessage ? FILE_PIPE_MESSAGE_TYPE : FILE_PIPE_BYTE_STREAM_TYPE;
308 Pipe->PipeWriteMode = Buffer->WriteModeMessage ? FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
309 Pipe->PipeReadMode = Buffer->ReadModeMessage ? FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
310 Pipe->PipeBlockMode = Buffer->NonBlocking;
311 Pipe->PipeConfiguration = IoStack->Parameters.Create.Options & 0x3;
312 Pipe->MaximumInstances = Buffer->MaxInstances;
313 Pipe->CurrentInstances = 0;
314 Pipe->TimeOut = Buffer->TimeOut;
315 if (!(IoStack->Parameters.Create.Options & FILE_PIPE_OUTBOUND) ||
316 IoStack->Parameters.Create.Options & FILE_PIPE_FULL_DUPLEX)
317 {
318 if (Buffer->InBufferSize == 0)
319 {
320 Pipe->InboundQuota = DeviceExt->DefaultQuota;
321 }
322 else
323 {
324 Pipe->InboundQuota = PAGE_ROUND_UP(Buffer->InBufferSize);
325 if (Pipe->InboundQuota < DeviceExt->MinQuota)
326 {
327 Pipe->InboundQuota = DeviceExt->MinQuota;
328 }
329 else if (Pipe->InboundQuota > DeviceExt->MaxQuota)
330 {
331 Pipe->InboundQuota = DeviceExt->MaxQuota;
332 }
333 }
334 }
335 else
336 {
337 Pipe->InboundQuota = 0;
338 }
339 if (IoStack->Parameters.Create.Options & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
340 {
341 if (Buffer->OutBufferSize == 0)
342 {
343 Pipe->OutboundQuota = DeviceExt->DefaultQuota;
344 }
345 else
346 {
347 Pipe->OutboundQuota = PAGE_ROUND_UP(Buffer->OutBufferSize);
348 if (Pipe->OutboundQuota < DeviceExt->MinQuota)
349 {
350 Pipe->OutboundQuota = DeviceExt->MinQuota;
351 }
352 else if (Pipe->OutboundQuota > DeviceExt->MaxQuota)
353 {
354 Pipe->OutboundQuota = DeviceExt->MaxQuota;
355 }
356 }
357 }
358 else
359 {
360 Pipe->OutboundQuota = 0;
361 }
362
363 InsertTailList(&DeviceExt->PipeListHead, &Pipe->PipeListEntry);
364 KeUnlockMutex(&DeviceExt->PipeListLock);
365 }
366
367 if (Pipe->OutboundQuota)
368 {
369 Fcb->Data = ExAllocatePool(NonPagedPool, Pipe->OutboundQuota);
370 if (Fcb->Data == NULL)
371 {
372 ExFreePool(Fcb);
373
374 if (Pipe != current)
375 {
376 RtlFreeUnicodeString(&Pipe->PipeName);
377 ExFreePool(Pipe);
378 }
379
380 Irp->IoStatus.Status = STATUS_NO_MEMORY;
381 IoCompleteRequest(Irp, IO_NO_INCREMENT);
382 return STATUS_NO_MEMORY;
383 }
384 }
385 else
386 {
387 Fcb->Data = NULL;
388 }
389
390 Fcb->ReadPtr = Fcb->Data;
391 Fcb->WritePtr = Fcb->Data;
392 Fcb->ReadDataAvailable = 0;
393 Fcb->WriteQuotaAvailable = Pipe->OutboundQuota;
394 Fcb->MaxDataLength = Pipe->OutboundQuota;
395 KeInitializeSpinLock(&Fcb->DataListLock);
396
397 Pipe->CurrentInstances++;
398
399 KeLockMutex(&Pipe->FcbListLock);
400 InsertTailList(&Pipe->ServerFcbListHead, &Fcb->FcbListEntry);
401 KeUnlockMutex(&Pipe->FcbListLock);
402
403 Fcb->Pipe = Pipe;
404 Fcb->PipeEnd = FILE_PIPE_SERVER_END;
405 Fcb->PipeState = FILE_PIPE_LISTENING_STATE;
406 Fcb->OtherSide = NULL;
407
408 KeInitializeEvent(&Fcb->ConnectEvent,
409 SynchronizationEvent,
410 FALSE);
411
412 KeInitializeEvent(&Fcb->Event,
413 SynchronizationEvent,
414 FALSE);
415
416 FileObject->FsContext = Fcb;
417
418 Irp->IoStatus.Status = STATUS_SUCCESS;
419 IoCompleteRequest(Irp, IO_NO_INCREMENT);
420
421 return(STATUS_SUCCESS);
422 }
423
424
425 NTSTATUS STDCALL
426 NpfsClose(
427 PDEVICE_OBJECT DeviceObject,
428 PIRP Irp)
429 {
430 PNPFS_DEVICE_EXTENSION DeviceExt;
431 PIO_STACK_LOCATION IoStack;
432 PFILE_OBJECT FileObject;
433 PNPFS_FCB Fcb;
434 PNPFS_PIPE Pipe;
435 BOOL Server;
436
437 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
438
439 IoStack = IoGetCurrentIrpStackLocation(Irp);
440 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
441 FileObject = IoStack->FileObject;
442 Fcb = FileObject->FsContext;
443
444 if (Fcb == NULL)
445 {
446 Irp->IoStatus.Status = STATUS_SUCCESS;
447 Irp->IoStatus.Information = 0;
448 IoCompleteRequest(Irp, IO_NO_INCREMENT);
449 return STATUS_SUCCESS;
450 }
451
452 DPRINT("Fcb %x\n", Fcb);
453 Pipe = Fcb->Pipe;
454
455 DPRINT("Closing pipe %wZ\n", &Pipe->PipeName);
456
457 KeLockMutex(&Pipe->FcbListLock);
458
459 Server = (Fcb->PipeEnd == FILE_PIPE_SERVER_END);
460
461 if (Server)
462 {
463 /* FIXME: Clean up existing connections here ?? */
464 DPRINT("Server\n");
465 Pipe->CurrentInstances--;
466 } else
467 {
468 DPRINT("Client\n");
469 }
470
471 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
472 {
473 if (Fcb->OtherSide)
474 {
475 Fcb->OtherSide->PipeState = FILE_PIPE_CLOSING_STATE;
476 /*
477 * Signaling the write event. If is possible that an other
478 * thread waits of an empty buffer.
479 */
480 KeSetEvent(&Fcb->OtherSide->Event, IO_NO_INCREMENT, FALSE);
481 }
482 Fcb->PipeState = 0;
483 }
484
485 FileObject->FsContext = NULL;
486
487 RemoveEntryList(&Fcb->FcbListEntry);
488 if (Fcb->Data)
489 ExFreePool(Fcb->Data);
490 ExFreePool(Fcb);
491
492 KeUnlockMutex(&Pipe->FcbListLock);
493
494 if (Server && Pipe->CurrentInstances == 0)
495 {
496 RtlFreeUnicodeString(&Pipe->PipeName);
497 KeLockMutex(&DeviceExt->PipeListLock);
498 RemoveEntryList(&Pipe->PipeListEntry);
499 KeUnlockMutex(&DeviceExt->PipeListLock);
500 ExFreePool(Pipe);
501 }
502
503 Irp->IoStatus.Status = STATUS_SUCCESS;
504 Irp->IoStatus.Information = 0;
505 IoCompleteRequest(Irp, IO_NO_INCREMENT);
506
507 return STATUS_SUCCESS;
508 }
509
510 /* EOF */