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