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