sync shlwapi with wine 1.1.13
[reactos.git] / reactos / drivers / filesystems / npfs / fsctrl.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/np/fsctrl.c
5 * PURPOSE: Named pipe filesystem
6 * PROGRAMMER: David Welch <welch@cwcom.net>
7 * Eric Kohl
8 * Michael Martin
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include "npfs.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* FUNCTIONS *****************************************************************/
19
20 static DRIVER_CANCEL NpfsListeningCancelRoutine;
21 static VOID NTAPI
22 NpfsListeningCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
23 IN PIRP Irp)
24 {
25 PNPFS_WAITER_ENTRY Waiter;
26
27 Waiter = (PNPFS_WAITER_ENTRY)&Irp->Tail.Overlay.DriverContext;
28
29 DPRINT("NpfsListeningCancelRoutine() called for <%wZ>\n",
30 &Waiter->Ccb->Fcb->PipeName);
31
32 IoReleaseCancelSpinLock(Irp->CancelIrql);
33
34
35 KeLockMutex(&Waiter->Ccb->Fcb->CcbListLock);
36 RemoveEntryList(&Waiter->Entry);
37 KeUnlockMutex(&Waiter->Ccb->Fcb->CcbListLock);
38
39 Irp->IoStatus.Status = STATUS_CANCELLED;
40 Irp->IoStatus.Information = 0;
41 IoCompleteRequest(Irp, IO_NO_INCREMENT);
42 }
43
44
45 static NTSTATUS
46 NpfsAddListeningServerInstance(PIRP Irp,
47 PNPFS_CCB Ccb)
48 {
49 PNPFS_WAITER_ENTRY Entry;
50 KIRQL oldIrql;
51
52 Entry = (PNPFS_WAITER_ENTRY)&Irp->Tail.Overlay.DriverContext;
53
54 Entry->Ccb = Ccb;
55
56 KeLockMutex(&Ccb->Fcb->CcbListLock);
57
58 IoMarkIrpPending(Irp);
59 InsertTailList(&Ccb->Fcb->WaiterListHead, &Entry->Entry);
60
61 IoAcquireCancelSpinLock(&oldIrql);
62 if (!Irp->Cancel)
63 {
64 (void)IoSetCancelRoutine(Irp, NpfsListeningCancelRoutine);
65 IoReleaseCancelSpinLock(oldIrql);
66 KeUnlockMutex(&Ccb->Fcb->CcbListLock);
67 return STATUS_PENDING;
68 }
69 IoReleaseCancelSpinLock(oldIrql);
70
71 RemoveEntryList(&Entry->Entry);
72
73 Irp->IoStatus.Status = STATUS_CANCELLED;
74 Irp->IoStatus.Information = 0;
75 IoCompleteRequest(Irp, IO_NO_INCREMENT);
76 KeUnlockMutex(&Ccb->Fcb->CcbListLock);
77
78 return STATUS_CANCELLED;
79 }
80
81
82 static NTSTATUS
83 NpfsConnectPipe(PIRP Irp,
84 PNPFS_CCB Ccb)
85 {
86 PIO_STACK_LOCATION IoStack;
87 PFILE_OBJECT FileObject;
88 ULONG Flags;
89 PLIST_ENTRY current_entry;
90 PNPFS_FCB Fcb;
91 PNPFS_CCB ClientCcb;
92 NTSTATUS Status;
93
94 DPRINT("NpfsConnectPipe()\n");
95
96 if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
97 {
98 KeResetEvent(&Ccb->ConnectEvent);
99 return STATUS_PIPE_CONNECTED;
100 }
101
102 if (Ccb->PipeState == FILE_PIPE_CLOSING_STATE)
103 return STATUS_PIPE_CLOSING;
104
105 DPRINT("Waiting for connection...\n");
106
107 Fcb = Ccb->Fcb;
108 IoStack = IoGetCurrentIrpStackLocation(Irp);
109 FileObject = IoStack->FileObject;
110 Flags = FileObject->Flags;
111
112 /* search for a listening client fcb */
113 KeLockMutex(&Fcb->CcbListLock);
114
115 current_entry = Fcb->ClientCcbListHead.Flink;
116 while (current_entry != &Fcb->ClientCcbListHead)
117 {
118 ClientCcb = CONTAINING_RECORD(current_entry,
119 NPFS_CCB,
120 CcbListEntry);
121
122 if (ClientCcb->PipeState == 0)
123 {
124 /* found a passive (waiting) client CCB */
125 DPRINT("Passive (waiting) client CCB found -- wake the client\n");
126 KeSetEvent(&ClientCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
127 break;
128 }
129
130 #if 0
131 if (ClientCcb->PipeState == FILE_PIPE_LISTENING_STATE)
132 {
133 /* found a listening client CCB */
134 DPRINT("Listening client CCB found -- connecting\n");
135
136 /* connect client and server CCBs */
137 Ccb->OtherSide = ClientCcb;
138 ClientCcb->OtherSide = Ccb;
139
140 /* set connected state */
141 Ccb->PipeState = FILE_PIPE_CONNECTED_STATE;
142 ClientCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
143
144 KeUnlockMutex(&Fcb->CcbListLock);
145
146 /* FIXME: create and initialize data queues */
147
148 /* signal client's connect event */
149 DPRINT("Setting the ConnectEvent for %x\n", ClientCcb);
150 KeSetEvent(&ClientCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
151
152 return STATUS_PIPE_CONNECTED;
153 }
154 #endif
155
156 current_entry = current_entry->Flink;
157 }
158
159 /* no listening client fcb found */
160 DPRINT("No listening client fcb found -- waiting for client\n");
161
162 Ccb->PipeState = FILE_PIPE_LISTENING_STATE;
163
164 Status = NpfsAddListeningServerInstance(Irp, Ccb);
165
166 KeUnlockMutex(&Fcb->CcbListLock);
167
168 if (Flags & FO_SYNCHRONOUS_IO)
169 {
170 KeWaitForSingleObject(&Ccb->ConnectEvent,
171 UserRequest,
172 Irp->RequestorMode,
173 FALSE,
174 NULL);
175 }
176
177 DPRINT("NpfsConnectPipe() done (Status %lx)\n", Status);
178
179 return Status;
180 }
181
182
183 static NTSTATUS
184 NpfsDisconnectPipe(PNPFS_CCB Ccb)
185 {
186 NTSTATUS Status;
187 PNPFS_FCB Fcb;
188 PNPFS_CCB OtherSide;
189 BOOLEAN Server;
190
191 DPRINT("NpfsDisconnectPipe()\n");
192
193 Fcb = Ccb->Fcb;
194 KeLockMutex(&Fcb->CcbListLock);
195
196 if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
197 {
198 DPRINT("Pipe is already disconnected\n");
199 Status = STATUS_SUCCESS;
200 }
201 else if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
202 {
203 Server = (Ccb->PipeEnd == FILE_PIPE_SERVER_END);
204 OtherSide = Ccb->OtherSide;
205 //Ccb->OtherSide = NULL;
206 Ccb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
207 /* Lock the server first */
208 if (Server)
209 {
210 ExAcquireFastMutex(&Ccb->DataListLock);
211 ExAcquireFastMutex(&OtherSide->DataListLock);
212 }
213 else
214 {
215 ExAcquireFastMutex(&OtherSide->DataListLock);
216 ExAcquireFastMutex(&Ccb->DataListLock);
217 }
218 OtherSide->PipeState = FILE_PIPE_DISCONNECTED_STATE;
219 //OtherSide->OtherSide = NULL;
220 /*
221 * Signaling the write event. If is possible that an other
222 * thread waits for an empty buffer.
223 */
224 KeSetEvent(&OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
225 KeSetEvent(&OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
226 if (Server)
227 {
228 ExReleaseFastMutex(&OtherSide->DataListLock);
229 ExReleaseFastMutex(&Ccb->DataListLock);
230 }
231 else
232 {
233 ExReleaseFastMutex(&Ccb->DataListLock);
234 ExReleaseFastMutex(&OtherSide->DataListLock);
235 }
236 Status = STATUS_SUCCESS;
237 }
238 else if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
239 {
240 PLIST_ENTRY Entry;
241 PNPFS_WAITER_ENTRY WaitEntry = NULL;
242 BOOLEAN Complete = FALSE;
243 PIRP Irp = NULL;
244
245 Entry = Ccb->Fcb->WaiterListHead.Flink;
246 while (Entry != &Ccb->Fcb->WaiterListHead)
247 {
248 WaitEntry = CONTAINING_RECORD(Entry, NPFS_WAITER_ENTRY, Entry);
249 if (WaitEntry->Ccb == Ccb)
250 {
251 RemoveEntryList(Entry);
252 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DriverContext);
253 Complete = (NULL == IoSetCancelRoutine(Irp, NULL));
254 break;
255 }
256 Entry = Entry->Flink;
257 }
258
259 if (Irp)
260 {
261 if (Complete)
262 {
263 Irp->IoStatus.Status = STATUS_PIPE_BROKEN;
264 Irp->IoStatus.Information = 0;
265 IoCompleteRequest(Irp, IO_NO_INCREMENT);
266 }
267 }
268 Ccb->PipeState = FILE_PIPE_DISCONNECTED_STATE;
269 Status = STATUS_SUCCESS;
270 }
271 else if (Ccb->PipeState == FILE_PIPE_CLOSING_STATE)
272 {
273 Status = STATUS_PIPE_CLOSING;
274 }
275 else
276 {
277 Status = STATUS_UNSUCCESSFUL;
278 }
279 KeUnlockMutex(&Fcb->CcbListLock);
280 return Status;
281 }
282
283
284 static NTSTATUS
285 NpfsWaitPipe(PIRP Irp,
286 PNPFS_CCB Ccb)
287 {
288 PLIST_ENTRY current_entry;
289 PNPFS_FCB Fcb;
290 PNPFS_CCB ServerCcb;
291 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe;
292 NTSTATUS Status;
293 LARGE_INTEGER TimeOut;
294
295 DPRINT("NpfsWaitPipe\n");
296
297 WaitPipe = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
298 Fcb = Ccb->Fcb;
299
300 if (Ccb->PipeState != 0)
301 {
302 DPRINT("Pipe is not in passive (waiting) state!\n");
303 return STATUS_UNSUCCESSFUL;
304 }
305
306 /* search for listening server */
307 current_entry = Fcb->ServerCcbListHead.Flink;
308 while (current_entry != &Fcb->ServerCcbListHead)
309 {
310 ServerCcb = CONTAINING_RECORD(current_entry,
311 NPFS_CCB,
312 CcbListEntry);
313
314 if (ServerCcb->PipeState == FILE_PIPE_LISTENING_STATE)
315 {
316 /* found a listening server CCB */
317 DPRINT("Listening server CCB found -- connecting\n");
318
319 return STATUS_SUCCESS;
320 }
321
322 current_entry = current_entry->Flink;
323 }
324
325 /* No listening server fcb found */
326
327 /* If no timeout specified, use the default one */
328 if (WaitPipe->TimeoutSpecified)
329 TimeOut = WaitPipe->Timeout;
330 else
331 TimeOut = Fcb->TimeOut;
332
333 /* Wait for one */
334 Status = KeWaitForSingleObject(&Ccb->ConnectEvent,
335 UserRequest,
336 KernelMode,
337 FALSE,
338 &TimeOut);
339
340 DPRINT("KeWaitForSingleObject() returned (Status %lx)\n", Status);
341
342 return Status;
343 }
344
345
346 /*
347 * FUNCTION: Return current state of a pipe
348 * ARGUMENTS:
349 * Irp = Pointer to I/O request packet
350 * IrpSp = Pointer to current stack location of Irp
351 * RETURNS:
352 * Status of operation
353 */
354
355 /*
356 * FUNCTION: Peek at a pipe (get information about messages)
357 * ARGUMENTS:
358 * Irp = Pointer to I/O request packet
359 * IoStack = Pointer to current stack location of Irp
360 * RETURNS:
361 * Status of operation
362 */
363 static NTSTATUS
364 NpfsPeekPipe(PIRP Irp,
365 PIO_STACK_LOCATION IoStack)
366 {
367 ULONG OutputBufferLength;
368 ULONG ReturnLength = 0;
369 PFILE_PIPE_PEEK_BUFFER Reply;
370 PNPFS_FCB Fcb;
371 PNPFS_CCB Ccb;
372 NTSTATUS Status;
373 ULONG MessageCount = 0;
374 ULONG MessageLength;
375 ULONG ReadDataAvailable;
376 PVOID BufferPtr;
377
378 DPRINT("NpfsPeekPipe\n");
379
380 OutputBufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
381 DPRINT("OutputBufferLength: %lu\n", OutputBufferLength);
382
383 /* Validate parameters */
384 if (OutputBufferLength < sizeof(FILE_PIPE_PEEK_BUFFER))
385 {
386 DPRINT1("Buffer too small\n");
387 return STATUS_INVALID_PARAMETER;
388 }
389
390 Ccb = IoStack->FileObject->FsContext2;
391 Reply = (PFILE_PIPE_PEEK_BUFFER)Irp->AssociatedIrp.SystemBuffer;
392 Fcb = Ccb->Fcb;
393
394
395 Reply->NamedPipeState = Ccb->PipeState;
396
397 Reply->ReadDataAvailable = Ccb->ReadDataAvailable;
398 DPRINT("ReadDataAvailable: %lu\n", Ccb->ReadDataAvailable);
399
400 ExAcquireFastMutex(&Ccb->DataListLock);
401 BufferPtr = Ccb->ReadPtr;
402 DPRINT("BufferPtr = %x\n", BufferPtr);
403 if (Ccb->Fcb->PipeType == FILE_PIPE_BYTE_STREAM_TYPE)
404 {
405 DPRINT("Byte Stream Mode\n");
406 Reply->MessageLength = Ccb->ReadDataAvailable;
407 DPRINT("Reply->MessageLength %lu\n",Reply->MessageLength );
408 MessageCount = 1;
409
410 if (Reply->Data[0] && (OutputBufferLength >= Ccb->ReadDataAvailable + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0])))
411 {
412 ReturnLength = Ccb->ReadDataAvailable;
413 memcpy(&Reply->Data[0], (PVOID)BufferPtr, Ccb->ReadDataAvailable);
414 }
415 }
416 else
417 {
418 DPRINT("Message Mode\n");
419 ReadDataAvailable=Ccb->ReadDataAvailable;
420
421 if (ReadDataAvailable > 0)
422 {
423 memcpy(&Reply->MessageLength, BufferPtr, sizeof(ULONG));
424
425 while ((ReadDataAvailable > 0) && (BufferPtr < Ccb->WritePtr))
426 {
427 memcpy(&MessageLength, BufferPtr, sizeof(MessageLength));
428
429 ASSERT(MessageLength > 0);
430
431 DPRINT("MessageLength = %lu\n",MessageLength);
432 ReadDataAvailable -= MessageLength;
433 MessageCount++;
434
435 /* If its the first message, copy the Message if the size of buffer is large enough */
436 if (MessageCount==1)
437 {
438 if ((Reply->Data[0])
439 && (OutputBufferLength >= (MessageLength + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]))))
440 {
441 memcpy(&Reply->Data[0], (PVOID)((ULONG)BufferPtr + sizeof(MessageLength)), MessageLength);
442 ReturnLength = MessageLength;
443 }
444 }
445
446 BufferPtr =(PVOID)((ULONG)BufferPtr + MessageLength + sizeof(MessageLength));
447 DPRINT("BufferPtr = %x\n", BufferPtr);
448 DPRINT("ReadDataAvailable: %lu\n", ReadDataAvailable);
449 }
450
451 if (ReadDataAvailable != 0)
452 {
453 DPRINT1("Possible memory corruption.\n");
454 ASSERT(FALSE);
455 }
456 }
457 }
458 ExReleaseFastMutex(&Ccb->DataListLock);
459
460 Reply->NumberOfMessages = MessageCount;
461
462 Irp->IoStatus.Information = ReturnLength + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
463 Irp->IoStatus.Status = STATUS_SUCCESS;
464
465 Status = STATUS_SUCCESS;
466
467 DPRINT("NpfsPeekPipe done\n");
468
469 return Status;
470 }
471
472
473 NTSTATUS NTAPI
474 NpfsFileSystemControl(PDEVICE_OBJECT DeviceObject,
475 PIRP Irp)
476 {
477 PIO_STACK_LOCATION IoStack;
478 PFILE_OBJECT FileObject;
479 NTSTATUS Status;
480 PNPFS_DEVICE_EXTENSION DeviceExt;
481 PNPFS_FCB Fcb;
482 PNPFS_CCB Ccb;
483
484 DPRINT("NpfsFileSystemContol(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
485
486 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
487 IoStack = IoGetCurrentIrpStackLocation(Irp);
488 DPRINT("IoStack: %p\n", IoStack);
489 FileObject = IoStack->FileObject;
490 DPRINT("FileObject: %p\n", FileObject);
491 Ccb = FileObject->FsContext2;
492 DPRINT("CCB: %p\n", Ccb);
493 Fcb = Ccb->Fcb;
494 DPRINT("Pipe: %p\n", Fcb);
495 DPRINT("PipeName: %wZ\n", &Fcb->PipeName);
496
497 Irp->IoStatus.Information = 0;
498
499 switch (IoStack->Parameters.FileSystemControl.FsControlCode)
500 {
501 case FSCTL_PIPE_ASSIGN_EVENT:
502 DPRINT1("Assign event not implemented\n");
503 Status = STATUS_NOT_IMPLEMENTED;
504 break;
505
506 case FSCTL_PIPE_DISCONNECT:
507 DPRINT("Disconnecting pipe %wZ\n", &Fcb->PipeName);
508 Status = NpfsDisconnectPipe(Ccb);
509 break;
510
511 case FSCTL_PIPE_LISTEN:
512 DPRINT("Connecting pipe %wZ\n", &Fcb->PipeName);
513 Status = NpfsConnectPipe(Irp, Ccb);
514 break;
515
516 case FSCTL_PIPE_PEEK:
517 DPRINT("Peeking pipe %wZ\n", &Fcb->PipeName);
518 Status = NpfsPeekPipe(Irp, (PIO_STACK_LOCATION)IoStack);
519 break;
520
521 case FSCTL_PIPE_QUERY_EVENT:
522 DPRINT1("Query event not implemented\n");
523 Status = STATUS_NOT_IMPLEMENTED;
524 break;
525
526 case FSCTL_PIPE_TRANSCEIVE:
527 /* If you implement this, please remove the workaround in
528 lib/kernel32/file/npipe.c function TransactNamedPipe() */
529 DPRINT1("Transceive not implemented\n");
530 Status = STATUS_NOT_IMPLEMENTED;
531 break;
532
533 case FSCTL_PIPE_WAIT:
534 DPRINT("Waiting for pipe %wZ\n", &Fcb->PipeName);
535 Status = NpfsWaitPipe(Irp, Ccb);
536 break;
537
538 case FSCTL_PIPE_IMPERSONATE:
539 DPRINT1("Impersonate not implemented\n");
540 Status = STATUS_NOT_IMPLEMENTED;
541 break;
542
543 case FSCTL_PIPE_SET_CLIENT_PROCESS:
544 DPRINT1("Set client process not implemented\n");
545 Status = STATUS_NOT_IMPLEMENTED;
546 break;
547
548 case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
549 DPRINT1("Query client process not implemented\n");
550 Status = STATUS_NOT_IMPLEMENTED;
551 break;
552
553 case FSCTL_PIPE_INTERNAL_READ:
554 DPRINT1("Internal read not implemented\n");
555 Status = STATUS_NOT_IMPLEMENTED;
556 break;
557
558 case FSCTL_PIPE_INTERNAL_WRITE:
559 DPRINT1("Internal write not implemented\n");
560 Status = STATUS_NOT_IMPLEMENTED;
561 break;
562
563 case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
564 DPRINT1("Internal transceive not implemented\n");
565 Status = STATUS_NOT_IMPLEMENTED;
566 break;
567
568 case FSCTL_PIPE_INTERNAL_READ_OVFLOW:
569 DPRINT1("Internal read overflow not implemented\n");
570 Status = STATUS_NOT_IMPLEMENTED;
571 break;
572
573 default:
574 DPRINT1("Unrecognized IoControlCode: %x\n",
575 IoStack->Parameters.FileSystemControl.FsControlCode);
576 Status = STATUS_UNSUCCESSFUL;
577 }
578
579 if (Status != STATUS_PENDING)
580 {
581 Irp->IoStatus.Status = Status;
582
583 IoCompleteRequest(Irp, IO_NO_INCREMENT);
584 }
585
586 return Status;
587 }
588
589
590 NTSTATUS NTAPI
591 NpfsFlushBuffers(PDEVICE_OBJECT DeviceObject,
592 PIRP Irp)
593 {
594 /* FIXME: Implement */
595
596 Irp->IoStatus.Status = STATUS_SUCCESS;
597 Irp->IoStatus.Information = 0;
598
599 IoCompleteRequest(Irp, IO_NO_INCREMENT);
600
601 return STATUS_SUCCESS;
602 }
603
604 /* EOF */