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