* Sync to trunk r63845.
[reactos.git] / ntoskrnl / io / iomgr / iofunc.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iofunc.c
5 * PURPOSE: Generic I/O Functions that build IRPs for various operations
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Gunnar Dalsnes
8 * Filip Navara (navaraf@reactos.org)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #include <ioevent.h>
15 #define NDEBUG
16 #include <debug.h>
17 #include "internal/io_i.h"
18
19 /* PRIVATE FUNCTIONS *********************************************************/
20
21 VOID
22 NTAPI
23 IopCleanupAfterException(IN PFILE_OBJECT FileObject,
24 IN PIRP Irp,
25 IN PKEVENT Event OPTIONAL,
26 IN PKEVENT LocalEvent OPTIONAL)
27 {
28 PAGED_CODE();
29 IOTRACE(IO_API_DEBUG, "IRP: %p. FO: %p \n", Irp, FileObject);
30
31 /* Check if we had a buffer */
32 if (Irp->AssociatedIrp.SystemBuffer)
33 {
34 /* Free it */
35 ExFreePool(Irp->AssociatedIrp.SystemBuffer);
36 }
37
38 /* Free the mdl */
39 if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress);
40
41 /* Free the IRP */
42 IoFreeIrp(Irp);
43
44 /* Check if we had a file lock */
45 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
46 {
47 /* Release it */
48 IopUnlockFileObject(FileObject);
49 }
50
51 /* Check if we had an event */
52 if (Event) ObDereferenceObject(Event);
53
54 /* Check if we had a local event */
55 if (LocalEvent) ExFreePool(LocalEvent);
56
57 /* Derefenrce the FO */
58 ObDereferenceObject(FileObject);
59 }
60
61 NTSTATUS
62 NTAPI
63 IopFinalizeAsynchronousIo(IN NTSTATUS SynchStatus,
64 IN PKEVENT Event,
65 IN PIRP Irp,
66 IN KPROCESSOR_MODE PreviousMode,
67 IN PIO_STATUS_BLOCK KernelIosb,
68 OUT PIO_STATUS_BLOCK IoStatusBlock)
69 {
70 NTSTATUS FinalStatus = SynchStatus;
71 PAGED_CODE();
72 IOTRACE(IO_API_DEBUG, "IRP: %p. Status: %lx \n", Irp, SynchStatus);
73
74 /* Make sure the IRP was completed, but returned pending */
75 if (FinalStatus == STATUS_PENDING)
76 {
77 /* Wait for the IRP */
78 FinalStatus = KeWaitForSingleObject(Event,
79 Executive,
80 PreviousMode,
81 FALSE,
82 NULL);
83 if (FinalStatus == STATUS_USER_APC)
84 {
85 /* Abort the request */
86 IopAbortInterruptedIrp(Event, Irp);
87 }
88
89 /* Set the final status */
90 FinalStatus = KernelIosb->Status;
91 }
92
93 /* Wrap potential user-mode write in SEH */
94 _SEH2_TRY
95 {
96 *IoStatusBlock = *KernelIosb;
97 }
98 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
99 {
100 /* Get the exception code */
101 FinalStatus = _SEH2_GetExceptionCode();
102 }
103 _SEH2_END;
104
105 /* Free the event and return status */
106 ExFreePool(Event);
107 return FinalStatus;
108 }
109
110 NTSTATUS
111 NTAPI
112 IopPerformSynchronousRequest(IN PDEVICE_OBJECT DeviceObject,
113 IN PIRP Irp,
114 IN PFILE_OBJECT FileObject,
115 IN BOOLEAN Deferred,
116 IN KPROCESSOR_MODE PreviousMode,
117 IN BOOLEAN SynchIo,
118 IN IOP_TRANSFER_TYPE TransferType)
119 {
120 NTSTATUS Status;
121 PKNORMAL_ROUTINE NormalRoutine;
122 PVOID NormalContext = NULL;
123 KIRQL OldIrql;
124 PAGED_CODE();
125 IOTRACE(IO_API_DEBUG, "IRP: %p. DO: %p. FO: %p \n",
126 Irp, DeviceObject, FileObject);
127
128 /* Queue the IRP */
129 IopQueueIrpToThread(Irp);
130
131 /* Update operation counts */
132 IopUpdateOperationCount(TransferType);
133
134 /* Call the driver */
135 Status = IoCallDriver(DeviceObject, Irp);
136
137 /* Check if we're optimizing this case */
138 if (Deferred)
139 {
140 /* We are! Check if the IRP wasn't completed */
141 if (Status != STATUS_PENDING)
142 {
143 /* Complete it ourselves */
144 ASSERT(!Irp->PendingReturned);
145 KeRaiseIrql(APC_LEVEL, &OldIrql);
146 IopCompleteRequest(&Irp->Tail.Apc,
147 &NormalRoutine,
148 &NormalContext,
149 (PVOID*)&FileObject,
150 &NormalContext);
151 KeLowerIrql(OldIrql);
152 }
153 }
154
155 /* Check if this was synch I/O */
156 if (SynchIo)
157 {
158 /* Make sure the IRP was completed, but returned pending */
159 if (Status == STATUS_PENDING)
160 {
161 /* Wait for the IRP */
162 Status = KeWaitForSingleObject(&FileObject->Event,
163 Executive,
164 PreviousMode,
165 (FileObject->Flags &
166 FO_ALERTABLE_IO) != 0,
167 NULL);
168 if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
169 {
170 /* Abort the request */
171 IopAbortInterruptedIrp(&FileObject->Event, Irp);
172 }
173
174 /* Set the final status */
175 Status = FileObject->FinalStatus;
176 }
177
178 /* Release the file lock */
179 IopUnlockFileObject(FileObject);
180 }
181
182 /* Return status */
183 return Status;
184 }
185
186 NTSTATUS
187 NTAPI
188 IopDeviceFsIoControl(IN HANDLE DeviceHandle,
189 IN HANDLE Event OPTIONAL,
190 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
191 IN PVOID UserApcContext OPTIONAL,
192 OUT PIO_STATUS_BLOCK IoStatusBlock,
193 IN ULONG IoControlCode,
194 IN PVOID InputBuffer,
195 IN ULONG InputBufferLength OPTIONAL,
196 OUT PVOID OutputBuffer,
197 IN ULONG OutputBufferLength OPTIONAL,
198 IN BOOLEAN IsDevIoCtl)
199 {
200 NTSTATUS Status;
201 PFILE_OBJECT FileObject;
202 PDEVICE_OBJECT DeviceObject;
203 PIRP Irp;
204 PIO_STACK_LOCATION StackPtr;
205 PKEVENT EventObject = NULL;
206 BOOLEAN LockedForSynch = FALSE;
207 ULONG AccessType;
208 OBJECT_HANDLE_INFORMATION HandleInformation;
209 ACCESS_MASK DesiredAccess;
210 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
211 ULONG BufferLength;
212 IOTRACE(IO_CTL_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n",
213 DeviceHandle, IoControlCode, IsDevIoCtl);
214
215 /* Get the access type */
216 AccessType = IO_METHOD_FROM_CTL_CODE(IoControlCode);
217
218 /* Check if we came from user mode */
219 if (PreviousMode != KernelMode)
220 {
221 _SEH2_TRY
222 {
223 /* Probe the status block */
224 ProbeForWriteIoStatusBlock(IoStatusBlock);
225
226 /* Check if this is buffered I/O */
227 if (AccessType == METHOD_BUFFERED)
228 {
229 /* Check if we have an output buffer */
230 if (OutputBuffer)
231 {
232 /* Probe the output buffer */
233 ProbeForWrite(OutputBuffer,
234 OutputBufferLength,
235 sizeof(CHAR));
236 }
237 else
238 {
239 /* Make sure the caller can't fake this as we depend on this */
240 OutputBufferLength = 0;
241 }
242 }
243
244 /* Check if we we have an input buffer I/O */
245 if (AccessType != METHOD_NEITHER)
246 {
247 /* Check if we have an input buffer */
248 if (InputBuffer)
249 {
250 /* Probe the input buffer */
251 ProbeForRead(InputBuffer, InputBufferLength, sizeof(CHAR));
252 }
253 else
254 {
255 /* Make sure the caller can't fake this as we depend on this */
256 InputBufferLength = 0;
257 }
258 }
259 }
260 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
261 {
262 /* Return the exception code */
263 _SEH2_YIELD(return _SEH2_GetExceptionCode());
264 }
265 _SEH2_END;
266 }
267
268 /* Don't check for access rights right now, KernelMode can do anything */
269 Status = ObReferenceObjectByHandle(DeviceHandle,
270 0,
271 IoFileObjectType,
272 PreviousMode,
273 (PVOID*)&FileObject,
274 &HandleInformation);
275 if (!NT_SUCCESS(Status)) return Status;
276
277 /* Can't use an I/O completion port and an APC in the same time */
278 if ((FileObject->CompletionContext) && (UserApcRoutine))
279 {
280 /* Fail */
281 ObDereferenceObject(FileObject);
282 return STATUS_INVALID_PARAMETER;
283 }
284
285 /* Check if we from user mode */
286 if (PreviousMode != KernelMode)
287 {
288 /* Get the access mask */
289 DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3);
290
291 /* Check if we can open it */
292 if ((DesiredAccess != FILE_ANY_ACCESS) &&
293 (HandleInformation.GrantedAccess & DesiredAccess) != DesiredAccess)
294 {
295 /* Dereference the file object and fail */
296 ObDereferenceObject(FileObject);
297 return STATUS_ACCESS_DENIED;
298 }
299 }
300
301 /* Check for an event */
302 if (Event)
303 {
304 /* Reference it */
305 Status = ObReferenceObjectByHandle(Event,
306 EVENT_MODIFY_STATE,
307 ExEventObjectType,
308 PreviousMode,
309 (PVOID*)&EventObject,
310 NULL);
311 if (!NT_SUCCESS(Status))
312 {
313 /* Dereference the file object and fail */
314 ObDereferenceObject(FileObject);
315 return Status;
316 }
317
318 /* Clear it */
319 KeClearEvent(EventObject);
320 }
321
322 /* Check if this is a file that was opened for Synch I/O */
323 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
324 {
325 /* Lock it */
326 IopLockFileObject(FileObject);
327
328 /* Remember to unlock later */
329 LockedForSynch = TRUE;
330 }
331
332 /* Check if this is a direct open or not */
333 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
334 {
335 /* It's a direct open, get the attached device */
336 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
337 }
338 else
339 {
340 /* Otherwise get the related device */
341 DeviceObject = IoGetRelatedDeviceObject(FileObject);
342 }
343
344 /* Clear the event */
345 KeClearEvent(&FileObject->Event);
346
347 /* Allocate IRP */
348 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
349 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
350
351 /* Setup the IRP */
352 Irp->UserIosb = IoStatusBlock;
353 Irp->UserEvent = EventObject;
354 Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
355 Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext;
356 Irp->Cancel = FALSE;
357 Irp->CancelRoutine = NULL;
358 Irp->PendingReturned = FALSE;
359 Irp->RequestorMode = PreviousMode;
360 Irp->MdlAddress = NULL;
361 Irp->AssociatedIrp.SystemBuffer = NULL;
362 Irp->Flags = 0;
363 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
364 Irp->Tail.Overlay.OriginalFileObject = FileObject;
365 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
366
367 /* Set stack location settings */
368 StackPtr = IoGetNextIrpStackLocation(Irp);
369 StackPtr->FileObject = FileObject;
370 StackPtr->MajorFunction = IsDevIoCtl ?
371 IRP_MJ_DEVICE_CONTROL :
372 IRP_MJ_FILE_SYSTEM_CONTROL;
373 StackPtr->MinorFunction = 0; /* Minor function 0 is IRP_MN_USER_FS_REQUEST */
374 StackPtr->Control = 0;
375 StackPtr->Flags = 0;
376 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
377
378 /* Set the IOCTL Data */
379 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
380 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
381 StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
382 OutputBufferLength;
383
384 /* Handle the Methods */
385 switch (AccessType)
386 {
387 /* Buffered I/O */
388 case METHOD_BUFFERED:
389
390 /* Enter SEH for allocations */
391 _SEH2_TRY
392 {
393 /* Select the right Buffer Length */
394 BufferLength = (InputBufferLength > OutputBufferLength) ?
395 InputBufferLength : OutputBufferLength;
396
397 /* Make sure there is one */
398 if (BufferLength)
399 {
400 /* Allocate the System Buffer */
401 Irp->AssociatedIrp.SystemBuffer =
402 ExAllocatePoolWithTag(NonPagedPool,
403 BufferLength,
404 TAG_SYS_BUF);
405
406 /* Check if we got a buffer */
407 if (InputBuffer)
408 {
409 /* Copy into the System Buffer */
410 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
411 InputBuffer,
412 InputBufferLength);
413 }
414
415 /* Write the flags */
416 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
417 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
418
419 /* Save the Buffer */
420 Irp->UserBuffer = OutputBuffer;
421 }
422 else
423 {
424 /* Clear the Flags and Buffer */
425 Irp->UserBuffer = NULL;
426 }
427 }
428 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
429 {
430 /* Cleanup after exception and return */
431 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
432 _SEH2_YIELD(return _SEH2_GetExceptionCode());
433 }
434 _SEH2_END;
435 break;
436
437 /* Direct I/O */
438 case METHOD_IN_DIRECT:
439 case METHOD_OUT_DIRECT:
440
441 /* Enter SEH */
442 _SEH2_TRY
443 {
444 /* Check if we got an input buffer */
445 if ((InputBufferLength) && (InputBuffer))
446 {
447 /* Allocate the System Buffer */
448 Irp->AssociatedIrp.SystemBuffer =
449 ExAllocatePoolWithTag(NonPagedPool,
450 InputBufferLength,
451 TAG_SYS_BUF);
452
453 /* Copy into the System Buffer */
454 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
455 InputBuffer,
456 InputBufferLength);
457
458 /* Write the flags */
459 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
460 }
461
462 /* Check if we got an output buffer */
463 if (OutputBuffer)
464 {
465 /* Allocate the System Buffer */
466 Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
467 OutputBufferLength,
468 FALSE,
469 FALSE,
470 Irp);
471 if (!Irp->MdlAddress)
472 {
473 /* Raise exception we'll catch */
474 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
475 }
476
477 /* Do the probe */
478 MmProbeAndLockPages(Irp->MdlAddress,
479 PreviousMode,
480 (AccessType == METHOD_IN_DIRECT) ?
481 IoReadAccess : IoWriteAccess);
482 }
483 }
484 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
485 {
486 /* Cleanup after exception and return */
487 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
488 _SEH2_YIELD(return _SEH2_GetExceptionCode());
489 }
490 _SEH2_END;
491 break;
492
493 case METHOD_NEITHER:
494
495 /* Just save the Buffer */
496 Irp->UserBuffer = OutputBuffer;
497 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
498 }
499
500 /* Use deferred completion for FS I/O */
501 Irp->Flags |= (!IsDevIoCtl) ? IRP_DEFER_IO_COMPLETION : 0;
502
503 /* Perform the call */
504 return IopPerformSynchronousRequest(DeviceObject,
505 Irp,
506 FileObject,
507 !IsDevIoCtl,
508 PreviousMode,
509 LockedForSynch,
510 IopOtherTransfer);
511 }
512
513 NTSTATUS
514 NTAPI
515 IopQueryDeviceInformation(IN PFILE_OBJECT FileObject,
516 IN ULONG InformationClass,
517 IN ULONG Length,
518 OUT PVOID Information,
519 OUT PULONG ReturnedLength,
520 IN BOOLEAN File)
521 {
522 IO_STATUS_BLOCK IoStatusBlock;
523 PIRP Irp;
524 PDEVICE_OBJECT DeviceObject;
525 PIO_STACK_LOCATION StackPtr;
526 BOOLEAN LocalEvent = FALSE;
527 KEVENT Event;
528 NTSTATUS Status;
529 PAGED_CODE();
530 IOTRACE(IO_API_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n",
531 FileObject, InformationClass, File);
532
533 /* Reference the object */
534 ObReferenceObject(FileObject);
535
536 /* Check if this is a file that was opened for Synch I/O */
537 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
538 {
539 /* Lock it */
540 IopLockFileObject(FileObject);
541
542 /* Use File Object event */
543 KeClearEvent(&FileObject->Event);
544 }
545 else
546 {
547 /* Use local event */
548 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
549 LocalEvent = TRUE;
550 }
551
552 /* Get the Device Object */
553 DeviceObject = IoGetRelatedDeviceObject(FileObject);
554
555 /* Allocate the IRP */
556 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
557 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
558
559 /* Set the IRP */
560 Irp->Tail.Overlay.OriginalFileObject = FileObject;
561 Irp->RequestorMode = KernelMode;
562 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
563 Irp->UserIosb = &IoStatusBlock;
564 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
565 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
566 Irp->Flags |= IRP_BUFFERED_IO;
567 Irp->AssociatedIrp.SystemBuffer = Information;
568 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
569
570 /* Set the Stack Data */
571 StackPtr = IoGetNextIrpStackLocation(Irp);
572 StackPtr->MajorFunction = File ? IRP_MJ_QUERY_INFORMATION:
573 IRP_MJ_QUERY_VOLUME_INFORMATION;
574 StackPtr->FileObject = FileObject;
575
576 /* Check which type this is */
577 if (File)
578 {
579 /* Set Parameters */
580 StackPtr->Parameters.QueryFile.FileInformationClass = InformationClass;
581 StackPtr->Parameters.QueryFile.Length = Length;
582 }
583 else
584 {
585 /* Set Parameters */
586 StackPtr->Parameters.QueryVolume.FsInformationClass = InformationClass;
587 StackPtr->Parameters.QueryVolume.Length = Length;
588 }
589
590 /* Queue the IRP */
591 IopQueueIrpToThread(Irp);
592
593 /* Call the Driver */
594 Status = IoCallDriver(DeviceObject, Irp);
595
596 /* Check if this was synch I/O */
597 if (!LocalEvent)
598 {
599 /* Check if the requet is pending */
600 if (Status == STATUS_PENDING)
601 {
602 /* Wait on the file object */
603 Status = KeWaitForSingleObject(&FileObject->Event,
604 Executive,
605 KernelMode,
606 (FileObject->Flags &
607 FO_ALERTABLE_IO) != 0,
608 NULL);
609 if (Status == STATUS_ALERTED)
610 {
611 /* Abort the operation */
612 IopAbortInterruptedIrp(&FileObject->Event, Irp);
613 }
614
615 /* Get the final status */
616 Status = FileObject->FinalStatus;
617 }
618
619 /* Release the file lock */
620 IopUnlockFileObject(FileObject);
621 }
622 else if (Status == STATUS_PENDING)
623 {
624 /* Wait on the local event and get the final status */
625 KeWaitForSingleObject(&Event,
626 Executive,
627 KernelMode,
628 FALSE,
629 NULL);
630 Status = IoStatusBlock.Status;
631 }
632
633 /* Return the Length and Status. ReturnedLength is NOT optional */
634 *ReturnedLength = (ULONG)IoStatusBlock.Information;
635 return Status;
636 }
637
638 NTSTATUS
639 NTAPI
640 IopGetFileInformation(IN PFILE_OBJECT FileObject,
641 IN ULONG Length,
642 IN FILE_INFORMATION_CLASS FileInfoClass,
643 OUT PVOID Buffer,
644 OUT PULONG ReturnedLength)
645 {
646 PIRP Irp;
647 KEVENT Event;
648 NTSTATUS Status;
649 PIO_STACK_LOCATION Stack;
650 PDEVICE_OBJECT DeviceObject;
651 IO_STATUS_BLOCK IoStatusBlock;
652
653 PAGED_CODE();
654
655 /* Allocate an IRP */
656 ObReferenceObject(FileObject);
657 DeviceObject = IoGetRelatedDeviceObject(FileObject);
658 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
659 if (Irp == NULL)
660 {
661 ObDereferenceObject(FileObject);
662 return STATUS_INSUFFICIENT_RESOURCES;
663 }
664
665 /* Init event */
666 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
667
668 /* Setup the IRP */
669 Irp->UserIosb = &IoStatusBlock;
670 Irp->UserEvent = &Event;
671 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
672 Irp->RequestorMode = KernelMode;
673 Irp->AssociatedIrp.SystemBuffer = Buffer;
674 Irp->Flags = IRP_SYNCHRONOUS_API | IRP_BUFFERED_IO | IRP_OB_QUERY_NAME;
675 Irp->Tail.Overlay.OriginalFileObject = FileObject;
676 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
677
678 Stack = IoGetNextIrpStackLocation(Irp);
679 Stack->MajorFunction = IRP_MJ_QUERY_INFORMATION;
680 Stack->FileObject = FileObject;
681 Stack->Parameters.QueryFile.FileInformationClass = FileInfoClass;
682 Stack->Parameters.QueryFile.Length = Length;
683
684
685 /* Queue the IRP */
686 IopQueueIrpToThread(Irp);
687
688 /* Call the driver */
689 Status = IoCallDriver(DeviceObject, Irp);
690 if (Status == STATUS_PENDING)
691 {
692 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
693 Status = IoStatusBlock.Status;
694 }
695
696 *ReturnedLength = IoStatusBlock.Information;
697 return Status;
698 }
699
700 NTSTATUS
701 NTAPI
702 IopGetBasicInformationFile(IN PFILE_OBJECT FileObject,
703 OUT PFILE_BASIC_INFORMATION BasicInfo)
704 {
705 ULONG ReturnedLength;
706 PDEVICE_OBJECT DeviceObject;
707 IO_STATUS_BLOCK IoStatusBlock;
708
709 PAGED_CODE();
710
711 /* Try to do it the fast way if possible */
712 DeviceObject = IoGetRelatedDeviceObject(FileObject);
713 if (DeviceObject->DriverObject->FastIoDispatch != NULL &&
714 DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo != NULL &&
715 DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(FileObject,
716 ((FileObject->Flags & FO_SYNCHRONOUS_IO) != 0),
717 BasicInfo,
718 &IoStatusBlock,
719 DeviceObject))
720 {
721 return IoStatusBlock.Status;
722 }
723
724 /* In case it failed, fall back to IRP-based method */
725 return IopGetFileInformation(FileObject, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation, BasicInfo, &ReturnedLength);
726 }
727
728 NTSTATUS
729 NTAPI
730 IopOpenLinkOrRenameTarget(OUT PHANDLE Handle,
731 IN PIRP Irp,
732 IN PFILE_RENAME_INFORMATION RenameInfo,
733 IN PFILE_OBJECT FileObject)
734 {
735 NTSTATUS Status;
736 HANDLE TargetHandle;
737 UNICODE_STRING FileName;
738 PIO_STACK_LOCATION Stack;
739 PFILE_OBJECT TargetFileObject;
740 IO_STATUS_BLOCK IoStatusBlock;
741 FILE_BASIC_INFORMATION BasicInfo;
742 OBJECT_ATTRIBUTES ObjectAttributes;
743 OBJECT_HANDLE_INFORMATION HandleInformation;
744 ACCESS_MASK DesiredAccess = FILE_WRITE_DATA;
745
746 PAGED_CODE();
747
748 /* First, establish whether our target is a directory */
749 if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
750 {
751 Status = IopGetBasicInformationFile(FileObject, &BasicInfo);
752 if (!NT_SUCCESS(Status))
753 {
754 return Status;
755 }
756
757 if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
758 DesiredAccess = FILE_ADD_SUBDIRECTORY;
759 }
760 }
761
762 /* Setup the string to the target */
763 FileName.Buffer = RenameInfo->FileName;
764 FileName.Length = RenameInfo->FileNameLength;
765 FileName.MaximumLength = RenameInfo->FileNameLength;
766
767 InitializeObjectAttributes(&ObjectAttributes,
768 &FileName,
769 (FileObject->Flags & FO_OPENED_CASE_SENSITIVE ? 0 : OBJ_CASE_INSENSITIVE) | OBJ_KERNEL_HANDLE,
770 RenameInfo->RootDirectory,
771 NULL);
772
773 /* And open its parent directory */
774 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
775 {
776 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
777 #if 0
778 /* Commented out - we don't support FO extension yet
779 * FIXME: Corrected last arg when it's supported
780 */
781 Status = IoCreateFileSpecifyDeviceObjectHint(&TargetHandle,
782 DesiredAccess | SYNCHRONIZE,
783 &ObjectAttributes,
784 &IoStatusBlock,
785 NULL,
786 0,
787 FILE_SHARE_READ | FILE_SHARE_WRITE,
788 FILE_OPEN,
789 FILE_OPEN_FOR_BACKUP_INTENT,
790 NULL,
791 0,
792 CreateFileTypeNone,
793 NULL,
794 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING,
795 FileObject->DeviceObject);
796 #else
797 ASSERT(FALSE);
798 UNIMPLEMENTED;
799 return STATUS_NOT_IMPLEMENTED;
800 #endif
801 }
802 else
803 {
804 Status = IoCreateFile(&TargetHandle,
805 DesiredAccess | SYNCHRONIZE,
806 &ObjectAttributes,
807 &IoStatusBlock,
808 NULL,
809 0,
810 FILE_SHARE_READ | FILE_SHARE_WRITE,
811 FILE_OPEN,
812 FILE_OPEN_FOR_BACKUP_INTENT,
813 NULL,
814 0,
815 CreateFileTypeNone,
816 NULL,
817 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING);
818 }
819
820 if (!NT_SUCCESS(Status))
821 {
822 return Status;
823 }
824
825 /* Once open, continue only if:
826 * Target exists and we're allowed to overwrite it
827 */
828 Stack = IoGetNextIrpStackLocation(Irp);
829 if (Stack->Parameters.SetFile.FileInformationClass == FileLinkInformation &&
830 !RenameInfo->ReplaceIfExists &&
831 IoStatusBlock.Information == FILE_EXISTS)
832 {
833 ObCloseHandle(TargetHandle, KernelMode);
834 return STATUS_OBJECT_NAME_COLLISION;
835 }
836
837 /* Now, we'll get the associated device of the target, to check for same device location
838 * So, get the FO first
839 */
840 Status = ObReferenceObjectByHandle(TargetHandle,
841 FILE_WRITE_DATA,
842 IoFileObjectType,
843 KernelMode,
844 (PVOID *)&TargetFileObject,
845 &HandleInformation);
846 if (!NT_SUCCESS(Status))
847 {
848 ObCloseHandle(TargetHandle, KernelMode);
849 return Status;
850 }
851
852 /* We can dereference, we have the handle */
853 ObDereferenceObject(TargetFileObject);
854 /* If we're not on the same device, error out **/
855 if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject))
856 {
857 ObCloseHandle(TargetHandle, KernelMode);
858 return STATUS_NOT_SAME_DEVICE;
859 }
860
861 /* Return parent directory file object and handle */
862 Stack->Parameters.SetFile.FileObject = TargetFileObject;
863 *Handle = TargetHandle;
864
865 return STATUS_SUCCESS;
866 }
867
868 /* PUBLIC FUNCTIONS **********************************************************/
869
870 /*
871 * @implemented
872 */
873 NTSTATUS
874 NTAPI
875 IoSynchronousPageWrite(IN PFILE_OBJECT FileObject,
876 IN PMDL Mdl,
877 IN PLARGE_INTEGER Offset,
878 IN PKEVENT Event,
879 IN PIO_STATUS_BLOCK StatusBlock)
880 {
881 PIRP Irp;
882 PIO_STACK_LOCATION StackPtr;
883 PDEVICE_OBJECT DeviceObject;
884 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
885 FileObject, Mdl, Offset);
886
887 /* Get the Device Object */
888 DeviceObject = IoGetRelatedDeviceObject(FileObject);
889
890 /* Allocate IRP */
891 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
892 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
893
894 /* Get the Stack */
895 StackPtr = IoGetNextIrpStackLocation(Irp);
896
897 /* Create the IRP Settings */
898 Irp->MdlAddress = Mdl;
899 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
900 Irp->UserIosb = StatusBlock;
901 Irp->UserEvent = Event;
902 Irp->RequestorMode = KernelMode;
903 Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO;
904 Irp->Tail.Overlay.OriginalFileObject = FileObject;
905 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
906
907 /* Set the Stack Settings */
908 StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl);
909 StackPtr->Parameters.Write.ByteOffset = *Offset;
910 StackPtr->MajorFunction = IRP_MJ_WRITE;
911 StackPtr->FileObject = FileObject;
912
913 /* Call the Driver */
914 return IoCallDriver(DeviceObject, Irp);
915 }
916
917 /*
918 * @implemented
919 */
920 NTSTATUS
921 NTAPI
922 IoPageRead(IN PFILE_OBJECT FileObject,
923 IN PMDL Mdl,
924 IN PLARGE_INTEGER Offset,
925 IN PKEVENT Event,
926 IN PIO_STATUS_BLOCK StatusBlock)
927 {
928 PIRP Irp;
929 PIO_STACK_LOCATION StackPtr;
930 PDEVICE_OBJECT DeviceObject;
931 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
932 FileObject, Mdl, Offset);
933
934 /* Get the Device Object */
935 DeviceObject = IoGetRelatedDeviceObject(FileObject);
936
937 /* Allocate IRP */
938 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
939 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
940
941 /* Get the Stack */
942 StackPtr = IoGetNextIrpStackLocation(Irp);
943
944 /* Create the IRP Settings */
945 Irp->MdlAddress = Mdl;
946 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
947 Irp->UserIosb = StatusBlock;
948 Irp->UserEvent = Event;
949 Irp->RequestorMode = KernelMode;
950 Irp->Flags = IRP_PAGING_IO |
951 IRP_NOCACHE |
952 IRP_SYNCHRONOUS_PAGING_IO |
953 IRP_INPUT_OPERATION;
954 Irp->Tail.Overlay.OriginalFileObject = FileObject;
955 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
956
957 /* Set the Stack Settings */
958 StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl);
959 StackPtr->Parameters.Read.ByteOffset = *Offset;
960 StackPtr->MajorFunction = IRP_MJ_READ;
961 StackPtr->FileObject = FileObject;
962
963 /* Call the Driver */
964 return IoCallDriver(DeviceObject, Irp);
965 }
966
967 /*
968 * @implemented
969 */
970 NTSTATUS
971 NTAPI
972 IoQueryFileInformation(IN PFILE_OBJECT FileObject,
973 IN FILE_INFORMATION_CLASS FileInformationClass,
974 IN ULONG Length,
975 OUT PVOID FileInformation,
976 OUT PULONG ReturnedLength)
977 {
978 /* Call the shared routine */
979 return IopQueryDeviceInformation(FileObject,
980 FileInformationClass,
981 Length,
982 FileInformation,
983 ReturnedLength,
984 TRUE);
985 }
986
987 /*
988 * @implemented
989 */
990 NTSTATUS
991 NTAPI
992 IoQueryVolumeInformation(IN PFILE_OBJECT FileObject,
993 IN FS_INFORMATION_CLASS FsInformationClass,
994 IN ULONG Length,
995 OUT PVOID FsInformation,
996 OUT PULONG ReturnedLength)
997 {
998 /* Call the shared routine */
999 return IopQueryDeviceInformation(FileObject,
1000 FsInformationClass,
1001 Length,
1002 FsInformation,
1003 ReturnedLength,
1004 FALSE);
1005 }
1006
1007 /*
1008 * @implemented
1009 */
1010 NTSTATUS
1011 NTAPI
1012 IoSetInformation(IN PFILE_OBJECT FileObject,
1013 IN FILE_INFORMATION_CLASS FileInformationClass,
1014 IN ULONG Length,
1015 IN PVOID FileInformation)
1016 {
1017 IO_STATUS_BLOCK IoStatusBlock;
1018 PIRP Irp;
1019 PDEVICE_OBJECT DeviceObject;
1020 PIO_STACK_LOCATION StackPtr;
1021 BOOLEAN LocalEvent = FALSE;
1022 KEVENT Event;
1023 NTSTATUS Status;
1024 PAGED_CODE();
1025 IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx \n",
1026 FileObject, FileInformationClass, Length);
1027
1028 /* Reference the object */
1029 ObReferenceObject(FileObject);
1030
1031 /* Check if this is a file that was opened for Synch I/O */
1032 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1033 {
1034 /* Lock it */
1035 IopLockFileObject(FileObject);
1036
1037 /* Use File Object event */
1038 KeClearEvent(&FileObject->Event);
1039 }
1040 else
1041 {
1042 /* Use local event */
1043 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1044 LocalEvent = TRUE;
1045 }
1046
1047 /* Get the Device Object */
1048 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1049
1050 /* Allocate the IRP */
1051 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1052 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1053
1054 /* Set the IRP */
1055 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1056 Irp->RequestorMode = KernelMode;
1057 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1058 Irp->UserIosb = &IoStatusBlock;
1059 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1060 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1061 Irp->Flags |= IRP_BUFFERED_IO;
1062 Irp->AssociatedIrp.SystemBuffer = FileInformation;
1063 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1064
1065 /* Set the Stack Data */
1066 StackPtr = IoGetNextIrpStackLocation(Irp);
1067 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
1068 StackPtr->FileObject = FileObject;
1069
1070 /* Set Parameters */
1071 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
1072 StackPtr->Parameters.SetFile.Length = Length;
1073
1074 /* Queue the IRP */
1075 IopQueueIrpToThread(Irp);
1076
1077 /* Call the Driver */
1078 Status = IoCallDriver(DeviceObject, Irp);
1079
1080 /* Check if this was synch I/O */
1081 if (!LocalEvent)
1082 {
1083 /* Check if the requet is pending */
1084 if (Status == STATUS_PENDING)
1085 {
1086 /* Wait on the file object */
1087 Status = KeWaitForSingleObject(&FileObject->Event,
1088 Executive,
1089 KernelMode,
1090 (FileObject->Flags &
1091 FO_ALERTABLE_IO) != 0,
1092 NULL);
1093 if (Status == STATUS_ALERTED)
1094 {
1095 /* Abort the operation */
1096 IopAbortInterruptedIrp(&FileObject->Event, Irp);
1097 }
1098
1099 /* Get the final status */
1100 Status = FileObject->FinalStatus;
1101 }
1102
1103 /* Release the file lock */
1104 IopUnlockFileObject(FileObject);
1105 }
1106 else if (Status == STATUS_PENDING)
1107 {
1108 /* Wait on the local event and get the final status */
1109 KeWaitForSingleObject(&Event,
1110 Executive,
1111 KernelMode,
1112 FALSE,
1113 NULL);
1114 Status = IoStatusBlock.Status;
1115 }
1116
1117 /* Return the status */
1118 return Status;
1119 }
1120
1121 /* NATIVE SERVICES ***********************************************************/
1122
1123 /*
1124 * @implemented
1125 */
1126 NTSTATUS
1127 NTAPI
1128 NtDeviceIoControlFile(IN HANDLE DeviceHandle,
1129 IN HANDLE Event OPTIONAL,
1130 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1131 IN PVOID UserApcContext OPTIONAL,
1132 OUT PIO_STATUS_BLOCK IoStatusBlock,
1133 IN ULONG IoControlCode,
1134 IN PVOID InputBuffer,
1135 IN ULONG InputBufferLength OPTIONAL,
1136 OUT PVOID OutputBuffer,
1137 IN ULONG OutputBufferLength OPTIONAL)
1138 {
1139 /* Call the Generic Function */
1140 return IopDeviceFsIoControl(DeviceHandle,
1141 Event,
1142 UserApcRoutine,
1143 UserApcContext,
1144 IoStatusBlock,
1145 IoControlCode,
1146 InputBuffer,
1147 InputBufferLength,
1148 OutputBuffer,
1149 OutputBufferLength,
1150 TRUE);
1151 }
1152
1153 /*
1154 * @implemented
1155 */
1156 NTSTATUS
1157 NTAPI
1158 NtFsControlFile(IN HANDLE DeviceHandle,
1159 IN HANDLE Event OPTIONAL,
1160 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1161 IN PVOID UserApcContext OPTIONAL,
1162 OUT PIO_STATUS_BLOCK IoStatusBlock,
1163 IN ULONG IoControlCode,
1164 IN PVOID InputBuffer,
1165 IN ULONG InputBufferLength OPTIONAL,
1166 OUT PVOID OutputBuffer,
1167 IN ULONG OutputBufferLength OPTIONAL)
1168 {
1169 /* Call the Generic Function */
1170 return IopDeviceFsIoControl(DeviceHandle,
1171 Event,
1172 UserApcRoutine,
1173 UserApcContext,
1174 IoStatusBlock,
1175 IoControlCode,
1176 InputBuffer,
1177 InputBufferLength,
1178 OutputBuffer,
1179 OutputBufferLength,
1180 FALSE);
1181 }
1182
1183 NTSTATUS
1184 NTAPI
1185 NtFlushBuffersFile(IN HANDLE FileHandle,
1186 OUT PIO_STATUS_BLOCK IoStatusBlock)
1187 {
1188 PFILE_OBJECT FileObject;
1189 PIRP Irp;
1190 PIO_STACK_LOCATION StackPtr;
1191 NTSTATUS Status;
1192 PDEVICE_OBJECT DeviceObject;
1193 PKEVENT Event = NULL;
1194 BOOLEAN LocalEvent = FALSE;
1195 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1196 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1197 IO_STATUS_BLOCK KernelIosb;
1198 PAGED_CODE();
1199 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1200
1201 if (PreviousMode != KernelMode)
1202 {
1203 /* Protect probes */
1204 _SEH2_TRY
1205 {
1206 /* Probe the I/O Status block */
1207 ProbeForWriteIoStatusBlock(IoStatusBlock);
1208 }
1209 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1210 {
1211 /* Return the exception code */
1212 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1213 }
1214 _SEH2_END;
1215 }
1216
1217 /* Get the File Object */
1218 Status = ObReferenceObjectByHandle(FileHandle,
1219 0,
1220 IoFileObjectType,
1221 PreviousMode,
1222 (PVOID*)&FileObject,
1223 &ObjectHandleInfo);
1224 if (!NT_SUCCESS(Status)) return Status;
1225
1226 /*
1227 * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
1228 * granted. However, if this is a named pipe, make sure we don't ask for
1229 * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
1230 * access right!
1231 */
1232 if (!(ObjectHandleInfo.GrantedAccess &
1233 ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) |
1234 FILE_WRITE_DATA)))
1235 {
1236 /* We failed */
1237 ObDereferenceObject(FileObject);
1238 return STATUS_ACCESS_DENIED;
1239 }
1240
1241 /* Check if we should use Sync IO or not */
1242 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1243 {
1244 /* Lock it */
1245 IopLockFileObject(FileObject);
1246 }
1247 else
1248 {
1249 /* Use local event */
1250 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
1251 if (!Event)
1252 {
1253 /* We failed */
1254 ObDereferenceObject(FileObject);
1255 return STATUS_INSUFFICIENT_RESOURCES;
1256 }
1257 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
1258 LocalEvent = TRUE;
1259 }
1260
1261 /* Get the Device Object */
1262 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1263
1264 /* Clear the event */
1265 KeClearEvent(&FileObject->Event);
1266
1267 /* Allocate the IRP */
1268 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1269 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
1270
1271 /* Set up the IRP */
1272 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1273 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
1274 Irp->UserEvent = (LocalEvent) ? Event : NULL;
1275 Irp->RequestorMode = PreviousMode;
1276 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1277 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1278 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1279
1280 /* Set up Stack Data */
1281 StackPtr = IoGetNextIrpStackLocation(Irp);
1282 StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
1283 StackPtr->FileObject = FileObject;
1284
1285 /* Call the Driver */
1286 Status = IopPerformSynchronousRequest(DeviceObject,
1287 Irp,
1288 FileObject,
1289 FALSE,
1290 PreviousMode,
1291 !LocalEvent,
1292 IopOtherTransfer);
1293
1294 /* Check if this was async I/O */
1295 if (LocalEvent)
1296 {
1297 /* It was, finalize this request */
1298 Status = IopFinalizeAsynchronousIo(Status,
1299 Event,
1300 Irp,
1301 PreviousMode,
1302 &KernelIosb,
1303 IoStatusBlock);
1304 }
1305
1306 /* Return the Status */
1307 return Status;
1308 }
1309
1310 /*
1311 * @implemented
1312 */
1313 NTSTATUS
1314 NTAPI
1315 NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
1316 IN HANDLE EventHandle OPTIONAL,
1317 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1318 IN PVOID ApcContext OPTIONAL,
1319 OUT PIO_STATUS_BLOCK IoStatusBlock,
1320 OUT PVOID Buffer,
1321 IN ULONG BufferSize,
1322 IN ULONG CompletionFilter,
1323 IN BOOLEAN WatchTree)
1324 {
1325 PIRP Irp;
1326 PKEVENT Event = NULL;
1327 PDEVICE_OBJECT DeviceObject;
1328 PFILE_OBJECT FileObject;
1329 PIO_STACK_LOCATION IoStack;
1330 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1331 NTSTATUS Status;
1332 BOOLEAN LockedForSync = FALSE;
1333 PAGED_CODE();
1334 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1335
1336 /* Check if we're called from user mode */
1337 if (PreviousMode != KernelMode)
1338 {
1339 /* Enter SEH for probing */
1340 _SEH2_TRY
1341 {
1342 /* Probe the I/O STatus block */
1343 ProbeForWriteIoStatusBlock(IoStatusBlock);
1344
1345 /* Probe the buffer */
1346 if (BufferSize) ProbeForWrite(Buffer, BufferSize, sizeof(ULONG));
1347 }
1348 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1349 {
1350 /* Return the exception code */
1351 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1352 }
1353 _SEH2_END;
1354
1355 /* Check if CompletionFilter is valid */
1356 if (!CompletionFilter || (CompletionFilter & ~FILE_NOTIFY_VALID_MASK))
1357 {
1358 return STATUS_INVALID_PARAMETER;
1359 }
1360 }
1361
1362 /* Get File Object */
1363 Status = ObReferenceObjectByHandle(FileHandle,
1364 FILE_LIST_DIRECTORY,
1365 IoFileObjectType,
1366 PreviousMode,
1367 (PVOID*)&FileObject,
1368 NULL);
1369 if (!NT_SUCCESS(Status)) return Status;
1370
1371 /* Check if we have an event handle */
1372 if (EventHandle)
1373 {
1374 /* Reference it */
1375 Status = ObReferenceObjectByHandle(EventHandle,
1376 EVENT_MODIFY_STATE,
1377 ExEventObjectType,
1378 PreviousMode,
1379 (PVOID *)&Event,
1380 NULL);
1381 if (Status != STATUS_SUCCESS)
1382 {
1383 ObDereferenceObject(FileObject);
1384 return Status;
1385 }
1386 KeClearEvent(Event);
1387 }
1388
1389 /* Check if we should use Sync IO or not */
1390 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1391 {
1392 /* Lock it */
1393 IopLockFileObject(FileObject);
1394 LockedForSync = TRUE;
1395 }
1396
1397 /* Clear File Object event */
1398 KeClearEvent(&FileObject->Event);
1399
1400 /* Get the device object */
1401 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1402
1403 /* Allocate the IRP */
1404 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1405 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1406
1407 /* Set up the IRP */
1408 Irp->RequestorMode = PreviousMode;
1409 Irp->UserIosb = IoStatusBlock;
1410 Irp->UserEvent = Event;
1411 Irp->UserBuffer = Buffer;
1412 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1413 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1414 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1415 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1416
1417 /* Set up Stack Data */
1418 IoStack = IoGetNextIrpStackLocation(Irp);
1419 IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
1420 IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
1421 IoStack->FileObject = FileObject;
1422
1423 /* Set parameters */
1424 IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
1425 IoStack->Parameters.NotifyDirectory.Length = BufferSize;
1426 if (WatchTree) IoStack->Flags = SL_WATCH_TREE;
1427
1428 /* Perform the call */
1429 return IopPerformSynchronousRequest(DeviceObject,
1430 Irp,
1431 FileObject,
1432 FALSE,
1433 PreviousMode,
1434 LockedForSync,
1435 IopOtherTransfer);
1436 }
1437
1438 /*
1439 * @implemented
1440 */
1441 NTSTATUS
1442 NTAPI
1443 NtLockFile(IN HANDLE FileHandle,
1444 IN HANDLE EventHandle OPTIONAL,
1445 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1446 IN PVOID ApcContext OPTIONAL,
1447 OUT PIO_STATUS_BLOCK IoStatusBlock,
1448 IN PLARGE_INTEGER ByteOffset,
1449 IN PLARGE_INTEGER Length,
1450 IN ULONG Key,
1451 IN BOOLEAN FailImmediately,
1452 IN BOOLEAN ExclusiveLock)
1453 {
1454 PFILE_OBJECT FileObject;
1455 PLARGE_INTEGER LocalLength = NULL;
1456 PIRP Irp;
1457 PIO_STACK_LOCATION StackPtr;
1458 PDEVICE_OBJECT DeviceObject;
1459 PKEVENT Event = NULL;
1460 BOOLEAN LockedForSync = FALSE;
1461 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1462 LARGE_INTEGER CapturedByteOffset, CapturedLength;
1463 NTSTATUS Status;
1464 OBJECT_HANDLE_INFORMATION HandleInformation;
1465 PAGED_CODE();
1466 CapturedByteOffset.QuadPart = 0;
1467 CapturedLength.QuadPart = 0;
1468 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1469
1470 /* Get File Object */
1471 Status = ObReferenceObjectByHandle(FileHandle,
1472 0,
1473 IoFileObjectType,
1474 PreviousMode,
1475 (PVOID*)&FileObject,
1476 &HandleInformation);
1477 if (!NT_SUCCESS(Status)) return Status;
1478
1479 /* Check if we're called from user mode */
1480 if (PreviousMode != KernelMode)
1481 {
1482 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
1483 if (!(HandleInformation.GrantedAccess &
1484 (FILE_WRITE_DATA | FILE_READ_DATA)))
1485 {
1486 ObDereferenceObject(FileObject);
1487 return STATUS_ACCESS_DENIED;
1488 }
1489
1490 /* Enter SEH for probing */
1491 _SEH2_TRY
1492 {
1493 /* Probe the I/O STatus block */
1494 ProbeForWriteIoStatusBlock(IoStatusBlock);
1495
1496 /* Probe and capture the large integers */
1497 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
1498 CapturedLength = ProbeForReadLargeInteger(Length);
1499 }
1500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1501 {
1502 /* Dereference the object and return exception code */
1503 ObDereferenceObject(FileObject);
1504 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1505 }
1506 _SEH2_END;
1507 }
1508 else
1509 {
1510 /* Otherwise, capture them directly */
1511 CapturedByteOffset = *ByteOffset;
1512 CapturedLength = *Length;
1513 }
1514
1515 /* Check if we have an event handle */
1516 if (EventHandle)
1517 {
1518 /* Reference it */
1519 Status = ObReferenceObjectByHandle(EventHandle,
1520 EVENT_MODIFY_STATE,
1521 ExEventObjectType,
1522 PreviousMode,
1523 (PVOID *)&Event,
1524 NULL);
1525 if (Status != STATUS_SUCCESS) return Status;
1526 KeClearEvent(Event);
1527 }
1528
1529 /* Get the device object */
1530 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1531
1532 /* Check if we should use Sync IO or not */
1533 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1534 {
1535 /* Lock it */
1536 IopLockFileObject(FileObject);
1537 LockedForSync = TRUE;
1538 }
1539
1540 /* Clear File Object event */
1541 KeClearEvent(&FileObject->Event);
1542 FileObject->LockOperation = TRUE;
1543
1544 /* Allocate the IRP */
1545 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1546 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1547
1548 /* Set up the IRP */
1549 Irp->RequestorMode = PreviousMode;
1550 Irp->UserIosb = IoStatusBlock;
1551 Irp->UserEvent = Event;
1552 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1553 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1554 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1555 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1556
1557 /* Set up Stack Data */
1558 StackPtr = IoGetNextIrpStackLocation(Irp);
1559 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
1560 StackPtr->MinorFunction = IRP_MN_LOCK;
1561 StackPtr->FileObject = FileObject;
1562
1563 /* Allocate local buffer */
1564 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
1565 sizeof(LARGE_INTEGER),
1566 TAG_LOCK);
1567 if (!LocalLength)
1568 {
1569 /* Allocating failed, clean up and return failure */
1570 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1571 return STATUS_INSUFFICIENT_RESOURCES;
1572 }
1573
1574 /* Set the length */
1575 *LocalLength = CapturedLength;
1576 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
1577 StackPtr->Parameters.LockControl.Length = LocalLength;
1578
1579 /* Set Parameters */
1580 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
1581 StackPtr->Parameters.LockControl.Key = Key;
1582
1583 /* Set Flags */
1584 if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
1585 if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
1586
1587 /* Perform the call */
1588 return IopPerformSynchronousRequest(DeviceObject,
1589 Irp,
1590 FileObject,
1591 FALSE,
1592 PreviousMode,
1593 LockedForSync,
1594 IopOtherTransfer);
1595 }
1596
1597 /*
1598 * @implemented
1599 */
1600 NTSTATUS
1601 NTAPI
1602 NtQueryDirectoryFile(IN HANDLE FileHandle,
1603 IN HANDLE EventHandle OPTIONAL,
1604 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1605 IN PVOID ApcContext OPTIONAL,
1606 OUT PIO_STATUS_BLOCK IoStatusBlock,
1607 OUT PVOID FileInformation,
1608 IN ULONG Length,
1609 IN FILE_INFORMATION_CLASS FileInformationClass,
1610 IN BOOLEAN ReturnSingleEntry,
1611 IN PUNICODE_STRING FileName OPTIONAL,
1612 IN BOOLEAN RestartScan)
1613 {
1614 PIRP Irp;
1615 PDEVICE_OBJECT DeviceObject;
1616 PFILE_OBJECT FileObject;
1617 PIO_STACK_LOCATION StackPtr;
1618 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1619 NTSTATUS Status;
1620 BOOLEAN LockedForSynch = FALSE;
1621 PKEVENT Event = NULL;
1622 volatile PVOID AuxBuffer = NULL;
1623 PMDL Mdl;
1624 UNICODE_STRING CapturedFileName;
1625 PUNICODE_STRING SearchPattern;
1626 PAGED_CODE();
1627 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1628
1629 /* Check if we came from user mode */
1630 if (PreviousMode != KernelMode)
1631 {
1632 /* Enter SEH for probing */
1633 _SEH2_TRY
1634 {
1635 /* Probe the I/O Status Block */
1636 ProbeForWriteIoStatusBlock(IoStatusBlock);
1637
1638 /* Probe the file information */
1639 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
1640
1641 /* Check if we have a file name */
1642 if (FileName)
1643 {
1644 /* Capture it */
1645 CapturedFileName = ProbeForReadUnicodeString(FileName);
1646 if (CapturedFileName.Length)
1647 {
1648 /* Probe its buffer */
1649 ProbeForRead(CapturedFileName.Buffer,
1650 CapturedFileName.Length,
1651 1);
1652 }
1653
1654 /* Allocate the auxiliary buffer */
1655 AuxBuffer = ExAllocatePoolWithTag(NonPagedPool,
1656 CapturedFileName.Length +
1657 sizeof(UNICODE_STRING),
1658 TAG_SYSB);
1659 RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer +
1660 sizeof(UNICODE_STRING)),
1661 CapturedFileName.Buffer,
1662 CapturedFileName.Length);
1663
1664 /* Setup the search pattern */
1665 SearchPattern = (PUNICODE_STRING)AuxBuffer;
1666 SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer +
1667 sizeof(UNICODE_STRING));
1668 SearchPattern->Length = CapturedFileName.Length;
1669 SearchPattern->MaximumLength = CapturedFileName.Length;
1670 }
1671 }
1672 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1673 {
1674 /* Free buffer and return the exception code */
1675 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1676 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1677 }
1678 _SEH2_END;
1679 }
1680
1681 /* Get File Object */
1682 Status = ObReferenceObjectByHandle(FileHandle,
1683 FILE_LIST_DIRECTORY,
1684 IoFileObjectType,
1685 PreviousMode,
1686 (PVOID *)&FileObject,
1687 NULL);
1688 if (!NT_SUCCESS(Status))
1689 {
1690 /* Fail */
1691 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1692 return Status;
1693 }
1694
1695 /* Check if we have an even handle */
1696 if (EventHandle)
1697 {
1698 /* Get its pointer */
1699 Status = ObReferenceObjectByHandle(EventHandle,
1700 EVENT_MODIFY_STATE,
1701 ExEventObjectType,
1702 PreviousMode,
1703 (PVOID *)&Event,
1704 NULL);
1705 if (!NT_SUCCESS(Status))
1706 {
1707 /* Fail */
1708 ObDereferenceObject(FileObject);
1709 return Status;
1710 }
1711
1712 /* Clear it */
1713 KeClearEvent(Event);
1714 }
1715
1716 /* Check if this is a file that was opened for Synch I/O */
1717 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1718 {
1719 /* Lock it */
1720 IopLockFileObject(FileObject);
1721
1722 /* Remember to unlock later */
1723 LockedForSynch = TRUE;
1724 }
1725
1726 /* Get the device object */
1727 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1728
1729 /* Clear the File Object's event */
1730 KeClearEvent(&FileObject->Event);
1731
1732 /* Allocate the IRP */
1733 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1734 if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer);
1735
1736 /* Set up the IRP */
1737 Irp->RequestorMode = PreviousMode;
1738 Irp->UserIosb = IoStatusBlock;
1739 Irp->UserEvent = Event;
1740 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1741 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1742 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1743 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1744 Irp->MdlAddress = NULL;
1745 Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer;
1746 Irp->AssociatedIrp.SystemBuffer = NULL;
1747
1748 /* Check if this is buffered I/O */
1749 if (DeviceObject->Flags & DO_BUFFERED_IO)
1750 {
1751 /* Allocate a buffer */
1752 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
1753 Length,
1754 TAG_SYSB);
1755 if (!Irp->AssociatedIrp.SystemBuffer)
1756 {
1757 /* Allocating failed, clean up and return the exception code */
1758 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1759 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1760
1761 /* Return the exception code */
1762 return STATUS_INSUFFICIENT_RESOURCES;
1763 }
1764
1765 /* Set the buffer and flags */
1766 Irp->UserBuffer = FileInformation;
1767 Irp->Flags = (IRP_BUFFERED_IO |
1768 IRP_DEALLOCATE_BUFFER |
1769 IRP_INPUT_OPERATION);
1770 }
1771 else if (DeviceObject->Flags & DO_DIRECT_IO)
1772 {
1773 _SEH2_TRY
1774 {
1775 /* Allocate an MDL */
1776 Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp);
1777 if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
1778 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
1779 }
1780 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1781 {
1782 /* Allocating failed, clean up and return the exception code */
1783 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1784 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1785 }
1786 _SEH2_END;
1787 }
1788 else
1789 {
1790 /* No allocation flags, and use the buffer directly */
1791 Irp->UserBuffer = FileInformation;
1792 }
1793
1794 /* Set up Stack Data */
1795 StackPtr = IoGetNextIrpStackLocation(Irp);
1796 StackPtr->FileObject = FileObject;
1797 StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
1798 StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY;
1799
1800 /* Set Parameters */
1801 StackPtr->Parameters.QueryDirectory.FileInformationClass =
1802 FileInformationClass;
1803 StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer;
1804 StackPtr->Parameters.QueryDirectory.FileIndex = 0;
1805 StackPtr->Parameters.QueryDirectory.Length = Length;
1806 StackPtr->Flags = 0;
1807 if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
1808 if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
1809
1810 /* Set deferred I/O */
1811 Irp->Flags |= IRP_DEFER_IO_COMPLETION;
1812
1813 /* Perform the call */
1814 return IopPerformSynchronousRequest(DeviceObject,
1815 Irp,
1816 FileObject,
1817 TRUE,
1818 PreviousMode,
1819 LockedForSynch,
1820 IopOtherTransfer);
1821 }
1822
1823 /*
1824 * @unimplemented
1825 */
1826 NTSTATUS
1827 NTAPI
1828 NtQueryEaFile(IN HANDLE FileHandle,
1829 OUT PIO_STATUS_BLOCK IoStatusBlock,
1830 OUT PVOID Buffer,
1831 IN ULONG Length,
1832 IN BOOLEAN ReturnSingleEntry,
1833 IN PVOID EaList OPTIONAL,
1834 IN ULONG EaListLength,
1835 IN PULONG EaIndex OPTIONAL,
1836 IN BOOLEAN RestartScan)
1837 {
1838 UNIMPLEMENTED;
1839 return STATUS_NOT_IMPLEMENTED;
1840 }
1841
1842 /*
1843 * @implemented
1844 */
1845 NTSTATUS
1846 NTAPI
1847 NtQueryInformationFile(IN HANDLE FileHandle,
1848 OUT PIO_STATUS_BLOCK IoStatusBlock,
1849 IN PVOID FileInformation,
1850 IN ULONG Length,
1851 IN FILE_INFORMATION_CLASS FileInformationClass)
1852 {
1853 OBJECT_HANDLE_INFORMATION HandleInformation;
1854 PFILE_OBJECT FileObject;
1855 NTSTATUS Status;
1856 PIRP Irp;
1857 PDEVICE_OBJECT DeviceObject;
1858 PIO_STACK_LOCATION StackPtr;
1859 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1860 PKEVENT Event = NULL;
1861 BOOLEAN LocalEvent = FALSE;
1862 PKNORMAL_ROUTINE NormalRoutine;
1863 PVOID NormalContext;
1864 KIRQL OldIrql;
1865 IO_STATUS_BLOCK KernelIosb;
1866 PAGED_CODE();
1867 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1868
1869 /* Check if we're called from user mode */
1870 if (PreviousMode != KernelMode)
1871 {
1872 /* Validate the information class */
1873 if ((FileInformationClass >= FileMaximumInformation) ||
1874 !(IopQueryOperationLength[FileInformationClass]))
1875 {
1876 /* Invalid class */
1877 return STATUS_INVALID_INFO_CLASS;
1878 }
1879
1880 /* Validate the length */
1881 if (Length < IopQueryOperationLength[FileInformationClass])
1882 {
1883 /* Invalid length */
1884 return STATUS_INFO_LENGTH_MISMATCH;
1885 }
1886
1887 /* Enter SEH for probing */
1888 _SEH2_TRY
1889 {
1890 /* Probe the I/O Status block */
1891 ProbeForWriteIoStatusBlock(IoStatusBlock);
1892
1893 /* Probe the information */
1894 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
1895 }
1896 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1897 {
1898 /* Return the exception code */
1899 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1900 }
1901 _SEH2_END;
1902 }
1903 else
1904 {
1905 /* Validate the information class */
1906 if ((FileInformationClass >= FileMaximumInformation) ||
1907 !(IopQueryOperationLength[FileInformationClass]))
1908 {
1909 /* Invalid class */
1910 return STATUS_INVALID_INFO_CLASS;
1911 }
1912
1913 /* Validate the length */
1914 if (Length < IopQueryOperationLength[FileInformationClass])
1915 {
1916 /* Invalid length */
1917 return STATUS_INFO_LENGTH_MISMATCH;
1918 }
1919 }
1920
1921 /* Reference the Handle */
1922 Status = ObReferenceObjectByHandle(FileHandle,
1923 IopQueryOperationAccess
1924 [FileInformationClass],
1925 IoFileObjectType,
1926 PreviousMode,
1927 (PVOID *)&FileObject,
1928 &HandleInformation);
1929 if (!NT_SUCCESS(Status)) return Status;
1930
1931 /* Check if this is a direct open or not */
1932 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1933 {
1934 /* Get the device object */
1935 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1936 }
1937 else
1938 {
1939 /* Get the device object */
1940 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1941 }
1942
1943 /* Check if this is a file that was opened for Synch I/O */
1944 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1945 {
1946 /* Lock it */
1947 IopLockFileObject(FileObject);
1948
1949 /* Check if the caller just wants the position */
1950 if (FileInformationClass == FilePositionInformation)
1951 {
1952 /* Protect write in SEH */
1953 _SEH2_TRY
1954 {
1955 /* Write the offset */
1956 ((PFILE_POSITION_INFORMATION)FileInformation)->
1957 CurrentByteOffset = FileObject->CurrentByteOffset;
1958
1959 /* Fill out the I/O Status Block */
1960 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
1961 Status = IoStatusBlock->Status = STATUS_SUCCESS;
1962 }
1963 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1964 {
1965 /* Get the exception code */
1966 Status = _SEH2_GetExceptionCode();
1967 }
1968 _SEH2_END;
1969
1970 /* Release the file lock, dereference the file and return */
1971 IopUnlockFileObject(FileObject);
1972 ObDereferenceObject(FileObject);
1973 return Status;
1974 }
1975 }
1976 else
1977 {
1978 /* Use local event */
1979 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
1980 if (!Event)
1981 {
1982 ObDereferenceObject(FileObject);
1983 return STATUS_INSUFFICIENT_RESOURCES;
1984 }
1985 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
1986 LocalEvent = TRUE;
1987 }
1988
1989 /* Clear the File Object event */
1990 KeClearEvent(&FileObject->Event);
1991
1992 /* Allocate the IRP */
1993 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1994 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
1995
1996 /* Set the IRP */
1997 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1998 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1999 Irp->RequestorMode = PreviousMode;
2000 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2001 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2002 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2003 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2004 Irp->AssociatedIrp.SystemBuffer = NULL;
2005 Irp->MdlAddress = NULL;
2006 Irp->UserBuffer = FileInformation;
2007
2008 /* Set the Stack Data */
2009 StackPtr = IoGetNextIrpStackLocation(Irp);
2010 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
2011 StackPtr->FileObject = FileObject;
2012
2013 /* Enter SEH */
2014 _SEH2_TRY
2015 {
2016 /* Allocate a buffer */
2017 Irp->AssociatedIrp.SystemBuffer =
2018 ExAllocatePoolWithTag(NonPagedPool,
2019 Length,
2020 TAG_SYSB);
2021 }
2022 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2023 {
2024 /* Allocating failed, clean up and return the exception code */
2025 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2026 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2027 }
2028 _SEH2_END;
2029
2030 /* Set the flags */
2031 Irp->Flags |= (IRP_BUFFERED_IO |
2032 IRP_DEALLOCATE_BUFFER |
2033 IRP_INPUT_OPERATION |
2034 IRP_DEFER_IO_COMPLETION);
2035
2036 /* Set the Parameters */
2037 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2038 StackPtr->Parameters.QueryFile.Length = Length;
2039
2040 /* Queue the IRP */
2041 IopQueueIrpToThread(Irp);
2042
2043 /* Update operation counts */
2044 IopUpdateOperationCount(IopOtherTransfer);
2045
2046 /* Call the Driver */
2047 Status = IoCallDriver(DeviceObject, Irp);
2048 if (Status == STATUS_PENDING)
2049 {
2050 /* Check if this was async I/O */
2051 if (LocalEvent)
2052 {
2053 /* Then to a non-alertable wait */
2054 Status = KeWaitForSingleObject(Event,
2055 Executive,
2056 PreviousMode,
2057 FALSE,
2058 NULL);
2059 if (Status == STATUS_USER_APC)
2060 {
2061 /* Abort the request */
2062 IopAbortInterruptedIrp(Event, Irp);
2063 }
2064
2065 /* Set the final status */
2066 Status = KernelIosb.Status;
2067
2068 /* Enter SEH to write the IOSB back */
2069 _SEH2_TRY
2070 {
2071 /* Write it back to the caller */
2072 *IoStatusBlock = KernelIosb;
2073 }
2074 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2075 {
2076 /* Get the exception code */
2077 Status = _SEH2_GetExceptionCode();
2078 }
2079 _SEH2_END;
2080
2081 /* Free the event */
2082 ExFreePoolWithTag(Event, TAG_IO);
2083 }
2084 else
2085 {
2086 /* Wait for the IRP */
2087 Status = KeWaitForSingleObject(&FileObject->Event,
2088 Executive,
2089 PreviousMode,
2090 (FileObject->Flags &
2091 FO_ALERTABLE_IO) != 0,
2092 NULL);
2093 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2094 {
2095 /* Abort the request */
2096 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2097 }
2098
2099 /* Set the final status */
2100 Status = FileObject->FinalStatus;
2101
2102 /* Release the file lock */
2103 IopUnlockFileObject(FileObject);
2104 }
2105 }
2106 else
2107 {
2108 /* Free the event if we had one */
2109 if (LocalEvent)
2110 {
2111 /* Clear it in the IRP for completion */
2112 Irp->UserEvent = NULL;
2113 ExFreePoolWithTag(Event, TAG_IO);
2114 }
2115
2116 /* Set the caller IOSB */
2117 Irp->UserIosb = IoStatusBlock;
2118
2119 /* The IRP wasn't completed, complete it ourselves */
2120 KeRaiseIrql(APC_LEVEL, &OldIrql);
2121 IopCompleteRequest(&Irp->Tail.Apc,
2122 &NormalRoutine,
2123 &NormalContext,
2124 (PVOID*)&FileObject,
2125 &NormalContext);
2126 KeLowerIrql(OldIrql);
2127
2128 /* Release the file object if we had locked it*/
2129 if (!LocalEvent) IopUnlockFileObject(FileObject);
2130 }
2131
2132 /* Return the Status */
2133 return Status;
2134 }
2135
2136 /*
2137 * @unimplemented
2138 */
2139 NTSTATUS
2140 NTAPI
2141 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
2142 OUT PIO_STATUS_BLOCK IoStatusBlock,
2143 OUT PVOID Buffer,
2144 IN ULONG Length,
2145 IN BOOLEAN ReturnSingleEntry,
2146 IN PVOID SidList OPTIONAL,
2147 IN ULONG SidListLength,
2148 IN PSID StartSid OPTIONAL,
2149 IN BOOLEAN RestartScan)
2150 {
2151 UNIMPLEMENTED;
2152 return STATUS_NOT_IMPLEMENTED;
2153 }
2154
2155 /*
2156 * @implemented
2157 */
2158 NTSTATUS
2159 NTAPI
2160 NtReadFile(IN HANDLE FileHandle,
2161 IN HANDLE Event OPTIONAL,
2162 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2163 IN PVOID ApcContext OPTIONAL,
2164 OUT PIO_STATUS_BLOCK IoStatusBlock,
2165 OUT PVOID Buffer,
2166 IN ULONG Length,
2167 IN PLARGE_INTEGER ByteOffset OPTIONAL,
2168 IN PULONG Key OPTIONAL)
2169 {
2170 NTSTATUS Status;
2171 PFILE_OBJECT FileObject;
2172 PIRP Irp;
2173 PDEVICE_OBJECT DeviceObject;
2174 PIO_STACK_LOCATION StackPtr;
2175 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2176 PKEVENT EventObject = NULL;
2177 LARGE_INTEGER CapturedByteOffset;
2178 ULONG CapturedKey = 0;
2179 BOOLEAN Synchronous = FALSE;
2180 PMDL Mdl;
2181 PAGED_CODE();
2182 CapturedByteOffset.QuadPart = 0;
2183 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2184
2185 /* Validate User-Mode Buffers */
2186 if (PreviousMode != KernelMode)
2187 {
2188 _SEH2_TRY
2189 {
2190 /* Probe the status block */
2191 ProbeForWriteIoStatusBlock(IoStatusBlock);
2192
2193 /* Probe the read buffer */
2194 ProbeForWrite(Buffer, Length, 1);
2195
2196 /* Check if we got a byte offset */
2197 if (ByteOffset)
2198 {
2199 /* Capture and probe it */
2200 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2201 }
2202
2203 /* Capture and probe the key */
2204 if (Key) CapturedKey = ProbeForReadUlong(Key);
2205 }
2206 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2207 {
2208 /* Return the exception code */
2209 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2210 }
2211 _SEH2_END;
2212 }
2213 else
2214 {
2215 /* Kernel mode: capture directly */
2216 if (ByteOffset) CapturedByteOffset = *ByteOffset;
2217 if (Key) CapturedKey = *Key;
2218 }
2219
2220 /* Get File Object */
2221 Status = ObReferenceObjectByHandle(FileHandle,
2222 FILE_READ_DATA,
2223 IoFileObjectType,
2224 PreviousMode,
2225 (PVOID*)&FileObject,
2226 NULL);
2227 if (!NT_SUCCESS(Status)) return Status;
2228
2229 /* Check for event */
2230 if (Event)
2231 {
2232 /* Reference it */
2233 Status = ObReferenceObjectByHandle(Event,
2234 EVENT_MODIFY_STATE,
2235 ExEventObjectType,
2236 PreviousMode,
2237 (PVOID*)&EventObject,
2238 NULL);
2239 if (!NT_SUCCESS(Status))
2240 {
2241 /* Fail */
2242 ObDereferenceObject(FileObject);
2243 return Status;
2244 }
2245
2246 /* Otherwise reset the event */
2247 KeClearEvent(EventObject);
2248 }
2249
2250 /* Check if we should use Sync IO or not */
2251 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2252 {
2253 /* Lock the file object */
2254 IopLockFileObject(FileObject);
2255
2256 /* Check if we don't have a byte offset avilable */
2257 if (!(ByteOffset) ||
2258 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2259 (CapturedByteOffset.u.HighPart == -1)))
2260 {
2261 /* Use the Current Byte Offset instead */
2262 CapturedByteOffset = FileObject->CurrentByteOffset;
2263 }
2264
2265 /* Remember we are sync */
2266 Synchronous = TRUE;
2267 }
2268 else if (!(ByteOffset) &&
2269 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2270 {
2271 /* Otherwise, this was async I/O without a byte offset, so fail */
2272 if (EventObject) ObDereferenceObject(EventObject);
2273 ObDereferenceObject(FileObject);
2274 return STATUS_INVALID_PARAMETER;
2275 }
2276
2277 /* Get the device object */
2278 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2279
2280 /* Clear the File Object's event */
2281 KeClearEvent(&FileObject->Event);
2282
2283 /* Allocate the IRP */
2284 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2285 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
2286
2287 /* Set the IRP */
2288 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2289 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2290 Irp->RequestorMode = PreviousMode;
2291 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2292 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2293 Irp->UserIosb = IoStatusBlock;
2294 Irp->UserEvent = EventObject;
2295 Irp->PendingReturned = FALSE;
2296 Irp->Cancel = FALSE;
2297 Irp->CancelRoutine = NULL;
2298 Irp->AssociatedIrp.SystemBuffer = NULL;
2299 Irp->MdlAddress = NULL;
2300
2301 /* Set the Stack Data */
2302 StackPtr = IoGetNextIrpStackLocation(Irp);
2303 StackPtr->MajorFunction = IRP_MJ_READ;
2304 StackPtr->FileObject = FileObject;
2305 StackPtr->Parameters.Read.Key = CapturedKey;
2306 StackPtr->Parameters.Read.Length = Length;
2307 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2308
2309 /* Check if this is buffered I/O */
2310 if (DeviceObject->Flags & DO_BUFFERED_IO)
2311 {
2312 /* Check if we have a buffer length */
2313 if (Length)
2314 {
2315 /* Enter SEH */
2316 _SEH2_TRY
2317 {
2318 /* Allocate a buffer */
2319 Irp->AssociatedIrp.SystemBuffer =
2320 ExAllocatePoolWithTag(NonPagedPool,
2321 Length,
2322 TAG_SYSB);
2323 }
2324 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2325 {
2326 /* Allocating failed, clean up and return the exception code */
2327 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2328 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2329 }
2330 _SEH2_END;
2331
2332 /* Set the buffer and flags */
2333 Irp->UserBuffer = Buffer;
2334 Irp->Flags = (IRP_BUFFERED_IO |
2335 IRP_DEALLOCATE_BUFFER |
2336 IRP_INPUT_OPERATION);
2337 }
2338 else
2339 {
2340 /* Not reading anything */
2341 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
2342 }
2343 }
2344 else if (DeviceObject->Flags & DO_DIRECT_IO)
2345 {
2346 /* Check if we have a buffer length */
2347 if (Length)
2348 {
2349 _SEH2_TRY
2350 {
2351 /* Allocate an MDL */
2352 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
2353 if (!Mdl)
2354 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2355 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2356 }
2357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2358 {
2359 /* Allocating failed, clean up and return the exception code */
2360 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2361 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2362 }
2363 _SEH2_END;
2364
2365 }
2366
2367 /* No allocation flags */
2368 Irp->Flags = 0;
2369 }
2370 else
2371 {
2372 /* No allocation flags, and use the buffer directly */
2373 Irp->Flags = 0;
2374 Irp->UserBuffer = Buffer;
2375 }
2376
2377 /* Now set the deferred read flags */
2378 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
2379 #if 0
2380 /* FIXME: VFAT SUCKS */
2381 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
2382 #endif
2383
2384 /* Perform the call */
2385 return IopPerformSynchronousRequest(DeviceObject,
2386 Irp,
2387 FileObject,
2388 TRUE,
2389 PreviousMode,
2390 Synchronous,
2391 IopReadTransfer);
2392 }
2393
2394 /*
2395 * @unimplemented
2396 */
2397 NTSTATUS
2398 NTAPI
2399 NtReadFileScatter(IN HANDLE FileHandle,
2400 IN HANDLE Event OPTIONAL,
2401 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
2402 IN PVOID UserApcContext OPTIONAL,
2403 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
2404 IN FILE_SEGMENT_ELEMENT BufferDescription [],
2405 IN ULONG BufferLength,
2406 IN PLARGE_INTEGER ByteOffset,
2407 IN PULONG Key OPTIONAL)
2408 {
2409 UNIMPLEMENTED;
2410 return STATUS_NOT_IMPLEMENTED;
2411 }
2412
2413 /*
2414 * @unimplemented
2415 */
2416 NTSTATUS
2417 NTAPI
2418 NtSetEaFile(IN HANDLE FileHandle,
2419 IN PIO_STATUS_BLOCK IoStatusBlock,
2420 IN PVOID EaBuffer,
2421 IN ULONG EaBufferSize)
2422 {
2423 UNIMPLEMENTED;
2424 return STATUS_NOT_IMPLEMENTED;
2425 }
2426
2427 /*
2428 * @implemented
2429 */
2430 NTSTATUS
2431 NTAPI
2432 NtSetInformationFile(IN HANDLE FileHandle,
2433 OUT PIO_STATUS_BLOCK IoStatusBlock,
2434 IN PVOID FileInformation,
2435 IN ULONG Length,
2436 IN FILE_INFORMATION_CLASS FileInformationClass)
2437 {
2438 PFILE_OBJECT FileObject;
2439 NTSTATUS Status;
2440 PIRP Irp;
2441 PDEVICE_OBJECT DeviceObject;
2442 PIO_STACK_LOCATION StackPtr;
2443 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2444 PKEVENT Event = NULL;
2445 BOOLEAN LocalEvent = FALSE;
2446 PKNORMAL_ROUTINE NormalRoutine;
2447 PVOID NormalContext;
2448 KIRQL OldIrql;
2449 IO_STATUS_BLOCK KernelIosb;
2450 PVOID Queue;
2451 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
2452 PIO_COMPLETION_CONTEXT Context;
2453 PFILE_RENAME_INFORMATION RenameInfo;
2454 HANDLE TargetHandle = NULL;
2455 PAGED_CODE();
2456 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2457
2458 /* Check if we're called from user mode */
2459 if (PreviousMode != KernelMode)
2460 {
2461 /* Validate the information class */
2462 if ((FileInformationClass >= FileMaximumInformation) ||
2463 !(IopSetOperationLength[FileInformationClass]))
2464 {
2465 /* Invalid class */
2466 return STATUS_INVALID_INFO_CLASS;
2467 }
2468
2469 /* Validate the length */
2470 if (Length < IopSetOperationLength[FileInformationClass])
2471 {
2472 /* Invalid length */
2473 return STATUS_INFO_LENGTH_MISMATCH;
2474 }
2475
2476 /* Enter SEH for probing */
2477 _SEH2_TRY
2478 {
2479 /* Probe the I/O Status block */
2480 ProbeForWriteIoStatusBlock(IoStatusBlock);
2481
2482 /* Probe the information */
2483 ProbeForRead(FileInformation,
2484 Length,
2485 (Length == sizeof(BOOLEAN)) ?
2486 sizeof(BOOLEAN) : sizeof(ULONG));
2487 }
2488 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2489 {
2490 /* Return the exception code */
2491 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2492 }
2493 _SEH2_END;
2494 }
2495 else
2496 {
2497 /* Validate the information class */
2498 if ((FileInformationClass >= FileMaximumInformation) ||
2499 !(IopSetOperationLength[FileInformationClass]))
2500 {
2501 /* Invalid class */
2502 return STATUS_INVALID_INFO_CLASS;
2503 }
2504
2505 /* Validate the length */
2506 if (Length < IopSetOperationLength[FileInformationClass])
2507 {
2508 /* Invalid length */
2509 return STATUS_INFO_LENGTH_MISMATCH;
2510 }
2511 }
2512
2513 /* Reference the Handle */
2514 Status = ObReferenceObjectByHandle(FileHandle,
2515 IopSetOperationAccess
2516 [FileInformationClass],
2517 IoFileObjectType,
2518 PreviousMode,
2519 (PVOID *)&FileObject,
2520 NULL);
2521 if (!NT_SUCCESS(Status)) return Status;
2522
2523 /* Check if this is a direct open or not */
2524 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2525 {
2526 /* Get the device object */
2527 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2528 }
2529 else
2530 {
2531 /* Get the device object */
2532 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2533 }
2534
2535 /* Check if this is a file that was opened for Synch I/O */
2536 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2537 {
2538 /* Lock it */
2539 IopLockFileObject(FileObject);
2540
2541 /* Check if the caller just wants the position */
2542 if (FileInformationClass == FilePositionInformation)
2543 {
2544 /* Protect write in SEH */
2545 _SEH2_TRY
2546 {
2547 /* Write the offset */
2548 FileObject->CurrentByteOffset =
2549 ((PFILE_POSITION_INFORMATION)FileInformation)->
2550 CurrentByteOffset;
2551
2552 /* Fill out the I/O Status Block */
2553 IoStatusBlock->Information = 0;
2554 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2555 }
2556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2557 {
2558 /* Get the exception code */
2559 Status = _SEH2_GetExceptionCode();
2560 }
2561 _SEH2_END;
2562
2563 /* Update transfer count */
2564 IopUpdateTransferCount(IopOtherTransfer, Length);
2565
2566 /* Release the file lock, dereference the file and return */
2567 IopUnlockFileObject(FileObject);
2568 ObDereferenceObject(FileObject);
2569 return Status;
2570 }
2571 }
2572 else
2573 {
2574 /* Use local event */
2575 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2576 if (!Event)
2577 {
2578 ObDereferenceObject(FileObject);
2579 return STATUS_INSUFFICIENT_RESOURCES;
2580 }
2581
2582 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2583 LocalEvent = TRUE;
2584 }
2585
2586 /* Clear the File Object event */
2587 KeClearEvent(&FileObject->Event);
2588
2589 /* Allocate the IRP */
2590 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
2591 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2592
2593 /* Set the IRP */
2594 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2595 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2596 Irp->RequestorMode = PreviousMode;
2597 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2598 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2599 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2600 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2601 Irp->AssociatedIrp.SystemBuffer = NULL;
2602 Irp->MdlAddress = NULL;
2603 Irp->UserBuffer = FileInformation;
2604
2605 /* Set the Stack Data */
2606 StackPtr = IoGetNextIrpStackLocation(Irp);
2607 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
2608 StackPtr->FileObject = FileObject;
2609
2610 /* Enter SEH */
2611 _SEH2_TRY
2612 {
2613 /* Allocate a buffer */
2614 Irp->AssociatedIrp.SystemBuffer =
2615 ExAllocatePoolWithTag(NonPagedPool,
2616 Length,
2617 TAG_SYSB);
2618
2619 /* Copy the data into it */
2620 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2621 FileInformation,
2622 Length);
2623 }
2624 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2625 {
2626 /* Allocating failed, clean up and return the exception code */
2627 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2628 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2629 }
2630 _SEH2_END;
2631
2632 /* Set the flags */
2633 Irp->Flags |= (IRP_BUFFERED_IO |
2634 IRP_DEALLOCATE_BUFFER |
2635 IRP_DEFER_IO_COMPLETION);
2636
2637 /* Set the Parameters */
2638 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
2639 StackPtr->Parameters.SetFile.Length = Length;
2640
2641 /* Queue the IRP */
2642 IopQueueIrpToThread(Irp);
2643
2644 /* Update operation counts */
2645 IopUpdateOperationCount(IopOtherTransfer);
2646
2647 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
2648 /* Handle IO Completion Port quickly */
2649 if (FileInformationClass == FileCompletionInformation)
2650 {
2651 /* Check if the file object already has a completion port */
2652 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
2653 (FileObject->CompletionContext))
2654 {
2655 /* Fail */
2656 Status = STATUS_INVALID_PARAMETER;
2657 }
2658 else
2659 {
2660 /* Reference the Port */
2661 CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
2662 Status = ObReferenceObjectByHandle(CompletionInfo->Port,
2663 IO_COMPLETION_MODIFY_STATE,
2664 IoCompletionType,
2665 PreviousMode,
2666 (PVOID*)&Queue,
2667 NULL);
2668 if (NT_SUCCESS(Status))
2669 {
2670 /* Allocate the Context */
2671 Context = ExAllocatePoolWithTag(PagedPool,
2672 sizeof(IO_COMPLETION_CONTEXT),
2673 IOC_TAG);
2674 if (Context)
2675 {
2676 /* Set the Data */
2677 Context->Key = CompletionInfo->Key;
2678 Context->Port = Queue;
2679 if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
2680 CompletionContext,
2681 Context,
2682 NULL))
2683 {
2684 /*
2685 * Someone else set the completion port in the
2686 * meanwhile, so dereference the port and fail.
2687 */
2688 ExFreePoolWithTag(Context, IOC_TAG);
2689 ObDereferenceObject(Queue);
2690 Status = STATUS_INVALID_PARAMETER;
2691 }
2692 }
2693 else
2694 {
2695 /* Dereference the Port now */
2696 ObDereferenceObject(Queue);
2697 Status = STATUS_INSUFFICIENT_RESOURCES;
2698 }
2699 }
2700 }
2701
2702 /* Set the IRP Status */
2703 Irp->IoStatus.Status = Status;
2704 Irp->IoStatus.Information = 0;
2705 }
2706 else if (FileInformationClass == FileRenameInformation ||
2707 FileInformationClass == FileLinkInformation ||
2708 FileInformationClass == FileMoveClusterInformation)
2709 {
2710 /* Get associated information */
2711 RenameInfo = Irp->AssociatedIrp.SystemBuffer;
2712
2713 /* Only rename if:
2714 * -> We have a name
2715 * -> In unicode
2716 * -> sizes are valid
2717 */
2718 if (RenameInfo->FileNameLength != 0 &&
2719 !(RenameInfo->FileNameLength & 1) &&
2720 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
2721 {
2722 /* Properly set information received */
2723 if (FileInformationClass == FileMoveClusterInformation)
2724 {
2725 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
2726 }
2727 else
2728 {
2729 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
2730 }
2731
2732 /* If we got fully path OR relative target, attempt a parent directory open */
2733 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
2734 {
2735 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
2736 if (!NT_SUCCESS(Status))
2737 {
2738 Irp->IoStatus.Status = Status;
2739 }
2740 else
2741 {
2742 /* Call the Driver */
2743 Status = IoCallDriver(DeviceObject, Irp);
2744 }
2745 }
2746 else
2747 {
2748 /* Call the Driver */
2749 Status = IoCallDriver(DeviceObject, Irp);
2750 }
2751 }
2752 else
2753 {
2754 Status = STATUS_INVALID_PARAMETER;
2755 Irp->IoStatus.Status = Status;
2756 }
2757 }
2758 else
2759 {
2760 /* Call the Driver */
2761 Status = IoCallDriver(DeviceObject, Irp);
2762 }
2763
2764 /* Check if we're waiting for the IRP to complete */
2765 if (Status == STATUS_PENDING)
2766 {
2767 /* Check if this was async I/O */
2768 if (LocalEvent)
2769 {
2770 /* Then to a non-alertable wait */
2771 Status = KeWaitForSingleObject(Event,
2772 Executive,
2773 PreviousMode,
2774 FALSE,
2775 NULL);
2776 if (Status == STATUS_USER_APC)
2777 {
2778 /* Abort the request */
2779 IopAbortInterruptedIrp(Event, Irp);
2780 }
2781
2782 /* Set the final status */
2783 Status = KernelIosb.Status;
2784
2785 /* Enter SEH to write the IOSB back */
2786 _SEH2_TRY
2787 {
2788 /* Write it back to the caller */
2789 *IoStatusBlock = KernelIosb;
2790 }
2791 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2792 {
2793 /* Get the exception code */
2794 Status = _SEH2_GetExceptionCode();
2795 }
2796 _SEH2_END;
2797
2798 /* Free the event */
2799 ExFreePoolWithTag(Event, TAG_IO);
2800 }
2801 else
2802 {
2803 /* Wait for the IRP */
2804 Status = KeWaitForSingleObject(&FileObject->Event,
2805 Executive,
2806 PreviousMode,
2807 (FileObject->Flags &
2808 FO_ALERTABLE_IO) != 0,
2809 NULL);
2810 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2811 {
2812 /* Abort the request */
2813 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2814 }
2815
2816 /* Set the final status */
2817 Status = FileObject->FinalStatus;
2818
2819 /* Release the file lock */
2820 IopUnlockFileObject(FileObject);
2821 }
2822 }
2823 else
2824 {
2825 /* Free the event if we had one */
2826 if (LocalEvent)
2827 {
2828 /* Clear it in the IRP for completion */
2829 Irp->UserEvent = NULL;
2830 ExFreePoolWithTag(Event, TAG_IO);
2831 }
2832
2833 /* Set the caller IOSB */
2834 Irp->UserIosb = IoStatusBlock;
2835
2836 /* The IRP wasn't completed, complete it ourselves */
2837 KeRaiseIrql(APC_LEVEL, &OldIrql);
2838 IopCompleteRequest(&Irp->Tail.Apc,
2839 &NormalRoutine,
2840 &NormalContext,
2841 (PVOID*)&FileObject,
2842 &NormalContext);
2843 KeLowerIrql(OldIrql);
2844
2845 /* Release the file object if we had locked it*/
2846 if (!LocalEvent) IopUnlockFileObject(FileObject);
2847 }
2848
2849 if (TargetHandle != NULL)
2850 {
2851 ObCloseHandle(TargetHandle, KernelMode);
2852 }
2853
2854 /* Return the Status */
2855 return Status;
2856 }
2857
2858 /*
2859 * @unimplemented
2860 */
2861 NTSTATUS
2862 NTAPI
2863 NtSetQuotaInformationFile(IN HANDLE FileHandle,
2864 OUT PIO_STATUS_BLOCK IoStatusBlock,
2865 IN PVOID Buffer,
2866 IN ULONG BufferLength)
2867 {
2868 UNIMPLEMENTED;
2869 return STATUS_NOT_IMPLEMENTED;
2870 }
2871
2872 /*
2873 * @implemented
2874 */
2875 NTSTATUS
2876 NTAPI
2877 NtUnlockFile(IN HANDLE FileHandle,
2878 OUT PIO_STATUS_BLOCK IoStatusBlock,
2879 IN PLARGE_INTEGER ByteOffset,
2880 IN PLARGE_INTEGER Length,
2881 IN ULONG Key OPTIONAL)
2882 {
2883 PFILE_OBJECT FileObject;
2884 PLARGE_INTEGER LocalLength = NULL;
2885 PIRP Irp;
2886 PIO_STACK_LOCATION StackPtr;
2887 PDEVICE_OBJECT DeviceObject;
2888 PKEVENT Event = NULL;
2889 BOOLEAN LocalEvent = FALSE;
2890 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2891 LARGE_INTEGER CapturedByteOffset, CapturedLength;
2892 NTSTATUS Status;
2893 OBJECT_HANDLE_INFORMATION HandleInformation;
2894 IO_STATUS_BLOCK KernelIosb;
2895 PAGED_CODE();
2896 CapturedByteOffset.QuadPart = 0;
2897 CapturedLength.QuadPart = 0;
2898 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2899
2900 /* Get File Object */
2901 Status = ObReferenceObjectByHandle(FileHandle,
2902 0,
2903 IoFileObjectType,
2904 PreviousMode,
2905 (PVOID*)&FileObject,
2906 &HandleInformation);
2907 if (!NT_SUCCESS(Status)) return Status;
2908
2909 /* Check if we're called from user mode */
2910 if (PreviousMode != KernelMode)
2911 {
2912 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
2913 if (!(HandleInformation.GrantedAccess &
2914 (FILE_WRITE_DATA | FILE_READ_DATA)))
2915 {
2916 ObDereferenceObject(FileObject);
2917 return STATUS_ACCESS_DENIED;
2918 }
2919
2920 /* Enter SEH for probing */
2921 _SEH2_TRY
2922 {
2923 /* Probe the I/O Status block */
2924 ProbeForWriteIoStatusBlock(IoStatusBlock);
2925
2926 /* Probe and capture the large integers */
2927 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2928 CapturedLength = ProbeForReadLargeInteger(Length);
2929 }
2930 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2931 {
2932 /* Dereference the object and return exception code */
2933 ObDereferenceObject(FileObject);
2934 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2935 }
2936 _SEH2_END;
2937 }
2938 else
2939 {
2940 /* Otherwise, capture them directly */
2941 CapturedByteOffset = *ByteOffset;
2942 CapturedLength = *Length;
2943 }
2944
2945 /* Check if this is a direct open or not */
2946 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2947 {
2948 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2949 }
2950 else
2951 {
2952 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2953 }
2954
2955 /* Check if we should use Sync IO or not */
2956 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2957 {
2958 /* Lock it */
2959 IopLockFileObject(FileObject);
2960 }
2961 else
2962 {
2963 /* Use local event */
2964 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2965 if (!Event)
2966 {
2967 ObDereferenceObject(FileObject);
2968 return STATUS_INSUFFICIENT_RESOURCES;
2969 }
2970 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2971 LocalEvent = TRUE;
2972 }
2973
2974 /* Clear File Object event */
2975 KeClearEvent(&FileObject->Event);
2976
2977 /* Allocate the IRP */
2978 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2979 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2980
2981 /* Set up the IRP */
2982 Irp->RequestorMode = PreviousMode;
2983 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2984 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2985 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2986 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2987 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2988 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2989
2990 /* Set up Stack Data */
2991 StackPtr = IoGetNextIrpStackLocation(Irp);
2992 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
2993 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
2994 StackPtr->FileObject = FileObject;
2995
2996 /* Enter SEH */
2997 _SEH2_TRY
2998 {
2999 /* Allocate a buffer */
3000 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
3001 sizeof(LARGE_INTEGER),
3002 TAG_LOCK);
3003
3004 /* Set the length */
3005 *LocalLength = CapturedLength;
3006 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3007 StackPtr->Parameters.LockControl.Length = LocalLength;
3008 }
3009 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3010 {
3011 /* Allocating failed, clean up and return the exception code */
3012 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3013 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3014
3015 /* Return the exception code */
3016 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3017 }
3018 _SEH2_END;
3019
3020 /* Set Parameters */
3021 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3022 StackPtr->Parameters.LockControl.Key = Key;
3023
3024 /* Call the Driver */
3025 Status = IopPerformSynchronousRequest(DeviceObject,
3026 Irp,
3027 FileObject,
3028 FALSE,
3029 PreviousMode,
3030 !LocalEvent,
3031 IopOtherTransfer);
3032
3033 /* Check if this was async I/O */
3034 if (LocalEvent)
3035 {
3036 /* It was, finalize this request */
3037 Status = IopFinalizeAsynchronousIo(Status,
3038 Event,
3039 Irp,
3040 PreviousMode,
3041 &KernelIosb,
3042 IoStatusBlock);
3043 }
3044
3045 /* Return status */
3046 return Status;
3047 }
3048
3049 /*
3050 * @implemented
3051 */
3052 NTSTATUS
3053 NTAPI
3054 NtWriteFile(IN HANDLE FileHandle,
3055 IN HANDLE Event OPTIONAL,
3056 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
3057 IN PVOID ApcContext OPTIONAL,
3058 OUT PIO_STATUS_BLOCK IoStatusBlock,
3059 IN PVOID Buffer,
3060 IN ULONG Length,
3061 IN PLARGE_INTEGER ByteOffset OPTIONAL,
3062 IN PULONG Key OPTIONAL)
3063 {
3064 NTSTATUS Status;
3065 PFILE_OBJECT FileObject;
3066 PIRP Irp;
3067 PDEVICE_OBJECT DeviceObject;
3068 PIO_STACK_LOCATION StackPtr;
3069 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3070 PKEVENT EventObject = NULL;
3071 LARGE_INTEGER CapturedByteOffset;
3072 ULONG CapturedKey = 0;
3073 BOOLEAN Synchronous = FALSE;
3074 PMDL Mdl;
3075 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
3076 PAGED_CODE();
3077 CapturedByteOffset.QuadPart = 0;
3078 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3079
3080 /* Get File Object */
3081 Status = ObReferenceObjectByHandle(FileHandle,
3082 0,
3083 IoFileObjectType,
3084 PreviousMode,
3085 (PVOID*)&FileObject,
3086 &ObjectHandleInfo);
3087 if (!NT_SUCCESS(Status)) return Status;
3088
3089 /* Validate User-Mode Buffers */
3090 if (PreviousMode != KernelMode)
3091 {
3092 _SEH2_TRY
3093 {
3094 /*
3095 * Check if the handle has either FILE_WRITE_DATA or
3096 * FILE_APPEND_DATA granted. However, if this is a named pipe,
3097 * make sure we don't ask for FILE_APPEND_DATA as it interferes
3098 * with the FILE_CREATE_PIPE_INSTANCE access right!
3099 */
3100 if (!(ObjectHandleInfo.GrantedAccess &
3101 ((!(FileObject->Flags & FO_NAMED_PIPE) ?
3102 FILE_APPEND_DATA : 0) | FILE_WRITE_DATA)))
3103 {
3104 /* We failed */
3105 ObDereferenceObject(FileObject);
3106 _SEH2_YIELD(return STATUS_ACCESS_DENIED);
3107 }
3108
3109 /* Probe the status block */
3110 ProbeForWriteIoStatusBlock(IoStatusBlock);
3111
3112 /* Probe the read buffer */
3113 ProbeForRead(Buffer, Length, 1);
3114
3115 /* Check if we got a byte offset */
3116 if (ByteOffset)
3117 {
3118 /* Capture and probe it */
3119 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3120 }
3121
3122 /* Capture and probe the key */
3123 if (Key) CapturedKey = ProbeForReadUlong(Key);
3124 }
3125 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3126 {
3127 /* Return the exception code */
3128 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3129 }
3130 _SEH2_END;
3131 }
3132 else
3133 {
3134 /* Kernel mode: capture directly */
3135 if (ByteOffset) CapturedByteOffset = *ByteOffset;
3136 if (Key) CapturedKey = *Key;
3137 }
3138
3139 /* Check if this is an append operation */
3140 if ((ObjectHandleInfo.GrantedAccess &
3141 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
3142 {
3143 /* Give the drivers something to understand */
3144 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3145 CapturedByteOffset.u.HighPart = -1;
3146 }
3147
3148 /* Check for event */
3149 if (Event)
3150 {
3151 /* Reference it */
3152 Status = ObReferenceObjectByHandle(Event,
3153 EVENT_MODIFY_STATE,
3154 ExEventObjectType,
3155 PreviousMode,
3156 (PVOID*)&EventObject,
3157 NULL);
3158 if (!NT_SUCCESS(Status))
3159 {
3160 /* Fail */
3161 ObDereferenceObject(FileObject);
3162 return Status;
3163 }
3164
3165 /* Otherwise reset the event */
3166 KeClearEvent(EventObject);
3167 }
3168
3169 /* Check if we should use Sync IO or not */
3170 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3171 {
3172 /* Lock the file object */
3173 IopLockFileObject(FileObject);
3174
3175 /* Check if we don't have a byte offset avilable */
3176 if (!(ByteOffset) ||
3177 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
3178 (CapturedByteOffset.u.HighPart == -1)))
3179 {
3180 /* Use the Current Byte Offset instead */
3181 CapturedByteOffset = FileObject->CurrentByteOffset;
3182 }
3183
3184 /* Remember we are sync */
3185 Synchronous = TRUE;
3186 }
3187 else if (!(ByteOffset) &&
3188 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
3189 {
3190 /* Otherwise, this was async I/O without a byte offset, so fail */
3191 if (EventObject) ObDereferenceObject(EventObject);
3192 ObDereferenceObject(FileObject);
3193 return STATUS_INVALID_PARAMETER;
3194 }
3195
3196 /* Get the device object */
3197 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3198
3199 /* Clear the File Object's event */
3200 KeClearEvent(&FileObject->Event);
3201
3202 /* Allocate the IRP */
3203 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3204 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
3205
3206 /* Set the IRP */
3207 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3208 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3209 Irp->RequestorMode = PreviousMode;
3210 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
3211 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
3212 Irp->UserIosb = IoStatusBlock;
3213 Irp->UserEvent = EventObject;
3214 Irp->PendingReturned = FALSE;
3215 Irp->Cancel = FALSE;
3216 Irp->CancelRoutine = NULL;
3217 Irp->AssociatedIrp.SystemBuffer = NULL;
3218 Irp->MdlAddress = NULL;
3219
3220 /* Set the Stack Data */
3221 StackPtr = IoGetNextIrpStackLocation(Irp);
3222 StackPtr->MajorFunction = IRP_MJ_WRITE;
3223 StackPtr->FileObject = FileObject;
3224 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
3225 SL_WRITE_THROUGH : 0;
3226 StackPtr->Parameters.Write.Key = CapturedKey;
3227 StackPtr->Parameters.Write.Length = Length;
3228 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
3229
3230 /* Check if this is buffered I/O */
3231 if (DeviceObject->Flags & DO_BUFFERED_IO)
3232 {
3233 /* Check if we have a buffer length */
3234 if (Length)
3235 {
3236 /* Enter SEH */
3237 _SEH2_TRY
3238 {
3239 /* Allocate a buffer */
3240 Irp->AssociatedIrp.SystemBuffer =
3241 ExAllocatePoolWithTag(NonPagedPool,
3242 Length,
3243 TAG_SYSB);
3244
3245 /* Copy the data into it */
3246 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
3247 }
3248 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3249 {
3250 /* Allocating failed, clean up and return the exception code */
3251 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3252 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3253 }
3254 _SEH2_END;
3255
3256 /* Set the flags */
3257 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
3258 }
3259 else
3260 {
3261 /* Not writing anything */
3262 Irp->Flags = IRP_BUFFERED_IO;
3263 }
3264 }
3265 else if (DeviceObject->Flags & DO_DIRECT_IO)
3266 {
3267 /* Check if we have a buffer length */
3268 if (Length)
3269 {
3270 _SEH2_TRY
3271 {
3272 /* Allocate an MDL */
3273 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
3274 if (!Mdl)
3275 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
3276 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
3277 }
3278 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3279 {
3280 /* Allocating failed, clean up and return the exception code */
3281 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3282 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3283 }
3284 _SEH2_END;
3285 }
3286
3287 /* No allocation flags */
3288 Irp->Flags = 0;
3289 }
3290 else
3291 {
3292 /* No allocation flags, and use the buffer directly */
3293 Irp->Flags = 0;
3294 Irp->UserBuffer = Buffer;
3295 }
3296
3297 /* Now set the deferred read flags */
3298 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION);
3299 #if 0
3300 /* FIXME: VFAT SUCKS */
3301 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3302 #endif
3303
3304 /* Perform the call */
3305 return IopPerformSynchronousRequest(DeviceObject,
3306 Irp,
3307 FileObject,
3308 TRUE,
3309 PreviousMode,
3310 Synchronous,
3311 IopWriteTransfer);
3312 }
3313
3314 NTSTATUS
3315 NTAPI
3316 NtWriteFileGather(IN HANDLE FileHandle,
3317 IN HANDLE Event OPTIONAL,
3318 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3319 IN PVOID UserApcContext OPTIONAL,
3320 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3321 IN FILE_SEGMENT_ELEMENT BufferDescription [],
3322 IN ULONG BufferLength,
3323 IN PLARGE_INTEGER ByteOffset,
3324 IN PULONG Key OPTIONAL)
3325 {
3326 UNIMPLEMENTED;
3327 return STATUS_NOT_IMPLEMENTED;
3328 }
3329
3330 /*
3331 * @implemented
3332 */
3333 NTSTATUS
3334 NTAPI
3335 NtQueryVolumeInformationFile(IN HANDLE FileHandle,
3336 OUT PIO_STATUS_BLOCK IoStatusBlock,
3337 OUT PVOID FsInformation,
3338 IN ULONG Length,
3339 IN FS_INFORMATION_CLASS FsInformationClass)
3340 {
3341 PFILE_OBJECT FileObject;
3342 PIRP Irp;
3343 PIO_STACK_LOCATION StackPtr;
3344 PDEVICE_OBJECT DeviceObject;
3345 PKEVENT Event = NULL;
3346 BOOLEAN LocalEvent = FALSE;
3347 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3348 NTSTATUS Status;
3349 IO_STATUS_BLOCK KernelIosb;
3350 PAGED_CODE();
3351 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3352
3353 /* Check if we're called from user mode */
3354 if (PreviousMode != KernelMode)
3355 {
3356 /* Validate the information class */
3357 if ((FsInformationClass >= FileFsMaximumInformation) ||
3358 !(IopQueryFsOperationLength[FsInformationClass]))
3359 {
3360 /* Invalid class */
3361 return STATUS_INVALID_INFO_CLASS;
3362 }
3363
3364 /* Validate the length */
3365 if (Length < IopQueryFsOperationLength[FsInformationClass])
3366 {
3367 /* Invalid length */
3368 return STATUS_INFO_LENGTH_MISMATCH;
3369 }
3370
3371 /* Enter SEH for probing */
3372 _SEH2_TRY
3373 {
3374 /* Probe the I/O Status block */
3375 ProbeForWriteIoStatusBlock(IoStatusBlock);
3376
3377 /* Probe the information */
3378 ProbeForWrite(FsInformation, Length, sizeof(ULONG));
3379 }
3380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3381 {
3382 /* Return the exception code */
3383 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3384 }
3385 _SEH2_END;
3386 }
3387
3388 /* Get File Object */
3389 Status = ObReferenceObjectByHandle(FileHandle,
3390 IopQueryFsOperationAccess
3391 [FsInformationClass],
3392 IoFileObjectType,
3393 PreviousMode,
3394 (PVOID*)&FileObject,
3395 NULL);
3396 if (!NT_SUCCESS(Status)) return Status;
3397
3398 /* Check if we should use Sync IO or not */
3399 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3400 {
3401 /* Lock it */
3402 IopLockFileObject(FileObject);
3403 }
3404 else
3405 {
3406 /* Use local event */
3407 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3408 if (!Event)
3409 {
3410 ObDereferenceObject(FileObject);
3411 return STATUS_INSUFFICIENT_RESOURCES;
3412 }
3413 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3414 LocalEvent = TRUE;
3415 }
3416
3417 /* Get the device object */
3418 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3419
3420 /* Clear File Object event */
3421 KeClearEvent(&FileObject->Event);
3422
3423 /* Allocate the IRP */
3424 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3425 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3426
3427 /* Set up the IRP */
3428 Irp->RequestorMode = PreviousMode;
3429 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3430 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3431 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3432 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3433 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3434 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3435 Irp->UserBuffer = FsInformation;
3436 Irp->AssociatedIrp.SystemBuffer = NULL;
3437 Irp->MdlAddress = NULL;
3438
3439 /* Set up Stack Data */
3440 StackPtr = IoGetNextIrpStackLocation(Irp);
3441 StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
3442 StackPtr->FileObject = FileObject;
3443
3444 /* Enter SEH */
3445 _SEH2_TRY
3446 {
3447 /* Allocate a buffer */
3448 Irp->AssociatedIrp.SystemBuffer =
3449 ExAllocatePoolWithTag(NonPagedPool,
3450 Length,
3451 TAG_SYSB);
3452 }
3453 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3454 {
3455 /* Allocating failed, clean up and return the exception code */
3456 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3457 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3458 }
3459 _SEH2_END;
3460
3461 /* Set the flags for this buffered + deferred I/O */
3462 Irp->Flags |= (IRP_BUFFERED_IO |
3463 IRP_DEALLOCATE_BUFFER |
3464 IRP_INPUT_OPERATION |
3465 IRP_DEFER_IO_COMPLETION);
3466
3467 /* Set Parameters */
3468 StackPtr->Parameters.QueryVolume.Length = Length;
3469 StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
3470
3471 /* Call the Driver */
3472 Status = IopPerformSynchronousRequest(DeviceObject,
3473 Irp,
3474 FileObject,
3475 TRUE,
3476 PreviousMode,
3477 !LocalEvent,
3478 IopOtherTransfer);
3479
3480 /* Check if this was async I/O */
3481 if (LocalEvent)
3482 {
3483 /* It was, finalize this request */
3484 Status = IopFinalizeAsynchronousIo(Status,
3485 Event,
3486 Irp,
3487 PreviousMode,
3488 &KernelIosb,
3489 IoStatusBlock);
3490 }
3491
3492 /* Return status */
3493 return Status;
3494 }
3495
3496 /*
3497 * @implemented
3498 */
3499 NTSTATUS
3500 NTAPI
3501 NtSetVolumeInformationFile(IN HANDLE FileHandle,
3502 OUT PIO_STATUS_BLOCK IoStatusBlock,
3503 IN PVOID FsInformation,
3504 IN ULONG Length,
3505 IN FS_INFORMATION_CLASS FsInformationClass)
3506 {
3507 PFILE_OBJECT FileObject;
3508 PIRP Irp;
3509 PIO_STACK_LOCATION StackPtr;
3510 PDEVICE_OBJECT DeviceObject, TargetDeviceObject;
3511 PKEVENT Event = NULL;
3512 BOOLEAN LocalEvent = FALSE;
3513 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3514 NTSTATUS Status;
3515 IO_STATUS_BLOCK KernelIosb;
3516 TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure;
3517 PAGED_CODE();
3518 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3519
3520 /* Check if we're called from user mode */
3521 if (PreviousMode != KernelMode)
3522 {
3523 /* Validate the information class */
3524 if ((FsInformationClass >= FileFsMaximumInformation) ||
3525 !(IopSetFsOperationLength[FsInformationClass]))
3526 {
3527 /* Invalid class */
3528 return STATUS_INVALID_INFO_CLASS;
3529 }
3530
3531 /* Validate the length */
3532 if (Length < IopSetFsOperationLength[FsInformationClass])
3533 {
3534 /* Invalid length */
3535 return STATUS_INFO_LENGTH_MISMATCH;
3536 }
3537
3538 /* Enter SEH for probing */
3539 _SEH2_TRY
3540 {
3541 /* Probe the I/O Status block */
3542 ProbeForWriteIoStatusBlock(IoStatusBlock);
3543
3544 /* Probe the information */
3545 ProbeForRead(FsInformation, Length, sizeof(ULONG));
3546 }
3547 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3548 {
3549 /* Return the exception code */
3550 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3551 }
3552 _SEH2_END;
3553 }
3554
3555 /* Get File Object */
3556 Status = ObReferenceObjectByHandle(FileHandle,
3557 IopSetFsOperationAccess
3558 [FsInformationClass],
3559 IoFileObjectType,
3560 PreviousMode,
3561 (PVOID*)&FileObject,
3562 NULL);
3563 if (!NT_SUCCESS(Status)) return Status;
3564
3565 /* Get target device for notification */
3566 Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject);
3567 if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL;
3568
3569 /* Check if we should use Sync IO or not */
3570 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3571 {
3572 /* Lock it */
3573 IopLockFileObject(FileObject);
3574 }
3575 else
3576 {
3577 /* Use local event */
3578 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3579 if (!Event)
3580 {
3581 ObDereferenceObject(FileObject);
3582 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3583 return STATUS_INSUFFICIENT_RESOURCES;
3584 }
3585 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3586 LocalEvent = TRUE;
3587 }
3588
3589 /* Get the device object */
3590 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3591
3592 /* Clear File Object event */
3593 KeClearEvent(&FileObject->Event);
3594
3595 /* Allocate the IRP */
3596 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3597 if (!Irp)
3598 {
3599 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3600 return IopCleanupFailedIrp(FileObject, NULL, Event);
3601 }
3602
3603 /* Set up the IRP */
3604 Irp->RequestorMode = PreviousMode;
3605 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3606 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3607 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3608 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3609 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3610 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3611 Irp->UserBuffer = FsInformation;
3612 Irp->AssociatedIrp.SystemBuffer = NULL;
3613 Irp->MdlAddress = NULL;
3614
3615 /* Set up Stack Data */
3616 StackPtr = IoGetNextIrpStackLocation(Irp);
3617 StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
3618 StackPtr->FileObject = FileObject;
3619
3620 /* Enter SEH */
3621 _SEH2_TRY
3622 {
3623 /* Allocate a buffer */
3624 Irp->AssociatedIrp.SystemBuffer =
3625 ExAllocatePoolWithTag(NonPagedPool,
3626 Length,
3627 TAG_SYSB);
3628
3629 /* Copy the data into it */
3630 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
3631 }
3632 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3633 {
3634 /* Allocating failed, clean up and return the exception code */
3635 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3636 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3637 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3638 }
3639 _SEH2_END;
3640
3641 /* Set the flags for this buffered + deferred I/O */
3642 Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
3643
3644 /* Set Parameters */
3645 StackPtr->Parameters.SetVolume.Length = Length;
3646 StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
3647
3648 /* Call the Driver */
3649 Status = IopPerformSynchronousRequest(DeviceObject,
3650 Irp,
3651 FileObject,
3652 FALSE,
3653 PreviousMode,
3654 !LocalEvent,
3655 IopOtherTransfer);
3656
3657 /* Check if this was async I/O */
3658 if (LocalEvent)
3659 {
3660 /* It was, finalize this request */
3661 Status = IopFinalizeAsynchronousIo(Status,
3662 Event,
3663 Irp,
3664 PreviousMode,
3665 &KernelIosb,
3666 IoStatusBlock);
3667 }
3668
3669 if (TargetDeviceObject && NT_SUCCESS(Status))
3670 {
3671 /* Time to report change */
3672 NotificationStructure.Version = 1;
3673 NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
3674 NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE;
3675 NotificationStructure.FileObject = NULL;
3676 NotificationStructure.NameBufferOffset = - 1;
3677 Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure);
3678 }
3679
3680 /* Return status */
3681 return Status;
3682 }
3683
3684 /*
3685 * @unimplemented
3686 */
3687 NTSTATUS
3688 NTAPI
3689 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle)
3690 {
3691 UNIMPLEMENTED;
3692 return STATUS_NOT_IMPLEMENTED;
3693 }
3694
3695 /*
3696 * @unimplemented
3697 */
3698 NTSTATUS
3699 NTAPI
3700 NtRequestDeviceWakeup(IN HANDLE DeviceHandle)
3701 {
3702 UNIMPLEMENTED;
3703 return STATUS_NOT_IMPLEMENTED;
3704 }