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