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