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