New ReactOS icon by Mindflyer. Just give ros a fresh look :)
[reactos.git] / reactos / drivers / fs / np / create.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: drivers/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->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
161 ClientFcb->Pipe = Pipe;
162 ClientFcb->PipeEnd = FILE_PIPE_CLIENT_END;
163 ClientFcb->OtherSide = NULL;
164 ClientFcb->PipeState = SpecialAccess ? 0 : FILE_PIPE_DISCONNECTED_STATE;
165
166 /* Initialize data list. */
167 if (Pipe->OutboundQuota)
168 {
169 ClientFcb->Data = ExAllocatePool(NonPagedPool, Pipe->OutboundQuota);
170 if (ClientFcb->Data == NULL)
171 {
172 DPRINT("No memory!\n");
173 ExFreePool(ClientFcb);
174 KeUnlockMutex(&Pipe->FcbListLock);
175 Irp->IoStatus.Status = STATUS_NO_MEMORY;
176 IoCompleteRequest(Irp, IO_NO_INCREMENT);
177 return STATUS_NO_MEMORY;
178 }
179 }
180 else
181 {
182 ClientFcb->Data = NULL;
183 }
184
185 ClientFcb->ReadPtr = ClientFcb->Data;
186 ClientFcb->WritePtr = ClientFcb->Data;
187 ClientFcb->ReadDataAvailable = 0;
188 ClientFcb->WriteQuotaAvailable = Pipe->OutboundQuota;
189 ClientFcb->MaxDataLength = Pipe->OutboundQuota;
190 KeInitializeSpinLock(&ClientFcb->DataListLock);
191 KeInitializeEvent(&ClientFcb->ConnectEvent, SynchronizationEvent, FALSE);
192 KeInitializeEvent(&ClientFcb->Event, SynchronizationEvent, FALSE);
193
194 /*
195 * Step 4. Add the client FCB to a list and connect it if possible.
196 */
197
198 /* Add the client FCB to the pipe FCB list. */
199 InsertTailList(&Pipe->ClientFcbListHead, &ClientFcb->FcbListEntry);
200
201 /* Connect to listening server side */
202 if (ServerFcb)
203 {
204 ClientFcb->OtherSide = ServerFcb;
205 ServerFcb->OtherSide = ClientFcb;
206 ClientFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
207 ServerFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
208
209 /* Wake server thread */
210 DPRINT("Setting the ConnectEvent for %x\n", ServerFcb);
211 KeSetEvent(&ServerFcb->ConnectEvent, 0, FALSE);
212 }
213
214 KeUnlockMutex(&Pipe->FcbListLock);
215
216 FileObject->FsContext = ClientFcb;
217
218 Irp->IoStatus.Status = STATUS_SUCCESS;
219 IoCompleteRequest(Irp, IO_NO_INCREMENT);
220
221 DPRINT("Success!\n");
222
223 return STATUS_SUCCESS;
224 }
225
226
227 NTSTATUS STDCALL
228 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
229 PIRP Irp)
230 {
231 PIO_STACK_LOCATION IoStack;
232 PFILE_OBJECT FileObject;
233 PNPFS_DEVICE_EXTENSION DeviceExt;
234 PNPFS_PIPE Pipe;
235 PNPFS_FCB Fcb;
236 PNAMED_PIPE_CREATE_PARAMETERS Buffer;
237 BOOLEAN NewPipe = FALSE;
238
239 DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
240
241 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
242 IoStack = IoGetCurrentIrpStackLocation(Irp);
243 FileObject = IoStack->FileObject;
244 DPRINT("FileObject %p\n", FileObject);
245 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
246
247 Buffer = IoStack->Parameters.CreatePipe.Parameters;
248
249 Irp->IoStatus.Information = 0;
250
251 Fcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
252 if (Fcb == NULL)
253 {
254 Irp->IoStatus.Status = STATUS_NO_MEMORY;
255 IoCompleteRequest(Irp, IO_NO_INCREMENT);
256 return STATUS_NO_MEMORY;
257 }
258
259 Fcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
260 KeLockMutex(&DeviceExt->PipeListLock);
261
262 /*
263 * First search for existing Pipe with the same name.
264 */
265 Pipe = NpfsFindPipe(DeviceExt,
266 &FileObject->FileName);
267 if (Pipe != NULL)
268 {
269 /*
270 * Found Pipe with the same name. Check if we are
271 * allowed to use it.
272 */
273 KeUnlockMutex(&DeviceExt->PipeListLock);
274
275 if (Pipe->CurrentInstances >= Pipe->MaximumInstances)
276 {
277 DPRINT("Out of instances.\n");
278 ExFreePool(Fcb);
279 Irp->IoStatus.Status = STATUS_PIPE_BUSY;
280 IoCompleteRequest(Irp, IO_NO_INCREMENT);
281 return STATUS_PIPE_BUSY;
282 }
283
284 /* FIXME: Check pipe modes also! */
285 if (Pipe->MaximumInstances != Buffer->MaximumInstances ||
286 Pipe->TimeOut.QuadPart != Buffer->DefaultTimeout.QuadPart)
287 {
288 DPRINT("Asked for invalid pipe mode.\n");
289 ExFreePool(Fcb);
290 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
291 IoCompleteRequest(Irp, IO_NO_INCREMENT);
292 return STATUS_ACCESS_DENIED;
293 }
294 }
295 else
296 {
297 NewPipe = TRUE;
298 Pipe = ExAllocatePool(NonPagedPool, sizeof(NPFS_PIPE));
299 if (Pipe == NULL)
300 {
301 KeUnlockMutex(&DeviceExt->PipeListLock);
302 Irp->IoStatus.Status = STATUS_NO_MEMORY;
303 Irp->IoStatus.Information = 0;
304 IoCompleteRequest(Irp, IO_NO_INCREMENT);
305 return STATUS_NO_MEMORY;
306 }
307
308 if (RtlCreateUnicodeString(&Pipe->PipeName, FileObject->FileName.Buffer) == FALSE)
309 {
310 KeUnlockMutex(&DeviceExt->PipeListLock);
311 ExFreePool(Pipe);
312 ExFreePool(Fcb);
313 Irp->IoStatus.Status = STATUS_NO_MEMORY;
314 Irp->IoStatus.Information = 0;
315 IoCompleteRequest(Irp, IO_NO_INCREMENT);
316 return STATUS_NO_MEMORY;
317 }
318
319 InitializeListHead(&Pipe->ServerFcbListHead);
320 InitializeListHead(&Pipe->ClientFcbListHead);
321 KeInitializeMutex(&Pipe->FcbListLock, 0);
322
323 Pipe->PipeType = Buffer->NamedPipeType;
324 Pipe->WriteMode = Buffer->ReadMode;
325 Pipe->ReadMode = Buffer->ReadMode;
326 Pipe->CompletionMode = Buffer->CompletionMode;
327 Pipe->PipeConfiguration = IoStack->Parameters.CreatePipe.Options & 0x3;
328 Pipe->MaximumInstances = Buffer->MaximumInstances;
329 Pipe->CurrentInstances = 0;
330 Pipe->TimeOut = Buffer->DefaultTimeout;
331 if (!(IoStack->Parameters.Create.Options & FILE_PIPE_OUTBOUND) ||
332 IoStack->Parameters.Create.Options & FILE_PIPE_FULL_DUPLEX)
333 {
334 if (Buffer->InboundQuota == 0)
335 {
336 Pipe->InboundQuota = DeviceExt->DefaultQuota;
337 }
338 else
339 {
340 Pipe->InboundQuota = PAGE_ROUND_UP(Buffer->InboundQuota);
341 if (Pipe->InboundQuota < DeviceExt->MinQuota)
342 {
343 Pipe->InboundQuota = DeviceExt->MinQuota;
344 }
345 else if (Pipe->InboundQuota > DeviceExt->MaxQuota)
346 {
347 Pipe->InboundQuota = DeviceExt->MaxQuota;
348 }
349 }
350 }
351 else
352 {
353 Pipe->InboundQuota = 0;
354 }
355
356 if (IoStack->Parameters.Create.Options & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND))
357 {
358 if (Buffer->OutboundQuota == 0)
359 {
360 Pipe->OutboundQuota = DeviceExt->DefaultQuota;
361 }
362 else
363 {
364 Pipe->OutboundQuota = PAGE_ROUND_UP(Buffer->OutboundQuota);
365 if (Pipe->OutboundQuota < DeviceExt->MinQuota)
366 {
367 Pipe->OutboundQuota = DeviceExt->MinQuota;
368 }
369 else if (Pipe->OutboundQuota > DeviceExt->MaxQuota)
370 {
371 Pipe->OutboundQuota = DeviceExt->MaxQuota;
372 }
373 }
374 }
375 else
376 {
377 Pipe->OutboundQuota = 0;
378 }
379
380 InsertTailList(&DeviceExt->PipeListHead, &Pipe->PipeListEntry);
381 KeUnlockMutex(&DeviceExt->PipeListLock);
382 }
383
384 if (Pipe->InboundQuota)
385 {
386 Fcb->Data = ExAllocatePool(NonPagedPool, Pipe->InboundQuota);
387 if (Fcb->Data == NULL)
388 {
389 ExFreePool(Fcb);
390
391 if (NewPipe)
392 {
393 RtlFreeUnicodeString(&Pipe->PipeName);
394 ExFreePool(Pipe);
395 }
396
397 Irp->IoStatus.Status = STATUS_NO_MEMORY;
398 IoCompleteRequest(Irp, IO_NO_INCREMENT);
399 return STATUS_NO_MEMORY;
400 }
401 }
402 else
403 {
404 Fcb->Data = NULL;
405 }
406
407 Fcb->ReadPtr = Fcb->Data;
408 Fcb->WritePtr = Fcb->Data;
409 Fcb->ReadDataAvailable = 0;
410 Fcb->WriteQuotaAvailable = Pipe->InboundQuota;
411 Fcb->MaxDataLength = Pipe->InboundQuota;
412 KeInitializeSpinLock(&Fcb->DataListLock);
413
414 Pipe->CurrentInstances++;
415
416 KeLockMutex(&Pipe->FcbListLock);
417 InsertTailList(&Pipe->ServerFcbListHead, &Fcb->FcbListEntry);
418 KeUnlockMutex(&Pipe->FcbListLock);
419
420 Fcb->Pipe = Pipe;
421 Fcb->PipeEnd = FILE_PIPE_SERVER_END;
422 Fcb->PipeState = FILE_PIPE_LISTENING_STATE;
423 Fcb->OtherSide = NULL;
424
425 KeInitializeEvent(&Fcb->ConnectEvent,
426 SynchronizationEvent,
427 FALSE);
428
429 KeInitializeEvent(&Fcb->Event,
430 SynchronizationEvent,
431 FALSE);
432
433 FileObject->FsContext = Fcb;
434
435 Irp->IoStatus.Status = STATUS_SUCCESS;
436 IoCompleteRequest(Irp, IO_NO_INCREMENT);
437
438 DPRINT("Success!\n");
439
440 return STATUS_SUCCESS;
441 }
442
443
444 NTSTATUS STDCALL
445 NpfsClose(PDEVICE_OBJECT DeviceObject,
446 PIRP Irp)
447 {
448 PNPFS_DEVICE_EXTENSION DeviceExt;
449 PIO_STACK_LOCATION IoStack;
450 PFILE_OBJECT FileObject;
451 PNPFS_FCB Fcb;
452 PNPFS_PIPE Pipe;
453 BOOL Server;
454
455 DPRINT("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
456
457 IoStack = IoGetCurrentIrpStackLocation(Irp);
458 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
459 FileObject = IoStack->FileObject;
460 Fcb = FileObject->FsContext;
461
462 if (Fcb == NULL)
463 {
464 DPRINT("Success!\n");
465 Irp->IoStatus.Status = STATUS_SUCCESS;
466 Irp->IoStatus.Information = 0;
467 IoCompleteRequest(Irp, IO_NO_INCREMENT);
468 return STATUS_SUCCESS;
469 }
470
471 DPRINT("Fcb %x\n", Fcb);
472 Pipe = Fcb->Pipe;
473
474 DPRINT("Closing pipe %wZ\n", &Pipe->PipeName);
475
476 KeLockMutex(&Pipe->FcbListLock);
477
478 Server = (Fcb->PipeEnd == FILE_PIPE_SERVER_END);
479
480 if (Server)
481 {
482 /* FIXME: Clean up existing connections here ?? */
483 DPRINT("Server\n");
484 Pipe->CurrentInstances--;
485 }
486 else
487 {
488 DPRINT("Client\n");
489 }
490
491 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
492 {
493 if (Fcb->OtherSide)
494 {
495 Fcb->OtherSide->PipeState = FILE_PIPE_CLOSING_STATE;
496 Fcb->OtherSide->OtherSide = NULL;
497 /*
498 * Signaling the write event. If is possible that an other
499 * thread waits for an empty buffer.
500 */
501 KeSetEvent(&Fcb->OtherSide->Event, IO_NO_INCREMENT, FALSE);
502 }
503
504 Fcb->PipeState = 0;
505 }
506
507 FileObject->FsContext = NULL;
508
509 RemoveEntryList(&Fcb->FcbListEntry);
510 if (Fcb->Data)
511 ExFreePool(Fcb->Data);
512 ExFreePool(Fcb);
513
514 KeUnlockMutex(&Pipe->FcbListLock);
515
516 if (IsListEmpty(&Pipe->ServerFcbListHead) &&
517 IsListEmpty(&Pipe->ClientFcbListHead))
518 {
519 RtlFreeUnicodeString(&Pipe->PipeName);
520 KeLockMutex(&DeviceExt->PipeListLock);
521 RemoveEntryList(&Pipe->PipeListEntry);
522 KeUnlockMutex(&DeviceExt->PipeListLock);
523 ExFreePool(Pipe);
524 }
525
526 Irp->IoStatus.Status = STATUS_SUCCESS;
527 Irp->IoStatus.Information = 0;
528 IoCompleteRequest(Irp, IO_NO_INCREMENT);
529
530 DPRINT("Success!\n");
531
532 return STATUS_SUCCESS;
533 }
534
535 /* EOF */