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