Cleanup isn't necessary after calling the driver in NtQueryDirectoryFile.
[reactos.git] / reactos / ntoskrnl / io / file.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/file.c
5 * PURPOSE: I/O File Object & NT File Handle Access/Managment of Files.
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 extern GENERIC_MAPPING IopFileMapping;
20
21 NTSTATUS
22 STDCALL
23 SeSetWorldSecurityDescriptor(SECURITY_INFORMATION SecurityInformation,
24 PSECURITY_DESCRIPTOR SecurityDescriptor,
25 PULONG BufferLength);
26
27 /* INTERNAL FUNCTIONS ********************************************************/
28
29 /*
30 * NAME INTERNAL
31 * IopCreateFile
32 *
33 * DESCRIPTION
34 *
35 * ARGUMENTS
36 *
37 * RETURN VALUE
38 *
39 * REVISIONS
40 */
41 NTSTATUS
42 STDCALL
43 IopCreateFile(PVOID ObjectBody,
44 PVOID Parent,
45 PWSTR RemainingPath,
46 POBJECT_CREATE_INFORMATION ObjectCreateInfo)
47 {
48 PDEVICE_OBJECT DeviceObject;
49 PFILE_OBJECT FileObject = (PFILE_OBJECT) ObjectBody;
50 POBJECT_TYPE ParentObjectType;
51 NTSTATUS Status;
52
53 DPRINT("IopCreateFile(ObjectBody 0x%p, Parent 0x%p, RemainingPath %S)\n",
54 ObjectBody,
55 Parent,
56 RemainingPath);
57
58 if (NULL == Parent)
59 {
60 /* This is probably an attempt to create a meta fileobject (eg. for FAT)
61 for the cache manager, so return STATUS_SUCCESS */
62 DPRINT("Parent object was NULL\n");
63 return(STATUS_SUCCESS);
64 }
65
66 ParentObjectType = BODY_TO_HEADER(Parent)->Type;
67
68 if (ParentObjectType != IoDeviceObjectType &&
69 ParentObjectType != IoFileObjectType)
70 {
71 DPRINT("Parent [%wZ] is a %S which is neither a file type nor a device type ; remaining path = %S\n",
72 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Parent))->Name,
73 BODY_TO_HEADER(Parent)->Type->Name.Buffer,
74 RemainingPath);
75 return(STATUS_UNSUCCESSFUL);
76 }
77
78 Status = ObReferenceObjectByPointer(Parent,
79 STANDARD_RIGHTS_REQUIRED,
80 ParentObjectType,
81 UserMode);
82 if (!NT_SUCCESS(Status))
83 {
84 CPRINT("Failed to reference parent object 0x%p\n", Parent);
85 return(Status);
86 }
87
88 if (ParentObjectType == IoDeviceObjectType)
89 {
90 /* Parent is a devce object */
91 DeviceObject = IoGetAttachedDevice((PDEVICE_OBJECT)Parent);
92 DPRINT("DeviceObject 0x%p\n", DeviceObject);
93
94 if (RemainingPath == NULL)
95 {
96 FileObject->Flags = FileObject->Flags | FO_DIRECT_DEVICE_OPEN;
97 FileObject->FileName.Buffer = 0;
98 FileObject->FileName.Length = FileObject->FileName.MaximumLength = 0;
99 }
100 else
101 {
102 if ((DeviceObject->DeviceType != FILE_DEVICE_FILE_SYSTEM)
103 && (DeviceObject->DeviceType != FILE_DEVICE_DISK)
104 && (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)
105 && (DeviceObject->DeviceType != FILE_DEVICE_TAPE)
106 && (DeviceObject->DeviceType != FILE_DEVICE_NETWORK)
107 && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
108 && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
109 {
110 CPRINT("Device was wrong type\n");
111 return(STATUS_UNSUCCESSFUL);
112 }
113
114 if (DeviceObject->DeviceType != FILE_DEVICE_NETWORK
115 && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
116 && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
117 {
118 if (!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
119 {
120 DPRINT("Mount the logical volume\n");
121 Status = IoMountVolume(DeviceObject, FALSE);
122 DPRINT("Status %x\n", Status);
123 if (!NT_SUCCESS(Status))
124 {
125 CPRINT("Failed to mount logical volume (Status %x)\n", Status);
126 return(Status);
127 }
128 }
129 DeviceObject = DeviceObject->Vpb->DeviceObject;
130 DPRINT("FsDeviceObject %lx\n", DeviceObject);
131 }
132 RtlCreateUnicodeString(&FileObject->FileName, RemainingPath);
133 }
134 }
135 else
136 {
137 /* Parent is a file object */
138 if (RemainingPath == NULL)
139 {
140 CPRINT("Device is unnamed\n");
141 return STATUS_UNSUCCESSFUL;
142 }
143
144 DeviceObject = ((PFILE_OBJECT)Parent)->DeviceObject;
145 DPRINT("DeviceObject 0x%p\n", DeviceObject);
146
147 FileObject->RelatedFileObject = (PFILE_OBJECT)Parent;
148
149 RtlCreateUnicodeString(&FileObject->FileName, RemainingPath);
150 }
151
152 DPRINT("FileObject->FileName %wZ\n",
153 &FileObject->FileName);
154 FileObject->DeviceObject = DeviceObject;
155 DPRINT("FileObject 0x%p DeviceObject 0x%p\n",
156 FileObject,
157 DeviceObject);
158 FileObject->Vpb = DeviceObject->Vpb;
159 FileObject->Type = IO_TYPE_FILE;
160
161 return(STATUS_SUCCESS);
162 }
163
164 VOID
165 STDCALL
166 IopDeleteFile(PVOID ObjectBody)
167 {
168 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
169 PIRP Irp;
170 PIO_STACK_LOCATION StackPtr;
171 NTSTATUS Status;
172 KEVENT Event;
173 PDEVICE_OBJECT DeviceObject;
174
175 DPRINT("IopDeleteFile()\n");
176
177 if (FileObject->DeviceObject)
178 {
179 /* Check if this is a direct open or not */
180 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
181 {
182 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
183 }
184 else
185 {
186 DeviceObject = IoGetRelatedDeviceObject(FileObject);
187 }
188
189 /* Clear and set up Events */
190 KeClearEvent(&FileObject->Event);
191 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
192
193 /* Allocate an IRP */
194 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
195
196 /* Set it up */
197 Irp->UserEvent = &Event;
198 Irp->UserIosb = &Irp->IoStatus;
199 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
200 Irp->Tail.Overlay.OriginalFileObject = FileObject;
201 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
202
203 /* Set up Stack Pointer Data */
204 StackPtr = IoGetNextIrpStackLocation(Irp);
205 StackPtr->MajorFunction = IRP_MJ_CLOSE;
206 StackPtr->DeviceObject = DeviceObject;
207 StackPtr->FileObject = FileObject;
208
209 /* Call the FS Driver */
210 Status = IoCallDriver(DeviceObject, Irp);
211
212 /* Wait for completion */
213 if (Status == STATUS_PENDING)
214 {
215 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
216 }
217 IoFreeIrp(Irp);
218
219 }
220
221 /* Clear the file name */
222 if (FileObject->FileName.Buffer)
223 {
224 ExFreePool(FileObject->FileName.Buffer);
225 FileObject->FileName.Buffer = NULL;
226 }
227
228 /* Free the completion context */
229 if (FileObject->CompletionContext)
230 {
231 ObDereferenceObject(FileObject->CompletionContext->Port);
232 ExFreePool(FileObject->CompletionContext);
233 }
234 }
235
236 NTSTATUS
237 STDCALL
238 IopSecurityFile(PVOID ObjectBody,
239 SECURITY_OPERATION_CODE OperationCode,
240 SECURITY_INFORMATION SecurityInformation,
241 PSECURITY_DESCRIPTOR SecurityDescriptor,
242 PULONG BufferLength,
243 PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
244 POOL_TYPE PoolType,
245 PGENERIC_MAPPING GenericMapping)
246 {
247 IO_STATUS_BLOCK IoStatusBlock;
248 PIO_STACK_LOCATION StackPtr;
249 PFILE_OBJECT FileObject;
250 PDEVICE_OBJECT DeviceObject;
251 ULONG MajorFunction;
252 PIRP Irp;
253 BOOLEAN LocalEvent = FALSE;
254 KEVENT Event;
255 NTSTATUS Status = STATUS_SUCCESS;
256
257 DPRINT("IopSecurityFile() called\n");
258
259 FileObject = (PFILE_OBJECT)ObjectBody;
260
261 if (OperationCode == QuerySecurityDescriptor)
262 {
263 MajorFunction = IRP_MJ_QUERY_SECURITY;
264 DPRINT("Query security descriptor\n");
265 }
266 else if (OperationCode == DeleteSecurityDescriptor)
267 {
268 DPRINT("Delete\n");
269 return STATUS_SUCCESS;
270 }
271 else if (OperationCode == AssignSecurityDescriptor)
272 {
273 /* If this is a direct open, we can assign it */
274 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
275 {
276 /* Get the Device Object */
277 DPRINT("here\n");
278 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
279
280 /* Assign the Security Descriptor */
281 DeviceObject->SecurityDescriptor = SecurityDescriptor;
282 }
283 return STATUS_SUCCESS;
284 }
285 else
286 {
287 MajorFunction = IRP_MJ_SET_SECURITY;
288 DPRINT("Set security descriptor\n");
289
290 /* If this is a direct open, we can set it */
291 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
292 {
293 DPRINT1("Set SD unimplemented for Devices\n");
294 return STATUS_SUCCESS;
295 }
296 }
297
298 /* Get the Device Object */
299 DPRINT1("FileObject: %p\n", FileObject);
300 DeviceObject = IoGetRelatedDeviceObject(FileObject);
301
302 /* Check if we should use Sync IO or not */
303 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
304 {
305 /* Use File Object event */
306 KeClearEvent(&FileObject->Event);
307 }
308 else
309 {
310 /* Use local event */
311 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
312 LocalEvent = TRUE;
313 }
314
315 /* Allocate the IRP */
316 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
317
318 /* Set the IRP */
319 Irp->Tail.Overlay.OriginalFileObject = FileObject;
320 Irp->RequestorMode = ExGetPreviousMode();
321 Irp->UserIosb = &IoStatusBlock;
322 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
323 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
324 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
325
326 /* Set Stack Parameters */
327 StackPtr = IoGetNextIrpStackLocation(Irp);
328 StackPtr->MajorFunction = MajorFunction;
329 StackPtr->FileObject = FileObject;
330
331 /* Set Parameters */
332 if (OperationCode == QuerySecurityDescriptor)
333 {
334 StackPtr->Parameters.QuerySecurity.SecurityInformation = SecurityInformation;
335 StackPtr->Parameters.QuerySecurity.Length = *BufferLength;
336 Irp->UserBuffer = SecurityDescriptor;
337 }
338 else
339 {
340 StackPtr->Parameters.SetSecurity.SecurityInformation = SecurityInformation;
341 StackPtr->Parameters.SetSecurity.SecurityDescriptor = SecurityDescriptor;
342 }
343
344 ObReferenceObject(FileObject);
345
346 /* Call the Driver */
347 Status = IoCallDriver(FileObject->DeviceObject, Irp);
348
349 if (Status == STATUS_PENDING)
350 {
351 if (LocalEvent)
352 {
353 KeWaitForSingleObject(&Event,
354 Executive,
355 KernelMode,
356 FileObject->Flags & FO_ALERTABLE_IO,
357 NULL);
358 Status = IoStatusBlock.Status;
359 }
360 else
361 {
362 KeWaitForSingleObject(&FileObject->Event,
363 Executive,
364 KernelMode,
365 FileObject->Flags & FO_ALERTABLE_IO,
366 NULL);
367 Status = FileObject->FinalStatus;
368 }
369 }
370
371 /* This Driver doesn't implement Security, so try to give it a default */
372 if (Status == STATUS_INVALID_DEVICE_REQUEST)
373 {
374 if (OperationCode == QuerySecurityDescriptor)
375 {
376 /* Set a World Security Descriptor */
377 Status = SeSetWorldSecurityDescriptor(SecurityInformation,
378 SecurityDescriptor,
379 BufferLength);
380 }
381 else
382 {
383 /* It wasn't a query, so just fake success */
384 Status = STATUS_SUCCESS;
385 }
386 }
387 else if (OperationCode == QuerySecurityDescriptor)
388 {
389 /* Return length */
390 *BufferLength = IoStatusBlock.Information;
391 }
392
393 /* Return Status */
394 return Status;
395 }
396
397 NTSTATUS
398 STDCALL
399 IopQueryNameFile(PVOID ObjectBody,
400 POBJECT_NAME_INFORMATION ObjectNameInfo,
401 ULONG Length,
402 PULONG ReturnLength)
403 {
404 POBJECT_NAME_INFORMATION LocalInfo;
405 PFILE_OBJECT FileObject;
406 ULONG LocalReturnLength;
407 NTSTATUS Status;
408
409 DPRINT1("IopQueryNameFile() called\n");
410
411 FileObject = (PFILE_OBJECT)ObjectBody;
412
413 /* Allocate Buffer */
414 LocalInfo = ExAllocatePool(PagedPool,
415 sizeof(OBJECT_NAME_INFORMATION) +
416 MAX_PATH * sizeof(WCHAR));
417 if (LocalInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES;
418
419 /* Query the name */
420 Status = ObQueryNameString(FileObject->DeviceObject,
421 LocalInfo,
422 MAX_PATH * sizeof(WCHAR),
423 &LocalReturnLength);
424 if (!NT_SUCCESS (Status))
425 {
426 ExFreePool (LocalInfo);
427 return Status;
428 }
429 DPRINT ("Device path: %wZ\n", &LocalInfo->Name);
430
431 /* Write Device Path */
432 Status = RtlAppendUnicodeStringToString(&ObjectNameInfo->Name,
433 &(LocalInfo)->Name);
434
435 /* Query the File name */
436 Status = IoQueryFileInformation(FileObject,
437 FileNameInformation,
438 LocalReturnLength,
439 LocalInfo,
440 NULL);
441 if (Status != STATUS_SUCCESS)
442 {
443 ExFreePool(LocalInfo);
444 return Status;
445 }
446
447 /* Write the Name */
448 Status = RtlAppendUnicodeToString(&ObjectNameInfo->Name,
449 ((PFILE_NAME_INFORMATION)LocalInfo)->FileName);
450 DPRINT ("Total path: %wZ\n", &ObjectNameInfo->Name);
451
452 /* Free buffer and return */
453 ExFreePool(LocalInfo);
454 return Status;
455 }
456
457 VOID
458 STDCALL
459 IopCloseFile(PVOID ObjectBody,
460 ULONG HandleCount)
461 {
462 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
463 KEVENT Event;
464 PIRP Irp;
465 PIO_STACK_LOCATION StackPtr;
466 NTSTATUS Status;
467 PDEVICE_OBJECT DeviceObject;
468
469 DPRINT("IopCloseFile()\n");
470
471 if (HandleCount > 1 || FileObject->DeviceObject == NULL) return;
472
473 /* Check if this is a direct open or not */
474 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
475 {
476 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
477 }
478 else
479 {
480 DeviceObject = IoGetRelatedDeviceObject(FileObject);
481 }
482
483 /* Clear and set up Events */
484 KeClearEvent(&FileObject->Event);
485 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
486
487 /* Allocate an IRP */
488 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
489
490 /* Set it up */
491 Irp->UserEvent = &Event;
492 Irp->UserIosb = &Irp->IoStatus;
493 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
494 Irp->Tail.Overlay.OriginalFileObject = FileObject;
495 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
496
497 /* Set up Stack Pointer Data */
498 StackPtr = IoGetNextIrpStackLocation(Irp);
499 StackPtr->MajorFunction = IRP_MJ_CLEANUP;
500 StackPtr->FileObject = FileObject;
501
502 /* Call the FS Driver */
503 Status = IoCallDriver(DeviceObject, Irp);
504
505 /* Wait for completion */
506 if (Status == STATUS_PENDING)
507 {
508 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
509 }
510 IoFreeIrp(Irp);
511 }
512
513 NTSTATUS
514 STDCALL
515 IopDeviceFsIoControl(IN HANDLE DeviceHandle,
516 IN HANDLE Event OPTIONAL,
517 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
518 IN PVOID UserApcContext OPTIONAL,
519 OUT PIO_STATUS_BLOCK IoStatusBlock,
520 IN ULONG IoControlCode,
521 IN PVOID InputBuffer,
522 IN ULONG InputBufferLength OPTIONAL,
523 OUT PVOID OutputBuffer,
524 IN ULONG OutputBufferLength OPTIONAL,
525 BOOLEAN IsDevIoCtl)
526 {
527 NTSTATUS Status = STATUS_SUCCESS;
528 PFILE_OBJECT FileObject;
529 PDEVICE_OBJECT DeviceObject;
530 PIRP Irp;
531 PIO_STACK_LOCATION StackPtr;
532 PKEVENT EventObject = NULL;
533 BOOLEAN LocalEvent = FALSE;
534 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
535
536 DPRINT("IopDeviceFsIoControl(DeviceHandle 0x%p Event 0x%p UserApcRoutine 0x%p "
537 "UserApcContext 0x%p IoStatusBlock 0x%p IoControlCode %x "
538 "InputBuffer 0x%p InputBufferLength %x OutputBuffer 0x%p "
539 "OutputBufferLength 0x%p)\n",
540 DeviceHandle,Event,UserApcRoutine,UserApcContext,IoStatusBlock,
541 IoControlCode,InputBuffer,InputBufferLength,OutputBuffer,
542 OutputBufferLength);
543
544 if (IoStatusBlock == NULL) return STATUS_ACCESS_VIOLATION;
545
546 /* Check granted access against the access rights from IoContolCode */
547 Status = ObReferenceObjectByHandle(DeviceHandle,
548 (IoControlCode >> 14) & 0x3,
549 IoFileObjectType,
550 PreviousMode,
551 (PVOID *) &FileObject,
552 NULL);
553 if (!NT_SUCCESS(Status)) return Status;
554
555 /* Check for an event */
556 if (Event)
557 {
558 /* Reference it */
559 Status = ObReferenceObjectByHandle(Event,
560 EVENT_MODIFY_STATE,
561 ExEventObjectType,
562 PreviousMode,
563 (PVOID*)&EventObject,
564 NULL);
565 if (!NT_SUCCESS(Status))
566 {
567 ObDereferenceObject (FileObject);
568 return Status;
569 }
570
571 /* Clear it */
572 KeClearEvent(EventObject);
573 }
574
575 /* Check if this is a direct open or not */
576 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
577 {
578 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
579 }
580 else
581 {
582 DeviceObject = IoGetRelatedDeviceObject(FileObject);
583 }
584
585 /* Check if we should use Sync IO or not */
586 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
587 {
588 /* Use File Object event */
589 KeClearEvent(&FileObject->Event);
590 }
591 else
592 {
593 /* Use local event */
594 LocalEvent = TRUE;
595 }
596
597 /* Build the IRP */
598 Irp = IoBuildDeviceIoControlRequest(IoControlCode,
599 DeviceObject,
600 InputBuffer,
601 InputBufferLength,
602 OutputBuffer,
603 OutputBufferLength,
604 FALSE,
605 EventObject,
606 IoStatusBlock);
607
608 /* Set some extra settings */
609 Irp->Tail.Overlay.OriginalFileObject = FileObject;
610 Irp->RequestorMode = PreviousMode;
611 Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
612 Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext;
613 StackPtr = IoGetNextIrpStackLocation(Irp);
614 StackPtr->FileObject = FileObject;
615 StackPtr->MajorFunction = IsDevIoCtl ?
616 IRP_MJ_DEVICE_CONTROL : IRP_MJ_FILE_SYSTEM_CONTROL;
617
618 /* Call the Driver */
619 Status = IoCallDriver(DeviceObject, Irp);
620 if (Status == STATUS_PENDING)
621 {
622 if (!LocalEvent)
623 {
624 KeWaitForSingleObject(&FileObject->Event,
625 Executive,
626 PreviousMode,
627 FileObject->Flags & FO_ALERTABLE_IO,
628 NULL);
629 Status = FileObject->FinalStatus;
630 }
631 }
632
633 /* Return the Status */
634 return Status;
635 }
636
637 /* FUNCTIONS *****************************************************************/
638
639 /*
640 * @unimplemented
641 */
642 NTSTATUS
643 STDCALL
644 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
645 IN ULONG Length,
646 IN BOOLEAN SetOperation)
647 {
648 UNIMPLEMENTED;
649 return STATUS_NOT_IMPLEMENTED;
650 }
651
652 /*
653 * @unimplemented
654 */
655 NTSTATUS
656 STDCALL
657 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
658 IN ULONG QuotaLength,
659 OUT PULONG ErrorOffset)
660 {
661 UNIMPLEMENTED;
662 return STATUS_NOT_IMPLEMENTED;
663 }
664
665 /*
666 * NAME EXPORTED
667 * IoCreateFile@56
668 *
669 * DESCRIPTION
670 * Either causes a new file or directory to be created, or it
671 * opens an existing file, device, directory or volume, giving
672 * the caller a handle for the file object. This handle can be
673 * used by subsequent calls to manipulate data within the file
674 * or the file object's state of attributes.
675 *
676 * ARGUMENTS
677 * FileHandle (OUT)
678 * Points to a variable which receives the file handle
679 * on return;
680 *
681 * DesiredAccess
682 * Desired access to the file;
683 *
684 * ObjectAttributes
685 * Structure describing the file;
686 *
687 * IoStatusBlock (OUT)
688 * Receives information about the operation on return;
689 *
690 * AllocationSize [OPTIONAL]
691 * Initial size of the file in bytes;
692 *
693 * FileAttributes
694 * Attributes to create the file with;
695 *
696 * ShareAccess
697 * Type of shared access the caller would like to the
698 * file;
699 *
700 * CreateDisposition
701 * Specifies what to do, depending on whether the
702 * file already exists;
703 *
704 * CreateOptions
705 * Options for creating a new file;
706 *
707 * EaBuffer [OPTIONAL]
708 * Undocumented;
709 *
710 * EaLength
711 * Undocumented;
712 *
713 * CreateFileType
714 * Type of file (normal, named pipe, mailslot) to create;
715 *
716 * ExtraCreateParameters [OPTIONAL]
717 * Additional creation data for named pipe and mailsots;
718 *
719 * Options
720 * Undocumented.
721 *
722 * RETURN VALUE
723 * Status
724 *
725 * NOTE
726 * Prototype taken from Bo Branten's ntifs.h v15.
727 * Description taken from old NtCreateFile's which is
728 * now a wrapper of this call.
729 *
730 * REVISIONS
731 *
732 * @implemented
733 */
734 NTSTATUS
735 STDCALL
736 IoCreateFile(OUT PHANDLE FileHandle,
737 IN ACCESS_MASK DesiredAccess,
738 IN POBJECT_ATTRIBUTES ObjectAttributes,
739 OUT PIO_STATUS_BLOCK IoStatusBlock,
740 IN PLARGE_INTEGER AllocationSize OPTIONAL,
741 IN ULONG FileAttributes,
742 IN ULONG ShareAccess,
743 IN ULONG CreateDisposition,
744 IN ULONG CreateOptions,
745 IN PVOID EaBuffer OPTIONAL,
746 IN ULONG EaLength,
747 IN CREATE_FILE_TYPE CreateFileType,
748 IN PVOID ExtraCreateParameters OPTIONAL,
749 IN ULONG Options)
750 {
751 PFILE_OBJECT FileObject = NULL;
752 PDEVICE_OBJECT DeviceObject;
753 PIRP Irp;
754 PEXTENDED_IO_STACK_LOCATION StackLoc;
755 IO_SECURITY_CONTEXT SecurityContext;
756 KPROCESSOR_MODE AccessMode;
757 HANDLE LocalHandle;
758 LARGE_INTEGER SafeAllocationSize;
759 PVOID SystemEaBuffer = NULL;
760 NTSTATUS Status = STATUS_SUCCESS;
761 AUX_DATA AuxData;
762 ACCESS_STATE AccessState;
763
764 DPRINT("IoCreateFile(FileHandle 0x%p, DesiredAccess %x, "
765 "ObjectAttributes 0x%p ObjectAttributes->ObjectName->Buffer %S)\n",
766 FileHandle,DesiredAccess,ObjectAttributes,
767 ObjectAttributes->ObjectName->Buffer);
768
769 ASSERT_IRQL(PASSIVE_LEVEL);
770
771 if (IoStatusBlock == NULL || FileHandle == NULL)
772 return STATUS_ACCESS_VIOLATION;
773
774 LocalHandle = 0;
775
776 if(Options & IO_NO_PARAMETER_CHECKING)
777 AccessMode = KernelMode;
778 else
779 AccessMode = ExGetPreviousMode();
780
781 if(AccessMode != KernelMode)
782 {
783 _SEH_TRY
784 {
785 ProbeForWriteHandle(FileHandle);
786 ProbeForWrite(IoStatusBlock,
787 sizeof(IO_STATUS_BLOCK),
788 sizeof(ULONG));
789 if(AllocationSize != NULL)
790 {
791 SafeAllocationSize = ProbeForReadLargeInteger(AllocationSize);
792 }
793 else
794 SafeAllocationSize.QuadPart = 0;
795
796 if(EaBuffer != NULL && EaLength > 0)
797 {
798 ProbeForRead(EaBuffer,
799 EaLength,
800 sizeof(ULONG));
801
802 /* marshal EaBuffer */
803 SystemEaBuffer = ExAllocatePool(NonPagedPool,
804 EaLength);
805 if(SystemEaBuffer == NULL)
806 {
807 Status = STATUS_INSUFFICIENT_RESOURCES;
808 _SEH_LEAVE;
809 }
810
811 RtlCopyMemory(SystemEaBuffer,
812 EaBuffer,
813 EaLength);
814 }
815 }
816 _SEH_HANDLE
817 {
818 Status = _SEH_GetExceptionCode();
819 }
820 _SEH_END;
821
822 if(!NT_SUCCESS(Status))
823 {
824 return Status;
825 }
826 }
827 else
828 {
829 if(AllocationSize != NULL)
830 SafeAllocationSize = *AllocationSize;
831 else
832 SafeAllocationSize.QuadPart = 0;
833
834 if(EaBuffer != NULL && EaLength > 0)
835 {
836 SystemEaBuffer = EaBuffer;
837 }
838 }
839
840 if(Options & IO_CHECK_CREATE_PARAMETERS)
841 {
842 DPRINT1("FIXME: IO_CHECK_CREATE_PARAMETERS not yet supported!\n");
843 }
844
845 /* First try to open an existing named object */
846 Status = ObOpenObjectByName(ObjectAttributes,
847 NULL,
848 NULL,
849 AccessMode,
850 DesiredAccess,
851 NULL,
852 &LocalHandle);
853
854 if (NT_SUCCESS(Status))
855 {
856 OBJECT_CREATE_INFORMATION ObjectCreateInfo;
857 OBJECT_ATTRIBUTES tmpObjectAttributes;
858 UNICODE_STRING ObjectName;
859
860 Status = ObReferenceObjectByHandle(LocalHandle,
861 DesiredAccess,
862 NULL,
863 AccessMode,
864 (PVOID*)&DeviceObject,
865 NULL);
866 ZwClose(LocalHandle);
867 if (!NT_SUCCESS(Status))
868 {
869 return Status;
870 }
871 if (BODY_TO_HEADER(DeviceObject)->Type != IoDeviceObjectType)
872 {
873 ObDereferenceObject (DeviceObject);
874 return STATUS_OBJECT_NAME_COLLISION;
875 }
876
877 Status = ObpCaptureObjectAttributes(ObjectAttributes,
878 AccessMode,
879 NULL,
880 &ObjectCreateInfo,
881 &ObjectName);
882 if (!NT_SUCCESS(Status))
883 {
884 ObDereferenceObject (DeviceObject);
885 return Status;
886 }
887
888 InitializeObjectAttributes(&tmpObjectAttributes,
889 NULL,
890 ObjectCreateInfo.Attributes & OBJ_INHERIT,
891 0,
892 NULL);
893 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
894 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
895
896
897 /* FIXME: wt... */
898 Status = ObCreateObject(KernelMode,
899 IoFileObjectType,
900 &tmpObjectAttributes,
901 KernelMode,
902 NULL,
903 sizeof(FILE_OBJECT),
904 0,
905 0,
906 (PVOID*)&FileObject);
907
908
909 /* Set File Object Data */
910 FileObject->DeviceObject = IoGetAttachedDevice(DeviceObject);
911 FileObject->Vpb = FileObject->DeviceObject->Vpb;
912
913 /* HACK */
914 FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
915 DPRINT("%wZ\n", ObjectAttributes->ObjectName);
916
917 ObDereferenceObject (DeviceObject);
918 }
919
920
921 if (FileObject == NULL)
922 {
923 Status = ObCreateObject(AccessMode,
924 IoFileObjectType,
925 ObjectAttributes,
926 AccessMode,
927 NULL,
928 sizeof(FILE_OBJECT),
929 0,
930 0,
931 (PVOID*)&FileObject);
932 if (!NT_SUCCESS(Status))
933 {
934 DPRINT("ObCreateObject() failed! (Status %lx)\n", Status);
935 return Status;
936 }
937 }
938 RtlMapGenericMask(&DesiredAccess,
939 &BODY_TO_HEADER(FileObject)->Type->TypeInfo.GenericMapping);
940
941 Status = ObInsertObject ((PVOID)FileObject,
942 NULL,
943 DesiredAccess,
944 0,
945 NULL,
946 &LocalHandle);
947 if (!NT_SUCCESS(Status))
948 {
949 DPRINT("ObInsertObject() failed! (Status %lx)\n", Status);
950 ObMakeTemporaryObject(FileObject);
951 ObDereferenceObject (FileObject);
952 return Status;
953 }
954
955 if (CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
956 {
957 FileObject->Flags |= (FO_ALERTABLE_IO | FO_SYNCHRONOUS_IO);
958 }
959 if (CreateOptions & FILE_SYNCHRONOUS_IO_NONALERT)
960 {
961 FileObject->Flags |= FO_SYNCHRONOUS_IO;
962 }
963
964 if (CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
965 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
966
967 /*
968 * FIXME: We should get the access state from Ob once this function becomes
969 * a parse routine once the Ob is refactored.
970 */
971 SeCreateAccessState(&AccessState, &AuxData, FILE_ALL_ACCESS, NULL);
972
973 SecurityContext.SecurityQos = NULL; /* ?? */
974 SecurityContext.AccessState = &AccessState;
975 SecurityContext.DesiredAccess = DesiredAccess;
976 SecurityContext.FullCreateOptions = 0; /* ?? */
977
978 KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, TRUE);
979 KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
980
981 DPRINT("FileObject 0x%p\n", FileObject);
982 DPRINT("FileObject->DeviceObject 0x%p\n", FileObject->DeviceObject);
983 /*
984 * Create a new IRP to hand to
985 * the FS driver: this may fail
986 * due to resource shortage.
987 */
988 Irp = IoAllocateIrp(FileObject->DeviceObject->StackSize, FALSE);
989 if (Irp == NULL)
990 {
991 ZwClose(LocalHandle);
992 return STATUS_UNSUCCESSFUL;
993 }
994
995 //trigger FileObject/Event dereferencing
996 Irp->Tail.Overlay.OriginalFileObject = FileObject;
997 Irp->RequestorMode = AccessMode;
998 Irp->UserIosb = IoStatusBlock;
999 Irp->AssociatedIrp.SystemBuffer = SystemEaBuffer;
1000 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
1001 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1002 Irp->UserEvent = &FileObject->Event;
1003 Irp->Overlay.AllocationSize = SafeAllocationSize;
1004
1005 /*
1006 * Get the stack location for the new
1007 * IRP and prepare it.
1008 */
1009 StackLoc = (PEXTENDED_IO_STACK_LOCATION)IoGetNextIrpStackLocation(Irp);
1010 StackLoc->MinorFunction = 0;
1011 StackLoc->Flags = (UCHAR)Options;
1012 StackLoc->Control = 0;
1013 StackLoc->DeviceObject = FileObject->DeviceObject;
1014 StackLoc->FileObject = FileObject;
1015
1016 switch (CreateFileType)
1017 {
1018 default:
1019 case CreateFileTypeNone:
1020 StackLoc->MajorFunction = IRP_MJ_CREATE;
1021 StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
1022 StackLoc->Parameters.Create.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
1023 StackLoc->Parameters.Create.Options |= (CreateDisposition << 24);
1024 StackLoc->Parameters.Create.FileAttributes = (USHORT)FileAttributes;
1025 StackLoc->Parameters.Create.ShareAccess = (USHORT)ShareAccess;
1026 StackLoc->Parameters.Create.EaLength = SystemEaBuffer != NULL ? EaLength : 0;
1027 break;
1028
1029 case CreateFileTypeNamedPipe:
1030 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
1031 StackLoc->Parameters.CreatePipe.SecurityContext = &SecurityContext;
1032 StackLoc->Parameters.CreatePipe.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
1033 StackLoc->Parameters.CreatePipe.Options |= (CreateDisposition << 24);
1034 StackLoc->Parameters.CreatePipe.ShareAccess = (USHORT)ShareAccess;
1035 StackLoc->Parameters.CreatePipe.Parameters = ExtraCreateParameters;
1036 break;
1037
1038 case CreateFileTypeMailslot:
1039 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
1040 StackLoc->Parameters.CreateMailslot.SecurityContext = &SecurityContext;
1041 StackLoc->Parameters.CreateMailslot.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
1042 StackLoc->Parameters.CreateMailslot.Options |= (CreateDisposition << 24);
1043 StackLoc->Parameters.CreateMailslot.ShareAccess = (USHORT)ShareAccess;
1044 StackLoc->Parameters.CreateMailslot.Parameters = ExtraCreateParameters;
1045 break;
1046 }
1047
1048 /*
1049 * Now call the driver and
1050 * possibly wait if it can
1051 * not complete the request
1052 * immediately.
1053 */
1054 Status = IofCallDriver(FileObject->DeviceObject, Irp );
1055 DPRINT("Status :%x\n", Status);
1056
1057 if (Status == STATUS_PENDING)
1058 {
1059 KeWaitForSingleObject(&FileObject->Event,
1060 Executive,
1061 AccessMode,
1062 FALSE,
1063 NULL);
1064 Status = IoStatusBlock->Status;
1065 }
1066 if (!NT_SUCCESS(Status))
1067 {
1068 DPRINT("Failing create request with status %x\n", Status);
1069 FileObject->DeviceObject = NULL;
1070 FileObject->Vpb = NULL;
1071
1072 ZwClose(LocalHandle);
1073 }
1074 else
1075 {
1076 _SEH_TRY
1077 {
1078 *FileHandle = LocalHandle;
1079 }
1080 _SEH_HANDLE
1081 {
1082 Status = _SEH_GetExceptionCode();
1083 }
1084 _SEH_END;
1085 }
1086
1087 /* cleanup EABuffer if captured */
1088 if(AccessMode != KernelMode && SystemEaBuffer != NULL)
1089 {
1090 ExFreePool(SystemEaBuffer);
1091 }
1092
1093 ASSERT_IRQL(PASSIVE_LEVEL);
1094
1095 DPRINT("Finished IoCreateFile() (*FileHandle) 0x%p\n", (*FileHandle));
1096
1097 return Status;
1098 }
1099
1100 /*
1101 * @unimplemented
1102 */
1103 NTSTATUS
1104 STDCALL
1105 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
1106 IN ACCESS_MASK DesiredAccess,
1107 IN POBJECT_ATTRIBUTES ObjectAttributes,
1108 OUT PIO_STATUS_BLOCK IoStatusBlock,
1109 IN PLARGE_INTEGER AllocationSize OPTIONAL,
1110 IN ULONG FileAttributes,
1111 IN ULONG ShareAccess,
1112 IN ULONG Disposition,
1113 IN ULONG CreateOptions,
1114 IN PVOID EaBuffer OPTIONAL,
1115 IN ULONG EaLength,
1116 IN CREATE_FILE_TYPE CreateFileType,
1117 IN PVOID ExtraCreateParameters OPTIONAL,
1118 IN ULONG Options,
1119 IN PVOID DeviceObject)
1120 {
1121 UNIMPLEMENTED;
1122 return STATUS_NOT_IMPLEMENTED;
1123 }
1124
1125 /*
1126 * NAME EXPORTED
1127 * IoCreateStreamFileObject@8
1128 *
1129 * DESCRIPTION
1130 *
1131 * ARGUMENTS
1132 * FileObject
1133 * ?
1134 *
1135 * DeviceObject
1136 * ?
1137 *
1138 * RETURN VALUE
1139 *
1140 * NOTE
1141 *
1142 * REVISIONS
1143 *
1144 * @implemented
1145 */
1146 PFILE_OBJECT
1147 STDCALL
1148 IoCreateStreamFileObject(PFILE_OBJECT FileObject,
1149 PDEVICE_OBJECT DeviceObject)
1150 {
1151 PFILE_OBJECT CreatedFileObject;
1152 NTSTATUS Status;
1153
1154 /* FIXME: This function should call ObInsertObject. The "Lite" version
1155 doesnt. This function is also called from IoCreateFile for some
1156 reason. These hacks need to be removed.
1157 */
1158
1159 DPRINT("IoCreateStreamFileObject(FileObject 0x%p, DeviceObject 0x%p)\n",
1160 FileObject, DeviceObject);
1161 PAGED_CODE();
1162
1163 /* Create the File Object */
1164 Status = ObCreateObject(KernelMode,
1165 IoFileObjectType,
1166 NULL,
1167 KernelMode,
1168 NULL,
1169 sizeof(FILE_OBJECT),
1170 0,
1171 0,
1172 (PVOID*)&CreatedFileObject);
1173 if (!NT_SUCCESS(Status))
1174 {
1175 DPRINT1("Could not create FileObject\n");
1176 return (NULL);
1177 }
1178
1179 /* Choose Device Object */
1180 if (FileObject) DeviceObject = FileObject->DeviceObject;
1181 DPRINT("DeviceObject 0x%p\n", DeviceObject);
1182
1183 /* HACK */
1184 DeviceObject = IoGetAttachedDevice(DeviceObject);
1185
1186 /* Set File Object Data */
1187 CreatedFileObject->DeviceObject = DeviceObject;
1188 CreatedFileObject->Vpb = DeviceObject->Vpb;
1189 CreatedFileObject->Type = IO_TYPE_FILE;
1190 CreatedFileObject->Flags |= FO_STREAM_FILE;
1191
1192 /* Initialize Lock and Event */
1193 KeInitializeEvent(&CreatedFileObject->Event, NotificationEvent, FALSE);
1194 KeInitializeEvent(&CreatedFileObject->Lock, SynchronizationEvent, TRUE);
1195
1196 /* Return file */
1197 return CreatedFileObject;
1198 }
1199
1200 /*
1201 * @unimplemented
1202 */
1203 PFILE_OBJECT
1204 STDCALL
1205 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
1206 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
1207 OUT PHANDLE FileObjectHandle OPTIONAL)
1208 {
1209 UNIMPLEMENTED;
1210 return 0;
1211 }
1212
1213 /*
1214 * @unimplemented
1215 */
1216 PFILE_OBJECT
1217 STDCALL
1218 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
1219 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
1220 {
1221 UNIMPLEMENTED;
1222 return 0;
1223 }
1224
1225 /*
1226 * @implemented
1227 */
1228 PGENERIC_MAPPING
1229 STDCALL
1230 IoGetFileObjectGenericMapping(VOID)
1231 {
1232 return &IopFileMapping;
1233 }
1234
1235 /*
1236 * @implemented
1237 */
1238 BOOLEAN
1239 STDCALL
1240 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
1241 {
1242 /* Return the flag status */
1243 return (FileObject->Flags & FO_REMOTE_ORIGIN);
1244 }
1245
1246 /*
1247 * @unimplemented
1248 */
1249 NTSTATUS
1250 STDCALL
1251 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
1252 OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
1253 {
1254 UNIMPLEMENTED;
1255 return STATUS_NOT_IMPLEMENTED;
1256 }
1257
1258 /*
1259 * @implemented
1260 */
1261 NTSTATUS
1262 STDCALL
1263 IoQueryFileInformation(IN PFILE_OBJECT FileObject,
1264 IN FILE_INFORMATION_CLASS FileInformationClass,
1265 IN ULONG Length,
1266 OUT PVOID FileInformation,
1267 OUT PULONG ReturnedLength)
1268 {
1269 IO_STATUS_BLOCK IoStatusBlock;
1270 PIRP Irp;
1271 PDEVICE_OBJECT DeviceObject;
1272 PIO_STACK_LOCATION StackPtr;
1273 BOOLEAN LocalEvent = FALSE;
1274 KEVENT Event;
1275 NTSTATUS Status;
1276
1277 ASSERT(FileInformation != NULL);
1278
1279 Status = ObReferenceObjectByPointer(FileObject,
1280 FILE_READ_ATTRIBUTES,
1281 IoFileObjectType,
1282 KernelMode);
1283 if (!NT_SUCCESS(Status)) return(Status);
1284
1285 DPRINT("FileObject 0x%p\n", FileObject);
1286
1287 /* Get the Device Object */
1288 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1289
1290 /* Check if we should use Sync IO or not */
1291 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1292 {
1293 /* Use File Object event */
1294 KeClearEvent(&FileObject->Event);
1295 }
1296 else
1297 {
1298 /* Use local event */
1299 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1300 LocalEvent = TRUE;
1301 }
1302
1303 /* Allocate the IRP */
1304 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1305
1306 /* Set the IRP */
1307 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1308 Irp->RequestorMode = KernelMode;
1309 Irp->AssociatedIrp.SystemBuffer = FileInformation;
1310 Irp->UserIosb = &IoStatusBlock;
1311 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1312 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1313 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1314
1315 /* Set the Stack Data */
1316 StackPtr = IoGetNextIrpStackLocation(Irp);
1317 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
1318 StackPtr->FileObject = FileObject;
1319
1320 /* Set Parameters */
1321 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
1322 StackPtr->Parameters.QueryFile.Length = Length;
1323
1324 /* Call the Driver */
1325 Status = IoCallDriver(FileObject->DeviceObject, Irp);
1326
1327 if (Status == STATUS_PENDING)
1328 {
1329 if (LocalEvent)
1330 {
1331 KeWaitForSingleObject(&Event,
1332 Executive,
1333 KernelMode,
1334 FileObject->Flags & FO_ALERTABLE_IO,
1335 NULL);
1336 Status = IoStatusBlock.Status;
1337 }
1338 else
1339 {
1340 KeWaitForSingleObject(&FileObject->Event,
1341 Executive,
1342 KernelMode,
1343 FileObject->Flags & FO_ALERTABLE_IO,
1344 NULL);
1345 Status = FileObject->FinalStatus;
1346 }
1347 }
1348
1349
1350 /* Return the Length and Status. ReturnedLength is NOT optional */
1351 *ReturnedLength = IoStatusBlock.Information;
1352 return Status;
1353 }
1354
1355 /*
1356 * @unimplemented
1357 */
1358 NTSTATUS
1359 STDCALL
1360 IoSetFileOrigin(IN PFILE_OBJECT FileObject,
1361 IN BOOLEAN Remote)
1362 {
1363 UNIMPLEMENTED;
1364 return STATUS_NOT_IMPLEMENTED;
1365 }
1366
1367 /**
1368 * @name NtCancelIoFile
1369 *
1370 * Cancel all pending I/O operations in the current thread for specified
1371 * file object.
1372 *
1373 * @param FileHandle
1374 * Handle to file object to cancel requests for. No specific
1375 * access rights are needed.
1376 * @param IoStatusBlock
1377 * Pointer to status block which is filled with final completition
1378 * status on successful return.
1379 *
1380 * @return Status.
1381 *
1382 * @implemented
1383 */
1384 NTSTATUS
1385 STDCALL
1386 NtCancelIoFile(IN HANDLE FileHandle,
1387 OUT PIO_STATUS_BLOCK IoStatusBlock)
1388 {
1389 PFILE_OBJECT FileObject;
1390 PETHREAD Thread;
1391 PIRP Irp;
1392 KIRQL OldIrql;
1393 BOOLEAN OurIrpsInList = FALSE;
1394 LARGE_INTEGER Interval;
1395 KPROCESSOR_MODE PreviousMode;
1396 NTSTATUS Status = STATUS_SUCCESS;
1397
1398 PAGED_CODE();
1399
1400 PreviousMode = KeGetPreviousMode();
1401
1402 if (PreviousMode != KernelMode)
1403 {
1404 _SEH_TRY
1405 {
1406 ProbeForWrite(IoStatusBlock,
1407 sizeof(IO_STATUS_BLOCK),
1408 sizeof(ULONG));
1409 }
1410 _SEH_HANDLE
1411 {
1412 Status = _SEH_GetExceptionCode();
1413 }
1414 _SEH_END;
1415
1416 if (!NT_SUCCESS(Status)) return Status;
1417 }
1418
1419 Status = ObReferenceObjectByHandle(FileHandle,
1420 0,
1421 IoFileObjectType,
1422 PreviousMode,
1423 (PVOID*)&FileObject,
1424 NULL);
1425 if (!NT_SUCCESS(Status))
1426 return Status;
1427
1428 /* IRP cancellations are synchronized at APC_LEVEL. */
1429 OldIrql = KfRaiseIrql(APC_LEVEL);
1430
1431 /*
1432 * Walk the list of active IRPs and cancel the ones that belong to
1433 * our file object.
1434 */
1435
1436 Thread = PsGetCurrentThread();
1437
1438 LIST_FOR_EACH(Irp, &Thread->IrpList, IRP, ThreadListEntry)
1439 {
1440 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
1441 {
1442 IoCancelIrp(Irp);
1443 /* Don't break here, we want to cancel all IRPs for the file object. */
1444 OurIrpsInList = TRUE;
1445 }
1446 }
1447
1448 KfLowerIrql(OldIrql);
1449
1450 while (OurIrpsInList)
1451 {
1452 OurIrpsInList = FALSE;
1453
1454 /* Wait a short while and then look if all our IRPs were completed. */
1455 Interval.QuadPart = -1000000; /* 100 milliseconds */
1456 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1457
1458 OldIrql = KfRaiseIrql(APC_LEVEL);
1459
1460 /*
1461 * Look in the list if all IRPs for the specified file object
1462 * are completed (or cancelled). If someone sends a new IRP
1463 * for our file object while we're here we can happily loop
1464 * forever.
1465 */
1466
1467 LIST_FOR_EACH(Irp, &Thread->IrpList, IRP, ThreadListEntry)
1468 {
1469 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
1470 {
1471 OurIrpsInList = TRUE;
1472 break;
1473 }
1474 }
1475
1476 KfLowerIrql(OldIrql);
1477 }
1478
1479 _SEH_TRY
1480 {
1481 IoStatusBlock->Status = STATUS_SUCCESS;
1482 IoStatusBlock->Information = 0;
1483 Status = STATUS_SUCCESS;
1484 }
1485 _SEH_HANDLE
1486 {
1487 Status = STATUS_UNSUCCESSFUL;
1488 }
1489 _SEH_END;
1490
1491 ObDereferenceObject(FileObject);
1492
1493 return Status;
1494 }
1495
1496 /*
1497 * NAME EXPORTED
1498 * NtCreateFile@44
1499 *
1500 * DESCRIPTION
1501 * Entry point to call IoCreateFile with
1502 * default parameters.
1503 *
1504 * ARGUMENTS
1505 * See IoCreateFile.
1506 *
1507 * RETURN VALUE
1508 * See IoCreateFile.
1509 *
1510 * REVISIONS
1511 * 2000-03-25 (ea)
1512 * Code originally in NtCreateFile moved in IoCreateFile.
1513 *
1514 * @implemented
1515 */
1516 NTSTATUS
1517 STDCALL
1518 NtCreateFile(PHANDLE FileHandle,
1519 ACCESS_MASK DesiredAccess,
1520 POBJECT_ATTRIBUTES ObjectAttributes,
1521 PIO_STATUS_BLOCK IoStatusBlock,
1522 PLARGE_INTEGER AllocateSize,
1523 ULONG FileAttributes,
1524 ULONG ShareAccess,
1525 ULONG CreateDisposition,
1526 ULONG CreateOptions,
1527 PVOID EaBuffer,
1528 ULONG EaLength)
1529 {
1530 /* Call the I/O Function */
1531 return IoCreateFile(FileHandle,
1532 DesiredAccess,
1533 ObjectAttributes,
1534 IoStatusBlock,
1535 AllocateSize,
1536 FileAttributes,
1537 ShareAccess,
1538 CreateDisposition,
1539 CreateOptions,
1540 EaBuffer,
1541 EaLength,
1542 CreateFileTypeNone,
1543 NULL,
1544 0);
1545 }
1546
1547 NTSTATUS
1548 STDCALL
1549 NtCreateMailslotFile(OUT PHANDLE FileHandle,
1550 IN ACCESS_MASK DesiredAccess,
1551 IN POBJECT_ATTRIBUTES ObjectAttributes,
1552 OUT PIO_STATUS_BLOCK IoStatusBlock,
1553 IN ULONG CreateOptions,
1554 IN ULONG MailslotQuota,
1555 IN ULONG MaxMessageSize,
1556 IN PLARGE_INTEGER TimeOut)
1557 {
1558 MAILSLOT_CREATE_PARAMETERS Buffer;
1559
1560 DPRINT("NtCreateMailslotFile(FileHandle 0x%p, DesiredAccess %x, "
1561 "ObjectAttributes 0x%p)\n",
1562 FileHandle,DesiredAccess,ObjectAttributes);
1563
1564 PAGED_CODE();
1565
1566 /* Check for Timeout */
1567 if (TimeOut != NULL)
1568 {
1569 if (KeGetPreviousMode() != KernelMode)
1570 {
1571 NTSTATUS Status = STATUS_SUCCESS;
1572
1573 _SEH_TRY
1574 {
1575 Buffer.ReadTimeout = ProbeForReadLargeInteger(TimeOut);
1576 }
1577 _SEH_HANDLE
1578 {
1579 Status = _SEH_GetExceptionCode();
1580 }
1581 _SEH_END;
1582
1583 if (!NT_SUCCESS(Status)) return Status;
1584 }
1585 else
1586 {
1587 Buffer.ReadTimeout = *TimeOut;
1588 }
1589
1590 Buffer.TimeoutSpecified = TRUE;
1591 }
1592 else
1593 {
1594 Buffer.TimeoutSpecified = FALSE;
1595 }
1596
1597 /* Set Settings */
1598 Buffer.MailslotQuota = MailslotQuota;
1599 Buffer.MaximumMessageSize = MaxMessageSize;
1600
1601 /* Call I/O */
1602 return IoCreateFile(FileHandle,
1603 DesiredAccess,
1604 ObjectAttributes,
1605 IoStatusBlock,
1606 NULL,
1607 FILE_ATTRIBUTE_NORMAL,
1608 FILE_SHARE_READ | FILE_SHARE_WRITE,
1609 FILE_CREATE,
1610 CreateOptions,
1611 NULL,
1612 0,
1613 CreateFileTypeMailslot,
1614 (PVOID)&Buffer,
1615 0);
1616 }
1617
1618 NTSTATUS
1619 STDCALL
1620 NtCreateNamedPipeFile(PHANDLE FileHandle,
1621 ACCESS_MASK DesiredAccess,
1622 POBJECT_ATTRIBUTES ObjectAttributes,
1623 PIO_STATUS_BLOCK IoStatusBlock,
1624 ULONG ShareAccess,
1625 ULONG CreateDisposition,
1626 ULONG CreateOptions,
1627 ULONG NamedPipeType,
1628 ULONG ReadMode,
1629 ULONG CompletionMode,
1630 ULONG MaximumInstances,
1631 ULONG InboundQuota,
1632 ULONG OutboundQuota,
1633 PLARGE_INTEGER DefaultTimeout)
1634 {
1635 NAMED_PIPE_CREATE_PARAMETERS Buffer;
1636
1637 DPRINT("NtCreateNamedPipeFile(FileHandle 0x%p, DesiredAccess %x, "
1638 "ObjectAttributes 0x%p)\n",
1639 FileHandle,DesiredAccess,ObjectAttributes);
1640
1641 PAGED_CODE();
1642
1643 /* Check for Timeout */
1644 if (DefaultTimeout != NULL)
1645 {
1646 if (KeGetPreviousMode() != KernelMode)
1647 {
1648 NTSTATUS Status = STATUS_SUCCESS;
1649
1650 _SEH_TRY
1651 {
1652 Buffer.DefaultTimeout = ProbeForReadLargeInteger(DefaultTimeout);
1653 }
1654 _SEH_HANDLE
1655 {
1656 Status = _SEH_GetExceptionCode();
1657 }
1658 _SEH_END;
1659
1660 if (!NT_SUCCESS(Status)) return Status;
1661 }
1662 else
1663 {
1664 Buffer.DefaultTimeout = *DefaultTimeout;
1665 }
1666
1667 Buffer.TimeoutSpecified = TRUE;
1668 }
1669 else
1670 Buffer.TimeoutSpecified = FALSE;
1671
1672 /* Set Settings */
1673 Buffer.NamedPipeType = NamedPipeType;
1674 Buffer.ReadMode = ReadMode;
1675 Buffer.CompletionMode = CompletionMode;
1676 Buffer.MaximumInstances = MaximumInstances;
1677 Buffer.InboundQuota = InboundQuota;
1678 Buffer.OutboundQuota = OutboundQuota;
1679
1680 /* Call I/O */
1681 return IoCreateFile(FileHandle,
1682 DesiredAccess,
1683 ObjectAttributes,
1684 IoStatusBlock,
1685 NULL,
1686 FILE_ATTRIBUTE_NORMAL,
1687 ShareAccess,
1688 CreateDisposition,
1689 CreateOptions,
1690 NULL,
1691 0,
1692 CreateFileTypeNamedPipe,
1693 (PVOID)&Buffer,
1694 0);
1695 }
1696
1697 /*
1698 * NAME EXPORTED
1699 * NtDeleteFile@4
1700 *
1701 * DESCRIPTION
1702 *
1703 * ARGUMENTS
1704 * ObjectAttributes
1705 * ?
1706 *
1707 * RETURN VALUE
1708 *
1709 * REVISIONS
1710 *
1711 * @unimplemented
1712 */
1713 NTSTATUS
1714 STDCALL
1715 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
1716 {
1717 UNIMPLEMENTED;
1718 return(STATUS_NOT_IMPLEMENTED);
1719 }
1720
1721 /*
1722 * @implemented
1723 */
1724 NTSTATUS
1725 STDCALL
1726 NtDeviceIoControlFile(IN HANDLE DeviceHandle,
1727 IN HANDLE Event OPTIONAL,
1728 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1729 IN PVOID UserApcContext OPTIONAL,
1730 OUT PIO_STATUS_BLOCK IoStatusBlock,
1731 IN ULONG IoControlCode,
1732 IN PVOID InputBuffer,
1733 IN ULONG InputBufferLength OPTIONAL,
1734 OUT PVOID OutputBuffer,
1735 IN ULONG OutputBufferLength OPTIONAL)
1736 {
1737 /* Call the Generic Function */
1738 return IopDeviceFsIoControl(DeviceHandle,
1739 Event,
1740 UserApcRoutine,
1741 UserApcContext,
1742 IoStatusBlock,
1743 IoControlCode,
1744 InputBuffer,
1745 InputBufferLength,
1746 OutputBuffer,
1747 OutputBufferLength,
1748 TRUE);
1749 }
1750
1751 /*
1752 * @implemented
1753 */
1754 NTSTATUS
1755 STDCALL
1756 NtFsControlFile(IN HANDLE DeviceHandle,
1757 IN HANDLE Event OPTIONAL,
1758 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1759 IN PVOID UserApcContext OPTIONAL,
1760 OUT PIO_STATUS_BLOCK IoStatusBlock,
1761 IN ULONG IoControlCode,
1762 IN PVOID InputBuffer,
1763 IN ULONG InputBufferLength OPTIONAL,
1764 OUT PVOID OutputBuffer,
1765 IN ULONG OutputBufferLength OPTIONAL)
1766 {
1767 return IopDeviceFsIoControl(DeviceHandle,
1768 Event,
1769 UserApcRoutine,
1770 UserApcContext,
1771 IoStatusBlock,
1772 IoControlCode,
1773 InputBuffer,
1774 InputBufferLength,
1775 OutputBuffer,
1776 OutputBufferLength,
1777 FALSE);
1778 }
1779
1780 NTSTATUS
1781 STDCALL
1782 NtFlushWriteBuffer(VOID)
1783 {
1784 PAGED_CODE();
1785
1786 KeFlushWriteBuffer();
1787 return STATUS_SUCCESS;
1788 }
1789
1790 /*
1791 * FUNCTION: Flushes cached file data to disk
1792 * ARGUMENTS:
1793 * FileHandle = Points to the file
1794 * IoStatusBlock = Caller must supply storage to receive the result of
1795 * the flush buffers operation. The information field is
1796 * set to number of bytes flushed to disk.
1797 * RETURNS: Status
1798 * REMARKS: This function maps to the win32 FlushFileBuffers
1799 */
1800 NTSTATUS
1801 STDCALL
1802 NtFlushBuffersFile(IN HANDLE FileHandle,
1803 OUT PIO_STATUS_BLOCK IoStatusBlock)
1804 {
1805 PFILE_OBJECT FileObject = NULL;
1806 PIRP Irp;
1807 PIO_STACK_LOCATION StackPtr;
1808 NTSTATUS Status = STATUS_SUCCESS;
1809 PDEVICE_OBJECT DeviceObject;
1810 KEVENT Event;
1811 BOOLEAN LocalEvent = FALSE;
1812 ACCESS_MASK DesiredAccess = FILE_WRITE_DATA;
1813 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1814 KPROCESSOR_MODE PreviousMode;
1815
1816 PAGED_CODE();
1817
1818 PreviousMode = KeGetPreviousMode();
1819
1820 if (PreviousMode != KernelMode)
1821 {
1822 _SEH_TRY
1823 {
1824 ProbeForWrite(IoStatusBlock,
1825 sizeof(IO_STATUS_BLOCK),
1826 sizeof(ULONG));
1827 }
1828 _SEH_HANDLE
1829 {
1830 Status = _SEH_GetExceptionCode();
1831 }
1832 _SEH_END;
1833
1834 if (!NT_SUCCESS(Status)) return Status;
1835 }
1836
1837 /* Get the File Object */
1838 Status = ObReferenceObjectByHandle(FileHandle,
1839 0,
1840 IoFileObjectType,
1841 PreviousMode,
1842 (PVOID*)&FileObject,
1843 &ObjectHandleInfo);
1844 if (!NT_SUCCESS(Status)) return(Status);
1845
1846 /* check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
1847 granted. However, if this is a named pipe, make sure we don't ask for
1848 FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
1849 access right! */
1850 if (!(FileObject->Flags & FO_NAMED_PIPE))
1851 DesiredAccess |= FILE_APPEND_DATA;
1852 if (!RtlAreAnyAccessesGranted(ObjectHandleInfo.GrantedAccess,
1853 DesiredAccess))
1854 {
1855 ObDereferenceObject(FileObject);
1856 return STATUS_ACCESS_DENIED;
1857 }
1858
1859 /* Check if this is a direct open or not */
1860 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1861 {
1862 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1863 }
1864 else
1865 {
1866 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1867 }
1868
1869 /* Check if we should use Sync IO or not */
1870 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1871 {
1872 /* Use File Object event */
1873 KeClearEvent(&FileObject->Event);
1874 }
1875 else
1876 {
1877 /* Use local event */
1878 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1879 LocalEvent = TRUE;
1880 }
1881
1882 /* Allocate the IRP */
1883 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
1884 {
1885 ObDereferenceObject(FileObject);
1886 return STATUS_INSUFFICIENT_RESOURCES;
1887 }
1888
1889 /* Set up the IRP */
1890 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1891 Irp->RequestorMode = PreviousMode;
1892 Irp->UserIosb = IoStatusBlock;
1893 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1894 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1895 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1896
1897 /* Set up Stack Data */
1898 StackPtr = IoGetNextIrpStackLocation(Irp);
1899 StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
1900 StackPtr->FileObject = FileObject;
1901
1902 /* Call the Driver */
1903 Status = IoCallDriver(DeviceObject, Irp);
1904 if (Status == STATUS_PENDING)
1905 {
1906 if (LocalEvent)
1907 {
1908 KeWaitForSingleObject(&Event,
1909 Executive,
1910 PreviousMode,
1911 FileObject->Flags & FO_ALERTABLE_IO,
1912 NULL);
1913 Status = IoStatusBlock->Status;
1914 }
1915 else
1916 {
1917 KeWaitForSingleObject(&FileObject->Event,
1918 Executive,
1919 PreviousMode,
1920 FileObject->Flags & FO_ALERTABLE_IO,
1921 NULL);
1922 Status = FileObject->FinalStatus;
1923 }
1924 }
1925
1926 /* Return the Status */
1927 return Status;
1928 }
1929
1930 /*
1931 * @implemented
1932 */
1933 NTSTATUS
1934 STDCALL
1935 NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
1936 IN HANDLE Event OPTIONAL,
1937 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1938 IN PVOID ApcContext OPTIONAL,
1939 OUT PIO_STATUS_BLOCK IoStatusBlock,
1940 OUT PVOID Buffer,
1941 IN ULONG BufferSize,
1942 IN ULONG CompletionFilter,
1943 IN BOOLEAN WatchTree)
1944 {
1945 PIRP Irp;
1946 PDEVICE_OBJECT DeviceObject;
1947 PFILE_OBJECT FileObject;
1948 PIO_STACK_LOCATION IoStack;
1949 KPROCESSOR_MODE PreviousMode;
1950 NTSTATUS Status = STATUS_SUCCESS;
1951
1952 DPRINT("NtNotifyChangeDirectoryFile()\n");
1953
1954 PAGED_CODE();
1955
1956 PreviousMode = ExGetPreviousMode();
1957
1958 if(PreviousMode != KernelMode)
1959 {
1960 _SEH_TRY
1961 {
1962 ProbeForWrite(IoStatusBlock,
1963 sizeof(IO_STATUS_BLOCK),
1964 sizeof(ULONG));
1965 if(BufferSize != 0)
1966 {
1967 ProbeForWrite(Buffer,
1968 BufferSize,
1969 sizeof(ULONG));
1970 }
1971 }
1972 _SEH_HANDLE
1973 {
1974 Status = _SEH_GetExceptionCode();
1975 }
1976 _SEH_END;
1977
1978 if(!NT_SUCCESS(Status))
1979 {
1980 return Status;
1981 }
1982 }
1983
1984 Status = ObReferenceObjectByHandle(FileHandle,
1985 FILE_LIST_DIRECTORY,
1986 IoFileObjectType,
1987 PreviousMode,
1988 (PVOID *)&FileObject,
1989 NULL);
1990 if (Status != STATUS_SUCCESS) return(Status);
1991
1992
1993 DeviceObject = FileObject->DeviceObject;
1994
1995
1996 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1997 if (Irp==NULL)
1998 {
1999 ObDereferenceObject(FileObject);
2000 return STATUS_UNSUCCESSFUL;
2001 }
2002
2003 if (Event == NULL)
2004 {
2005 Event = &FileObject->Event;
2006 }
2007
2008 /* Trigger FileObject/Event dereferencing */
2009 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2010 Irp->RequestorMode = PreviousMode;
2011 Irp->UserIosb = IoStatusBlock;
2012 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2013 Irp->UserEvent = Event;
2014 KeResetEvent( Event );
2015 Irp->UserBuffer = Buffer;
2016 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2017 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2018
2019 IoStack = IoGetNextIrpStackLocation(Irp);
2020
2021 IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
2022 IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
2023 IoStack->Flags = 0;
2024 IoStack->Control = 0;
2025 IoStack->DeviceObject = DeviceObject;
2026 IoStack->FileObject = FileObject;
2027
2028 if (WatchTree)
2029 {
2030 IoStack->Flags = SL_WATCH_TREE;
2031 }
2032
2033 IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
2034 IoStack->Parameters.NotifyDirectory.Length = BufferSize;
2035
2036 Status = IoCallDriver(FileObject->DeviceObject,Irp);
2037
2038 /* FIXME: Should we wait here or not for synchronously opened files? */
2039
2040 return Status;
2041 }
2042
2043 /*
2044 * @unimplemented
2045 */
2046 NTSTATUS
2047 STDCALL
2048 NtLockFile(IN HANDLE FileHandle,
2049 IN HANDLE EventHandle OPTIONAL,
2050 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2051 IN PVOID ApcContext OPTIONAL,
2052 OUT PIO_STATUS_BLOCK IoStatusBlock,
2053 IN PLARGE_INTEGER ByteOffset,
2054 IN PLARGE_INTEGER Length,
2055 IN ULONG Key,
2056 IN BOOLEAN FailImmediately,
2057 IN BOOLEAN ExclusiveLock)
2058 {
2059 PFILE_OBJECT FileObject = NULL;
2060 PLARGE_INTEGER LocalLength = NULL;
2061 PIRP Irp = NULL;
2062 PIO_STACK_LOCATION StackPtr;
2063 PDEVICE_OBJECT DeviceObject;
2064 PKEVENT Event = NULL;
2065 BOOLEAN LocalEvent = FALSE;
2066 KPROCESSOR_MODE PreviousMode;
2067 LARGE_INTEGER CapturedByteOffset, CapturedLength;
2068 NTSTATUS Status = STATUS_SUCCESS;
2069 OBJECT_HANDLE_INFORMATION HandleInformation;
2070
2071 PAGED_CODE();
2072
2073 PreviousMode = KeGetPreviousMode();
2074
2075 CapturedByteOffset.QuadPart = 0;
2076 CapturedLength.QuadPart = 0;
2077
2078 /* Get File Object */
2079 Status = ObReferenceObjectByHandle(FileHandle,
2080 0,
2081 IoFileObjectType,
2082 PreviousMode,
2083 (PVOID*)&FileObject,
2084 &HandleInformation);
2085 if (!NT_SUCCESS(Status)) return Status;
2086
2087 if (PreviousMode != KernelMode)
2088 {
2089 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access unless
2090 we're in KernelMode! */
2091 if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
2092 {
2093 DPRINT1("Invalid access rights\n");
2094 ObDereferenceObject(FileObject);
2095 return STATUS_ACCESS_DENIED;
2096 }
2097
2098 _SEH_TRY
2099 {
2100 ProbeForWrite(IoStatusBlock,
2101 sizeof(IO_STATUS_BLOCK),
2102 sizeof(ULONG));
2103 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2104 CapturedLength = ProbeForReadLargeInteger(Length);
2105 }
2106 _SEH_HANDLE
2107 {
2108 Status = _SEH_GetExceptionCode();
2109 }
2110 _SEH_END;
2111
2112 if (!NT_SUCCESS(Status))
2113 {
2114 ObDereferenceObject(FileObject);
2115 return Status;
2116 }
2117 }
2118 else
2119 {
2120 CapturedByteOffset = *ByteOffset;
2121 CapturedLength = *Length;
2122 }
2123
2124 /* Get Event Object */
2125 if (EventHandle)
2126 {
2127 Status = ObReferenceObjectByHandle(EventHandle,
2128 EVENT_MODIFY_STATE,
2129 ExEventObjectType,
2130 PreviousMode,
2131 (PVOID *)&Event,
2132 NULL);
2133 if (Status != STATUS_SUCCESS) return(Status);
2134 KeClearEvent(Event);
2135 }
2136
2137 /* Check if this is a direct open or not */
2138 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2139 {
2140 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2141 }
2142 else
2143 {
2144 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2145 }
2146
2147 /* Check if we should use Sync IO or not */
2148 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2149 {
2150 /* Use File Object event */
2151 KeClearEvent(&FileObject->Event);
2152 }
2153 else
2154 {
2155 LocalEvent = TRUE;
2156 }
2157
2158 /* Allocate the IRP */
2159 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
2160 {
2161 ObDereferenceObject(FileObject);
2162 return STATUS_INSUFFICIENT_RESOURCES;
2163 }
2164
2165 /* Allocate local buffer */
2166 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
2167 sizeof(LARGE_INTEGER),
2168 TAG_LOCK);
2169 if (!LocalLength)
2170 {
2171 IoFreeIrp(Irp);
2172 ObDereferenceObject(FileObject);
2173 return STATUS_INSUFFICIENT_RESOURCES;
2174 }
2175 *LocalLength = CapturedLength;
2176
2177 /* Set up the IRP */
2178 Irp->RequestorMode = PreviousMode;
2179 Irp->UserIosb = IoStatusBlock;
2180 Irp->UserEvent = Event;
2181 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2182 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2183
2184 /* Set up Stack Data */
2185 StackPtr = IoGetNextIrpStackLocation(Irp);
2186 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
2187 StackPtr->MinorFunction = IRP_MN_LOCK;
2188 StackPtr->FileObject = FileObject;
2189
2190 /* Set Parameters */
2191 StackPtr->Parameters.LockControl.Length = LocalLength;
2192 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
2193 StackPtr->Parameters.LockControl.Key = Key;
2194
2195 /* Set Flags */
2196 if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
2197 if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
2198
2199 /* Call the Driver */
2200 FileObject->LockOperation = TRUE;
2201 Status = IoCallDriver(DeviceObject, Irp);
2202 if (Status == STATUS_PENDING)
2203 {
2204 if (!LocalEvent)
2205 {
2206 KeWaitForSingleObject(&FileObject->Event,
2207 Executive,
2208 PreviousMode,
2209 FileObject->Flags & FO_ALERTABLE_IO,
2210 NULL);
2211 Status = FileObject->FinalStatus;
2212 }
2213 }
2214
2215 /* Return the Status */
2216 return Status;
2217 }
2218
2219 /*
2220 * NAME EXPORTED
2221 * NtOpenFile@24
2222 *
2223 * DESCRIPTION
2224 * Opens an existing file (simpler than NtCreateFile).
2225 *
2226 * ARGUMENTS
2227 * FileHandle (OUT)
2228 * Variable that receives the file handle on return;
2229 *
2230 * DesiredAccess
2231 * Access desired by the caller to the file;
2232 *
2233 * ObjectAttributes
2234 * Structue describing the file to be opened;
2235 *
2236 * IoStatusBlock (OUT)
2237 * Receives details about the result of the
2238 * operation;
2239 *
2240 * ShareAccess
2241 * Type of shared access the caller requires;
2242 *
2243 * OpenOptions
2244 * Options for the file open.
2245 *
2246 * RETURN VALUE
2247 * Status.
2248 *
2249 * NOTE
2250 * Undocumented.
2251 *
2252 * @implemented
2253 */
2254 NTSTATUS
2255 STDCALL
2256 NtOpenFile(PHANDLE FileHandle,
2257 ACCESS_MASK DesiredAccess,
2258 POBJECT_ATTRIBUTES ObjectAttributes,
2259 PIO_STATUS_BLOCK IoStatusBlock,
2260 ULONG ShareAccess,
2261 ULONG OpenOptions)
2262 {
2263 /* Call the I/O Function */
2264 return IoCreateFile(FileHandle,
2265 DesiredAccess,
2266 ObjectAttributes,
2267 IoStatusBlock,
2268 NULL,
2269 0,
2270 ShareAccess,
2271 FILE_OPEN,
2272 OpenOptions,
2273 NULL,
2274 0,
2275 CreateFileTypeNone,
2276 NULL,
2277 0);
2278 }
2279
2280 NTSTATUS
2281 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2282 IN FILE_INFORMATION_CLASS FileInformationClass,
2283 OUT PVOID FileInformation)
2284 {
2285 IO_STATUS_BLOCK IoStatusBlock;
2286 HANDLE FileHandle;
2287 NTSTATUS Status;
2288 KPROCESSOR_MODE AccessMode;
2289 UNICODE_STRING ObjectName;
2290 OBJECT_CREATE_INFORMATION ObjectCreateInfo;
2291 OBJECT_ATTRIBUTES LocalObjectAttributes;
2292 ULONG BufferSize;
2293 union
2294 {
2295 FILE_BASIC_INFORMATION BasicInformation;
2296 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInformation;
2297 }LocalFileInformation;
2298
2299 if (FileInformationClass == FileBasicInformation)
2300 {
2301 BufferSize = sizeof(FILE_BASIC_INFORMATION);
2302 }
2303 else if (FileInformationClass == FileNetworkOpenInformation)
2304 {
2305 BufferSize = sizeof(FILE_NETWORK_OPEN_INFORMATION);
2306 }
2307 else
2308 {
2309 return STATUS_INVALID_PARAMETER;
2310 }
2311
2312 AccessMode = ExGetPreviousMode();
2313
2314 if (AccessMode != KernelMode)
2315 {
2316 Status = STATUS_SUCCESS;
2317 _SEH_TRY
2318 {
2319 ProbeForWrite(FileInformation,
2320 BufferSize,
2321 sizeof(ULONG));
2322 }
2323 _SEH_HANDLE
2324 {
2325 Status = _SEH_GetExceptionCode();
2326 }
2327 _SEH_END;
2328 if (NT_SUCCESS(Status))
2329 {
2330 Status = ObpCaptureObjectAttributes(ObjectAttributes,
2331 AccessMode,
2332 NULL,
2333 &ObjectCreateInfo,
2334 &ObjectName);
2335 }
2336 if (!NT_SUCCESS(Status))
2337 {
2338 return Status;
2339 }
2340 InitializeObjectAttributes(&LocalObjectAttributes,
2341 &ObjectName,
2342 ObjectCreateInfo.Attributes,
2343 ObjectCreateInfo.RootDirectory,
2344 ObjectCreateInfo.SecurityDescriptor);
2345 }
2346
2347 /* Open the file */
2348 Status = ZwOpenFile(&FileHandle,
2349 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
2350 AccessMode == KernelMode ? ObjectAttributes : &LocalObjectAttributes,
2351 &IoStatusBlock,
2352 0,
2353 FILE_SYNCHRONOUS_IO_NONALERT);
2354 if (AccessMode != KernelMode)
2355 {
2356 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
2357 ExFreePool(ObjectName.Buffer);
2358 }
2359 if (!NT_SUCCESS (Status))
2360 {
2361 DPRINT ("ZwOpenFile() failed (Status %lx)\n", Status);
2362 return Status;
2363 }
2364
2365 /* Get file attributes */
2366 Status = ZwQueryInformationFile(FileHandle,
2367 &IoStatusBlock,
2368 AccessMode == KernelMode ? FileInformation : &LocalFileInformation,
2369 BufferSize,
2370 FileInformationClass);
2371 if (!NT_SUCCESS (Status))
2372 {
2373 DPRINT ("ZwQueryInformationFile() failed (Status %lx)\n", Status);
2374 }
2375 ZwClose(FileHandle);
2376
2377 if (NT_SUCCESS(Status) && AccessMode != KernelMode)
2378 {
2379 _SEH_TRY
2380 {
2381 memcpy(FileInformation, &LocalFileInformation, BufferSize);
2382 }
2383 _SEH_HANDLE
2384 {
2385 Status = _SEH_GetExceptionCode();
2386 }
2387 _SEH_END;
2388 }
2389 return Status;
2390 }
2391
2392 NTSTATUS
2393 STDCALL
2394 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2395 OUT PFILE_BASIC_INFORMATION FileInformation)
2396 {
2397 return IopQueryAttributesFile(ObjectAttributes,
2398 FileBasicInformation,
2399 FileInformation);
2400 }
2401
2402 static NTSTATUS NTAPI
2403 IopQueryDirectoryFileCompletion(IN PDEVICE_OBJECT DeviceObject,
2404 IN PIRP Irp,
2405 IN PVOID Context)
2406 {
2407 ASSERT (Context);
2408
2409 DPRINT("IopQueryDirectoryFileCompletion was called for \'%wZ\'\n", Context);
2410
2411 ExFreePool(Context);
2412
2413 return STATUS_SUCCESS;
2414 }
2415
2416
2417 /*
2418 * @implemented
2419 *
2420 * FUNCTION: Queries a directory file.
2421 * ARGUMENTS:
2422 * FileHandle = Handle to a directory file
2423 * EventHandle = Handle to the event signaled on completion
2424 * ApcRoutine = Asynchroneous procedure callback, called on completion
2425 * ApcContext = Argument to the apc.
2426 * IoStatusBlock = Caller supplies storage for extended status information.
2427 * FileInformation = Caller supplies storage for the resulting information.
2428 *
2429 * FileNameInformation FILE_NAMES_INFORMATION
2430 * FileDirectoryInformation FILE_DIRECTORY_INFORMATION
2431 * FileFullDirectoryInformation FILE_FULL_DIRECTORY_INFORMATION
2432 * FileBothDirectoryInformation FILE_BOTH_DIR_INFORMATION
2433 *
2434 * Length = Size of the storage supplied
2435 * FileInformationClass = Indicates the type of information requested.
2436 * ReturnSingleEntry = Specify true if caller only requests the first
2437 * directory found.
2438 * FileName = Initial directory name to query, that may contain wild
2439 * cards.
2440 * RestartScan = Number of times the action should be repeated
2441 * RETURNS: Status [ STATUS_SUCCESS, STATUS_ACCESS_DENIED, STATUS_INSUFFICIENT_RESOURCES,
2442 * STATUS_INVALID_PARAMETER, STATUS_INVALID_DEVICE_REQUEST, STATUS_BUFFER_OVERFLOW,
2443 * STATUS_INVALID_INFO_CLASS, STATUS_NO_SUCH_FILE, STATUS_NO_MORE_FILES ]
2444 */
2445 NTSTATUS
2446 STDCALL
2447 NtQueryDirectoryFile(IN HANDLE FileHandle,
2448 IN HANDLE PEvent OPTIONAL,
2449 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2450 IN PVOID ApcContext OPTIONAL,
2451 OUT PIO_STATUS_BLOCK IoStatusBlock,
2452 OUT PVOID FileInformation,
2453 IN ULONG Length,
2454 IN FILE_INFORMATION_CLASS FileInformationClass,
2455 IN BOOLEAN ReturnSingleEntry,
2456 IN PUNICODE_STRING FileName OPTIONAL,
2457 IN BOOLEAN RestartScan)
2458 {
2459 PIRP Irp;
2460 PDEVICE_OBJECT DeviceObject;
2461 PFILE_OBJECT FileObject = NULL;
2462 PIO_STACK_LOCATION StackPtr;
2463 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2464 NTSTATUS Status = STATUS_SUCCESS;
2465 BOOLEAN LocalEvent = FALSE;
2466 PKEVENT Event = NULL;
2467 PUNICODE_STRING SearchPattern = NULL;
2468
2469 DPRINT("NtQueryDirectoryFile()\n");
2470 PAGED_CODE();
2471
2472 /* Validate User-Mode Buffers */
2473 if(PreviousMode != KernelMode)
2474 {
2475 _SEH_TRY
2476 {
2477 ProbeForWrite(IoStatusBlock,
2478 sizeof(IO_STATUS_BLOCK),
2479 sizeof(ULONG));
2480 ProbeForWrite(FileInformation,
2481 Length,
2482 sizeof(ULONG));
2483 if (FileName)
2484 {
2485 UNICODE_STRING CapturedFileName;
2486
2487 CapturedFileName = ProbeForReadUnicodeString(FileName);
2488 ProbeForRead(CapturedFileName.Buffer,
2489 CapturedFileName.MaximumLength,
2490 1);
2491 SearchPattern = ExAllocatePool(NonPagedPool, CapturedFileName.Length + sizeof(WCHAR) + sizeof(UNICODE_STRING));
2492 if (SearchPattern == NULL)
2493 {
2494 Status = STATUS_INSUFFICIENT_RESOURCES;
2495 _SEH_LEAVE;
2496 }
2497 SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)SearchPattern + sizeof(UNICODE_STRING));
2498 SearchPattern->MaximumLength = CapturedFileName.Length + sizeof(WCHAR);
2499 RtlCopyUnicodeString(SearchPattern, &CapturedFileName);
2500 }
2501 }
2502 _SEH_HANDLE
2503 {
2504 Status = _SEH_GetExceptionCode();
2505 }
2506 _SEH_END;
2507
2508 if(!NT_SUCCESS(Status))
2509 {
2510 goto Cleanup;
2511 }
2512 }
2513
2514 /* Get File Object */
2515 Status = ObReferenceObjectByHandle(FileHandle,
2516 FILE_LIST_DIRECTORY,
2517 IoFileObjectType,
2518 PreviousMode,
2519 (PVOID *)&FileObject,
2520 NULL);
2521 if (!NT_SUCCESS(Status))
2522 {
2523 goto Cleanup;
2524 }
2525
2526 /* Get Event Object */
2527 if (PEvent)
2528 {
2529 Status = ObReferenceObjectByHandle(PEvent,
2530 EVENT_MODIFY_STATE,
2531 ExEventObjectType,
2532 PreviousMode,
2533 (PVOID *)&Event,
2534 NULL);
2535 if (!NT_SUCCESS(Status))
2536 {
2537 goto Cleanup;
2538 }
2539
2540 KeClearEvent(Event);
2541 }
2542
2543 /* Check if this is a direct open or not */
2544 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2545 {
2546 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2547 }
2548 else
2549 {
2550 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2551 }
2552
2553 /* Check if we should use Sync IO or not */
2554 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2555 {
2556 /* Use File Object event */
2557 KeClearEvent(&FileObject->Event);
2558 }
2559 else
2560 {
2561 LocalEvent = TRUE;
2562 }
2563
2564 /* Allocate the IRP */
2565 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
2566 {
2567 Status = STATUS_INSUFFICIENT_RESOURCES;
2568 goto Cleanup;
2569 }
2570
2571 /* Set up the IRP */
2572 Irp->RequestorMode = PreviousMode;
2573 Irp->UserIosb = IoStatusBlock;
2574 Irp->UserEvent = Event;
2575 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2576 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2577 Irp->UserBuffer = FileInformation;
2578 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2579 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2580
2581 /* Set up Stack Data */
2582 StackPtr = IoGetNextIrpStackLocation(Irp);
2583 StackPtr->FileObject = FileObject;
2584 StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
2585 StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY;
2586
2587 /* Set Parameters */
2588 StackPtr->Parameters.QueryDirectory.FileInformationClass = FileInformationClass;
2589 StackPtr->Parameters.QueryDirectory.FileName = SearchPattern ? SearchPattern : FileName;
2590 StackPtr->Parameters.QueryDirectory.FileIndex = 0;
2591 StackPtr->Parameters.QueryDirectory.Length = Length;
2592 StackPtr->Flags = 0;
2593 if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
2594 if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
2595
2596 if (SearchPattern)
2597 {
2598 IoSetCompletionRoutine(Irp,
2599 IopQueryDirectoryFileCompletion,
2600 SearchPattern,
2601 TRUE,
2602 TRUE,
2603 TRUE);
2604 }
2605
2606 /* Call the Driver */
2607 Status = IoCallDriver(DeviceObject, Irp);
2608 if (Status == STATUS_PENDING)
2609 {
2610 if (!LocalEvent)
2611 {
2612 KeWaitForSingleObject(&FileObject->Event,
2613 Executive,
2614 PreviousMode,
2615 FileObject->Flags & FO_ALERTABLE_IO,
2616 NULL);
2617 Status = FileObject->FinalStatus;
2618 }
2619 }
2620
2621
2622 return Status;
2623
2624 Cleanup:
2625 if (FileObject != NULL)
2626 {
2627 ObDereferenceObject(FileObject);
2628 }
2629 if (Event != NULL)
2630 {
2631 ObDereferenceObject(Event);
2632 }
2633 if (SearchPattern != NULL)
2634 {
2635 ExFreePool(SearchPattern);
2636 }
2637
2638 /* Return the Status */
2639 return Status;
2640 }
2641
2642 /*
2643 * @unimplemented
2644 */
2645 NTSTATUS STDCALL
2646 NtQueryEaFile(IN HANDLE FileHandle,
2647 OUT PIO_STATUS_BLOCK IoStatusBlock,
2648 OUT PVOID Buffer,
2649 IN ULONG Length,
2650 IN BOOLEAN ReturnSingleEntry,
2651 IN PVOID EaList OPTIONAL,
2652 IN ULONG EaListLength,
2653 IN PULONG EaIndex OPTIONAL,
2654 IN BOOLEAN RestartScan)
2655 {
2656 UNIMPLEMENTED;
2657 return STATUS_NOT_IMPLEMENTED;
2658 }
2659
2660 NTSTATUS
2661 STDCALL
2662 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2663 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
2664 {
2665 return IopQueryAttributesFile(ObjectAttributes,
2666 FileNetworkOpenInformation,
2667 FileInformation);
2668 }
2669
2670 /*
2671 * @implemented
2672 */
2673 NTSTATUS STDCALL
2674 NtQueryInformationFile(HANDLE FileHandle,
2675 PIO_STATUS_BLOCK IoStatusBlock,
2676 PVOID FileInformation,
2677 ULONG Length,
2678 FILE_INFORMATION_CLASS FileInformationClass)
2679 {
2680 OBJECT_HANDLE_INFORMATION HandleInformation;
2681 PFILE_OBJECT FileObject;
2682 NTSTATUS Status;
2683 PIRP Irp;
2684 PDEVICE_OBJECT DeviceObject;
2685 PIO_STACK_LOCATION StackPtr;
2686 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2687 KEVENT Event;
2688 BOOLEAN LocalEvent = FALSE;
2689 BOOLEAN Failed = FALSE;
2690
2691 ASSERT(IoStatusBlock != NULL);
2692 ASSERT(FileInformation != NULL);
2693
2694 DPRINT("NtQueryInformationFile(Handle 0x%p StatBlk 0x%p FileInfo 0x%p Length %d "
2695 "Class %d)\n", FileHandle, IoStatusBlock, FileInformation,
2696 Length, FileInformationClass);
2697
2698 /* Reference the Handle */
2699 Status = ObReferenceObjectByHandle(FileHandle,
2700 0,
2701 IoFileObjectType,
2702 PreviousMode,
2703 (PVOID *)&FileObject,
2704 &HandleInformation);
2705 if (!NT_SUCCESS(Status)) return Status;
2706
2707 /* Check information class specific access rights */
2708 switch (FileInformationClass)
2709 {
2710 case FileBasicInformation:
2711 if (!(HandleInformation.GrantedAccess & FILE_READ_ATTRIBUTES))
2712 Failed = TRUE;
2713 break;
2714
2715 case FilePositionInformation:
2716 if (!(HandleInformation.GrantedAccess & (FILE_READ_DATA | FILE_WRITE_DATA)) ||
2717 !(FileObject->Flags & FO_SYNCHRONOUS_IO))
2718 Failed = TRUE;
2719 break;
2720
2721 default:
2722 break;
2723 }
2724
2725 if (Failed)
2726 {
2727 DPRINT1("NtQueryInformationFile() returns STATUS_ACCESS_DENIED!\n");
2728 ObDereferenceObject(FileObject);
2729 return STATUS_ACCESS_DENIED;
2730 }
2731
2732 if (FileInformationClass == FilePositionInformation)
2733 {
2734 if (Length < sizeof(FILE_POSITION_INFORMATION))
2735 {
2736 Status = STATUS_BUFFER_OVERFLOW;
2737 }
2738 else
2739 {
2740 _SEH_TRY
2741 {
2742 ((PFILE_POSITION_INFORMATION)FileInformation)->CurrentByteOffset = FileObject->CurrentByteOffset;
2743 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
2744 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2745 }
2746 _SEH_HANDLE
2747 {
2748 Status = _SEH_GetExceptionCode();
2749 }
2750 _SEH_END;
2751 }
2752 ObDereferenceObject(FileObject);
2753 return Status;
2754 }
2755
2756 DPRINT("FileObject 0x%p\n", FileObject);
2757
2758 /* Check if this is a direct open or not */
2759 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2760 {
2761 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2762 }
2763 else
2764 {
2765 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2766 }
2767
2768 if (FileInformationClass == FileAlignmentInformation)
2769 {
2770 if (Length < sizeof(FILE_ALIGNMENT_INFORMATION))
2771 {
2772 Status = STATUS_BUFFER_OVERFLOW;
2773 }
2774 else
2775 {
2776 _SEH_TRY
2777 {
2778 ((PFILE_ALIGNMENT_INFORMATION)FileInformation)->AlignmentRequirement = DeviceObject->AlignmentRequirement;
2779 IoStatusBlock->Information = sizeof(FILE_ALIGNMENT_INFORMATION);
2780 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2781 }
2782 _SEH_HANDLE
2783 {
2784 Status = _SEH_GetExceptionCode();
2785 }
2786 _SEH_END;
2787 }
2788 ObDereferenceObject(FileObject);
2789 return Status;
2790 }
2791
2792 /* Check if we should use Sync IO or not */
2793 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2794 {
2795 /* Use File Object event */
2796 KeClearEvent(&FileObject->Event);
2797 }
2798 else
2799 {
2800 /* Use local event */
2801 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2802 LocalEvent = TRUE;
2803 }
2804
2805 /* Allocate the IRP */
2806 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
2807 {
2808 ObDereferenceObject(FileObject);
2809 return STATUS_INSUFFICIENT_RESOURCES;
2810 }
2811
2812 /* Allocate the System Buffer */
2813 if (!(Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
2814 Length,
2815 TAG_SYSB)))
2816 {
2817 IoFreeIrp(Irp);
2818 ObDereferenceObject(FileObject);
2819 return STATUS_INSUFFICIENT_RESOURCES;
2820 }
2821
2822 /* Set up the IRP */
2823 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2824 Irp->RequestorMode = PreviousMode;
2825 Irp->UserIosb = IoStatusBlock;
2826 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
2827 Irp->UserBuffer = FileInformation;
2828 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2829 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
2830 Irp->Flags |= (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2831
2832 /* Set up Stack Data */
2833 StackPtr = IoGetNextIrpStackLocation(Irp);
2834 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
2835 StackPtr->FileObject = FileObject;
2836
2837 /* Set the Parameters */
2838 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2839 StackPtr->Parameters.QueryFile.Length = Length;
2840
2841 /* Call the Driver */
2842 Status = IoCallDriver(DeviceObject, Irp);
2843 if (Status == STATUS_PENDING)
2844 {
2845 if (LocalEvent)
2846 {
2847 KeWaitForSingleObject(&Event,
2848 Executive,
2849 PreviousMode,
2850 FileObject->Flags & FO_ALERTABLE_IO,
2851 NULL);
2852 Status = IoStatusBlock->Status;
2853 }
2854 else
2855 {
2856 KeWaitForSingleObject(&FileObject->Event,
2857 Executive,
2858 PreviousMode,
2859 FileObject->Flags & FO_ALERTABLE_IO,
2860 NULL);
2861 Status = FileObject->FinalStatus;
2862 }
2863 }
2864
2865 /* Return the Status */
2866 return Status;
2867 }
2868
2869 /*
2870 * @unimplemented
2871 */
2872 NTSTATUS
2873 STDCALL
2874 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
2875 OUT PIO_STATUS_BLOCK IoStatusBlock,
2876 OUT PVOID Buffer,
2877 IN ULONG Length,
2878 IN BOOLEAN ReturnSingleEntry,
2879 IN PVOID SidList OPTIONAL,
2880 IN ULONG SidListLength,
2881 IN PSID StartSid OPTIONAL,
2882 IN BOOLEAN RestartScan)
2883 {
2884 UNIMPLEMENTED;
2885 return STATUS_NOT_IMPLEMENTED;
2886 }
2887
2888 /*
2889 * NAME EXPORTED
2890 * NtReadFile
2891 *
2892 * DESCRIPTION
2893 *
2894 * ARGUMENTS
2895 *
2896 * RETURN VALUE
2897 *
2898 * REVISIONS
2899 *
2900 * @implemented
2901 */
2902 NTSTATUS
2903 STDCALL
2904 NtReadFile(IN HANDLE FileHandle,
2905 IN HANDLE Event OPTIONAL,
2906 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2907 IN PVOID ApcContext OPTIONAL,
2908 OUT PIO_STATUS_BLOCK IoStatusBlock,
2909 OUT PVOID Buffer,
2910 IN ULONG Length,
2911 IN PLARGE_INTEGER ByteOffset OPTIONAL,
2912 IN PULONG Key OPTIONAL)
2913 {
2914 NTSTATUS Status = STATUS_SUCCESS;
2915 PFILE_OBJECT FileObject;
2916 PIRP Irp = NULL;
2917 PDEVICE_OBJECT DeviceObject;
2918 PIO_STACK_LOCATION StackPtr;
2919 KPROCESSOR_MODE PreviousMode;
2920 BOOLEAN LocalEvent = FALSE;
2921 PKEVENT EventObject = NULL;
2922 LARGE_INTEGER CapturedByteOffset;
2923
2924 DPRINT("NtReadFile(FileHandle 0x%p Buffer 0x%p Length %x ByteOffset 0x%p, "
2925 "IoStatusBlock 0x%p)\n", FileHandle, Buffer, Length, ByteOffset,
2926 IoStatusBlock);
2927
2928 PAGED_CODE();
2929
2930 PreviousMode = KeGetPreviousMode();
2931 CapturedByteOffset.QuadPart = 0;
2932
2933 /* Validate User-Mode Buffers */
2934 if(PreviousMode != KernelMode)
2935 {
2936 _SEH_TRY
2937 {
2938 ProbeForWrite(IoStatusBlock,
2939 sizeof(IO_STATUS_BLOCK),
2940 sizeof(ULONG));
2941 ProbeForWrite(Buffer,
2942 Length,
2943 1);
2944 if (ByteOffset != NULL)
2945 {
2946 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2947 }
2948 /* FIXME - probe other pointers and capture information */
2949 }
2950 _SEH_HANDLE
2951 {
2952 Status = _SEH_GetExceptionCode();
2953 }
2954 _SEH_END;
2955
2956 if(!NT_SUCCESS(Status)) return Status;
2957 }
2958 else
2959 {
2960 if (ByteOffset != NULL)
2961 {
2962 CapturedByteOffset = *ByteOffset;
2963 }
2964 }
2965
2966 /* Get File Object */
2967 Status = ObReferenceObjectByHandle(FileHandle,
2968 FILE_READ_DATA,
2969 IoFileObjectType,
2970 PreviousMode,
2971 (PVOID*)&FileObject,
2972 NULL);
2973 if (!NT_SUCCESS(Status)) return Status;
2974
2975 /* Check the Byte Offset */
2976 if (ByteOffset == NULL ||
2977 (CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION &&
2978 CapturedByteOffset.u.HighPart == -1))
2979 {
2980 /* a valid ByteOffset is required if asynch. op. */
2981 if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
2982 {
2983 DPRINT1("NtReadFile: missing ByteOffset for asynch. op\n");
2984 ObDereferenceObject(FileObject);
2985 return STATUS_INVALID_PARAMETER;
2986 }
2987
2988 /* Use the Current Byte OFfset */
2989 CapturedByteOffset = FileObject->CurrentByteOffset;
2990 }
2991
2992 /* Check for event */
2993 if (Event)
2994 {
2995 /* Reference it */
2996 Status = ObReferenceObjectByHandle(Event,
2997 EVENT_MODIFY_STATE,
2998 ExEventObjectType,
2999 PreviousMode,
3000 (PVOID*)&EventObject,
3001 NULL);
3002 if (!NT_SUCCESS(Status))
3003 {
3004 ObDereferenceObject(FileObject);
3005 return Status;
3006 }
3007 KeClearEvent(EventObject);
3008 }
3009
3010 /* Check if this is a direct open or not */
3011 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3012 {
3013 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3014 }
3015 else
3016 {
3017 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3018 }
3019
3020 /* Check if we should use Sync IO or not */
3021 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3022 {
3023 /* Use File Object event */
3024 KeClearEvent(&FileObject->Event);
3025 }
3026 else
3027 {
3028 LocalEvent = TRUE;
3029 }
3030
3031 /* Create the IRP */
3032 _SEH_TRY
3033 {
3034 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
3035 DeviceObject,
3036 Buffer,
3037 Length,
3038 &CapturedByteOffset,
3039 EventObject,
3040 IoStatusBlock);
3041 if (Irp == NULL)
3042 {
3043 Status = STATUS_INSUFFICIENT_RESOURCES;
3044 }
3045 }
3046 _SEH_HANDLE
3047 {
3048 Status = _SEH_GetExceptionCode();
3049 }
3050 _SEH_END;
3051
3052 /* Cleanup if IRP Allocation Failed */
3053 if (!NT_SUCCESS(Status))
3054 {
3055 if (Event) ObDereferenceObject(EventObject);
3056 ObDereferenceObject(FileObject);
3057 return Status;
3058 }
3059
3060 /* Set up IRP Data */
3061 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3062 Irp->RequestorMode = PreviousMode;
3063 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
3064 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
3065 Irp->Flags |= IRP_READ_OPERATION;
3066 #if 0
3067 /* FIXME:
3068 * Vfat doesn't handle non cached files correctly.
3069 */
3070 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3071 #endif
3072
3073 /* Setup Stack Data */
3074 StackPtr = IoGetNextIrpStackLocation(Irp);
3075 StackPtr->FileObject = FileObject;
3076 StackPtr->Parameters.Read.Key = Key ? *Key : 0;
3077
3078 /* Call the Driver */
3079 Status = IoCallDriver(DeviceObject, Irp);
3080 if (Status == STATUS_PENDING)
3081 {
3082 if (!LocalEvent)
3083 {
3084 KeWaitForSingleObject(&FileObject->Event,
3085 Executive,
3086 PreviousMode,
3087 FileObject->Flags & FO_ALERTABLE_IO,
3088 NULL);
3089 Status = FileObject->FinalStatus;
3090 }
3091 }
3092
3093 /* Return the Status */
3094 return Status;
3095 }
3096
3097 /*
3098 * NAME EXPORTED
3099 * NtReadFileScatter
3100 *
3101 * DESCRIPTION
3102 *
3103 * ARGUMENTS
3104 *
3105 * RETURN VALUE
3106 *
3107 * REVISIONS
3108 */
3109 NTSTATUS
3110 STDCALL
3111 NtReadFileScatter(IN HANDLE FileHandle,
3112 IN HANDLE Event OPTIONAL,
3113 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3114 IN PVOID UserApcContext OPTIONAL,
3115 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3116 IN FILE_SEGMENT_ELEMENT BufferDescription [],
3117 IN ULONG BufferLength,
3118 IN PLARGE_INTEGER ByteOffset,
3119 IN PULONG Key OPTIONAL)
3120 {
3121 UNIMPLEMENTED;
3122 return(STATUS_NOT_IMPLEMENTED);
3123 }
3124
3125 /*
3126 * @unimplemented
3127 */
3128 NTSTATUS
3129 STDCALL
3130 NtSetEaFile(IN HANDLE FileHandle,
3131 IN PIO_STATUS_BLOCK IoStatusBlock,
3132 IN PVOID EaBuffer,
3133 IN ULONG EaBufferSize)
3134 {
3135 UNIMPLEMENTED;
3136 return STATUS_NOT_IMPLEMENTED;
3137 }
3138
3139 /*
3140 * @implemented
3141 */
3142 NTSTATUS STDCALL
3143 NtSetInformationFile(HANDLE FileHandle,
3144 PIO_STATUS_BLOCK IoStatusBlock,
3145 PVOID FileInformation,
3146 ULONG Length,
3147 FILE_INFORMATION_CLASS FileInformationClass)
3148 {
3149 OBJECT_HANDLE_INFORMATION HandleInformation;
3150 PIO_STACK_LOCATION StackPtr;
3151 PFILE_OBJECT FileObject;
3152 PDEVICE_OBJECT DeviceObject;
3153 PIRP Irp;
3154 KEVENT Event;
3155 BOOLEAN LocalEvent = FALSE;
3156 NTSTATUS Status = STATUS_SUCCESS;
3157 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
3158 BOOLEAN Failed = FALSE;
3159
3160 DPRINT("NtSetInformationFile(Handle 0x%p StatBlk 0x%p FileInfo 0x%p Length %d "
3161 "Class %d)\n", FileHandle, IoStatusBlock, FileInformation,
3162 Length, FileInformationClass);
3163
3164 if (PreviousMode != KernelMode)
3165 {
3166 _SEH_TRY
3167 {
3168 if (IoStatusBlock != NULL)
3169 {
3170 ProbeForWrite(IoStatusBlock,
3171 sizeof(IO_STATUS_BLOCK),
3172 sizeof(ULONG));
3173 }
3174
3175 if (Length != 0)
3176 {
3177 ProbeForRead(FileInformation,
3178 Length,
3179 1);
3180 }
3181 }
3182 _SEH_HANDLE
3183 {
3184 Status = _SEH_GetExceptionCode();
3185 }
3186 _SEH_END;
3187
3188 if (!NT_SUCCESS(Status))
3189 {
3190 return Status;
3191 }
3192 }
3193 else
3194 {
3195 ASSERT(IoStatusBlock != NULL);
3196 ASSERT(FileInformation != NULL);
3197 }
3198
3199 /* Get the file object from the file handle */
3200 Status = ObReferenceObjectByHandle(FileHandle,
3201 0,
3202 IoFileObjectType,
3203 PreviousMode,
3204 (PVOID *)&FileObject,
3205 &HandleInformation);
3206 if (!NT_SUCCESS(Status)) return Status;
3207
3208 /* Check information class specific access rights */
3209 switch (FileInformationClass)
3210 {
3211 case FileBasicInformation:
3212 if (!(HandleInformation.GrantedAccess & FILE_WRITE_ATTRIBUTES))
3213 Failed = TRUE;
3214 break;
3215
3216 case FileDispositionInformation:
3217 if (!(HandleInformation.GrantedAccess & DELETE))
3218 Failed = TRUE;
3219 break;
3220
3221 case FilePositionInformation:
3222 if (!(HandleInformation.GrantedAccess & (FILE_READ_DATA | FILE_WRITE_DATA)) ||
3223 !(FileObject->Flags & FO_SYNCHRONOUS_IO))
3224 Failed = TRUE;
3225 break;
3226
3227 case FileEndOfFileInformation:
3228 if (!(HandleInformation.GrantedAccess & FILE_WRITE_DATA))
3229 Failed = TRUE;
3230 break;
3231
3232 default:
3233 break;
3234 }
3235
3236 if (Failed)
3237 {
3238 DPRINT1("NtSetInformationFile() returns STATUS_ACCESS_DENIED!\n");
3239 ObDereferenceObject(FileObject);
3240 return STATUS_ACCESS_DENIED;
3241 }
3242
3243 DPRINT("FileObject 0x%p\n", FileObject);
3244
3245 if (FileInformationClass == FilePositionInformation)
3246 {
3247 if (Length < sizeof(FILE_POSITION_INFORMATION))
3248 {
3249 Status = STATUS_BUFFER_OVERFLOW;
3250 }
3251 else
3252 {
3253 _SEH_TRY
3254 {
3255 FileObject->CurrentByteOffset = ((PFILE_POSITION_INFORMATION)FileInformation)->CurrentByteOffset;
3256 IoStatusBlock->Information = 0;
3257 Status = IoStatusBlock->Status = STATUS_SUCCESS;
3258 }
3259 _SEH_HANDLE
3260 {
3261 Status = _SEH_GetExceptionCode();
3262 }
3263 _SEH_END;
3264 }
3265 ObDereferenceObject(FileObject);
3266 return Status;
3267 }
3268
3269 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
3270 /* Handle IO Completion Port quickly */
3271 if (FileInformationClass == FileCompletionInformation)
3272 {
3273 PVOID Queue;
3274 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
3275 PIO_COMPLETION_CONTEXT Context;
3276
3277 if (FileObject->Flags & FO_SYNCHRONOUS_IO || FileObject->CompletionContext != NULL)
3278 {
3279 Status = STATUS_INVALID_PARAMETER;
3280 }
3281 else
3282 {
3283 if (Length < sizeof(FILE_COMPLETION_INFORMATION))
3284 {
3285 Status = STATUS_INFO_LENGTH_MISMATCH;
3286 }
3287 else
3288 {
3289 /* Reference the Port */
3290 Status = ObReferenceObjectByHandle(CompletionInfo->Port, /* FIXME - protect with SEH! */
3291 IO_COMPLETION_MODIFY_STATE,
3292 IoCompletionType,
3293 PreviousMode,
3294 (PVOID*)&Queue,
3295 NULL);
3296 if (NT_SUCCESS(Status))
3297 {
3298 /* Allocate the Context */
3299 Context = ExAllocatePoolWithTag(PagedPool,
3300 sizeof(IO_COMPLETION_CONTEXT),
3301 TAG('I', 'o', 'C', 'p'));
3302
3303 if (Context != NULL)
3304 {
3305 /* Set the Data */
3306 Context->Key = CompletionInfo->Key; /* FIXME - protect with SEH! */
3307 Context->Port = Queue;
3308
3309 if (InterlockedCompareExchangePointer(&FileObject->CompletionContext,
3310 Context,
3311 NULL) != NULL)
3312 {
3313 /* someone else set the completion port in the
3314 meanwhile, fail */
3315 ExFreePool(Context);
3316 ObDereferenceObject(Queue);
3317 Status = STATUS_INVALID_PARAMETER;
3318 }
3319 }
3320 else
3321 {
3322 /* Dereference the Port now */
3323 ObDereferenceObject(Queue);
3324 Status = STATUS_INSUFFICIENT_RESOURCES;
3325 }
3326 }
3327 }
3328 }
3329
3330 /* Complete the I/O */
3331 ObDereferenceObject(FileObject);
3332 return Status;
3333 }
3334
3335 /* Check if this is a direct open or not */
3336 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3337 {
3338 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3339 }
3340 else
3341 {
3342 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3343 }
3344
3345 /* Check if we should use Sync IO or not */
3346 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3347 {
3348 /* Use File Object event */
3349 KeClearEvent(&FileObject->Event);
3350 }
3351 else
3352 {
3353 /* Use local event */
3354 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
3355 LocalEvent = TRUE;
3356 }
3357
3358 /* Allocate the IRP */
3359 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
3360 {
3361 ObDereferenceObject(FileObject);
3362 return STATUS_INSUFFICIENT_RESOURCES;
3363 }
3364
3365 /* Allocate the System Buffer */
3366 if (!(Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
3367 Length,
3368 TAG_SYSB)))
3369 {
3370 Status = STATUS_INSUFFICIENT_RESOURCES;
3371 goto failfreeirp;
3372 }
3373
3374 /* Copy the data inside */
3375 if (PreviousMode != KernelMode)
3376 {
3377 _SEH_TRY
3378 {
3379 /* no need to probe again */
3380 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
3381 FileInformation,
3382 Length);
3383 }
3384 _SEH_HANDLE
3385 {
3386 Status = _SEH_GetExceptionCode();
3387 }
3388 _SEH_END;
3389
3390 if (!NT_SUCCESS(Status))
3391 {
3392 ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer,
3393 TAG_SYSB);
3394 Irp->AssociatedIrp.SystemBuffer = NULL;
3395 failfreeirp:
3396 IoFreeIrp(Irp);
3397 ObDereferenceObject(FileObject);
3398 return Status;
3399 }
3400 }
3401 else
3402 {
3403 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
3404 FileInformation,
3405 Length);
3406 }
3407
3408 /* Set up the IRP */
3409 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3410 Irp->RequestorMode = PreviousMode;
3411 Irp->UserIosb = IoStatusBlock;
3412 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
3413 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3414 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
3415 Irp->Flags |= (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3416
3417 /* Set up Stack Data */
3418 StackPtr = IoGetNextIrpStackLocation(Irp);
3419 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
3420 StackPtr->FileObject = FileObject;
3421
3422 /* Set the Parameters */
3423 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
3424 StackPtr->Parameters.SetFile.Length = Length;
3425
3426 /* Call the Driver */
3427 Status = IoCallDriver(DeviceObject, Irp);
3428 if (Status == STATUS_PENDING)
3429 {
3430 if (LocalEvent)
3431 {
3432 KeWaitForSingleObject(&Event,
3433 Executive,
3434 PreviousMode,
3435 FileObject->Flags & FO_ALERTABLE_IO,
3436 NULL);
3437 _SEH_TRY
3438 {
3439 Status = IoStatusBlock->Status;
3440 }
3441 _SEH_HANDLE
3442 {
3443 Status = _SEH_GetExceptionCode();
3444 }
3445 _SEH_END;
3446 }
3447 else
3448 {
3449 KeWaitForSingleObject(&FileObject->Event,
3450 Executive,
3451 PreviousMode,
3452 FileObject->Flags & FO_ALERTABLE_IO,
3453 NULL);
3454 _SEH_TRY
3455 {
3456 Status = FileObject->FinalStatus;
3457 }
3458 _SEH_HANDLE
3459 {
3460 Status = _SEH_GetExceptionCode();
3461 }
3462 _SEH_END;
3463 }
3464 }
3465
3466 /* Return the Status */
3467 return Status;
3468 }
3469
3470 /*
3471 * @unimplemented
3472 */
3473 NTSTATUS
3474 STDCALL
3475 NtSetQuotaInformationFile(HANDLE FileHandle,
3476 PIO_STATUS_BLOCK IoStatusBlock,
3477 PVOID Buffer,
3478 ULONG BufferLength)
3479 {
3480 UNIMPLEMENTED;
3481 return STATUS_NOT_IMPLEMENTED;
3482 }
3483
3484 /*
3485 * @unimplemented
3486 */
3487 NTSTATUS
3488 STDCALL
3489 NtUnlockFile(IN HANDLE FileHandle,
3490 OUT PIO_STATUS_BLOCK IoStatusBlock,
3491 IN PLARGE_INTEGER ByteOffset,
3492 IN PLARGE_INTEGER Length,
3493 IN ULONG Key OPTIONAL)
3494 {
3495 PFILE_OBJECT FileObject = NULL;
3496 PLARGE_INTEGER LocalLength = NULL;
3497 PIRP Irp = NULL;
3498 PIO_STACK_LOCATION StackPtr;
3499 PDEVICE_OBJECT DeviceObject;
3500 KEVENT Event;
3501 BOOLEAN LocalEvent = FALSE;
3502 KPROCESSOR_MODE PreviousMode;
3503 NTSTATUS Status = STATUS_SUCCESS;
3504 LARGE_INTEGER CapturedByteOffset, CapturedLength;
3505 OBJECT_HANDLE_INFORMATION HandleInformation;
3506
3507 PAGED_CODE();
3508
3509 PreviousMode = KeGetPreviousMode();
3510
3511 CapturedByteOffset.QuadPart = 0;
3512 CapturedLength.QuadPart = 0;
3513
3514 /* Get File Object */
3515 Status = ObReferenceObjectByHandle(FileHandle,
3516 0,
3517 IoFileObjectType,
3518 PreviousMode,
3519 (PVOID*)&FileObject,
3520 &HandleInformation);
3521 if (!NT_SUCCESS(Status)) return Status;
3522
3523 if (PreviousMode != KernelMode)
3524 {
3525 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access unless we're
3526 in KernelMode! */
3527 if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
3528 {
3529 DPRINT1("Invalid access rights\n");
3530 ObDereferenceObject(FileObject);
3531 return STATUS_ACCESS_DENIED;
3532 }
3533
3534 _SEH_TRY
3535 {
3536 ProbeForWrite(IoStatusBlock,
3537 sizeof(IO_STATUS_BLOCK),
3538 sizeof(ULONG));
3539 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3540 CapturedLength = ProbeForReadLargeInteger(Length);
3541 }
3542 _SEH_HANDLE
3543 {
3544 Status = _SEH_GetExceptionCode();
3545 }
3546 _SEH_END;
3547
3548 if (!NT_SUCCESS(Status))
3549 {
3550 ObDereferenceObject(FileObject);
3551 return Status;
3552 }
3553 }
3554 else
3555 {