Sync with trunk r63343.
[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 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2354 }
2355 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2356 {
2357 /* Allocating failed, clean up and return the exception code */
2358 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2359 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2360 }
2361 _SEH2_END;
2362
2363 }
2364
2365 /* No allocation flags */
2366 Irp->Flags = 0;
2367 }
2368 else
2369 {
2370 /* No allocation flags, and use the buffer directly */
2371 Irp->Flags = 0;
2372 Irp->UserBuffer = Buffer;
2373 }
2374
2375 /* Now set the deferred read flags */
2376 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
2377 #if 0
2378 /* FIXME: VFAT SUCKS */
2379 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
2380 #endif
2381
2382 /* Perform the call */
2383 return IopPerformSynchronousRequest(DeviceObject,
2384 Irp,
2385 FileObject,
2386 TRUE,
2387 PreviousMode,
2388 Synchronous,
2389 IopReadTransfer);
2390 }
2391
2392 /*
2393 * @unimplemented
2394 */
2395 NTSTATUS
2396 NTAPI
2397 NtReadFileScatter(IN HANDLE FileHandle,
2398 IN HANDLE Event OPTIONAL,
2399 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
2400 IN PVOID UserApcContext OPTIONAL,
2401 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
2402 IN FILE_SEGMENT_ELEMENT BufferDescription [],
2403 IN ULONG BufferLength,
2404 IN PLARGE_INTEGER ByteOffset,
2405 IN PULONG Key OPTIONAL)
2406 {
2407 UNIMPLEMENTED;
2408 return STATUS_NOT_IMPLEMENTED;
2409 }
2410
2411 /*
2412 * @unimplemented
2413 */
2414 NTSTATUS
2415 NTAPI
2416 NtSetEaFile(IN HANDLE FileHandle,
2417 IN PIO_STATUS_BLOCK IoStatusBlock,
2418 IN PVOID EaBuffer,
2419 IN ULONG EaBufferSize)
2420 {
2421 UNIMPLEMENTED;
2422 return STATUS_NOT_IMPLEMENTED;
2423 }
2424
2425 /*
2426 * @implemented
2427 */
2428 NTSTATUS
2429 NTAPI
2430 NtSetInformationFile(IN HANDLE FileHandle,
2431 OUT PIO_STATUS_BLOCK IoStatusBlock,
2432 IN PVOID FileInformation,
2433 IN ULONG Length,
2434 IN FILE_INFORMATION_CLASS FileInformationClass)
2435 {
2436 PFILE_OBJECT FileObject;
2437 NTSTATUS Status;
2438 PIRP Irp;
2439 PDEVICE_OBJECT DeviceObject;
2440 PIO_STACK_LOCATION StackPtr;
2441 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2442 PKEVENT Event = NULL;
2443 BOOLEAN LocalEvent = FALSE;
2444 PKNORMAL_ROUTINE NormalRoutine;
2445 PVOID NormalContext;
2446 KIRQL OldIrql;
2447 IO_STATUS_BLOCK KernelIosb;
2448 PVOID Queue;
2449 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
2450 PIO_COMPLETION_CONTEXT Context;
2451 PFILE_RENAME_INFORMATION RenameInfo;
2452 HANDLE TargetHandle = NULL;
2453 PAGED_CODE();
2454 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2455
2456 /* Check if we're called from user mode */
2457 if (PreviousMode != KernelMode)
2458 {
2459 /* Validate the information class */
2460 if ((FileInformationClass >= FileMaximumInformation) ||
2461 !(IopSetOperationLength[FileInformationClass]))
2462 {
2463 /* Invalid class */
2464 return STATUS_INVALID_INFO_CLASS;
2465 }
2466
2467 /* Validate the length */
2468 if (Length < IopSetOperationLength[FileInformationClass])
2469 {
2470 /* Invalid length */
2471 return STATUS_INFO_LENGTH_MISMATCH;
2472 }
2473
2474 /* Enter SEH for probing */
2475 _SEH2_TRY
2476 {
2477 /* Probe the I/O Status block */
2478 ProbeForWriteIoStatusBlock(IoStatusBlock);
2479
2480 /* Probe the information */
2481 ProbeForRead(FileInformation,
2482 Length,
2483 (Length == sizeof(BOOLEAN)) ?
2484 sizeof(BOOLEAN) : sizeof(ULONG));
2485 }
2486 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2487 {
2488 /* Return the exception code */
2489 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2490 }
2491 _SEH2_END;
2492 }
2493 else
2494 {
2495 /* Validate the information class */
2496 if ((FileInformationClass >= FileMaximumInformation) ||
2497 !(IopSetOperationLength[FileInformationClass]))
2498 {
2499 /* Invalid class */
2500 return STATUS_INVALID_INFO_CLASS;
2501 }
2502
2503 /* Validate the length */
2504 if (Length < IopSetOperationLength[FileInformationClass])
2505 {
2506 /* Invalid length */
2507 return STATUS_INFO_LENGTH_MISMATCH;
2508 }
2509 }
2510
2511 /* Reference the Handle */
2512 Status = ObReferenceObjectByHandle(FileHandle,
2513 IopSetOperationAccess
2514 [FileInformationClass],
2515 IoFileObjectType,
2516 PreviousMode,
2517 (PVOID *)&FileObject,
2518 NULL);
2519 if (!NT_SUCCESS(Status)) return Status;
2520
2521 /* Check if this is a direct open or not */
2522 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2523 {
2524 /* Get the device object */
2525 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2526 }
2527 else
2528 {
2529 /* Get the device object */
2530 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2531 }
2532
2533 /* Check if this is a file that was opened for Synch I/O */
2534 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2535 {
2536 /* Lock it */
2537 IopLockFileObject(FileObject);
2538
2539 /* Check if the caller just wants the position */
2540 if (FileInformationClass == FilePositionInformation)
2541 {
2542 /* Protect write in SEH */
2543 _SEH2_TRY
2544 {
2545 /* Write the offset */
2546 FileObject->CurrentByteOffset =
2547 ((PFILE_POSITION_INFORMATION)FileInformation)->
2548 CurrentByteOffset;
2549
2550 /* Fill out the I/O Status Block */
2551 IoStatusBlock->Information = 0;
2552 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2553 }
2554 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2555 {
2556 /* Get the exception code */
2557 Status = _SEH2_GetExceptionCode();
2558 }
2559 _SEH2_END;
2560
2561 /* Update transfer count */
2562 IopUpdateTransferCount(IopOtherTransfer, Length);
2563
2564 /* Release the file lock, dereference the file and return */
2565 IopUnlockFileObject(FileObject);
2566 ObDereferenceObject(FileObject);
2567 return Status;
2568 }
2569 }
2570 else
2571 {
2572 /* Use local event */
2573 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2574 if (!Event)
2575 {
2576 ObDereferenceObject(FileObject);
2577 return STATUS_INSUFFICIENT_RESOURCES;
2578 }
2579
2580 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2581 LocalEvent = TRUE;
2582 }
2583
2584 /* Clear the File Object event */
2585 KeClearEvent(&FileObject->Event);
2586
2587 /* Allocate the IRP */
2588 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
2589 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2590
2591 /* Set the IRP */
2592 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2593 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2594 Irp->RequestorMode = PreviousMode;
2595 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2596 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2597 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2598 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2599 Irp->AssociatedIrp.SystemBuffer = NULL;
2600 Irp->MdlAddress = NULL;
2601 Irp->UserBuffer = FileInformation;
2602
2603 /* Set the Stack Data */
2604 StackPtr = IoGetNextIrpStackLocation(Irp);
2605 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
2606 StackPtr->FileObject = FileObject;
2607
2608 /* Enter SEH */
2609 _SEH2_TRY
2610 {
2611 /* Allocate a buffer */
2612 Irp->AssociatedIrp.SystemBuffer =
2613 ExAllocatePoolWithTag(NonPagedPool,
2614 Length,
2615 TAG_SYSB);
2616
2617 /* Copy the data into it */
2618 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2619 FileInformation,
2620 Length);
2621 }
2622 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2623 {
2624 /* Allocating failed, clean up and return the exception code */
2625 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2626 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2627 }
2628 _SEH2_END;
2629
2630 /* Set the flags */
2631 Irp->Flags |= (IRP_BUFFERED_IO |
2632 IRP_DEALLOCATE_BUFFER |
2633 IRP_DEFER_IO_COMPLETION);
2634
2635 /* Set the Parameters */
2636 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
2637 StackPtr->Parameters.SetFile.Length = Length;
2638
2639 /* Queue the IRP */
2640 IopQueueIrpToThread(Irp);
2641
2642 /* Update operation counts */
2643 IopUpdateOperationCount(IopOtherTransfer);
2644
2645 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
2646 /* Handle IO Completion Port quickly */
2647 if (FileInformationClass == FileCompletionInformation)
2648 {
2649 /* Check if the file object already has a completion port */
2650 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
2651 (FileObject->CompletionContext))
2652 {
2653 /* Fail */
2654 Status = STATUS_INVALID_PARAMETER;
2655 }
2656 else
2657 {
2658 /* Reference the Port */
2659 CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
2660 Status = ObReferenceObjectByHandle(CompletionInfo->Port,
2661 IO_COMPLETION_MODIFY_STATE,
2662 IoCompletionType,
2663 PreviousMode,
2664 (PVOID*)&Queue,
2665 NULL);
2666 if (NT_SUCCESS(Status))
2667 {
2668 /* Allocate the Context */
2669 Context = ExAllocatePoolWithTag(PagedPool,
2670 sizeof(IO_COMPLETION_CONTEXT),
2671 IOC_TAG);
2672 if (Context)
2673 {
2674 /* Set the Data */
2675 Context->Key = CompletionInfo->Key;
2676 Context->Port = Queue;
2677 if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
2678 CompletionContext,
2679 Context,
2680 NULL))
2681 {
2682 /*
2683 * Someone else set the completion port in the
2684 * meanwhile, so dereference the port and fail.
2685 */
2686 ExFreePoolWithTag(Context, IOC_TAG);
2687 ObDereferenceObject(Queue);
2688 Status = STATUS_INVALID_PARAMETER;
2689 }
2690 }
2691 else
2692 {
2693 /* Dereference the Port now */
2694 ObDereferenceObject(Queue);
2695 Status = STATUS_INSUFFICIENT_RESOURCES;
2696 }
2697 }
2698 }
2699
2700 /* Set the IRP Status */
2701 Irp->IoStatus.Status = Status;
2702 Irp->IoStatus.Information = 0;
2703 }
2704 else if (FileInformationClass == FileRenameInformation ||
2705 FileInformationClass == FileLinkInformation ||
2706 FileInformationClass == FileMoveClusterInformation)
2707 {
2708 /* Get associated information */
2709 RenameInfo = Irp->AssociatedIrp.SystemBuffer;
2710
2711 /* Only rename if:
2712 * -> We have a name
2713 * -> In unicode
2714 * -> sizes are valid
2715 */
2716 if (RenameInfo->FileNameLength != 0 &&
2717 !(RenameInfo->FileNameLength & 1) &&
2718 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
2719 {
2720 /* Properly set information received */
2721 if (FileInformationClass == FileMoveClusterInformation)
2722 {
2723 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
2724 }
2725 else
2726 {
2727 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
2728 }
2729
2730 /* If we got fully path OR relative target, attempt a parent directory open */
2731 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
2732 {
2733 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
2734 if (!NT_SUCCESS(Status))
2735 {
2736 Irp->IoStatus.Status = Status;
2737 }
2738 else
2739 {
2740 /* Call the Driver */
2741 Status = IoCallDriver(DeviceObject, Irp);
2742 }
2743 }
2744 else
2745 {
2746 /* Call the Driver */
2747 Status = IoCallDriver(DeviceObject, Irp);
2748 }
2749 }
2750 else
2751 {
2752 Status = STATUS_INVALID_PARAMETER;
2753 Irp->IoStatus.Status = Status;
2754 }
2755 }
2756 else
2757 {
2758 /* Call the Driver */
2759 Status = IoCallDriver(DeviceObject, Irp);
2760 }
2761
2762 /* Check if we're waiting for the IRP to complete */
2763 if (Status == STATUS_PENDING)
2764 {
2765 /* Check if this was async I/O */
2766 if (LocalEvent)
2767 {
2768 /* Then to a non-alertable wait */
2769 Status = KeWaitForSingleObject(Event,
2770 Executive,
2771 PreviousMode,
2772 FALSE,
2773 NULL);
2774 if (Status == STATUS_USER_APC)
2775 {
2776 /* Abort the request */
2777 IopAbortInterruptedIrp(Event, Irp);
2778 }
2779
2780 /* Set the final status */
2781 Status = KernelIosb.Status;
2782
2783 /* Enter SEH to write the IOSB back */
2784 _SEH2_TRY
2785 {
2786 /* Write it back to the caller */
2787 *IoStatusBlock = KernelIosb;
2788 }
2789 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2790 {
2791 /* Get the exception code */
2792 Status = _SEH2_GetExceptionCode();
2793 }
2794 _SEH2_END;
2795
2796 /* Free the event */
2797 ExFreePoolWithTag(Event, TAG_IO);
2798 }
2799 else
2800 {
2801 /* Wait for the IRP */
2802 Status = KeWaitForSingleObject(&FileObject->Event,
2803 Executive,
2804 PreviousMode,
2805 (FileObject->Flags &
2806 FO_ALERTABLE_IO) != 0,
2807 NULL);
2808 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2809 {
2810 /* Abort the request */
2811 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2812 }
2813
2814 /* Set the final status */
2815 Status = FileObject->FinalStatus;
2816
2817 /* Release the file lock */
2818 IopUnlockFileObject(FileObject);
2819 }
2820 }
2821 else
2822 {
2823 /* Free the event if we had one */
2824 if (LocalEvent)
2825 {
2826 /* Clear it in the IRP for completion */
2827 Irp->UserEvent = NULL;
2828 ExFreePoolWithTag(Event, TAG_IO);
2829 }
2830
2831 /* Set the caller IOSB */
2832 Irp->UserIosb = IoStatusBlock;
2833
2834 /* The IRP wasn't completed, complete it ourselves */
2835 KeRaiseIrql(APC_LEVEL, &OldIrql);
2836 IopCompleteRequest(&Irp->Tail.Apc,
2837 &NormalRoutine,
2838 &NormalContext,
2839 (PVOID*)&FileObject,
2840 &NormalContext);
2841 KeLowerIrql(OldIrql);
2842
2843 /* Release the file object if we had locked it*/
2844 if (!LocalEvent) IopUnlockFileObject(FileObject);
2845 }
2846
2847 if (TargetHandle != NULL)
2848 {
2849 ObCloseHandle(TargetHandle, KernelMode);
2850 }
2851
2852 /* Return the Status */
2853 return Status;
2854 }
2855
2856 /*
2857 * @unimplemented
2858 */
2859 NTSTATUS
2860 NTAPI
2861 NtSetQuotaInformationFile(IN HANDLE FileHandle,
2862 OUT PIO_STATUS_BLOCK IoStatusBlock,
2863 IN PVOID Buffer,
2864 IN ULONG BufferLength)
2865 {
2866 UNIMPLEMENTED;
2867 return STATUS_NOT_IMPLEMENTED;
2868 }
2869
2870 /*
2871 * @implemented
2872 */
2873 NTSTATUS
2874 NTAPI
2875 NtUnlockFile(IN HANDLE FileHandle,
2876 OUT PIO_STATUS_BLOCK IoStatusBlock,
2877 IN PLARGE_INTEGER ByteOffset,
2878 IN PLARGE_INTEGER Length,
2879 IN ULONG Key OPTIONAL)
2880 {
2881 PFILE_OBJECT FileObject;
2882 PLARGE_INTEGER LocalLength = NULL;
2883 PIRP Irp;
2884 PIO_STACK_LOCATION StackPtr;
2885 PDEVICE_OBJECT DeviceObject;
2886 PKEVENT Event = NULL;
2887 BOOLEAN LocalEvent = FALSE;
2888 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2889 LARGE_INTEGER CapturedByteOffset, CapturedLength;
2890 NTSTATUS Status;
2891 OBJECT_HANDLE_INFORMATION HandleInformation;
2892 IO_STATUS_BLOCK KernelIosb;
2893 PAGED_CODE();
2894 CapturedByteOffset.QuadPart = 0;
2895 CapturedLength.QuadPart = 0;
2896 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2897
2898 /* Get File Object */
2899 Status = ObReferenceObjectByHandle(FileHandle,
2900 0,
2901 IoFileObjectType,
2902 PreviousMode,
2903 (PVOID*)&FileObject,
2904 &HandleInformation);
2905 if (!NT_SUCCESS(Status)) return Status;
2906
2907 /* Check if we're called from user mode */
2908 if (PreviousMode != KernelMode)
2909 {
2910 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
2911 if (!(HandleInformation.GrantedAccess &
2912 (FILE_WRITE_DATA | FILE_READ_DATA)))
2913 {
2914 ObDereferenceObject(FileObject);
2915 return STATUS_ACCESS_DENIED;
2916 }
2917
2918 /* Enter SEH for probing */
2919 _SEH2_TRY
2920 {
2921 /* Probe the I/O Status block */
2922 ProbeForWriteIoStatusBlock(IoStatusBlock);
2923
2924 /* Probe and capture the large integers */
2925 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2926 CapturedLength = ProbeForReadLargeInteger(Length);
2927 }
2928 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2929 {
2930 /* Dereference the object and return exception code */
2931 ObDereferenceObject(FileObject);
2932 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2933 }
2934 _SEH2_END;
2935 }
2936 else
2937 {
2938 /* Otherwise, capture them directly */
2939 CapturedByteOffset = *ByteOffset;
2940 CapturedLength = *Length;
2941 }
2942
2943 /* Check if this is a direct open or not */
2944 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2945 {
2946 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2947 }
2948 else
2949 {
2950 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2951 }
2952
2953 /* Check if we should use Sync IO or not */
2954 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2955 {
2956 /* Lock it */
2957 IopLockFileObject(FileObject);
2958 }
2959 else
2960 {
2961 /* Use local event */
2962 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2963 if (!Event)
2964 {
2965 ObDereferenceObject(FileObject);
2966 return STATUS_INSUFFICIENT_RESOURCES;
2967 }
2968 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2969 LocalEvent = TRUE;
2970 }
2971
2972 /* Clear File Object event */
2973 KeClearEvent(&FileObject->Event);
2974
2975 /* Allocate the IRP */
2976 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2977 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2978
2979 /* Set up the IRP */
2980 Irp->RequestorMode = PreviousMode;
2981 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2982 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2983 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2984 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2985 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2986 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2987
2988 /* Set up Stack Data */
2989 StackPtr = IoGetNextIrpStackLocation(Irp);
2990 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
2991 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
2992 StackPtr->FileObject = FileObject;
2993
2994 /* Enter SEH */
2995 _SEH2_TRY
2996 {
2997 /* Allocate a buffer */
2998 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
2999 sizeof(LARGE_INTEGER),
3000 TAG_LOCK);
3001
3002 /* Set the length */
3003 *LocalLength = CapturedLength;
3004 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3005 StackPtr->Parameters.LockControl.Length = LocalLength;
3006 }
3007 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3008 {
3009 /* Allocating failed, clean up and return the exception code */
3010 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3011 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3012
3013 /* Return the exception code */
3014 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3015 }
3016 _SEH2_END;
3017
3018 /* Set Parameters */
3019 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3020 StackPtr->Parameters.LockControl.Key = Key;
3021
3022 /* Call the Driver */
3023 Status = IopPerformSynchronousRequest(DeviceObject,
3024 Irp,
3025 FileObject,
3026 FALSE,
3027 PreviousMode,
3028 !LocalEvent,
3029 IopOtherTransfer);
3030
3031 /* Check if this was async I/O */
3032 if (LocalEvent)
3033 {
3034 /* It was, finalize this request */
3035 Status = IopFinalizeAsynchronousIo(Status,
3036 Event,
3037 Irp,
3038 PreviousMode,
3039 &KernelIosb,
3040 IoStatusBlock);
3041 }
3042
3043 /* Return status */
3044 return Status;
3045 }
3046
3047 /*
3048 * @implemented
3049 */
3050 NTSTATUS
3051 NTAPI
3052 NtWriteFile(IN HANDLE FileHandle,
3053 IN HANDLE Event OPTIONAL,
3054 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
3055 IN PVOID ApcContext OPTIONAL,
3056 OUT PIO_STATUS_BLOCK IoStatusBlock,
3057 IN PVOID Buffer,
3058 IN ULONG Length,
3059 IN PLARGE_INTEGER ByteOffset OPTIONAL,
3060 IN PULONG Key OPTIONAL)
3061 {
3062 NTSTATUS Status;
3063 PFILE_OBJECT FileObject;
3064 PIRP Irp;
3065 PDEVICE_OBJECT DeviceObject;
3066 PIO_STACK_LOCATION StackPtr;
3067 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3068 PKEVENT EventObject = NULL;
3069 LARGE_INTEGER CapturedByteOffset;
3070 ULONG CapturedKey = 0;
3071 BOOLEAN Synchronous = FALSE;
3072 PMDL Mdl;
3073 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
3074 PAGED_CODE();
3075 CapturedByteOffset.QuadPart = 0;
3076 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3077
3078 /* Get File Object */
3079 Status = ObReferenceObjectByHandle(FileHandle,
3080 0,
3081 IoFileObjectType,
3082 PreviousMode,
3083 (PVOID*)&FileObject,
3084 &ObjectHandleInfo);
3085 if (!NT_SUCCESS(Status)) return Status;
3086
3087 /* Validate User-Mode Buffers */
3088 if (PreviousMode != KernelMode)
3089 {
3090 _SEH2_TRY
3091 {
3092 /*
3093 * Check if the handle has either FILE_WRITE_DATA or
3094 * FILE_APPEND_DATA granted. However, if this is a named pipe,
3095 * make sure we don't ask for FILE_APPEND_DATA as it interferes
3096 * with the FILE_CREATE_PIPE_INSTANCE access right!
3097 */
3098 if (!(ObjectHandleInfo.GrantedAccess &
3099 ((!(FileObject->Flags & FO_NAMED_PIPE) ?
3100 FILE_APPEND_DATA : 0) | FILE_WRITE_DATA)))
3101 {
3102 /* We failed */
3103 ObDereferenceObject(FileObject);
3104 _SEH2_YIELD(return STATUS_ACCESS_DENIED);
3105 }
3106
3107 /* Probe the status block */
3108 ProbeForWriteIoStatusBlock(IoStatusBlock);
3109
3110 /* Probe the read buffer */
3111 ProbeForRead(Buffer, Length, 1);
3112
3113 /* Check if we got a byte offset */
3114 if (ByteOffset)
3115 {
3116 /* Capture and probe it */
3117 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3118 }
3119
3120 /* Capture and probe the key */
3121 if (Key) CapturedKey = ProbeForReadUlong(Key);
3122 }
3123 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3124 {
3125 /* Return the exception code */
3126 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3127 }
3128 _SEH2_END;
3129 }
3130 else
3131 {
3132 /* Kernel mode: capture directly */
3133 if (ByteOffset) CapturedByteOffset = *ByteOffset;
3134 if (Key) CapturedKey = *Key;
3135 }
3136
3137 /* Check if this is an append operation */
3138 if ((ObjectHandleInfo.GrantedAccess &
3139 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
3140 {
3141 /* Give the drivers something to understand */
3142 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3143 CapturedByteOffset.u.HighPart = -1;
3144 }
3145
3146 /* Check for event */
3147 if (Event)
3148 {
3149 /* Reference it */
3150 Status = ObReferenceObjectByHandle(Event,
3151 EVENT_MODIFY_STATE,
3152 ExEventObjectType,
3153 PreviousMode,
3154 (PVOID*)&EventObject,
3155 NULL);
3156 if (!NT_SUCCESS(Status))
3157 {
3158 /* Fail */
3159 ObDereferenceObject(FileObject);
3160 return Status;
3161 }
3162
3163 /* Otherwise reset the event */
3164 KeClearEvent(EventObject);
3165 }
3166
3167 /* Check if we should use Sync IO or not */
3168 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3169 {
3170 /* Lock the file object */
3171 IopLockFileObject(FileObject);
3172
3173 /* Check if we don't have a byte offset avilable */
3174 if (!(ByteOffset) ||
3175 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
3176 (CapturedByteOffset.u.HighPart == -1)))
3177 {
3178 /* Use the Current Byte Offset instead */
3179 CapturedByteOffset = FileObject->CurrentByteOffset;
3180 }
3181
3182 /* Remember we are sync */
3183 Synchronous = TRUE;
3184 }
3185 else if (!(ByteOffset) &&
3186 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
3187 {
3188 /* Otherwise, this was async I/O without a byte offset, so fail */
3189 if (EventObject) ObDereferenceObject(EventObject);
3190 ObDereferenceObject(FileObject);
3191 return STATUS_INVALID_PARAMETER;
3192 }
3193
3194 /* Get the device object */
3195 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3196
3197 /* Clear the File Object's event */
3198 KeClearEvent(&FileObject->Event);
3199
3200 /* Allocate the IRP */
3201 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3202 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
3203
3204 /* Set the IRP */
3205 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3206 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3207 Irp->RequestorMode = PreviousMode;
3208 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
3209 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
3210 Irp->UserIosb = IoStatusBlock;
3211 Irp->UserEvent = EventObject;
3212 Irp->PendingReturned = FALSE;
3213 Irp->Cancel = FALSE;
3214 Irp->CancelRoutine = NULL;
3215 Irp->AssociatedIrp.SystemBuffer = NULL;
3216 Irp->MdlAddress = NULL;
3217
3218 /* Set the Stack Data */
3219 StackPtr = IoGetNextIrpStackLocation(Irp);
3220 StackPtr->MajorFunction = IRP_MJ_WRITE;
3221 StackPtr->FileObject = FileObject;
3222 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
3223 SL_WRITE_THROUGH : 0;
3224 StackPtr->Parameters.Write.Key = CapturedKey;
3225 StackPtr->Parameters.Write.Length = Length;
3226 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
3227
3228 /* Check if this is buffered I/O */
3229 if (DeviceObject->Flags & DO_BUFFERED_IO)
3230 {
3231 /* Check if we have a buffer length */
3232 if (Length)
3233 {
3234 /* Enter SEH */
3235 _SEH2_TRY
3236 {
3237 /* Allocate a buffer */
3238 Irp->AssociatedIrp.SystemBuffer =
3239 ExAllocatePoolWithTag(NonPagedPool,
3240 Length,
3241 TAG_SYSB);
3242
3243 /* Copy the data into it */
3244 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
3245 }
3246 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3247 {
3248 /* Allocating failed, clean up and return the exception code */
3249 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3250 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3251 }
3252 _SEH2_END;
3253
3254 /* Set the flags */
3255 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
3256 }
3257 else
3258 {
3259 /* Not writing anything */
3260 Irp->Flags = IRP_BUFFERED_IO;
3261 }
3262 }
3263 else if (DeviceObject->Flags & DO_DIRECT_IO)
3264 {
3265 /* Check if we have a buffer length */
3266 if (Length)
3267 {
3268 _SEH2_TRY
3269 {
3270 /* Allocate an MDL */
3271 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
3272 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
3273 }
3274 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3275 {
3276 /* Allocating failed, clean up and return the exception code */
3277 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3278 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3279 }
3280 _SEH2_END;
3281 }
3282
3283 /* No allocation flags */
3284 Irp->Flags = 0;
3285 }
3286 else
3287 {
3288 /* No allocation flags, and use the buffer directly */
3289 Irp->Flags = 0;
3290 Irp->UserBuffer = Buffer;
3291 }
3292
3293 /* Now set the deferred read flags */
3294 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION);
3295 #if 0
3296 /* FIXME: VFAT SUCKS */
3297 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3298 #endif
3299
3300 /* Perform the call */
3301 return IopPerformSynchronousRequest(DeviceObject,
3302 Irp,
3303 FileObject,
3304 TRUE,
3305 PreviousMode,
3306 Synchronous,
3307 IopWriteTransfer);
3308 }
3309
3310 NTSTATUS
3311 NTAPI
3312 NtWriteFileGather(IN HANDLE FileHandle,
3313 IN HANDLE Event OPTIONAL,
3314 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3315 IN PVOID UserApcContext OPTIONAL,
3316 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3317 IN FILE_SEGMENT_ELEMENT BufferDescription [],
3318 IN ULONG BufferLength,
3319 IN PLARGE_INTEGER ByteOffset,
3320 IN PULONG Key OPTIONAL)
3321 {
3322 UNIMPLEMENTED;
3323 return STATUS_NOT_IMPLEMENTED;
3324 }
3325
3326 /*
3327 * @implemented
3328 */
3329 NTSTATUS
3330 NTAPI
3331 NtQueryVolumeInformationFile(IN HANDLE FileHandle,
3332 OUT PIO_STATUS_BLOCK IoStatusBlock,
3333 OUT PVOID FsInformation,
3334 IN ULONG Length,
3335 IN FS_INFORMATION_CLASS FsInformationClass)
3336 {
3337 PFILE_OBJECT FileObject;
3338 PIRP Irp;
3339 PIO_STACK_LOCATION StackPtr;
3340 PDEVICE_OBJECT DeviceObject;
3341 PKEVENT Event = NULL;
3342 BOOLEAN LocalEvent = FALSE;
3343 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3344 NTSTATUS Status;
3345 IO_STATUS_BLOCK KernelIosb;
3346 PAGED_CODE();
3347 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3348
3349 /* Check if we're called from user mode */
3350 if (PreviousMode != KernelMode)
3351 {
3352 /* Validate the information class */
3353 if ((FsInformationClass >= FileFsMaximumInformation) ||
3354 !(IopQueryFsOperationLength[FsInformationClass]))
3355 {
3356 /* Invalid class */
3357 return STATUS_INVALID_INFO_CLASS;
3358 }
3359
3360 /* Validate the length */
3361 if (Length < IopQueryFsOperationLength[FsInformationClass])
3362 {
3363 /* Invalid length */
3364 return STATUS_INFO_LENGTH_MISMATCH;
3365 }
3366
3367 /* Enter SEH for probing */
3368 _SEH2_TRY
3369 {
3370 /* Probe the I/O Status block */
3371 ProbeForWriteIoStatusBlock(IoStatusBlock);
3372
3373 /* Probe the information */
3374 ProbeForWrite(FsInformation, Length, sizeof(ULONG));
3375 }
3376 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3377 {
3378 /* Return the exception code */
3379 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3380 }
3381 _SEH2_END;
3382 }
3383
3384 /* Get File Object */
3385 Status = ObReferenceObjectByHandle(FileHandle,
3386 IopQueryFsOperationAccess
3387 [FsInformationClass],
3388 IoFileObjectType,
3389 PreviousMode,
3390 (PVOID*)&FileObject,
3391 NULL);
3392 if (!NT_SUCCESS(Status)) return Status;
3393
3394 /* Check if we should use Sync IO or not */
3395 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3396 {
3397 /* Lock it */
3398 IopLockFileObject(FileObject);
3399 }
3400 else
3401 {
3402 /* Use local event */
3403 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3404 if (!Event)
3405 {
3406 ObDereferenceObject(FileObject);
3407 return STATUS_INSUFFICIENT_RESOURCES;
3408 }
3409 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3410 LocalEvent = TRUE;
3411 }
3412
3413 /* Get the device object */
3414 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3415
3416 /* Clear File Object event */
3417 KeClearEvent(&FileObject->Event);
3418
3419 /* Allocate the IRP */
3420 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3421 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3422
3423 /* Set up the IRP */
3424 Irp->RequestorMode = PreviousMode;
3425 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3426 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3427 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3428 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3429 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3430 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3431 Irp->UserBuffer = FsInformation;
3432 Irp->AssociatedIrp.SystemBuffer = NULL;
3433 Irp->MdlAddress = NULL;
3434
3435 /* Set up Stack Data */
3436 StackPtr = IoGetNextIrpStackLocation(Irp);
3437 StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
3438 StackPtr->FileObject = FileObject;
3439
3440 /* Enter SEH */
3441 _SEH2_TRY
3442 {
3443 /* Allocate a buffer */
3444 Irp->AssociatedIrp.SystemBuffer =
3445 ExAllocatePoolWithTag(NonPagedPool,
3446 Length,
3447 TAG_SYSB);
3448 }
3449 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3450 {
3451 /* Allocating failed, clean up and return the exception code */
3452 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3453 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3454 }
3455 _SEH2_END;
3456
3457 /* Set the flags for this buffered + deferred I/O */
3458 Irp->Flags |= (IRP_BUFFERED_IO |
3459 IRP_DEALLOCATE_BUFFER |
3460 IRP_INPUT_OPERATION |
3461 IRP_DEFER_IO_COMPLETION);
3462
3463 /* Set Parameters */
3464 StackPtr->Parameters.QueryVolume.Length = Length;
3465 StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
3466
3467 /* Call the Driver */
3468 Status = IopPerformSynchronousRequest(DeviceObject,
3469 Irp,
3470 FileObject,
3471 TRUE,
3472 PreviousMode,
3473 !LocalEvent,
3474 IopOtherTransfer);
3475
3476 /* Check if this was async I/O */
3477 if (LocalEvent)
3478 {
3479 /* It was, finalize this request */
3480 Status = IopFinalizeAsynchronousIo(Status,
3481 Event,
3482 Irp,
3483 PreviousMode,
3484 &KernelIosb,
3485 IoStatusBlock);
3486 }
3487
3488 /* Return status */
3489 return Status;
3490 }
3491
3492 /*
3493 * @implemented
3494 */
3495 NTSTATUS
3496 NTAPI
3497 NtSetVolumeInformationFile(IN HANDLE FileHandle,
3498 OUT PIO_STATUS_BLOCK IoStatusBlock,
3499 IN PVOID FsInformation,
3500 IN ULONG Length,
3501 IN FS_INFORMATION_CLASS FsInformationClass)
3502 {
3503 PFILE_OBJECT FileObject;
3504 PIRP Irp;
3505 PIO_STACK_LOCATION StackPtr;
3506 PDEVICE_OBJECT DeviceObject, TargetDeviceObject;
3507 PKEVENT Event = NULL;
3508 BOOLEAN LocalEvent = FALSE;
3509 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3510 NTSTATUS Status;
3511 IO_STATUS_BLOCK KernelIosb;
3512 TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure;
3513 PAGED_CODE();
3514 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3515
3516 /* Check if we're called from user mode */
3517 if (PreviousMode != KernelMode)
3518 {
3519 /* Validate the information class */
3520 if ((FsInformationClass >= FileFsMaximumInformation) ||
3521 !(IopSetFsOperationLength[FsInformationClass]))
3522 {
3523 /* Invalid class */
3524 return STATUS_INVALID_INFO_CLASS;
3525 }
3526
3527 /* Validate the length */
3528 if (Length < IopSetFsOperationLength[FsInformationClass])
3529 {
3530 /* Invalid length */
3531 return STATUS_INFO_LENGTH_MISMATCH;
3532 }
3533
3534 /* Enter SEH for probing */
3535 _SEH2_TRY
3536 {
3537 /* Probe the I/O Status block */
3538 ProbeForWriteIoStatusBlock(IoStatusBlock);
3539
3540 /* Probe the information */
3541 ProbeForRead(FsInformation, Length, sizeof(ULONG));
3542 }
3543 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3544 {
3545 /* Return the exception code */
3546 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3547 }
3548 _SEH2_END;
3549 }
3550
3551 /* Get File Object */
3552 Status = ObReferenceObjectByHandle(FileHandle,
3553 IopSetFsOperationAccess
3554 [FsInformationClass],
3555 IoFileObjectType,
3556 PreviousMode,
3557 (PVOID*)&FileObject,
3558 NULL);
3559 if (!NT_SUCCESS(Status)) return Status;
3560
3561 /* Get target device for notification */
3562 Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject);
3563 if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL;
3564
3565 /* Check if we should use Sync IO or not */
3566 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3567 {
3568 /* Lock it */
3569 IopLockFileObject(FileObject);
3570 }
3571 else
3572 {
3573 /* Use local event */
3574 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3575 if (!Event)
3576 {
3577 ObDereferenceObject(FileObject);
3578 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3579 return STATUS_INSUFFICIENT_RESOURCES;
3580 }
3581 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3582 LocalEvent = TRUE;
3583 }
3584
3585 /* Get the device object */
3586 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3587
3588 /* Clear File Object event */
3589 KeClearEvent(&FileObject->Event);
3590
3591 /* Allocate the IRP */
3592 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3593 if (!Irp)
3594 {
3595 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3596 return IopCleanupFailedIrp(FileObject, NULL, Event);
3597 }
3598
3599 /* Set up the IRP */
3600 Irp->RequestorMode = PreviousMode;
3601 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3602 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3603 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3604 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3605 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3606 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3607 Irp->UserBuffer = FsInformation;
3608 Irp->AssociatedIrp.SystemBuffer = NULL;
3609 Irp->MdlAddress = NULL;
3610
3611 /* Set up Stack Data */
3612 StackPtr = IoGetNextIrpStackLocation(Irp);
3613 StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
3614 StackPtr->FileObject = FileObject;
3615
3616 /* Enter SEH */
3617 _SEH2_TRY
3618 {
3619 /* Allocate a buffer */
3620 Irp->AssociatedIrp.SystemBuffer =
3621 ExAllocatePoolWithTag(NonPagedPool,
3622 Length,
3623 TAG_SYSB);
3624
3625 /* Copy the data into it */
3626 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
3627 }
3628 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3629 {
3630 /* Allocating failed, clean up and return the exception code */
3631 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3632 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3633 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3634 }
3635 _SEH2_END;
3636
3637 /* Set the flags for this buffered + deferred I/O */
3638 Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
3639
3640 /* Set Parameters */
3641 StackPtr->Parameters.SetVolume.Length = Length;
3642 StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
3643
3644 /* Call the Driver */
3645 Status = IopPerformSynchronousRequest(DeviceObject,
3646 Irp,
3647 FileObject,
3648 FALSE,
3649 PreviousMode,
3650 !LocalEvent,
3651 IopOtherTransfer);
3652
3653 /* Check if this was async I/O */
3654 if (LocalEvent)
3655 {
3656 /* It was, finalize this request */
3657 Status = IopFinalizeAsynchronousIo(Status,
3658 Event,
3659 Irp,
3660 PreviousMode,
3661 &KernelIosb,
3662 IoStatusBlock);
3663 }
3664
3665 if (TargetDeviceObject && NT_SUCCESS(Status))
3666 {
3667 /* Time to report change */
3668 NotificationStructure.Version = 1;
3669 NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
3670 NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE;
3671 NotificationStructure.FileObject = NULL;
3672 NotificationStructure.NameBufferOffset = - 1;
3673 Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure);
3674 }
3675
3676 /* Return status */
3677 return Status;
3678 }
3679
3680 /*
3681 * @unimplemented
3682 */
3683 NTSTATUS
3684 NTAPI
3685 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle)
3686 {
3687 UNIMPLEMENTED;
3688 return STATUS_NOT_IMPLEMENTED;
3689 }
3690
3691 /*
3692 * @unimplemented
3693 */
3694 NTSTATUS
3695 NTAPI
3696 NtRequestDeviceWakeup(IN HANDLE DeviceHandle)
3697 {
3698 UNIMPLEMENTED;
3699 return STATUS_NOT_IMPLEMENTED;
3700 }