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