34624e79a391dbb0250be7852947ff1c3afc56cc
[reactos.git] / drivers / fs / np / create.c
1 /* $Id$
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
20 /* GLOBALS *******************************************************************/
21
22
23 /* FUNCTIONS *****************************************************************/
24
25 NTSTATUS STDCALL
26 NpfsCreate(PDEVICE_OBJECT DeviceObject,
27            PIRP Irp)
28 {
29    PIO_STACK_LOCATION IoStack;
30    PFILE_OBJECT FileObject;
31    PNPFS_PIPE Pipe;
32    PNPFS_FCB ClientFcb;
33    PNPFS_FCB ServerFcb;
34    PNPFS_PIPE current;
35    PLIST_ENTRY current_entry;
36    PNPFS_DEVICE_EXTENSION DeviceExt;
37    KIRQL oldIrql;
38    ULONG Disposition;
39    
40    DPRINT1("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
41    
42    DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
43    IoStack = IoGetCurrentIrpStackLocation(Irp);
44    FileObject = IoStack->FileObject;
45    Disposition = ((IoStack->Parameters.Create.Options >> 24) & 0xff);
46    DPRINT("FileObject %p\n", FileObject);
47    DPRINT("FileName %wZ\n", &FileObject->FileName);
48
49    ClientFcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
50    if (ClientFcb == NULL)
51      {
52         Irp->IoStatus.Status = STATUS_NO_MEMORY;
53         Irp->IoStatus.Information = 0;
54         
55         IoCompleteRequest(Irp, IO_NO_INCREMENT);
56         DPRINT("No memory!\n");
57         
58         return(STATUS_NO_MEMORY);
59      }
60    
61    KeLockMutex(&DeviceExt->PipeListLock);
62    current_entry = DeviceExt->PipeListHead.Flink;
63    while (current_entry != &DeviceExt->PipeListHead)
64      {
65         current = CONTAINING_RECORD(current_entry,
66                                     NPFS_PIPE,
67                                     PipeListEntry);
68         
69         if (RtlCompareUnicodeString(&FileObject->FileName,
70                                     &current->PipeName,
71                                     TRUE) == 0)
72           {
73              break;
74           }
75         
76         current_entry = current_entry->Flink;
77      }
78    
79    if (current_entry == &DeviceExt->PipeListHead)
80      {
81         ExFreePool(ClientFcb);
82         KeUnlockMutex(&DeviceExt->PipeListLock);
83         
84         Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
85         Irp->IoStatus.Information = 0;
86         
87         IoCompleteRequest(Irp, IO_NO_INCREMENT);
88         DPRINT("No pipe found!\n");
89         
90         return(STATUS_OBJECT_NAME_NOT_FOUND);
91      }
92    
93    Pipe = current;
94    
95    ClientFcb->Pipe = Pipe;
96    ClientFcb->PipeEnd = FILE_PIPE_CLIENT_END;
97    ClientFcb->OtherSide = NULL;
98    ClientFcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
99    
100    /* initialize data list */
101    InitializeListHead(&ClientFcb->DataListHead);
102    KeInitializeSpinLock(&ClientFcb->DataListLock);
103    
104    KeInitializeEvent(&ClientFcb->ConnectEvent,
105                      SynchronizationEvent,
106                      FALSE);
107    
108    KeInitializeEvent(&ClientFcb->ReadEvent,
109                      SynchronizationEvent,
110                      FALSE);
111    
112    KeAcquireSpinLock(&Pipe->FcbListLock, &oldIrql);
113    InsertTailList(&Pipe->ClientFcbListHead, &ClientFcb->FcbListEntry);
114    KeReleaseSpinLock(&Pipe->FcbListLock, oldIrql);
115    
116    Pipe->ReferenceCount++;
117    
118    KeUnlockMutex(&DeviceExt->PipeListLock);
119
120 #if 0
121   if (Disposition == OPEN_EXISTING)
122     {
123       /* do not connect to listening servers */
124       FileObject->FsContext = ClientFcb;
125
126       Irp->IoStatus.Status = STATUS_SUCCESS;
127       Irp->IoStatus.Information = 0;
128
129       IoCompleteRequest(Irp, IO_NO_INCREMENT);
130       DPRINT("Success!\n");
131
132       return(STATUS_SUCCESS);
133     }
134 #endif
135
136    /* search for disconnected or listening server fcb */
137    current_entry = Pipe->ServerFcbListHead.Flink;
138    while (current_entry != &Pipe->ServerFcbListHead)
139      {
140         ServerFcb = CONTAINING_RECORD(current_entry,
141                                       NPFS_FCB,
142                                       FcbListEntry);
143         if ((ServerFcb->PipeState == FILE_PIPE_LISTENING_STATE)
144             || (ServerFcb->PipeState == FILE_PIPE_DISCONNECTED_STATE))
145           {
146              DPRINT("Server found! Fcb %p\n", ServerFcb);
147              break;
148           }
149         current_entry = current_entry->Flink;
150      }
151    
152    if (current_entry == &Pipe->ServerFcbListHead)
153      {
154         DPRINT("No server fcb found!\n");
155
156         FileObject->FsContext = ClientFcb;
157
158         Irp->IoStatus.Status = STATUS_SUCCESS;
159         Irp->IoStatus.Information = 0;
160
161         IoCompleteRequest(Irp, IO_NO_INCREMENT);
162
163         return(STATUS_SUCCESS);
164      }
165    
166    ClientFcb->OtherSide = ServerFcb;
167    ServerFcb->OtherSide = ClientFcb;
168    ClientFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
169    ServerFcb->PipeState = FILE_PIPE_CONNECTED_STATE;
170    
171    /* FIXME: create data queue(s) */
172    
173    /* wake server thread */
174    KeSetEvent(&ServerFcb->ConnectEvent, 0, FALSE);
175    
176    FileObject->FsContext = ClientFcb;
177    
178    Irp->IoStatus.Status = STATUS_SUCCESS;
179    Irp->IoStatus.Information = 0;
180    
181    IoCompleteRequest(Irp, IO_NO_INCREMENT);
182    DPRINT("Success!\n");
183    
184    return(STATUS_SUCCESS);
185 }
186
187
188 NTSTATUS STDCALL
189 NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
190                     PIRP Irp)
191 {
192    PIO_STACK_LOCATION IoStack;
193    PFILE_OBJECT FileObject;
194    PNPFS_DEVICE_EXTENSION DeviceExt;
195    PNPFS_PIPE Pipe;
196    PNPFS_FCB Fcb;
197    KIRQL oldIrql;
198    PLIST_ENTRY current_entry;
199    PNPFS_PIPE current;
200    PIO_PIPE_CREATE_BUFFER Buffer;
201    
202    DPRINT1("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
203    
204    DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
205    IoStack = IoGetCurrentIrpStackLocation(Irp);
206    FileObject = IoStack->FileObject;
207    DPRINT("FileObject %p\n", FileObject);
208    DPRINT("Pipe name %wZ\n", &FileObject->FileName);
209    
210    Buffer = (PIO_PIPE_CREATE_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
211    
212    Pipe = ExAllocatePool(NonPagedPool, sizeof(NPFS_PIPE));
213    if (Pipe == NULL)
214      {
215         Irp->IoStatus.Status = STATUS_NO_MEMORY;
216         Irp->IoStatus.Information = 0;
217         
218         IoCompleteRequest(Irp, IO_NO_INCREMENT);
219         
220         return(STATUS_NO_MEMORY);
221      }
222    
223    Fcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_FCB));
224    if (Fcb == NULL)
225      {
226         ExFreePool(Pipe);
227         
228         Irp->IoStatus.Status = STATUS_NO_MEMORY;
229         Irp->IoStatus.Information = 0;
230         
231         IoCompleteRequest(Irp, IO_NO_INCREMENT);
232         
233         return(STATUS_NO_MEMORY);
234      }
235    
236    if (RtlCreateUnicodeString(&Pipe->PipeName, FileObject->FileName.Buffer) == 0)
237      {
238         ExFreePool(Pipe);
239         ExFreePool(Fcb);
240         
241         Irp->IoStatus.Status = STATUS_NO_MEMORY;
242         Irp->IoStatus.Information = 0;
243         
244         IoCompleteRequest(Irp, IO_NO_INCREMENT);
245
246         return(STATUS_NO_MEMORY);
247      }
248    
249    Pipe->ReferenceCount = 0;
250    InitializeListHead(&Pipe->ServerFcbListHead);
251    InitializeListHead(&Pipe->ClientFcbListHead);
252    KeInitializeSpinLock(&Pipe->FcbListLock);
253
254    Pipe->PipeType = Buffer->WriteModeMessage ? FILE_PIPE_MESSAGE_TYPE : FILE_PIPE_BYTE_STREAM_TYPE;
255    Pipe->PipeWriteMode = Buffer->WriteModeMessage ? FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
256    Pipe->PipeReadMode = Buffer->ReadModeMessage ? FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
257    Pipe->PipeBlockMode = Buffer->NonBlocking;
258    Pipe->PipeConfiguration = IoStack->Parameters.Create.Options & 0x3;
259    Pipe->MaximumInstances = Buffer->MaxInstances;
260    Pipe->CurrentInstances = 0;
261    Pipe->TimeOut = Buffer->TimeOut;
262    Pipe->InboundQuota = Buffer->InBufferSize;
263    Pipe->OutboundQuota = Buffer->OutBufferSize;
264    
265    KeLockMutex(&DeviceExt->PipeListLock);
266    current_entry = DeviceExt->PipeListHead.Flink;
267    while (current_entry != &DeviceExt->PipeListHead)
268      {
269         current = CONTAINING_RECORD(current_entry,
270                                     NPFS_PIPE,
271                                     PipeListEntry);
272         
273         if (RtlCompareUnicodeString(&Pipe->PipeName, &current->PipeName, TRUE) == 0)
274           {
275              break;
276           }
277         
278         current_entry = current_entry->Flink;
279      }
280    
281    if (current_entry != &DeviceExt->PipeListHead)
282      {
283         RtlFreeUnicodeString(&Pipe->PipeName);
284         ExFreePool(Pipe);
285         
286         Pipe = current;
287      }
288    else
289      {
290         InsertTailList(&DeviceExt->PipeListHead, &Pipe->PipeListEntry);
291      }
292    Pipe->ReferenceCount++;
293    Pipe->CurrentInstances++;
294    
295    KeAcquireSpinLock(&Pipe->FcbListLock, &oldIrql);
296    InsertTailList(&Pipe->ServerFcbListHead, &Fcb->FcbListEntry);
297    KeReleaseSpinLock(&Pipe->FcbListLock, oldIrql);
298    
299    Fcb->Pipe = Pipe;
300    Fcb->PipeEnd = FILE_PIPE_SERVER_END;
301    Fcb->OtherSide = NULL;
302    Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
303    Fcb->ReadDataAvailable = 0;
304    Fcb->WriteQuotaAvailable = 0;
305
306    /* initialize data list */
307    InitializeListHead(&Fcb->DataListHead);
308    KeInitializeSpinLock(&Fcb->DataListLock);
309
310    KeInitializeEvent(&Fcb->ConnectEvent,
311                      SynchronizationEvent,
312                      FALSE);
313    
314    KeInitializeEvent(&Fcb->ReadEvent,
315                      SynchronizationEvent,
316                      FALSE);
317
318
319    KeUnlockMutex(&DeviceExt->PipeListLock);
320    
321    FileObject->FsContext = Fcb;
322    
323    Irp->IoStatus.Status = STATUS_SUCCESS;
324    Irp->IoStatus.Information = 0;
325    
326    IoCompleteRequest(Irp, IO_NO_INCREMENT);
327    
328    return(STATUS_SUCCESS);
329 }
330
331
332 NTSTATUS STDCALL
333 NpfsClose(PDEVICE_OBJECT DeviceObject,
334           PIRP Irp)
335 {
336   PNPFS_DEVICE_EXTENSION DeviceExt;
337   PIO_STACK_LOCATION IoStack;
338   PFILE_OBJECT FileObject;
339   PNPFS_FCB Fcb;
340   PNPFS_PIPE Pipe;
341   KIRQL oldIrql;
342   PLIST_ENTRY CurrentEntry;
343   PNPFS_PIPE_DATA Current;
344
345
346   DPRINT1("NpfsClose(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
347
348   IoStack = IoGetCurrentIrpStackLocation(Irp);
349   DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
350   FileObject = IoStack->FileObject;
351   Fcb =  FileObject->FsContext;
352
353   if (Fcb == NULL)
354     {
355       Irp->IoStatus.Status = STATUS_SUCCESS;
356       Irp->IoStatus.Information = 0;
357
358       IoCompleteRequest(Irp, IO_NO_INCREMENT);
359
360       return(STATUS_SUCCESS);
361     }
362
363   DPRINT("Fcb %x\n", Fcb);
364   Pipe = Fcb->Pipe;
365
366   DPRINT("Closing pipe %wZ\n", &Pipe->PipeName);
367
368   KeLockMutex(&DeviceExt->PipeListLock);
369
370
371    if (Fcb->PipeEnd == FILE_PIPE_SERVER_END)
372     {
373       /* FIXME: Clean up existing connections here ?? */
374       DPRINT("Server\n");
375       Pipe->CurrentInstances--;
376       if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
377       {
378            if (Fcb->OtherSide)
379            {
380               Fcb->OtherSide->PipeState = FILE_PIPE_CLOSING_STATE;
381            }
382            Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
383       }
384     }
385   Pipe->ReferenceCount--;
386
387   if (Fcb->PipeEnd == FILE_PIPE_CLIENT_END)
388   {
389       DPRINT("Client\n");
390       if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
391       {
392          if (Fcb->OtherSide)
393          {
394             Fcb->OtherSide->PipeState = FILE_PIPE_CLOSING_STATE;
395
396             /* Signaling the read event. If is possible that an other
397              * thread waits of read data.
398              */
399             KeSetEvent(&Fcb->OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
400          }
401          Fcb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
402       }
403   }
404   
405   FileObject->FsContext = NULL;
406
407   if (Pipe->ReferenceCount == 0)
408     {
409       KeAcquireSpinLock(&Pipe->FcbListLock, &oldIrql);
410       if (Fcb->OtherSide)
411       {
412          RemoveEntryList(&Fcb->OtherSide->FcbListEntry);
413       }
414       RemoveEntryList(&Fcb->FcbListEntry);
415       KeReleaseSpinLock(&Pipe->FcbListLock, oldIrql);
416       if (Fcb->OtherSide)
417       {  
418          KeAcquireSpinLock(&Fcb->OtherSide->DataListLock, &oldIrql);
419          while (!IsListEmpty(&Fcb->OtherSide->DataListHead))
420          {
421              CurrentEntry = RemoveHeadList(&Fcb->OtherSide->DataListHead);
422              Current = CONTAINING_RECORD(CurrentEntry, NPFS_PIPE_DATA, ListEntry);
423
424              NpfsFreePipeData(Current);
425          }
426          KeReleaseSpinLock(&Fcb->OtherSide->DataListLock, oldIrql);
427          ExFreePool(Fcb->OtherSide);
428       }
429
430       KeAcquireSpinLock(&Fcb->DataListLock, &oldIrql);
431       while (!IsListEmpty(&Fcb->DataListHead))
432       {
433          CurrentEntry = RemoveHeadList(&Fcb->DataListHead);
434          Current = CONTAINING_RECORD(CurrentEntry, NPFS_PIPE_DATA, ListEntry);
435          NpfsFreePipeData(Current);
436       }
437       KeReleaseSpinLock(&Fcb->DataListLock, oldIrql);
438       ExFreePool(Fcb);
439       RtlFreeUnicodeString(&Pipe->PipeName);
440       RemoveEntryList(&Pipe->PipeListEntry);
441       ExFreePool(Pipe);
442     }
443
444   KeUnlockMutex(&DeviceExt->PipeListLock);
445
446   Irp->IoStatus.Status = STATUS_SUCCESS;
447   Irp->IoStatus.Information = 0;
448
449   IoCompleteRequest(Irp, IO_NO_INCREMENT);
450
451   return(STATUS_SUCCESS);
452 }
453
454 /* EOF */