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