[NPFS]
[reactos.git] / reactos / drivers / filesystems / npfs / create.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/np/create.c
5 * PURPOSE: Named pipe filesystem
6 * PROGRAMMER: David Welch <welch@cwcom.net>
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "npfs.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FUNCTIONS *****************************************************************/
17
18 PNPFS_FCB
19 NpfsFindPipe(PNPFS_VCB Vcb,
20 PUNICODE_STRING PipeName)
21 {
22 PLIST_ENTRY CurrentEntry;
23 PNPFS_FCB Fcb;
24
25 CurrentEntry = Vcb->PipeListHead.Flink;
26 while (CurrentEntry != &Vcb->PipeListHead)
27 {
28 Fcb = CONTAINING_RECORD(CurrentEntry, NPFS_FCB, PipeListEntry);
29 if (RtlCompareUnicodeString(PipeName,
30 &Fcb->PipeName,
31 TRUE) == 0)
32 {
33 DPRINT("<%wZ> = <%wZ>\n", PipeName, &Fcb->PipeName);
34 return Fcb;
35 }
36
37 CurrentEntry = CurrentEntry->Flink;
38 }
39
40 return NULL;
41 }
42
43
44 static PNPFS_CCB
45 NpfsFindListeningServerInstance(PNPFS_FCB Fcb)
46 {
47 PLIST_ENTRY CurrentEntry;
48 PNPFS_WAITER_ENTRY Waiter;
49 KIRQL oldIrql;
50 PIRP Irp;
51
52 CurrentEntry = Fcb->WaiterListHead.Flink;
53 while (CurrentEntry != &Fcb->WaiterListHead)
54 {
55 Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
56 Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
57 if (Waiter->Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
58 {
59 DPRINT("Server found! CCB %p\n", Waiter->Ccb);
60
61 IoAcquireCancelSpinLock(&oldIrql);
62 if (!Irp->Cancel)
63 {
64 (void)IoSetCancelRoutine(Irp, NULL);
65 IoReleaseCancelSpinLock(oldIrql);
66 return Waiter->Ccb;
67 }
68 IoReleaseCancelSpinLock(oldIrql);
69 }
70
71 CurrentEntry = CurrentEntry->Flink;
72 }
73
74 return NULL;
75 }
76
77
78 static VOID
79 NpfsSignalAndRemoveListeningServerInstance(PNPFS_FCB Fcb,
80 PNPFS_CCB Ccb)
81 {
82 PLIST_ENTRY CurrentEntry;
83 PNPFS_WAITER_ENTRY Waiter;
84 PIRP Irp;
85
86 CurrentEntry = Fcb->WaiterListHead.Flink;
87 while (CurrentEntry != &Fcb->WaiterListHead)
88 {
89 Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
90 if (Waiter->Ccb == Ccb)
91 {
92 DPRINT("Server found! CCB %p\n", Waiter->Ccb);
93
94 RemoveEntryList(&Waiter->Entry);
95 Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
96 Irp->IoStatus.Status = STATUS_SUCCESS;
97 Irp->IoStatus.Information = 0;
98 IoCompleteRequest(Irp, IO_NO_INCREMENT);
99 break;
100 }
101 CurrentEntry = CurrentEntry->Flink;
102 }
103 }
104
105
106 static VOID
107 NpfsOpenRootDirectory(PNPFS_FCB Fcb,
108 PFILE_OBJECT FileObject,
109 PIO_STATUS_BLOCK IoStatus)
110 {
111 PNPFS_CCB Ccb;
112
113 DPRINT("NpfsOpenRootDirectory()\n");
114
115 Ccb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
116 if (Ccb == NULL)
117 {
118 IoStatus->Status = STATUS_NO_MEMORY;
119 return;
120 }
121
122 Ccb->Type = CCB_DIRECTORY;
123 Ccb->Fcb = Fcb;
124
125 FileObject->FsContext = Fcb;
126 FileObject->FsContext2 = Ccb;
127
128 IoStatus->Information = FILE_OPENED;
129 IoStatus->Status = STATUS_SUCCESS;
130
131 return;
132 }
133
134
135 NTSTATUS NTAPI
136 NpfsCreate(PDEVICE_OBJECT DeviceObject,
137 PIRP Irp)
138 {
139 PEXTENDED_IO_STACK_LOCATION IoStack;
140 PUNICODE_STRING FileName;
141 PFILE_OBJECT FileObject;
142 PFILE_OBJECT RelatedFileObject;
143 PNPFS_FCB Fcb;
144 PNPFS_CCB ClientCcb;
145 PNPFS_CCB ServerCcb = NULL;
146 PNPFS_VCB Vcb;
147 ACCESS_MASK DesiredAccess;
148 NTSTATUS Status;
149
150 DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
151
152 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
153 IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
154 FileObject = IoStack->FileObject;
155 RelatedFileObject = FileObject->RelatedFileObject;
156 FileName = &FileObject->FileName;
157 DesiredAccess = IoStack->Parameters.CreatePipe.SecurityContext->DesiredAccess;
158
159 DPRINT("FileObject %p\n", FileObject);
160 DPRINT("FileName %wZ\n", &FileObject->FileName);
161
162 Irp->IoStatus.Information = 0;
163
164 if (FileName->Length == 2 && FileName->Buffer[0] == L'\\' && RelatedFileObject == NULL)
165 {
166 DPRINT("Open the root directory\n");
167
168 NpfsOpenRootDirectory(Vcb->RootFcb,
169 FileObject,
170 &Irp->IoStatus);
171
172 Status = Irp->IoStatus.Status;
173 IoCompleteRequest(Irp, IO_NO_INCREMENT);
174 return Status;
175 }
176
177
178 /*
179 * Step 1. Find the pipe we're trying to open.
180 */
181 KeLockMutex(&Vcb->PipeListLock);
182 Fcb = NpfsFindPipe(Vcb,
183 &FileObject->FileName);
184 if (Fcb == NULL)
185 {
186 /* Not found, bail out with error. */
187 DPRINT("No pipe found!\n");
188 KeUnlockMutex(&Vcb->PipeListLock);
189 Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND;
190 IoCompleteRequest(Irp, IO_NO_INCREMENT);
191 return STATUS_OBJECT_NAME_NOT_FOUND;
192 }
193
194 KeUnlockMutex(&Vcb->PipeListLock);
195
196 /*
197 * Acquire the lock for CCB lists. From now on no modifications to the
198 * CCB lists are allowed, because it can cause various misconsistencies.
199 */
200 KeLockMutex(&Fcb->CcbListLock);
201
202 /*
203 * Step 2. Create the client CCB.
204 */
205 ClientCcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
206 if (ClientCcb == NULL)
207 {
208 DPRINT("No memory!\n");
209 KeUnlockMutex(&Fcb->CcbListLock);
210 Irp->IoStatus.Status = STATUS_NO_MEMORY;
211 IoCompleteRequest(Irp, IO_NO_INCREMENT);
212 return STATUS_NO_MEMORY;
213 }
214
215 ClientCcb->Type = CCB_PIPE;
216 ClientCcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
217 ClientCcb->Fcb = Fcb;
218 ClientCcb->PipeEnd = FILE_PIPE_CLIENT_END;
219 ClientCcb->OtherSide = NULL;
220 // ClientCcb->PipeState = SpecialAccess ? 0 : FILE_PIPE_DISCONNECTED_STATE;
221 ClientCcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
222 InitializeListHead(&ClientCcb->ReadRequestListHead);
223
224 DPRINT("CCB: %p\n", ClientCcb);
225
226 /* Initialize data list. */
227 if (Fcb->OutboundQuota)
228 {
229 ClientCcb->Data = ExAllocatePool(PagedPool, Fcb->OutboundQuota);
230 if (ClientCcb->Data == NULL)
231 {
232 DPRINT("No memory!\n");
233 ExFreePool(ClientCcb);
234 KeUnlockMutex(&Fcb->CcbListLock);
235 Irp->IoStatus.Status = STATUS_NO_MEMORY;
236 IoCompleteRequest(Irp, IO_NO_INCREMENT);
237 return STATUS_NO_MEMORY;
238 }
239 }
240 else
241 {
242 ClientCcb->Data = NULL;
243 }
244
245 ClientCcb->ReadPtr = ClientCcb->Data;
246 ClientCcb->WritePtr = ClientCcb->Data;
247 ClientCcb->ReadDataAvailable = 0;
248 ClientCcb->WriteQuotaAvailable = Fcb->OutboundQuota;
249 ClientCcb->MaxDataLength = Fcb->OutboundQuota;
250 ExInitializeFastMutex(&ClientCcb->DataListLock);
251 KeInitializeEvent(&ClientCcb->ConnectEvent, SynchronizationEvent, FALSE);
252 KeInitializeEvent(&ClientCcb->ReadEvent, NotificationEvent, FALSE);
253 KeInitializeEvent(&ClientCcb->WriteEvent, NotificationEvent, FALSE);
254
255
256 /*
257 * Step 3. Search for listening server CCB.
258 */
259 /*
260 if (!SpecialAccess)
261 {
262 */
263 /*
264 * WARNING: Point of no return! Once we get the server CCB it's
265 * possible that we completed a wait request and so we have to
266 * complete even this request.
267 */
268
269 ServerCcb = NpfsFindListeningServerInstance(Fcb);
270 if (ServerCcb == NULL)
271 {
272 PLIST_ENTRY CurrentEntry;
273 PNPFS_CCB Ccb;
274
275 /*
276 * If no waiting server CCB was found then try to pick
277 * one of the listing server CCB on the pipe.
278 */
279
280 CurrentEntry = Fcb->ServerCcbListHead.Flink;
281 while (CurrentEntry != &Fcb->ServerCcbListHead)
282 {
283 Ccb = CONTAINING_RECORD(CurrentEntry, NPFS_CCB, CcbListEntry);
284 if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
285 {
286 ServerCcb = Ccb;
287 break;
288 }
289 CurrentEntry = CurrentEntry->Flink;
290 }
291
292 /*
293 * No one is listening to me?! I'm so lonely... :(
294 */
295
296 if (ServerCcb == NULL)
297 {
298 /* Not found, bail out with error for FILE_OPEN requests. */
299 DPRINT("No listening server CCB found!\n");
300 if (ClientCcb->Data)
301 {
302 ExFreePool(ClientCcb->Data);
303 }
304
305 ExFreePool(ClientCcb);
306 KeUnlockMutex(&Fcb->CcbListLock);
307 Irp->IoStatus.Status = STATUS_OBJECT_PATH_NOT_FOUND;
308 IoCompleteRequest(Irp, IO_NO_INCREMENT);
309 return STATUS_OBJECT_PATH_NOT_FOUND;
310 }
311 }
312 else
313 {
314 /* Signal the server thread and remove it from the waiter list */
315 /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */
316 NpfsSignalAndRemoveListeningServerInstance(Fcb, ServerCcb);
317 }
318 /*
319 }
320 else if (IsListEmpty(&Fcb->ServerCcbListHead))
321 {
322 DPRINT("No server fcb found!\n");
323
324 if (ClientCcb->Data)
325 {
326 ExFreePool(ClientCcb->Data);
327 }
328
329 ExFreePool(ClientCcb);
330
331 KeUnlockMutex(&Fcb->CcbListLock);
332 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
333 IoCompleteRequest(Irp, IO_NO_INCREMENT);
334 return STATUS_UNSUCCESSFUL;
335 }
336 */
337
338 /*
339 * Step 4. Add the client CCB to a list and connect it if possible.
340 */
341
342 /* Add the client CCB to the pipe CCB list. */
343 InsertTailList(&Fcb->ClientCcbListHead, &ClientCcb->CcbListEntry);
344
345 /* Connect to listening server side */
346 if (ServerCcb)
347 {
348 ClientCcb->OtherSide = ServerCcb;
349 ServerCcb->OtherSide = ClientCcb;
350 ClientCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
351 ServerCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
352 KeSetEvent(&ServerCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
353 }
354
355 KeUnlockMutex(&Fcb->CcbListLock);
356
357 FileObject->FsContext = Fcb;
358 FileObject->FsContext2 = ClientCcb;
359 FileObject->Flags |= FO_NAMED_PIPE;
360
361 Irp->IoStatus.Status = STATUS_SUCCESS;
362 IoCompleteRequest(Irp, IO_NO_INCREMENT);
363
364 DPRINT("Success!\n");
365
366 return STATUS_SUCCESS;
367 }
368
369
370 NTSTATUS NTAPI
371 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
372 PIRP Irp)
373 {
374 PEXTENDED_IO_STACK_LOCATION IoStack;
375 PFILE_OBJECT FileObject;
376 PNPFS_VCB Vcb;
377 PNPFS_FCB Fcb;
378 PNPFS_CCB Ccb;
379 PNAMED_PIPE_CREATE_PARAMETERS Buffer;
380 BOOLEAN NewPipe = FALSE;
381
382 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
383
384 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
385 IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
386 FileObject = IoStack->FileObject;
387 DPRINT("FileObject %p\n", FileObject);
388 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
389
390 Buffer = IoStack->Parameters.CreatePipe.Parameters;
391
392 Irp->IoStatus.Information = 0;
393
394 if (!(IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE)) ||
395 (IoStack->Parameters.CreatePipe.ShareAccess & ~(FILE_SHARE_READ|FILE_SHARE_WRITE)))
396 {
397 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
398 IoCompleteRequest(Irp, IO_NO_INCREMENT);
399 return STATUS_INVALID_PARAMETER;
400 }
401
402 Ccb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
403 if (Ccb == NULL)
404 {
405 Irp->IoStatus.Status = STATUS_NO_MEMORY;
406 IoCompleteRequest(Irp, IO_NO_INCREMENT);
407 return STATUS_NO_MEMORY;
408 }
409
410 Ccb->Type = CCB_PIPE;
411 Ccb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
412 KeLockMutex(&Vcb->PipeListLock);
413
414 /*
415 * First search for existing Pipe with the same name.
416 */
417 Fcb = NpfsFindPipe(Vcb,
418 &FileObject->FileName);
419 if (Fcb != NULL)
420 {
421 /*
422 * Found Pipe with the same name. Check if we are
423 * allowed to use it.
424 */
425 KeUnlockMutex(&Vcb->PipeListLock);
426
427 if (Fcb->CurrentInstances >= Fcb->MaximumInstances)
428 {
429 DPRINT("Out of instances.\n");
430 ExFreePool(Ccb);
431 Irp->IoStatus.Status = STATUS_INSTANCE_NOT_AVAILABLE;
432 IoCompleteRequest(Irp, IO_NO_INCREMENT);
433 return STATUS_INSTANCE_NOT_AVAILABLE;
434 }
435
436 if (Fcb->MaximumInstances != Buffer->MaximumInstances ||
437 Fcb->TimeOut.QuadPart != Buffer->DefaultTimeout.QuadPart ||
438 Fcb->PipeType != Buffer->NamedPipeType)
439 {
440 DPRINT("Asked for invalid pipe mode.\n");
441 ExFreePool(Ccb);
442 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
443 IoCompleteRequest(Irp, IO_NO_INCREMENT);
444 return STATUS_ACCESS_DENIED;
445 }
446 }
447 else
448 {
449 NewPipe = TRUE;
450 Fcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
451 if (Fcb == NULL)
452 {
453 KeUnlockMutex(&Vcb->PipeListLock);
454 ExFreePool(Ccb);
455 Irp->IoStatus.Status = STATUS_NO_MEMORY;
456 Irp->IoStatus.Information = 0;
457 IoCompleteRequest(Irp, IO_NO_INCREMENT);
458 return STATUS_NO_MEMORY;
459 }
460
461 Fcb->Type = FCB_PIPE;
462 Fcb->Vcb = Vcb;
463 Fcb->PipeName.Length = FileObject->FileName.Length;
464 Fcb->PipeName.MaximumLength = Fcb->PipeName.Length + sizeof(UNICODE_NULL);
465 Fcb->PipeName.Buffer = ExAllocatePool(NonPagedPool, Fcb->PipeName.MaximumLength);
466 if (Fcb->PipeName.Buffer == NULL)
467 {
468 KeUnlockMutex(&Vcb->PipeListLock);
469 ExFreePool(Fcb);
470 ExFreePool(Ccb);
471 Irp->IoStatus.Status = STATUS_NO_MEMORY;
472 Irp->IoStatus.Information = 0;
473 IoCompleteRequest(Irp, IO_NO_INCREMENT);
474 return STATUS_NO_MEMORY;
475 }
476
477 RtlCopyUnicodeString(&Fcb->PipeName, &FileObject->FileName);
478
479 InitializeListHead(&Fcb->ServerCcbListHead);
480 InitializeListHead(&Fcb->ClientCcbListHead);
481 InitializeListHead(&Fcb->WaiterListHead);
482 KeInitializeMutex(&Fcb->CcbListLock, 0);
483
484 Fcb->PipeType = Buffer->NamedPipeType;
485 Fcb->ServerReadMode = Buffer->ReadMode;
486 /* MSDN documentation reads that clients always start off in byte mode */
487 Fcb->ClientReadMode = FILE_PIPE_BYTE_STREAM_MODE;
488
489 Fcb->CompletionMode = Buffer->CompletionMode;
490 switch (IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE))
491 {
492 case FILE_SHARE_READ:
493 Fcb->PipeConfiguration = FILE_PIPE_OUTBOUND;
494 break;
495 case FILE_SHARE_WRITE:
496 Fcb->PipeConfiguration = FILE_PIPE_INBOUND;
497 break;
498 case FILE_SHARE_READ|FILE_SHARE_WRITE:
499 Fcb->PipeConfiguration = FILE_PIPE_FULL_DUPLEX;
500 break;
501 }
502 Fcb->MaximumInstances = Buffer->MaximumInstances;
503 Fcb->CurrentInstances = 0;
504 Fcb->TimeOut = Buffer->DefaultTimeout;
505 if (!(Fcb->PipeConfiguration & FILE_PIPE_OUTBOUND) ||
506 Fcb->PipeConfiguration & FILE_PIPE_FULL_DUPLEX)
507 {
508 if (Buffer->InboundQuota == 0)
509 {
510 Fcb->InboundQuota = Vcb->DefaultQuota;
511 }
512 else
513 {
514 Fcb->InboundQuota = PAGE_ROUND_UP(Buffer->InboundQuota);
515 if (Fcb->InboundQuota < Vcb->MinQuota)
516 {
517 Fcb->InboundQuota = Vcb->MinQuota;
518 }
519 else if (Fcb->InboundQuota > Vcb->MaxQuota)
520 {
521 Fcb->InboundQuota = Vcb->MaxQuota;
522 }
523 }
524 }
525 else
526 {
527 Fcb->InboundQuota = 0;
528 }
529
530 if (Fcb->PipeConfiguration & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
531 {
532 if (Buffer->OutboundQuota == 0)
533 {
534 Fcb->OutboundQuota = Vcb->DefaultQuota;
535 }
536 else
537 {
538 Fcb->OutboundQuota = PAGE_ROUND_UP(Buffer->OutboundQuota);
539 if (Fcb->OutboundQuota < Vcb->MinQuota)
540 {
541 Fcb->OutboundQuota = Vcb->MinQuota;
542 }
543 else if (Fcb->OutboundQuota > Vcb->MaxQuota)
544 {
545 Fcb->OutboundQuota = Vcb->MaxQuota;
546 }
547 }
548 }
549 else
550 {
551 Fcb->OutboundQuota = 0;
552 }
553
554 InsertTailList(&Vcb->PipeListHead, &Fcb->PipeListEntry);
555 KeUnlockMutex(&Vcb->PipeListLock);
556 }
557
558 if (Fcb->InboundQuota)
559 {
560 Ccb->Data = ExAllocatePool(PagedPool, Fcb->InboundQuota);
561 if (Ccb->Data == NULL)
562 {
563 ExFreePool(Ccb);
564
565 if (NewPipe)
566 {
567 KeLockMutex(&Vcb->PipeListLock);
568 RemoveEntryList(&Fcb->PipeListEntry);
569 KeUnlockMutex(&Vcb->PipeListLock);
570 RtlFreeUnicodeString(&Fcb->PipeName);
571 ExFreePool(Fcb);
572 }
573
574 Irp->IoStatus.Status = STATUS_NO_MEMORY;
575 IoCompleteRequest(Irp, IO_NO_INCREMENT);
576 return STATUS_NO_MEMORY;
577 }
578 }
579 else
580 {
581 Ccb->Data = NULL;
582 }
583
584 Ccb->ReadPtr = Ccb->Data;
585 Ccb->WritePtr = Ccb->Data;
586 Ccb->ReadDataAvailable = 0;
587 Ccb->WriteQuotaAvailable = Fcb->InboundQuota;
588 Ccb->MaxDataLength = Fcb->InboundQuota;
589 InitializeListHead(&Ccb->ReadRequestListHead);
590 ExInitializeFastMutex(&Ccb->DataListLock);
591
592 Fcb->CurrentInstances++;
593
594 Ccb->Fcb = Fcb;
595 Ccb->PipeEnd = FILE_PIPE_SERVER_END;
596 Ccb->PipeState = FILE_PIPE_LISTENING_STATE;
597 Ccb->OtherSide = NULL;
598
599 DPRINT("CCB: %p\n", Ccb);
600
601 KeInitializeEvent(&Ccb->ConnectEvent, SynchronizationEvent, FALSE);
602 KeInitializeEvent(&Ccb->ReadEvent, NotificationEvent, FALSE);
603 KeInitializeEvent(&Ccb->WriteEvent, NotificationEvent, FALSE);
604
605 KeLockMutex(&Fcb->CcbListLock);
606 InsertTailList(&Fcb->ServerCcbListHead, &Ccb->CcbListEntry);
607 KeUnlockMutex(&Fcb->CcbListLock);
608
609 FileObject->FsContext = Fcb;
610 FileObject->FsContext2 = Ccb;
611 FileObject->Flags |= FO_NAMED_PIPE;
612
613 Irp->IoStatus.Status = STATUS_SUCCESS;
614 IoCompleteRequest(Irp, IO_NO_INCREMENT);
615
616 DPRINT("Success!\n");
617
618 return STATUS_SUCCESS;
619 }
620
621
622 NTSTATUS NTAPI
623 NpfsCleanup(PDEVICE_OBJECT DeviceObject,
624 PIRP Irp)
625 {
626 PNPFS_VCB Vcb;
627 PIO_STACK_LOCATION IoStack;
628 PFILE_OBJECT FileObject;
629 PNPFS_CCB Ccb, OtherSide;
630 PNPFS_FCB Fcb;
631 BOOLEAN Server;
632
633 DPRINT("NpfsCleanup(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
634
635 IoStack = IoGetCurrentIrpStackLocation(Irp);
636 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
637 FileObject = IoStack->FileObject;
638 Ccb = FileObject->FsContext2;
639
640 if (Ccb == NULL)
641 {
642 DPRINT("Success!\n");
643 Irp->IoStatus.Status = STATUS_SUCCESS;
644 Irp->IoStatus.Information = 0;
645 IoCompleteRequest(Irp, IO_NO_INCREMENT);
646 return STATUS_SUCCESS;
647 }
648
649 if (Ccb->Type == CCB_DIRECTORY)
650 {
651 DPRINT("Cleanup the root directory!\n");
652 Irp->IoStatus.Status = STATUS_SUCCESS;
653 Irp->IoStatus.Information = 0;
654 IoCompleteRequest(Irp, IO_NO_INCREMENT);
655 return STATUS_SUCCESS;
656 }
657
658 DPRINT("CCB %p\n", Ccb);
659 Fcb = Ccb->Fcb;
660
661 DPRINT("Cleaning pipe %wZ\n", &Fcb->PipeName);
662
663 KeLockMutex(&Fcb->CcbListLock);
664
665 Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
666
667 if (Server)
668 {
669 /* FIXME: Clean up existing connections here ?? */
670 DPRINT("Server\n");
671 }
672 else
673 {
674 DPRINT("Client\n");
675 }
676 if ((Ccb->PipeState == FILE_PIPE_CONNECTED_STATE) && (Ccb->OtherSide))
677 {
678 OtherSide = Ccb->OtherSide;
679 /* Lock the server first */
680 if (Server)
681 {
682 ExAcquireFastMutex(&Ccb->DataListLock);
683 ExAcquireFastMutex(&OtherSide->DataListLock);
684 }
685 else
686 {
687 ExAcquireFastMutex(&OtherSide->DataListLock);
688 ExAcquireFastMutex(&Ccb->DataListLock);
689 }
690 OtherSide->OtherSide = NULL;
691 /*
692 * Signaling the write event. If is possible that an other
693 * thread waits for an empty buffer.
694 */
695 KeSetEvent(&OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
696 KeSetEvent(&OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
697 if (Server)
698 {
699 ExReleaseFastMutex(&OtherSide->DataListLock);
700 ExReleaseFastMutex(&Ccb->DataListLock);
701 }
702 else
703 {
704 ExReleaseFastMutex(&Ccb->DataListLock);
705 ExReleaseFastMutex(&OtherSide->DataListLock);
706 }
707 }
708 else if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
709 {
710 PLIST_ENTRY Entry;
711 PNPFS_WAITER_ENTRY WaitEntry = NULL;
712 BOOLEAN Complete = FALSE;
713 KIRQL oldIrql;
714 PIRP tmpIrp;
715
716 Entry = Ccb->Fcb->WaiterListHead.Flink;
717 while (Entry != &Ccb->Fcb->WaiterListHead)
718 {
719 WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
720 if (WaitEntry->Ccb == Ccb)
721 {
722 RemoveEntryList(Entry);
723 tmpIrp = CONTAINING_RECORD(WaitEntry, IRP, Tail.Overlay.DriverContext);
724 IoAcquireCancelSpinLock(&oldIrql);
725 if (!tmpIrp->Cancel)
726 {
727 (void)IoSetCancelRoutine(tmpIrp, NULL);
728 Complete = TRUE;
729 }
730 IoReleaseCancelSpinLock(oldIrql);
731 if (Complete)
732 {
733 tmpIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
734 tmpIrp->IoStatus.Information = 0;
735 IoCompleteRequest(tmpIrp, IO_NO_INCREMENT);
736 }
737 break;
738 }
739 Entry = Entry->Flink;
740 }
741
742 }
743 Ccb->PipeState = FILE_PIPE_CLOSING_STATE;
744
745 KeUnlockMutex(&Fcb->CcbListLock);
746
747 ExAcquireFastMutex(&Ccb->DataListLock);
748 if (Ccb->Data)
749 {
750 ExFreePool(Ccb->Data);
751 Ccb->Data = NULL;
752 Ccb->ReadPtr = NULL;
753 Ccb->WritePtr = NULL;
754 }
755 ExReleaseFastMutex(&Ccb->DataListLock);
756
757 Irp->IoStatus.Status = STATUS_SUCCESS;
758 Irp->IoStatus.Information = 0;
759 IoCompleteRequest(Irp, IO_NO_INCREMENT);
760
761 DPRINT("Success!\n");
762
763 return STATUS_SUCCESS;
764 }
765
766 NTSTATUS NTAPI
767 NpfsClose(PDEVICE_OBJECT DeviceObject,
768 PIRP Irp)
769 {
770 PIO_STACK_LOCATION IoStack;
771 PFILE_OBJECT FileObject;
772 PNPFS_VCB Vcb;
773 PNPFS_FCB Fcb;
774 PNPFS_CCB Ccb;
775 BOOLEAN Server;
776
777 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
778
779 IoStack = IoGetCurrentIrpStackLocation(Irp);
780 Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension;
781 FileObject = IoStack->FileObject;
782 Ccb = FileObject->FsContext2;
783
784 if (Ccb == NULL)
785 {
786 DPRINT("Success!\n");
787 Irp->IoStatus.Status = STATUS_SUCCESS;
788 Irp->IoStatus.Information = 0;
789 IoCompleteRequest(Irp, IO_NO_INCREMENT);
790 return STATUS_SUCCESS;
791 }
792
793 if (Ccb->Type == CCB_DIRECTORY)
794 {
795 DPRINT("Closing the root directory!\n");
796
797 ExFreePool(Ccb);
798 FileObject->FsContext = NULL;
799 FileObject->FsContext2 = NULL;
800
801 Irp->IoStatus.Status = STATUS_SUCCESS;
802 Irp->IoStatus.Information = 0;
803 IoCompleteRequest(Irp, IO_NO_INCREMENT);
804 return STATUS_SUCCESS;
805 }
806
807 DPRINT("CCB %p\n", Ccb);
808 Fcb = Ccb->Fcb;
809
810 DPRINT("Closing pipe %wZ\n", &Fcb->PipeName);
811
812 KeLockMutex(&Fcb->CcbListLock);
813
814 Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
815
816 if (Server)
817 {
818 DPRINT("Server\n");
819 Fcb->CurrentInstances--;
820 }
821 else
822 {
823 DPRINT("Client\n");
824 }
825
826 /* Disconnect the pipes */
827 if (Ccb->OtherSide)
828 {
829 Ccb->OtherSide->OtherSide = NULL;
830 Ccb->OtherSide = NULL;
831 }
832
833 ASSERT(Ccb->PipeState == FILE_PIPE_CLOSING_STATE);
834
835 FileObject->FsContext2 = NULL;
836
837 RemoveEntryList(&Ccb->CcbListEntry);
838
839 ExFreePool(Ccb);
840
841 KeUnlockMutex(&Fcb->CcbListLock);
842
843 if (IsListEmpty(&Fcb->ServerCcbListHead) &&
844 IsListEmpty(&Fcb->ClientCcbListHead))
845 {
846 RtlFreeUnicodeString(&Fcb->PipeName);
847 KeLockMutex(&Vcb->PipeListLock);
848 RemoveEntryList(&Fcb->PipeListEntry);
849 KeUnlockMutex(&Vcb->PipeListLock);
850 ExFreePool(Fcb);
851 FileObject->FsContext = NULL;
852 }
853
854 Irp->IoStatus.Status = STATUS_SUCCESS;
855 Irp->IoStatus.Information = 0;
856 IoCompleteRequest(Irp, IO_NO_INCREMENT);
857
858 DPRINT("Success!\n");
859
860 return STATUS_SUCCESS;
861 }
862
863 /* EOF */